Ich bin schier am Verzweifeln:
Ich bastle immer noch (oder immer wieder) an Softwaremodulen für STM8
unter SDCC (weil Linux).
So... war ich am Anfang noch freudig überrascht dass das relativ einfach
funktionierte, wächst nun der Frust und ich glaube SDCC ist dafür
verantwortlich.
Ich kann schwierig an Codebeispielen erklären was nicht so recht
funktioniert, aber mich beschleicht langsam das Gefühl, dass die RAM und
Stack - Verwaltung des SDCC's in Verbindung mit STM8 buggy ist.
Schreibe ich eine Codesequenz, die funktioniert und lagere ich diese in
eine Funktion aus, funktioniert sie plötzlich nicht mehr (obwohl ich sie
mittels Copy und Paste aus meiner eigenen Main dorthin verfrachtet hab.)
Ich weiß sehr wohl, dass ein Funktionsaufruf den Stack belastet.
Erweitere ich ein Programm, bleibt manchmal dieses weit vor Erreichen
des neuen Programmteils hängen. Dann funktioniert manchmal ein
1 | volatile char dummy;
|
2 |
|
3 | dummy= 5;
|
4 | dummy= dummy;
|
oder ähnlicher nutzloser Programmcode, der nichts sinnvolles ausführt,
vor einem neuen Programmteil und der Code funktioniert wieder.
Ich habe mittlerweile Codeanalyse der erzeugten ASM und MAP-Dateien
betrieben und durchschaue einiges, aber nicht alles.
Am Schlimmsten ist wohl, dass ich nirgendwo, das Ende des Stacks
initalisieren kann und ich (ich bin wieder am Lesen des Datenblatts)
schlicht davon ausgehe, dass der Stackpointer auf das Ende des RAMS nach
dem Einschalten liegt.
Im Datenblatt steht:
In the default stack model this pointer is initialized to the
RAM end address.
Sind die Resetwerte der STM8 - Serie tatsächlich so, dass der
Stackpointer auf das Ende des Rams zeigt und mit Verwendung dem
RAM-Anfang (in dem Variable abgelegt sind) entgegen wächst?
Kann ich mich darauf verlassen ... oder liegt mein Fehler irgendwo
anderst in bspw. der Initialisierung?
1 | /* ------------------------------------------------------
|
2 | sysclock_init
|
3 | stellt den Taktgeber fuer den Controller ein.
|
4 | Bei Verwendung des internen Oszillators werden
|
5 | 16MHz eingestellt
|
6 |
|
7 | (Xtal enable) xtalen = 1 => externer Quarz
|
8 | = 0 => interner RC-Oszillator
|
9 |
|
10 | Anmerkung:
|
11 | soll der MCU mit externem Quarz laufen, ist
|
12 | zuerst ein Aufruf
|
13 |
|
14 | sysclock_init(0);
|
15 |
|
16 | gefolgt von einem Aufruf
|
17 |
|
18 | sysclock_init(1);
|
19 |
|
20 | zu erfolgen !
|
21 | ------------------------------------------------------ */
|
22 | void sysclock_init(char xtalen)
|
23 | {
|
24 | if (xtalen)
|
25 | {
|
26 | CLK_ICKR = 0; // Reset Register interner clock
|
27 | CLK_ECKR = HSEEN;
|
28 |
|
29 | while ((CLK_ECKR & HSERDY) == 0); // warten bis Quarz eingeschwungen ist;
|
30 |
|
31 | CLK_SWR = 0xb4; // int. Generator als Taktquelle
|
32 | CLK_SWCR = SWEN; // Enable switching.
|
33 |
|
34 | CLK_CKDIVR = 0; // Taktteiler auf volle Geschwindigkeit
|
35 | CLK_PCKENR1 = 0xff; // alle Peripherietakte an
|
36 | CLK_PCKENR2 = 0xff; // dto.
|
37 | }
|
38 | else
|
39 | {
|
40 | CLK_ICKR = 0; // Reset Register interner clock
|
41 | CLK_ECKR = 0; // Reset Register externer clock (ext. clock disable)
|
42 |
|
43 | CLK_ICKR = HSIEN; // Interner clock enable
|
44 | while ((CLK_ICKR & (HSIRDY)) == 0); // warten bis int. Takt eingeschwungen ist
|
45 |
|
46 |
|
47 | CLK_CKDIVR = 0; // Taktteiler auf volle Geschwindigkeit
|
48 | CLK_PCKENR1 = 0xff; // alle Peripherietakte an
|
49 | CLK_PCKENR2 = 0xff; // dto.
|
50 |
|
51 | CLK_CCOR = 0; // CCO aus
|
52 | CLK_HSITRIMR = 0; // keine Taktjustierung
|
53 | CLK_SWIMCCR = 0; // SWIM = clock / 2.
|
54 | CLK_SWR = 0xe1; // int. Generator als Taktquelle
|
55 | CLK_SWCR = 0; // Reset clock switch control register.
|
56 | CLK_SWCR = SWEN; // Enable switching.
|
57 | while ((CLK_SWCR & SWBSY) != 0); // warten bis Peripherietakt stabil
|
58 | }
|
59 | }
|
Das war bisher meine Initialisierung (es werden keine anderen
Initialisierungen vorgenommen) und hat bei den bisherigen kurzen
Programmen (mit wenig RAM - Verwendung und ca. 5 Stackebenen) auch gut
funktioniert, aber schön langsam ist der Wurm drin ...
Kann man an den RAM Einstellungen in Verbindung mit STM8 etwas
einstellen?
In meiner Not bin ich sogar hergegangen, hab (im jetzigen Programm) das
Hardware I2C absichtlich nicht verwendet, eine softe I2C -
Implementierung geschrieben und das ganze Programm so geschrieben, dass
es bis auf das Bitbanging der Ports und das Initialisieren eines Timers
identisch für einen AT89S52 ist ... und siehe da, auf diesem MCU macht
der SDCC keine Mucken, nur für den STM8.
Der Timerinterrupt verwendet keine 16-Bit Variable, nur uint8_t Typen
(weil ich mir erst überlegte, ob ein Interrupt mir vllt. zwischen einer
soften 16-Bit Rechenoperation dazwischen spuckt und nach dem Interrupt
die Register nicht mehr ihre Inhalte aufweisen).
Hey, ihr könnt mir gerne die Rübe abhauen ... aber bitte von
Beleidigungen abstand nehmen.
Die Dinge hab ich für MCS-51, für AVR und (nach langer Kleinarbeit) auch
für STM32 und LPC hinbekommen ...
Weiß irgendjemand etwas über Bugs vom SDCC ganz im Speziellen mit der
Speicherverwaltung ?