www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem mit EEPROM 24LC64 an MSP430


Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Ich habe folgendes Problem. Es geht um ein Projekt mit dem MSP430, 
genauer gesagt dem MSP430F1611. Teil dieses Projektes ist es, Presets in 
ein EEPROM zu schreiben und später wieder daraus zu lesen. Genau hier 
liegt mein Problem, denn das funktioniert offenbar nicht.

Mein MSP430 läuft mit einem 4MHz-Quarz; sowohl MCLK als auch SMCLK 
laufen mit 4MHz. Da ich die beiden UARTs bereits anderweitig in Gebrauch 
habe, habe ich das EEPROM an zwei GPIO-Pins angeschlossen und den 
I²C-Bus per Software realisiert. Die Pins sind P4.3 (SDA) und P4.4 
(SCL). Beide sind mit 10k-Pullup-Widerständen gegen Vcc (+3,3V) 
versehen. Ich war davon ausgegangen, daß man hier die freie Wahl der 
GPIO-Pins hat, da man ja nicht auf die I²C-Pins der UART0 des MSP430 
festgelegt ist.

Hardwaremäßig habe ich keinen Fehler finden können; ich gehe davon aus, 
daß in der Software was nicht stimmt. Wie ist es denn z.B. mit dem 
I²C-Takt, der ja 100kHz oder 400kHz betragen soll. Kann mir jemand 
zeigen, wo das in den Assembler-Routinen eingestellt wird? Sind 
vielleicht die Pullup-Widerstände zu groß - laut Datenblatt des 24LC64 
sollen es 10k für einen I²C-Takt von 100kHz und 2k für 400kHz sein. Ich 
weiß halt nicht, wie hoch mein I²C-Takt überhaupt ist.

Hier mal der Code, den ich hierfür benutzt habe. Im C-Headerfile werden 
die Routinen
extern BYTE Read_A16_I2C_BYTE(BYTE SlaveAdresse, WORD PointerAdresse);
 und
extern BYTE Write_A16_I2C_BYTE(BYTE SlaveAdresse, WORD PointerAdresse, BYTE SendeDaten);
 deklariert. Über diese beiden soll der Schreib- und Lesezugriff auf das 
EEPROM von C aus erfolgen. Die Routinen stammen nicht von mir - da sie 
in anderen Projekten bereits erfolgreich eingesetzt wurden, habe ich sie 
von dort übernommen. Da ich mich mit Assembler-Programmierung nicht 
auskenne - was kann ich daran vielleicht noch verändern? Kann der Fehler 
darin liegen?
/*************************************************************************/
/* CPU-Registerbelegung                                                  */
/*************************************************************************/

  #define   RXTXI2C         R7
  #define   Fehler          R8
  #define   DATAI2C         R9
  #define   BITI2C          R10
  #define   SlaveAdresse    R12
  #define   SendeDaten      R13
  #define   PointerAdresse  R14


/*************************************************************************/
/* Header-Files                                                          */
/*************************************************************************/

  #include "owndef.h"

/*************************************************************************/
/* in owndef.h werden diese Ersatznamen definiert:                       */
/*                                                                       */
/* #define SDA 0x08           // P4.3                                    */
/* #define SCL 0x10           // P4.4                                    */
/* #define I2C_PORT_OUT P4OUT                                            */
/* #define I2C_PORT_IN  P4IN                                             */
/* #define I2C_PORT_DIR P4DIR                                            */
/*************************************************************************/

/*************************************************************************/
/* Ein Byte lesen für Slaves mit 16-Bit Pointer-Adresse                  */
/*                                                                       */
/* Übergabe-Parameter:   SlaveAdresse   = Adresse des I²C-Slaves         */
/*                       PointerAdresse = Pointer-Register-Wort des I²C- */
/*                                        Slaves                         */
/* Rückkehr-Parameter:   Daten-Byte vom Slave (R12)                      */
/*************************************************************************/

      PUBLIC  Read_A16_I2C_BYTE
      RSEG    CODE

Read_A16_I2C_BYTE

            push    R7                      ; Sichern der in C verwendeten
                                            ; Register
            push    R8
            push    R9
            push    R10

            rla.b   SlaveAdresse            ; Herstellen der Slave-Adresse
                                            ; für Übertragung

            clr.b   DATAI2C                 ; Datenregister löschen
            clr.b   Fehler                  ; Fehlerstatus zurücksetzen
            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
                                            ; Register laden
            inc     Fehler                  ; 1 --> kein Slave mit dieser
                                            ; Adresse
            call    #I2C_Start              ; Senden: START, Slave-Address-
                                            ; Byte, Slave Ack prüfen

            mov.w   PointerAdresse,RXTXI2C  ; Pointer-Adresse ins RXTX-
                                            ; Register laden
            inc     Fehler                  ; 2 --> kein solches High-
                                            ; Register
            call    #I2C_TX_16              ; Senden: 1. Pointer-Address-
                                            ; Byte, Slave Ack prüfen
            inc     Fehler                  ; 3 --> kein solches Low-
                                            ; Register
            call    #I2C_TX_16              ; Senden: 2. Pointer-Address-
                                            ; Byte, Slave Ack prüfen

            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
                                            ; Register laden
            bis.b   #01h,RXTXI2C            ; Slave-Adresse auf "read" 
                                            ; modifizieren (R/W-setzen)
            inc     Fehler                  ; 4 --> kein Slave mit dieser
                                            ; Adresse
            call    #I2C_Start              ; Senden: START, Slave-Address-
                                            ; Byte, Slave Ack prüfen

            call    #I2C_RX_8               ; Lesen: Datenbyte
            call    #I2C_RX_NAck_8          ; Senden: No Acknowledge
            call    #I2C_Stop               ; Senden: STOP
            mov.b   DATAI2C,R12             ; Gelesenes Byte nach R12 
                                            ; schieben

            pop     R10                     ; Wiederherstellen der 
            pop     R9                      ; Register für C
            pop     R8
            pop     R7

            ret                             ; Rücksprung zu C (ohne Fehler)


/*************************************************************************/
/* Ein Byte schreiben für Slaves mit 16-Bit Pointer-Adresse              */
/*                                                                       */
/* Übergabe-Parameter:   SlaveAdresse   = Adresse des I²C-Slaves         */
/*                       PointerAdresse = Pointer-Register-Wort des I²C- */
/*                                        Slaves                         */
/*                       SendeDaten     = zu sendendes Daten-Byte        */
/* Rückkehr-Parameter:   0 --> kein Fehler aufgetreten                   */
/*************************************************************************/

      PUBLIC  Write_A16_I2C_BYTE
      RSEG    CODE

Write_A16_I2C_BYTE

            mov.b 2(SP),SendeDaten          ; Übergabeparameter vom Stack
                                            ; holen

            push    R7                      ; Sichern der in C verwendeten
                                            ; Register
            push    R8
            push    R9
            push    R10

            rla.b   SlaveAdresse            ; Herstellen der Slave-Adresse
                                            ; für Übertragung

            clr.b   DATAI2C                 ; Datenregister löschen
            clr.b   Fehler                  ; Fehlerstatus zurücksetzen

            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
                                            ; Register laden
            inc     Fehler                  ; 1 --> kein Slave mit dieser
                                            ; Adresse
            call    #I2C_Start              ; Senden: START, Slave-Address-
                                            ; Byte, Prüfen von Slave Ack

            mov.w   PointerAdresse,RXTXI2C  ; Pointer-Adresse ins RXTX-
                                            ; Register laden
            inc     Fehler                  ; 2 --> kein solches High-
                                            ; Register
            call    #I2C_TX_16              ; Senden: 1. Pointer-Register-
                                            ; Byte, Prüfen Slave Ack
            inc     Fehler                  ; 3 --> kein solches Low-
                                            ; Register
            call    #I2C_TX_16              ; Senden: 2. Pointer-Register-
                                            ; Byte, Prüfen Slave Ack

            mov.b   SendeDaten,RXTXI2C      ; zu sendende Datenbyte ins
                                            ; RXTX-Register laden
            inc     Fehler                  ; 4 --> Fehler im Datenbyte
            call    #I2C_TX_8               ; Senden: Datenbyte 1
            call    #I2C_Stop               ; Senden: STOP
            mov.b   #0,R12                  ; Kein Fehler aufgetreten

            pop     R10                     ; Wiederherstellen der 
            pop     R9                      ; Register für C
            pop     R8
            pop     R7

            ret                             ; Rücksprung zu C (ohne Fehler)


/*************************************************************************/
/* START senden                                                          */
/*                                                                       */
/* Start: SDA=x, SCL=x                                                   */
/* Ende:  SDA=0, SCL=0                                                   */
/*************************************************************************/

I2C_Start                   

            bic.b   #SCL+SDA,&I2C_PORT_DIR  ; SCL und SDA auf Eingang 
                                            ; setzen
            bic.b   #SCL+SDA,&I2C_PORT_OUT  ; SCL=0, SDA=0 ins
                                            ; Ausgangsregister laden
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0


/*************************************************************************/
/* Ein Byte Daten senden                                                 */
/*                                                                       */
/* Start: SDA=0, SCL=0                                                   */
/* Ende:  SDA=0 --> kein Fehler, SDA=1 --> Fehler, SCL=0                 */
/*************************************************************************/

I2C_TX_8                

            mov     #08,BITI2C              ; Schleifenzähler (Bit-Anzahl)

I2C_TX_Bit_8   

            rla.b   RXTXI2C                 ; Daten-Bit -> Carry
            jc      I2C_TX1_8               ; wenn Carry=1, dann Sprung

I2C_TX0_8       

            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0
            jmp     I2C_TXx_8               ;

I2C_TX1_8       

            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1

I2C_TXx_8       

            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            nop                             ;
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
            dec     BITI2C                  ; Schleifenzähler
                                            ; dekrementieren
            jnz     I2C_TX_Bit_8            ; Abbruchbedingung
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1

I2C_TX_Ack_8    

            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            bit.b   #SDA,&I2C_PORT_IN       ; Slave_NAck --> Carry
            jc      I2C_Error               ; Sprung zu Fehlerbehandlung
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
            ret                             ; Rückkehr

/*************************************************************************/
/* Zwei Bytes Daten senden                                               */
/*                                                                       */
/* Start: SDA=0, SCL=0                                                   */
/* Ende:  SDA=0 --> kein Fehler, SDA=1 --> Fehler, SCL=0                 */
/*************************************************************************/

I2C_TX_16

            mov     #8,BITI2C               ; Schleifenzähler (Bit-Anzahl)

I2C_TX_Bit_16   

            rla.w   RXTXI2C                 ; Daten-Bit -> Carry
            jc      I2C_TX1_16              ; wenn Carry=1, dann Sprung

I2C_TX0_16      

            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0
            jmp     I2C_TXx_16              ;

I2C_TX1_16      

            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1

I2C_TXx_16      

            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            nop                             ;
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
            dec     BITI2C                  ; Schleifenzähler 
                                            ; dekrementieren
            jnz     I2C_TX_Bit_16           ; Abbruchbedingung
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1

I2C_TX_Ack_16   

            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            bit.b   #SDA,&I2C_PORT_IN       ; Slave_NAck --> Carry
            jc      I2C_Error               ; Sprung zu Fehlerbehandlung
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
            ret                             ; Rückkehr


/*************************************************************************/
/* Ein Byte Daten empfangen                                              */
/*                                                                       */
/* Start: SDA=0, SCL=0                                                   */
/* Ende:  SDA=1, SCL=0                                                   */
/*************************************************************************/

I2C_RX_8    

            mov.b   #08,BITI2C              ; Schleifenzähler (Bit-Anzahl)

I2C_RX_Bit_8   

            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1
            bit.b   #SDA,&I2C_PORT_IN       ; Daten-Bit -> Carry
            rlc.b   DATAI2C                 ; Carry als LSB speichern
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
            dec     BITI2C                  ; Schleifenzähler 
                                            ; dekrementieren
            jnz     I2C_RX_Bit_8            ; Abbruchbedingung
            ret                             ; Rückkehr

I2C_RX_Ack_8    

            bis.b   #SDA,&I2C_PORT_DIR      ; SDA=0, Master Acknowledge

I2C_RX_NAck_8   

            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1, Master No Acknowledge
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            nop                             ;
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA=1
            ret                             ; Rückkehr


/*************************************************************************/
/* STOP senden                                                           */
/*                                                                       */
/* Start: SDA=x, SCL=0                                                   */
/* Ende:  SDA=1, SCL=1                                                   */
/*************************************************************************/

I2C_Stop
         
            bis.b   #SDA,&I2C_PORT_DIR      ; SDA = 0
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL = 1
            bic.b   #SDA,&I2C_PORT_DIR      ; SDA = 1

I2C_End         

            ret  


/*************************************************************************/
/* Fehlerbehandlung                                                      */
/*                                                                       */
/* Start: SDA=1, SCL=0                                                   */
/* Ende:  Rücksprung zu C, Fehler-Code in R12                            */
/*************************************************************************/

I2C_Error   
                
            mov     Fehler,R12        ; Fehler-Code in Rückkehrregister
                                      ; laden
            incd    SP                ; Stack-Pointer erhöhen, um
                                      ; Rückkehradresse zu C zu ändern

            pop     R10               ; Wiederherstellen der Register für C
            pop     R9
            pop     R8
            pop     R7
            ret                       ; Rückkehr zu C bei einem Fehler
                                      ; (mit Fehler-Code)


/*************************************************************************/
                
      END

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn du den i2c in Software implementierst, musst du dann nicht den Takt 
auch selber erzeugen?

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gesagt, ich habe die Routinen nicht selbst erstellt, sondern von 
einem anderen Projekt übernommen. Dort hat die Sache mit genau diesem 
Code funktioniert. Da der MSP430 in dem anderen Projekt mit dem internen 
DCO bei ca. 800kHz betrieben wurde, hatte ich testweise mal die 
Initialisierung meines Quarzes auskommentiert, aber auch mit dem DCO 
funktioniert es bei mir nicht. Ich habe keine Ahnung, wo der Fehler 
liegen könnte - nicht, daß am Ende mein EEPROM defekt ist...

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat denn keiner eine Idee? Die Pullup-Widerstände kann ich ausschließen; 
habe es heute mal mit 2k versucht, aber es hat sich nichts geändert...

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Z. wrote:
> Hat denn keiner eine Idee? Die Pullup-Widerstände kann ich ausschließen;
> habe es heute mal mit 2k versucht, aber es hat sich nichts geändert...

ich hab keine Ahnung von Assembler, aber schau dir mal die i2c-Library 
von Peter Fleury an...da ist auch Assembler-Code für eine 
Software-Implementierung für i2c dabei. Der ist zwar dafür gedacht, von 
c aus aufgerufen zu werden, aber vielleicht hilft es dir ja weiter...

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ich hab keine Ahnung von Assembler, aber schau dir mal die i2c-Library
> von Peter Fleury an...da ist auch Assembler-Code für eine
> Software-Implementierung für i2c dabei.

Ich hab grad mal danach gesucht. Was ich gefunden habe, ist aber für AVR 
und nicht für den MSP430. Hab ich nicht richtig gesucht, oder meintest 
du das? Dann hilft mir das leider nicht, sorry.

> Der ist zwar dafür gedacht, von c aus aufgerufen zu werden

Ist bei mir auch so, die Assemblerroutinen werden von C aus aufgerufen.

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand was zur I²C-Takterzeugung in meinem Code sagen?

Autor: Tobias Korrmann (kurzschluss81)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt auf der TI Seite Aplication Notes ein Beispiel für ein Software 
I2C.

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du meinst die slaa330.pdf? Die habe ich schon gelesen. Worüber ich dort 
stutzig geworden bin, ist folgendes: Für einen I²C-Takt von 100kHz 
werden dort µC-Takte von Minimum 5,22MHz (schreiben) und 6MHz (lesen) 
angegeben. Mein MSP430 läuft, wie gesagt, mit externem Quarz an XT2 mit 
4MHz. Kann es denn daran liegen? Ich wundere mich nur, da die Routinen 
vorher in einem Projekt genutzt wurden, bei dem der MSP430 mit dem DCO 
in Standardeinstellung genutzt wurde, also mit ca. 800kHz lief. Kann ich 
denn vor dem Aufruf der Lese- oder Schreibroutinen einfach die 
Takterzeugung ändern? Also den MSP430 für den normalen Betrieb mit 
externem Quarz und 4MHz initialisieren und vor dem Zugriff auf die 
I²C-Routinen auf den DCO mit z.B. 6MHz wechseln? Nach dem I²C-Zugriff 
müßte ich dann wieder zurückwechseln. Geht das? Könnte das Problem daran 
liegen?

Autor: kamil (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Takt wird bei I²C erzeugt indem SCL auf 1 und dann wieder auf 0 
gesetzt wird.
            bic.b   #SCL,&I2C_PORT_DIR      ; SCL=1, Master No Acknowledge
            nop                             ; Verzögerung für I²C-
                                            ; Spezifikation
            nop                             ;
            bis.b   #SCL,&I2C_PORT_DIR      ; SCL=0

Hast du dir die Kommentare angeschaut? "Verzögerung für 
I²C-Spezifikation" Wenn die Routinen für 800kHz geschrieben sind laufen 
sie bei 4MHz natürlich deutlich schneller...

Details zu I²C findest du in der Spezifikation von NXP oder Philips: 
http://www.jp.nxp.com/acrobat_download/literature/...
Im Datenblatt des EEPROMs findest du normalerweise auch Informationen 
wie I²C Signale aussehen.

Hast du dir mal angeschaut was an den Pins deines µC passiert wenn du 
die Routinen ausführst? Vielleicht hast du deine Hardware falsch 
initialisiert... es gibt so viele Fehlermöglichkeiten... es könnte auch 
sein, dass dein C-Compiler die Parameter falsch an die 
Assembler-Routinen übergibt.
Wie macht sich denn das Problem denn bemerkbar? Was hast du denn bisher 
alles untersucht um den Fehler zu finden? Warum nimmst du nicht I²C 
Routinen, die in C implementiert wurden wenn du kein Assembler kannst? 
Z.B. 
http://www.mikrocontroller.net/articles/MSP430_Cod...

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Kamil!

> Hast du dir die Kommentare angeschaut? "Verzögerung für
> I²C-Spezifikation" Wenn die Routinen für 800kHz geschrieben sind laufen
> sie bei 4MHz natürlich deutlich schneller...

Natürlich habe ich mir die Kommentare angeschaut. Ich wußte nur nicht, 
daß mit "für I²C-Spezifikation" die Takterzeugung gemeint ist. Du meinst 
also, mit einer Anpassung an der Stelle könnte es klappen? Werde ich mal 
ausprobieren.

> Hast du dir mal angeschaut was an den Pins deines µC passiert wenn du
> die Routinen ausführst? Vielleicht hast du deine Hardware falsch
> initialisiert...

Ich habe das Oszi schonmal drangehabt und es passiert auch was. Aber ich 
konnte die Sequenz noch nicht festhalten, also einfrieren, um sie 
auszuwerten. Die Hardware ist, denke ich, richtig initialisiert, denn es 
funktioniert ja sonst alles.

> es könnte auch sein, dass dein C-Compiler die Parameter
> falsch an die Assembler-Routinen übergibt.

Ich benutze IAR Embedded Workbench, da sollte es eigentlich keine 
Probleme geben.

> Wie macht sich denn das Problem denn bemerkbar?

Indem nach einem Schreibvorgang auf das EEPROM das geschriebene nicht 
daraus zu lesen ist. Ich hatte auch schon überlegt, ob beim Schreiben 
und Lesen evtl. nicht die gleiche Adresse verwendet wird, aber die 
C-Routinen habe ich durchgesehen und die Adressen fürs Schreiben und 
Lesen stimmen überein.

Hier mal meine Schreib- und Leseroutinen im C:

void Load_Data()
  {
    BYTE i, j;    
    for (i = 0; i<NUMBER_OF_PRESETS; i++)           // Stationsnummern erzeugen
      preset_number[i] = i+1;
    LCD_Clear();
    LCD_Cursor_Set(0,0);      
    LCD_Awrite("lade Datensatz...   ");  
    for (i = 0; i<NUMBER_OF_PRESETS; i++)           // Presetnamen aus EEPROM lesen
      {
        for (j = 0; j<(STR_LENGTH-1); j++)          // Lesen ab Adresse 1
          names[i][j] = Read_A16_I2C_BYTE(0x50,1+i*(STR_LENGTH-1)+j);   
        names[i][STR_LENGTH-1]='\0';
      }
    for (i = 0; i<NUMBER_OF_PRESETS; j++)           // Presetwerte aus EEPROM lesen
      {
        for(j = 0; j<8; i++)                        // Lesen ab Adresse 5001
          values[i][j] = Read_A16_I2C_BYTE(0x50,5001+8*i+j);      
      }  
  }


void Save_Data()
  {
    BYTE j;
    for (j = 0; j<(STR_LENGTH-1); j++)              // Presetnamen ins EEPROM speichern
      {
        Write_A16_I2C_BYTE(0x50, 1+(STR_LENGTH-1)*(PRESET_COUNT)+j, names[PRESET_COUNT][j]);
        WAIT_ms(3);
      }
    for (j = 0; j<8; j++)                           // Presetwerte ins EEPROM speichern
      {
        Write_A16_I2C_BYTE(0x50,5001+8*(PRESET_COUNT)+j,values[PRESET_COUNT][j]);
        WAIT_ms(3);
      }
  }


void Fill_EEPROM()                                  // Hilfsfunktion zum Beschreiben eines  
  {                                                 // neuen EEPROMs.
     BYTE i, j;
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetwerte
       {
          values[i][0] = 128;
          values[i][1] = 128;
          values[i][2] = 128;
          values[i][3] = 128;
          values[i][4] = 128;
          values[i][5] = 0;
          values[i][6] = 255;
          values[i][7] = 255;
       }            
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetnamen
       memcpy(names[i], "     kein Name      \0", STR_LENGTH); 
     LCD_Clear(); 
     LCD_Cursor_Set(0,0);      
     LCD_Awrite("Werte werden in den ");
     LCD_Cursor_Set(1,0);  
     LCD_Awrite("Speicher geschrieben");  
     LCD_Cursor_Set(3,0);
     LCD_Awrite(" ...bitte warten... ");  
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetnamen ins EEPROM schreiben
       {
          for (j = 0; j<(STR_LENGTH-1); j++)
            {                                       // Schreiben ab Adresse 1 bis 3800
              Write_A16_I2C_BYTE(0x50,1+i*(STR_LENGTH-1)+j,names[i][j]);            
              WAIT_ms(3);
            }
       }
     for (i = 0; i<NUMBER_OF_PRESETS; i++)          // Presetwerte ins EEPROM schreiben
       {
          for(j = 0; j<8; j++)
            {                                       // Schreiben ab Adresse 5001 bis 6600
              Write_A16_I2C_BYTE(0x50,5001+8*i+j,values[i][j]);           
              WAIT_ms(3);
            }
       }
  }

> Was hast du denn bisher alles untersucht um den Fehler zu finden?

Den Aufbau habe ich auf Kurzschlüsse und Leiterbahnunterbrechungen 
untersucht. Die Pullup-Widerstände an SCL und SDA habe ich gegen andere 
Werte getauscht. Ich habe nachgesehen, ob bei einem Zugriff an beim 
EEPROM ein Signal ankommt, konnte dieses aber wie gesagt noch nicht 
auswerten. Die C-Routinen sollten meiner Meinung nach auch ok sein. Mehr 
habe ich nicht untersucht, weil mir die Ideen ausgingen, was ich noch 
untersuchen könnte...

> Warum nimmst du nicht I²C Routinen, die in C implementiert wurden
> wenn du kein Assembler kannst?

Weil ich noch keine gefunden hatte und ich angenommen hatte, daß ich mit 
den Assemblerroutinen arbeiten kann, weil sie schon getestet wurden...

> Z.B.
> 
http://www.mikrocontroller.net/articles/MSP430_Cod...

Danke, das habe ich offenbar bisher übersehen! Ich schaus mir mal an.

Autor: Kamil P. (kamil)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie 
siehts mit dem Pin WP aus?

Bist du dir sicher, dass IAR die Parameter richtig an die Assembler 
Routinen übergibt? Die Assembler Routinen erwarten die Parameter in den 
Registern
  #define   SlaveAdresse    R12
  #define   SendeDaten      R13
  #define   PointerAdresse  R14

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie
> siehts mit dem Pin WP aus?

Die liegen allesamt an Masse.

> Bist du dir sicher, dass IAR die Parameter richtig an die Assembler
> Routinen übergibt? Die Assembler Routinen erwarten die Parameter in den
> Registern
>
>   #define   SlaveAdresse    R12
>   #define   SendeDaten      R13
>   #define   PointerAdresse  R14
> 

Wie kann ich das überprüfen?

Autor: Kamil P. (kamil)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entweder in der Dokumentation vom IAR-Compiler nachlesen wie er das 
macht oder Schritt für Schritt debuggen (nicht den C-Code sondern den 
Assembler-Code).
Bei MSPGCC sieht es mit der Parameterübergabe so aus: Es wird zuerst R15 
dann R14,... bis R12 verwendet (in dieser Reihenfolge) Bei mehr 
Parametern wird der Stack verwendet. Wie es IAR macht hab ich allerdings 
keine Ahnung... aber irgendwie habe ich das Gefühl, dass es nicht  R12, 
R14 und dann R13 ist. Man kann jedoch nie wissen...

Autor: Kamil P. (kamil)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier das dazugehörige Dokument, dass dir die Parameterübergabe erklärt: 
http://focus.ti.com/mcu/docs/mcusupporttechdocsc.t...

Hier ist also definitiv der Fehler. So sollte es sein:
Parameter 1 (SlaveAdresse) aus Register R12 laden
Parameter 2 (PointerAdresse) aus Register R14 laden
Parameter 3 (SendeDaten) vom Stack holen

Das heißt aber nicht, dass das alles war. Das Clock-Signal könnte noch 
immer zu kurz sein.

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke dir, Kamil. Das werde ich morgen gleich mal ausprobieren! Ich meld 
mich dann nochmal und berichte.

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ic hab gerade nochmal nachgesehen. Eigentlich macht der Code doch, was 
er soll.

>Parameter 1 (SlaveAdresse) aus Register R12 laden
>Parameter 2 (PointerAdresse) aus Register R14 laden
>Parameter 3 (SendeDaten) vom Stack holen

Das letzte passiert doch mit dieser Anweisung unter Write_A16_I2C_BYTE:
mov.b   2(SP),SendeDaten

Der Parameter 3 wird vom Stackpointer geholt und in R13 abgelegt. Sollte 
doch so ok sein?

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es hat sich nichts geändert. Ich konnte mit den NOPs experimentieren, 
wie ich wollte, das Verhalten ist immer noch das gleiche.

Autor: Kamil P. (kamil)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kamil P. wrote:
> Ok, wie hast du die Pins A2, A1 und A0 des EEPROMs beschaltet? Wie
> siehts mit dem Pin WP aus?

Es könnte sein, dass die SlaveAdresse falsch ist. Oder das die 
Writeprotection aktiviert ist.

Hast du es schon mit einem anderen EEPROM versucht? (es könnte ja kaputt 
sein...)

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es könnte sein, dass die SlaveAdresse falsch ist.

Laut Datenblatt ist 50h richtig.

> Oder das die Writeprotection aktiviert ist.

Das sollte doch aber durch das Auf-Masse-Legen von WP ausgeschlossen 
sein.

> Hast du es schon mit einem anderen EEPROM versucht? (es könnte ja kaputt
> sein...)

Das habe ich auch schon überlegt. Probiert habe ich das aber noch nicht, 
da ein neues erst bestellt werden müßte.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Z. wrote:
>> Es könnte sein, dass die SlaveAdresse falsch ist.
>
> Laut Datenblatt ist 50h richtig.
>

Probier doch mal just4fun 0xA0...

Autor: Kamil P. (kamil)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Z. wrote:
>> Es könnte sein, dass die SlaveAdresse falsch ist.
>
> Laut Datenblatt ist 50h richtig.
>

Die Adresse ist abhängig von den Pins A0 bis A2.

>> Oder das die Writeprotection aktiviert ist.
>
> Das sollte doch aber durch das Auf-Masse-Legen von WP ausgeschlossen
> sein.
>
Schau im Datenblatt nach.

>Indem nach einem Schreibvorgang auf das EEPROM das geschriebene nicht
>daraus zu lesen ist. Ich hatte auch schon überlegt, ob beim Schreiben
>und Lesen evtl. nicht die gleiche Adresse verwendet wird, aber die
>C-Routinen habe ich durchgesehen und die Adressen fürs Schreiben und
>Lesen stimmen überein.

Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu 
schreiben)?

Ist das EEPROM 100%ig richtig angeschlossen? Hast du dir die Signale an 
SDA und SCL angeschaut und analysiert? Deinen Code schon mal Schritt für 
Schritt mit dem Debugger abgearbeitet?

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Adresse ist abhängig von den Pins A0 bis A2.

Richtig, sie setzt sich aus dem Control Code 1010 und den Bits für A2, 
A1, A0 zusammen. Da A0 bis A2 Null sind (und das sind sie definitiv), 
heißt die Adresse 1010000b = 50h.

> Schau im Datenblatt nach.

Daher weiß ich ja, daß das so ist.

> Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu
> schreiben)?

Naja, nur was lese ich denn dann? Wenn vorher garnichts ins EEPROM 
geschrieben wurde, wie kann ich dann beurteilen, ob der Lesezugriff 
erfolgreich war? Ein Lesezugriff ohne direkt vorangehendes Schreiben 
erfolgt bei jedem Start des Aufbaus, da dann das erste Preset ausgelesen 
wird.

> Ist das EEPROM 100%ig richtig angeschlossen?

Ja, definitiv. Das habe ich mehrfach penibelst überprüft.

> Hast du dir die Signale an SDA und SCL angeschaut und analysiert?

Noch nicht weiter als oben schonmal beschrieben.

>Deinen Code schon mal Schritt für Schritt mit dem Debugger abgearbeitet?

Das könnte ich mal machen, aber mir fehlt jede Erfahrung mit solchen 
Dingen. Ich müßte mich in den Gebrauch des Debuggers mal einarbeiten.

Autor: Christian Z. (fiselgrulm)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Probier doch mal just4fun 0xA0...

Du spielst auf das R/W-Bit an, das sich an die Adresse anschließt? Dann 
müßte es 0xA0 für Schreiben und 0xA1 für Lesen sein. Aber das Bit gehört 
eigentlich nicht zur Adresse. Probieren kann ich's trotzdem, just4fun...

Autor: Kamil P. (kamil)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Z. wrote:
>> Hast du denn getestet, ob der Lese-Zugriff funktioniert (ohne vorher zu
>> schreiben)?
>
> Naja, nur was lese ich denn dann? Wenn vorher garnichts ins EEPROM
> geschrieben wurde, wie kann ich dann beurteilen, ob der Lesezugriff
> erfolgreich war? Ein Lesezugriff ohne direkt vorangehendes Schreiben
> erfolgt bei jedem Start des Aufbaus, da dann das erste Preset ausgelesen
> wird.
Mit einem Schreibgerät das EEPROM beschreiben und dann mit deiner 
Hardware auslesen.
>> Ist das EEPROM 100%ig richtig angeschlossen?

>> Hast du dir die Signale an SDA und SCL angeschaut und analysiert?
>
> Noch nicht weiter als oben schonmal beschrieben.
Unbedingt überprüfen, ob da alles stimmt.

>>Deinen Code schon mal Schritt für Schritt mit dem Debugger abgearbeitet?
>
> Das könnte ich mal machen, aber mir fehlt jede Erfahrung mit solchen
> Dingen. Ich müßte mich in den Gebrauch des Debuggers mal einarbeiten.
Ohne zu wissen wie man einen Debugger verwendet, wirst du sehr viel Zeit 
mit Fehlersuche verbringen. Ließ dir also unbedingt Tutorials durch.
Debugger sind normalerweise sehr einfach zu bedienen.

Autor: Justus Skorps (jussa)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian Z. wrote:
>> Probier doch mal just4fun 0xA0...
>
> Du spielst auf das R/W-Bit an, das sich an die Adresse anschließt? Dann
> müßte es 0xA0 für Schreiben und 0xA1 für Lesen sein. Aber das Bit gehört
> eigentlich nicht zur Adresse. Probieren kann ich's trotzdem, just4fun...

aber es gehört zum ersten übertragenen Byte...Bits 7-4 für den Typen, 
3-1 für A0..A2 und Bit 0 für R/W..und soweit ich sehe, wird deine 
1010000 im Code nicht automatisch geshiftet:
            mov.b   SlaveAdresse,RXTXI2C    ; Slave-Adresse ins RXTX-
                                            ; Register laden
            bis.b   #01h,RXTXI2C
so wie ich das verstehe, wird im Moment deine 7Bit lange Adresse in das 
Register kopiert und dann das letzte Bit geändert, was eigentlich noch 
deinem A0 entsprechen würde

Autor: Christian Z. (fiselgrulm)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Die Adresse zu ändern hat nichts gebracht. Ich habe mal den Takt an SCL 
(gemessen direkt am EEPROM) mit dem Oszi untersucht; ein Bild davon ist 
im Anhang. Die Frequenz bewegt sich mit ca. 160kHz in Bereichen, die 
schonmal nicht völlig falsch sind. Ich weiß nicht, wie ich die Form der 
High-Pegel deuten soll. Sind derart verschliffene Taktspitzen ok?

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kommt durch die PullUps, und dadurch, dass der MSP430 den High Pegel 
nicht treibt, sondern den Pin auf Eingang schaltet. Eventuell sind die 
Widerstände zu hochohmig. Und so asymmetrisch ist das ganze ja auch.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Sind derart verschliffene Taktspitzen ok?

Schalte den Tastkopf mal auf 10:1 oder gleiche ihn ab ;)

Autor: Christian Z. (fiselgrulm)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe jetzt mal versucht, alternativ die Hardware-I²C-Schnittstelle 
der UART0 zu benutzen. Ich stehe dabei jedoch schon wieder vor dem 
nächsten Problem:

Ich benutze diese Routinen, die TI irgendwo als Beispielcode 
vorgeschlagen hat (s.Anhang).

Irgendwo scheint noch was nicht zu stimmen. Wenn ich schreiben will, 
rufe ich
EEPROM_Write(adresse, daten);
 auf, gefolgt von
EEPROM_Ack_Polling();
 Beim Ack_Polling bleibt er dann bei
while (I2CTCTL & I2CSTT);
 hängen. Wenn ich zum Lesen
EEPROM_Read(adresse);
 aufrufe bleibt er bei
while((~I2CIFG) & ARDYIFG);
 hängen.

Habe ich irgendwo einen Fehler drin? Muß ich beim Aufrufen noch 
irgendwas beachten?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.