Kann sich jemand den Code ansehen ? Sind meine EEPROM-Routinen
grundsätzlich korrekt? Ich habe vorsichtshalber auch Flags getestet,
die eigentlich egal sein müssten.
Ich habe das Problem, dass nach einem(absichtlichen) Watchdog-Reset der
nächste EEPROM - Schreibzugriff nach dem Reset zu einem kompletten Core
- Lockup führt.
Manchmal passiert das nicht, wenn etwas über die UART herausgesendet
wird.
Normale Schreibzugriffe (vor dem Watchdog-Reset) auf das EEPROM
funktionieren problemlos.
Was ich bereits probiert habe:
- sim()/rim() damit während der Schreibvorgangs kein Interrupt auftritt
- Ca. 10 NOPs nach jedem geschriebenen Byte
- Prüfen des HV-Flags, was bei STM8 Low-Density nicht nötig sein sollte
- Prüfen, ob das EEPROM nicht schreibgeschützt ist, bevor ich die
MASS-Keys schreibe (was auch nicht notwendig sein sollte)
- Die CPU-Taktfrequenz vor dem Reset heruntersetzen
(es gibt ein Erratum im Bezug auf Halt-State und Flash-Zugriffe)
Mein Code macht folgendes:
(UART-RX und Timer-Interrupts Aktiv)
1. Flag-Byte im EEPROM setzen. Das funktioniert
2. Absichtlichen WDT-Reset erzeugen
3. Nach Reboot das Flag prüfen
4. Das Flag resetten -> Hier passiert es.
Auch ohne sim() gibt es einen kompletten CPU-Lockup, denn auch auf
externe Interrupts wird nicht reagiert (für jedes UART-Byte wird eine
Board-LED angeschalten und nach 1s durch den Timer, der auch für
Timeouts zuständig ist, abgeschalten).
1 | unsigned char eeprom_peek(unsigned char offset)
|
2 | {
|
3 | unsigned char *eeprom = 0x4000 + (unsigned char *)offset;
|
4 | return *eeprom;
|
5 | }
|
6 |
|
7 | void eeprom_poke(unsigned char data, unsigned char offset)
|
8 | {
|
9 | volatile unsigned char *eeprom = 0x4000 + (unsigned char *)offset;
|
10 | sim(); // Is this needed?
|
11 | // Unlock EEPROM
|
12 | if (!(FLASH_IAPSR & (1 << 3))) // Check should not be needed?
|
13 | {
|
14 | FLASH_DUKR = 0xAE; // First MASS key
|
15 | FLASH_DUKR = 0x56; // Second MASS key
|
16 | while (!(FLASH_IAPSR & (1 << 3))); // Wait for EEPROM to unlock
|
17 | }
|
18 | *eeprom = data;
|
19 | while (!(FLASH_IAPSR & (1 << 6))); // Wait for EEPROM to finish, is it needed?
|
20 | // Is this needed on Low-Density STM8 ?!
|
21 |
|
22 | FLASH_IAPSR &= ~(1 << 3); // Relock EEPROM
|
23 | rim(); // Is this needed?
|
24 | }
|
25 |
|
26 | void eeprom_write(unsigned char * data, unsigned char offset, unsigned char size)
|
27 | {
|
28 | volatile unsigned char *eeprom = 0x4000 + (unsigned char *)offset;
|
29 | sim(); // Is this needed?
|
30 | // Unlock EEPROM
|
31 | if (!(FLASH_IAPSR & (1 << 3))) // Check should not be needed?
|
32 | {
|
33 | FLASH_DUKR = 0xAE; // First MASS key
|
34 | FLASH_DUKR = 0x56; // Second MASS key
|
35 | while (!(FLASH_IAPSR & (1 << 3))); // Wait for EEPROM to unlock
|
36 | }
|
37 |
|
38 | while (size--)
|
39 | {
|
40 | *eeprom++ = *data++;
|
41 | while (!(FLASH_IAPSR & (1 << 6))); // Wait for EEPROM to finish, is it needed?
|
42 | }
|
43 |
|
44 | FLASH_IAPSR &= ~(1 << 3); // Relock EEPROM
|
45 | rim(); // Is this needed?
|
46 | }
|
47 |
|
48 | void eeprom_read(unsigned char * data, unsigned char offset, unsigned char size)
|
49 | {
|
50 | volatile unsigned char * eeprom = 0x4000 + (unsigned char * ) offset;
|
51 | while (size--)
|
52 | *data++ = *eeprom++;
|
53 | }
|
54 |
|
55 | unsigned char eeprom_compare(unsigned char * data, unsigned char offset, unsigned char size)
|
56 | {
|
57 | volatile unsigned char *eeprom = 0x4000 + (unsigned char *)offset;
|
58 |
|
59 | while (size--)
|
60 | if ( *data++ != *eeprom++)
|
61 | return 0;
|
62 |
|
63 | return 1;
|
64 | }
|
All das hat nichts gebracht, ich habe es zurückgeführt auf den
Watchdog-Reset - nur dann tritt dieses Problem auf.
Wenn ich statt dem absichtlichen Watchdog-Softreset:
1 | CLK_CKDIVR = 0x06;
|
2 | IWDG_KR = 0xCC; // Start the independent watchdog.
|
3 | IWDG_KR = 0x55; // Allow the IWDG registers to be programmed.
|
4 | IWDG_PR = 0x06; // Prescaler is 2 => each count is 250uS
|
5 | IWDG_KR = 0xAA; // Reset the counter.
|
6 | while(1);
|
einen Sprung an den Reset-Vektor mache:
tritt das Problem nicht mehr auf, der Code funktioniert perfekt in der
Applikation.
Nun habe ich einen Testbench-Code (eeprom.c) geschrieben um das
Verhalten zu replizieren, und siehe da: Es tritt nicht mehr auf!
Meine Vermutung ist zum derzeitigen Stand: Es hat irgendwas mit
Interrupts zu tun oder es ist ein Silicon-Bug, denn der Testbench-Code
verwendet keine Interrupts, meine Applikation jedoch UART-RX und
Timer-Interrupts. Ich schalte jedoch explizit auch die Interrupts ab
um eventuellen Problemen vorzubeugen.
Weiss einer der STM8/SDCC Gurus (SDCC Maintainer) weiter?
Hab ich etwas nicht beachtet?