Hallo zusammen,
ich nutze einen STM32F103 mit einem EEPROM 24C02 am I2C-Bus, um den
Flash etwas zu schonen. Der I2C läuft mit 400kHz auf 5V mit Pull-Ups von
momentan 1kOhm.
Ich habe vier Testroutinen geschrieben:
void eeprom_test_read(void)
void eeprom_test_write(void)
void eeprom_test_read_block(void)
void eeprom_test_write_block(void),
die das EEPROM jeweils komplett auslesen b.z.w. beschreiben, einmal
byteweise, einmal pageweise b.z.w. alles hintereinander.
Das Beschreiben des EEPROMs klappt immer, sei es Block- oder byteweise.
Das Lesen schlägt oft fehl, es sei denn, der I2C-Sniffer von Peter
Dannegger (Beitrag "I2C (TWI) Sniffer mit AVR") ist
angeschlossen, wobei es egal ist, ob direkt oder über Potenzialtrennung
mittels ADUM 1250.
Die Pull-up-Widerstände habe ich zwischen 4k7 und 1k0 variiert- das
Oszillogramm wird zwar schöner, aber die Funktion wird nur über das
Vorhanden- und Nichtvorhandensein der Bus-Sniffers entschieden.
Der Fehler äußert sich immer mit dem Status 0x64, also z.B. in
eeprom_read_byte wird in Zeile 69 die Routine I2C_read_nack mit einem
Timeout abgebrochen (I2C_NORMALTIMEOUT, hier 300 Millisekunden).
Der Fehler tritt auch nur bei 400kHz (eingestelltem) I2C-Takt auf, bei
100kHz läuft alles einwandfrei, wobei der EEPROM auch für 400kHz
spezifiziert ist.
Die I2C-Routinen sind größtenteils von
http://eliaselectronics.com/stm32f4-tutorials/stm32f4-i2c-master-tutorial/
abgekupfert, wobei nur ein wenig Fehlerhandling hinzugekommen ist und
das Warten auf das Busyflag vor dem Senden der Startbedingung
ausgelagert wurde.
"printf_P" und "PSTR" sind nur definiert, um Kompatibilität mit einem
AVR zu behalten und sind definiert als:
1
#define PSTR(a) (a)
2
#define printf_P printf
. Die Funktion key_getstroke() wartet auf einen Tastendruck, um mir eine
Chance zu geben, das Display abzulesen.
Warum kann das EEPROM nur ausgelesen werden, wenn der I2C-Sniffer
angeschlossen ist?
Und warum liefert ein mit 400kHz initialisierter I2C einen realen Takt
von 420kHz und ist das für mein Problem relevant?
Viele Grüße
W.T.
> Und warum liefert ein mit 400kHz initialisierter I2C einen realen Takt> von 420kHz und ist das für mein Problem relevant?
Wahrscheinlich stimmt dein Prescaler nicht.
Da I2C synchron ist sollte das eigentliche Timing nicht so relevant
sein.
Was ich mir aber vorstellen könnte ist, dass das EEPROM nur auf 400kHz
spezifiziert ist. Leider schreibst du nicht was für eins du verwendest.
Schon mal den Takt etwas runter genommen?
Jetzt geht alles.
Der Unterschied 420kHz zu 400kHz war wohl tatsächlich relevant. Ursache
des Problems war eine kleine Lötperle, die einen Pin des
Quarzoszillators gegen seinen Nachbarn kurzgeschlossen hat, so daß der
STM32F103 klammheimlich auf seinen internen Oszillator umgeschaltet hat.
Danke fürs Lesen
W.T.
Jetzt komme ich nach ein paar Wochen wieder dazu, mit dem I2C
weiterzumachen. Es ist doch noch nicht so alles Gold, was glänzt.
Aus irgendeinem Grund muß ich die Initialisierung (init_I2C1()) immer
zweimal durchführen (nach einem normalen Reset, kein Power cycle nötig);
nach dem ersten Mal wird noch nicht einmal die Start-Bedingung auf den
Bus gesendet; nach dem zweiten Mal geht sofort alles glatt.
Mit zweimal aufrufen meine ich auch unmittelbar doppelt, kein Warten:
1
uint8_tbyte;
2
3
init_I2C1();// initialize I2C peripheral
4
init_I2C1();
5
6
status=eeprom_read_byte(0,&byte);
funktioniert unmittelbar, die "Variante"
1
uint8_tbyte;
2
3
init_I2C1();// initialize I2C peripheral
4
5
status=eeprom_read_byte(0,&byte);
funktioniert immer erst beim zweiten Versuch; beim ersten Versuch wird
nichts auf den Bus geschickt.
Die Initialisierungsroutine entspricht eigentlich fast genau dem
obengenannten Tutorial. Zur Übersicht habe ich sie noch einmal
angehängt.
1
#define STM32F10x
2
voidinit_I2C1(void){
3
4
GPIO_InitTypeDefGPIO_InitStruct;
5
I2C_InitTypeDefI2C_InitStruct;
6
7
#ifdef STM32F10x
8
// enable APB1 peripheral clock for I2C1, SCL and SDA pins