Forum: Mikrocontroller und Digitale Elektronik STM32: Fehlersuche I2C EPPROM


von Michl (Gast)


Lesenswert?

Hallo zusammen,

ich bin wieder einmal ratlos beim Schreiben (u. Lesen eines 24C256 I2C 
EEPROMS an einem STM32F103)

Stand:
Epr_WriteBuffer funktioniert mit Array von Länge 52Byte
Epr_ReadBuffer funktioniert mit Array von Länge 52Byte

StoreCalibrationValues()schrieb ehemals 20Byte (mittels Wpr_WriteBuffer) 
in das EEPROM (bei altem Projekt, und hat funktioniert)

nun schreibt diese Funktion 52 Byte in das EEPROM.
Aber wenn ich einmal diese Funktion aufrufe und versuche diese Werte (zu 
schreiben) löst er einen Error aus weil er das nicht schreiben kann.

Das für mich unverständliche ist:
Nach dem einmaligen Misserfolg dieser Funktion ist das EEPROM absolut 
nicht mehr ansprechbar. Selbst rein mit der Funktion Epr_WriteBuffer 
(die vorher funktionierte) hängt sich der Controller auf, auch wenn die 
"schadhafte" funktion auskommentiert wurde. Es scheint also als hätte 
ich mit dieser Funktion das EEPROM "zerschossen"... Der Einbau eines 
neuen Speichers hat zur Folge dass dieser mti der Epr_WriteBuffer wieder 
funktioniert... solange bis die schadhafte Funktion verwendet wird.

Spg. abschalten, neu flashen (und damit epr neu initialisieren) bringt 
keine Abhilfe, nur umlöten...

Also an welcher Stelle überhaupt kann sich der Zustand der Fehlerhaften 
Übertragung "gemerkt" werden, dass eine Kommunikation danach unmöglich 
ist?!

in main zum debuggen:
1
    //Debug: Test if EEPROM is write and readable: was successful
2
    uint8_t wBuffer[30];
3
    uint8_t rBuffer[30];
4
    wBuffer[0]=6;
5
    wBuffer[1]=6;
6
    uint8_t i ;
7
8
    if(Epr_WriteBuffer(wBuffer, 102, 52) == ERROR)
9
       EH_SetErrorCode(ERR_EEPROM);
10
11
    if(Epr_ReadBuffer(rBuffer, 102, 52) == ERROR)
12
       EH_SetErrorCode(ERR_EEPROM);
13
14
    uint8_t test = 0;
15
16
    test = rBuffer[1] + 4;
17
    rBuffer[0]++;
18
19
    /*////////////////////////////////////
20
    CalibrationTemp.fNominalLow = 10.0;
21
    for (i=0; i<24 ;i++){
22
      CalibrationTemp.fZoneLow[i] = 11.1;
23
    }
24
    CalibrationTemp.fLidLow = 11.5;
25
    //***********************************
26
    CalibrationTemp.fNominalHigh = 90.0;
27
    for (i=0; i<24 ;i++){
28
      CalibrationTemp.fZoneLow[i] = 88.8;
29
    }
30
    CalibrationTemp.fLidLow = 92.0;
31
    //////////////////////////////////////
32
    StoreCalibrationValues();
33
  if(ReadCalibrationValues() == ERROR)
34
  {
35
    EH_SetErrorCode(ERR_EEPROM);
36
  }
37
  CalibrationTemp.fLidHigh = CalibrationTemp.fLidHigh + 3.0;
38
  test = CalibrationTemp.fLidHigh;
39
  */

"schadhafte funktion: StoreCalibrationValues":
1
void StoreCalibrationValues(void)
2
{
3
  uint8_t nBuffer[52];
4
  uint8_t i, j;
5
  uint16_t nTmpVal;
6
7
  FncDispEnable(false);           // disable periodically function dispatcher
8
9
  //-----------------------------------------------------------------------------------
10
  // mark this block as calibrated or not as not calibrated -> store this information within CALIBRATION_STATUS section of EEPROM
11
  //-----------------------------------------------------------------------------------
12
  if (CalibrationTemp.fNominalLow == 0.0)
13
  {
14
    // by define a nominal low calibration point of 0.0 degree Celsius will mark this block as not calibrated
15
    nBuffer[0] = 0x00;
16
    nBuffer[1] = 0xFF;
17
    nBuffer[2] = 0x00;
18
  }
19
  else
20
  {
21
    // mark this block as calibrated
22
    nBuffer[0] = 0xA5;
23
    nBuffer[1] = 0x00;
24
    nBuffer[2] = 0x5A;
25
  }
26
  // write unique pattern to EEPROM to detect read / write access problems as well
27
  if(Epr_WriteBuffer(nBuffer, CALIB_STATUS_ADDRESS, 3) == ERROR)
28
     EH_SetErrorCode(ERR_EEPROM);
29
30
31
  //-----------------------------------------------------------------------------------
32
  // write calibration values for lower calibration point to EEPROM
33
  //-----------------------------------------------------------------------------------
34
35
  // clear temporary buffer
36
  // was 20 for (1+8+1)*2, for dlx (1+24+1)*2
37
  for (i=0; i<52; i++)
38
    nBuffer[i] = 0;
39
40
  // fill write buffer -> multiply values by 100 to store values including tenth and hundredth rank as integer and split them into two bytes
41
  i = 0;
42
  nTmpVal = (uint16_t)(CalibrationTemp.fNominalLow * 100.0);
43
  nBuffer[i++] = (nTmpVal & 0xFF00) >> 8;     // high byte
44
  nBuffer[i++] = nTmpVal & 0x00FF;            // low byte
45
46
  //AM: TODO: j max is changed from 8 to 24 channels for dlx
47
  for(j = 0; j < 24; j++)
48
  {
49
    nTmpVal =(uint16_t)(CalibrationTemp.fZoneLow[j] * 100.0);
50
    nBuffer[i++] = (nTmpVal & 0xFF00) >> 8;
51
    nBuffer[i++] = nTmpVal & 0x00FF;
52
  }
53
54
  nTmpVal =(uint16_t)(CalibrationTemp.fLidLow * 100.0);
55
  nBuffer[i++] = (nTmpVal & 0xFF00) >> 8;
56
  nBuffer[i++] = nTmpVal & 0x00FF;
57
58
  // write buffer to EEPROM
59
  if(Epr_WriteBuffer(nBuffer, CALIB_LOW_ADDRESS, 52) == ERROR)
60
     EH_SetErrorCode(ERR_EEPROM);
61
62
  //-----------------------------------------------------------------------------------
63
  // write calibration values for upper calibration point to EEPROM
64
  //-----------------------------------------------------------------------------------
65
66
  // clear temporary buffer
67
  for (i=0; i<52; i++)
68
    nBuffer[i] = 0;
69
70
  // fill write buffer -> multiply values by 100 to store values including tenth and hundredth rank as integer
71
  i = 0;
72
  nTmpVal =(uint16_t)(CalibrationTemp.fNominalHigh * 100.0);
73
  nBuffer[i++] = (nTmpVal & 0xFF00) >> 8;       // high byte
74
  nBuffer[i++] = nTmpVal & 0x00FF;              // low byte
75
76
  for(j = 0; j < 24; j++)
77
  {
78
    nTmpVal =(uint16_t)(CalibrationTemp.fZoneHigh[j] * 100.0);
79
    nBuffer[i++] = (nTmpVal & 0xFF00) >> 8;
80
    nBuffer[i++] = nTmpVal & 0x00FF;
81
  }
82
83
  nTmpVal =(uint16_t)(CalibrationTemp.fLidHigh * 100.0);
84
  nBuffer[i++] = (nTmpVal & 0xFF00) >> 8;
85
  nBuffer[i++] = nTmpVal & 0x00FF;
86
87
  // write buffer to EEPROM
88
  if(Epr_WriteBuffer(nBuffer, CALIB_HIGH_ADDRESS, 52) == ERROR)
89
     EH_SetErrorCode(ERR_EEPROM);
90
91
  FncDispEnable(true);                          // enable periodically function dispatcher
92
}

Wäre super wenn mal jemand drüber schauen könnte, bzw. grundsätzlich 
etwas dazu sagen könnte warum das EEPROM danach mit vorher 
funktionierenden Funktion nun nicht mehr ansprechbar is.
Danke!

von Krapao (Gast)


Lesenswert?

> Epr_WriteBuffer()
> Epr_ReadBuffer()

Gibt es zu diesen Low-Level-Funktionen eine Doku oder Sourcecode?

Dort würde ich in Verbindung mit dem Datenblatt des 24C256 I2C
EEPROMS kontrollieren, ob die Funktionsparameter korrekt sind und ob die 
Funktion selbst wartet, bis das EEPROM nach einem Zugriff wieder 
ansprechbar ist oder ob das der Anwendercode machen muss.

von Steel (Gast)


Lesenswert?

Sicher dass die Lowlevel-Funktionen mit 52 Byte funktionieren? Mich 
dünket dass nur Happen von 32 Byte auf einmal geschrieben werden können. 
Das müssen die berücksichtigen.

von Krapao (Gast)


Lesenswert?

>    uint8_t wBuffer[30];
>    uint8_t rBuffer[30];
>    ...
>    if(Epr_WriteBuffer(wBuffer, 102, 52) == ERROR)
>       EH_SetErrorCode(ERR_EEPROM);
>
>    if(Epr_ReadBuffer(rBuffer, 102, 52) == ERROR)
>       EH_SetErrorCode(ERR_EEPROM);

Du hast da übrigens in main() einen Bufferoverflow (30 Platz im Array 
aber 52 schreiben/lesen). Der Read-Aufruf zerstört dann deinen Stack!

von Mike R. (thesealion)


Lesenswert?

Michl schrieb:
>
1
>     if(Epr_WriteBuffer(wBuffer, 102, 52) == ERROR)
2
>        EH_SetErrorCode(ERR_EEPROM);
3
>

Wenn die 102 die Adresse im EEPROM sein soll, dann geht dein 
Schreibvorgang sicher über mehrere Pages (die 20 Byte taten das nicht). 
Hier muss also die Schreibroutine entsprechend ausgelegt sein.

Das das EEPROM komplett nicht mehr funktioniert glaube ich nicht, ich 
würde eher annehmen, das die danach daraus gelesen Daten ungültig sind 
und damit das Programm "aufhängen".

Das solltest du einfach verifizieren können, wenn du dir das schreiben 
und lesen mit einem Scope ansiehst. Ansonsten einfach mal ein nicht 
funktionierendes EEPROM bei Byte schrieben mit 0xFF füllen, ich möchte 
fast wetten, dass es dann wieder richtig funktioniert.

von Michl (Gast)


Lesenswert?

Zu dem overflow das arrays, jetzt wird nämlich komisch:

mit genau diesem sourcecode hat die übertragung funktioniert.
Den Fehler habe ich kurz darauf auch festgestellt und oben als Größe des 
Arrays die 52 angegeben.
(im Aufruf der Schreib-funktion blieb natürlich die 52)

Ab genau diesem Zeitpunkt (Änderung Deklaration von 30 auf 52 Bytes)hat 
die Übertragung nicht mehr funktioniert, und ist immer hängen geblieben 
in dieser Routine:

Epr_WaitStandbyState();
1
ErrorStatus Epr_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite)
2
{
3
  uint16_t nAddr, nPage, nCount, nNumOfBytes;
4
  ErrorStatus status = ERROR;
5
6
  nAddr = WriteAddr;
7
  nPage = 0;
8
  nCount = 0;
9
  nNumOfBytes = 0;
10
11
  while (NumByteToWrite > 0)
12
  {
13
    // get page where to write to
14
    nPage  = nAddr / I2C_PAGE_SIZE;
15
16
    // get number of bytes which can be written to this page
17
    nNumOfBytes = ((nPage + 1) * I2C_PAGE_SIZE) - nAddr;
18
19
    // if there are more bytes to write than remaining space in this page -> fill up this page completely
20
    if(NumByteToWrite > nNumOfBytes)
21
      nCount = nNumOfBytes;
22
    else
23
      nCount = NumByteToWrite;
24
25
    // write data to EEPROM
26
    status = Epr_WritePage(pBuffer, nAddr, nCount);
27
    Epr_WaitStandbyState();
28
29
    // update variables
30
    NumByteToWrite -= nCount;
31
    nAddr += nCount;
32
    pBuffer += nCount;
33
  }
34
35
  return status;

und in dieser Routine bleibt er in

while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
1
void Epr_WaitStandbyState(void)
2
{
3
  __IO uint16_t SR1_Tmp = 0;
4
5
  do
6
  {
7
    /* Send START condition */
8
    I2C_GenerateSTART(I2C1, ENABLE);
9
    /* Read I2C1 SR1 register */
10
    SR1_Tmp = I2C_ReadRegister(I2C1, I2C_Register_SR1);
11
    /* Send EEPROM address for write */
12
    I2C_Send7bitAddress(I2C1, EEPROM_ADDRESS, I2C_Direction_Transmitter);
13
  }
14
  //while(0);
15
  while(!(I2C_ReadRegister(I2C1, I2C_Register_SR1) & 0x0002));
16
17
  /* Clear AF flag */
18
  I2C_ClearFlag(I2C1, I2C_FLAG_AF);
19
20
  /* STOP condition */
21
  I2C_GenerateSTOP(I2C1, ENABLE);
22
}

die I2C_ReadRegister Routine gibt den Wert 1073763348 d gecastet auf 16 
bit zurück. Das ist klar dass er hier stehen bleibt denn der o.g. 
Rückgabewert hat als letzte 4 Stellen binär die 0100. Aber ich bräuchte 
hier die 1 an vorletzter Stelle um weiter zu gehen.

Kommentiere ich das aus und schreibe ->
do
while (0)

hängt er sich dort natürlich nicht mehr auf und liest den Speicher ... 
allerdings is das natürlich sehr sehr "dirty"

von Mike R. (thesealion)


Lesenswert?

Das klingt dann danach das das I2C Interface nach einem Fehler (und das 
Epr_WaitStandbyState() erzeugt einen Menge davon :) nicht korrekt 
resettet wird und deshalb keine neue Start-Condition mehr generiert 
wird.

Zeigt mal die Write Page Routine, die Initialisierung der Schnittstelle 
und ob/welche I2C Interrupts aktiviert sind.

P.S. das Hardware I2C interface der STM32 ist einfach schrecklich ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.