PIC32- und I2C-EEPROM-Schnittstellenprobleme

Ich schreibe Code für einen PIC32MX250F128B als Schnittstelle zum Microchip 24LC02B EEPROM mit I2C-Schnittstelle. Ich habe das Datenblatt des EEPROM, des PIC32 und Abschnitt 24 des Referenzhandbuchs der PIC32-Familie sehr genau befolgt und versucht, Code für die Schnittstelle mit dem EEPROM zu schreiben. Ich bekomme kein "Hängen" bei einem der Tests für die Bits, die gelöscht/gesetzt werden müssen, z. ein ACK wird empfangen - der Code wird vollständig ausgeführt. Wenn ich jedoch den Wert der Datenvariablen direkt am Ende der readEeprom-Funktion überprüfe, erhalte ich nur ein Null-Zeichen (nach dem Schreiben eines 'H' in die angegebene EEPROM-Speicheradresse im Byte-Schreibmodus (Seitenschreibcode ist mit #if auskommentiert). Dies weist darauf hin, dass entweder das Schreiben nicht richtig erfolgte oder das Lesen nicht ordnungsgemäß erfolgte.

Ich habe keinen Zugriff auf ein Oszilloskop oder einen Logikanalysator, um zu überprüfen, was genau auf den SDA- und SCL-Leitungen passiert.

Der PIC32-Oszillator ist auf 8 MHz eingestellt und ich beabsichtigte, eine Baudrate von 100 kHz für die Kommunikation mit dem EEPROM zu verwenden. Daher verwende ich unter Verwendung der Gleichung I2CBRG = (PBCLK/(2*FSCK))-2, wie sie in Abschnitt 24 der Referenzdokumente der PIC32-Familie zu finden ist, 0x26 für den I2CBRG-Wert.

Vielleicht kann jemand erkennen, ob etwas in meinem Code falsch ist? Ich habe jetzt über einen Tag versucht, das Problem zu finden, aber es ist mir nicht gelungen.

Hier ist mein Code: /* Schnittstellentest für I2C EEPROM mit PIC32 */

#include <plib.h>
#include <p32xxxx.h>


/* Pin outline:
 * SCL1 - pin 17 - (EEPROM pin 6)
 * SDA1 - pin 18 - (EEPROM pin 5)
 * WP - pin 16 (RB7) (EEPROM pin 7) - Currently connected to GND
 */


//configuration bits
// DEVCFG3
//#pragma config PMDL1WAY = OFF           // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
//#pragma config IOL1WAY = OFF            // Peripheral Pin Select Configuration (Allow multiple reconfigurations)
//#pragma config FUSBIDIO = OFF            // USB USID Selection (Controlled by the USB Module)
//#pragma config FVBUSONIO = OFF           // USB VBUS ON Selection (Controlled by USB Module)
// DEVCFG2
#pragma config FPLLIDIV = DIV_1        // PLL Input Divider (12x Divider)
#pragma config FPLLMUL = MUL_24        // PLL Multiplier (24x Multiplier)
//#pragma config UPLLIDIV = DIV_1        // USB PLL Input Divider (12x Divider)
//#pragma config UPLLEN = OFF             // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_1       // System PLL Output Clock Divider (PLL Divide by 256)
// DEVCFG1
#pragma config FNOSC = FRC              // Oscillator Selection Bits (Fast RC Osc (FRC))
#pragma config FSOSCEN = OFF             // Secondary Oscillator Disnable (Disabled)
#pragma config IESO = ON                // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSECMD           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
//#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
//#pragma config FWDTWINSZ = WISZ_25      // Watchdog Timer Window Size (Window Size is 25%)
// DEVCFG0
//#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx2        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (Protection Disabled)
//////////////////////////////////////////

#define EEPROM_WP PORTBbits.RB7
#define CLOCK   8000000 /*8 MHz clock*/
#define HIGH 1 //logic values declaration
#define LOW 0 //logic values declaration

char data[10];
void init(void);
void readEeprom(void);
void writeEeprom(void);

int main (void)
{
    init();
    writeEeprom();
    readEeprom();
} /*main*/

void init(void)
{
    SYSTEMConfigPerformance(CLOCK);
    TRISBbits.TRISB7 = 0x01;
    /*I2C peripheral overrides states of respective interface pins - no need
     to set state of SCLx and SDAx pins here*/   

    /*Initialize I2C Peripheral*/    
    I2C1CONbits.DISSLW = HIGH; /*disable slew rate for 100 kHz*/
    I2C1BRG = 0x26; /*Set Baud Rate Generator*/
    I2C1CONbits.ON = HIGH;

    int i = 0;
    for (i = 0; i < 10; i++)
    {
        data[i] = '0';
    } /*for*/
} /*init*/

void writeEeprom(void)
{
    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = 0b10100000;

    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);

    /*Send word address for read*/
    I2C1TRN = 0x00;
    while (I2C1STATbits.ACKSTAT == HIGH); /*wait for ACK from device*/

#if 0 /*Page write*/
    int i;
    /*24LC02 can only write up to 8 bytes at a time*/
    for (i = 0; i < 7; i++)
    {
        I2C1TRN = i;
        /*Wait for transmit buffer empty - indicates that write is completed*/
        while (I2C1STATbits.TBF == HIGH); 
        /*Generate ACK event*/        
        I2C1CONbits.ACKEN;
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 1 /*Byte write*/    
    I2C1TRN = 'H';
    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 
    /*Generate ACK event*/        
    I2C1CONbits.ACKEN; 
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif
} /*writeEeprom*/

void readEeprom(void)
{
    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = 0b10100000;

    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);

    /*Send address for read*/
    I2C1TRN = 0x00; /*Upper 8 bits of address*/
    while (I2C1STATbits.ACKSTAT == HIGH); /*wait for ACK from device*/

    /*Send Repeated start event again*/
    I2C1CONbits.RSEN = HIGH;

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and read indication*/
    I2C1TRN = 0b10100001;

    while (I2C1STATbits.ACKSTAT == HIGH);
    int i = 0;
#if 0 /*Sequential read*/    
    for (i = 0; i < 10; i++)
    {
        /*Enable receive mode - RCEN cleared after 8th bit is received*/
        I2C1CONbits.RCEN = HIGH; 
        while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
        data[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
        while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
        /*Generate ACK event - do not send ACK for last sequential read*/
        if (i < 9)
        {
            I2C1CONbits.ACKEN;
        } /*if*/
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 1 /*Single read*/
    /*Enable receive mode - RCEN cleared after 8th bit is received*/
    I2C1CONbits.RCEN = HIGH; 
    //while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
    data[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
    while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
    /*Send stop event - no ACK event must be sent*/
    I2C1CONbits.PEN;
#endif
} /*readEeprom()*/

Ich würde mich sehr über jede Hilfe freuen, die jemand anbieten kann. Vielen Dank im Voraus.

BEARBEITEN : Mir ist klar, dass ich im Datenblatt falsch gelesen habe, dass für den 24LC02 nur ein Wortadressenbyte (anstelle von 2 - MSByte und LSByte) erforderlich ist. Also habe ich das in meinem Code behoben, aber ich habe immer noch das gleiche Problem. Ich habe auch ein Arduino verwendet, um (erfolgreich) in das EEPROM zu schreiben und die Daten zu lesen, und daher kann ich bestätigen, dass sogar die Funktion writeEeprom in meinem Code nicht funktioniert.

Nach einigen Google-Suchen habe ich auch gelesen, dass das I2C-Peripheriegerät Probleme bereiten könnte, während sich der PIC im Debug-Modus befindet, den ich derzeit verwende.


Das Neueste:

Ich habe das Leseproblem gelöst, obwohl meine sequentielle Lesemethode es nicht wie beabsichtigt ausführt, aber es funktioniert. Ich habe jedoch Probleme beim Schreiben in das EEPROM. Mein Code folgt genau den Richtlinien des Datenblatts (auch mit einigen zusätzlichen Verzögerungen aus Sicherheitsgründen), aber es funktioniert immer noch nicht. Meine Schreibfunktion ist die Funktion namens "writeEeprom" im folgenden Code:

/* Interface test for I2C EEPROM 24LC02B with PIC32
 */

#include <plib.h>
#include <p32xxxx.h>


/* Pin outline:
 * SCL1 - pin 17 - (EEPROM pin 6)
 * SDA1 - pin 18 - (EEPROM pin 5)
 * WP - pin 16 (RB7) (EEPROM pin 7) - Currently connected to GND
 */


//configuration bits
// DEVCFG3
//#pragma config PMDL1WAY = OFF           // Peripheral Module Disable Configuration (Allow multiple reconfigurations)
//#pragma config IOL1WAY = OFF            // Peripheral Pin Select Configuration (Allow multiple reconfigurations)
//#pragma config FUSBIDIO = OFF            // USB USID Selection (Controlled by the USB Module)
//#pragma config FVBUSONIO = OFF           // USB VBUS ON Selection (Controlled by USB Module)
// DEVCFG2
#pragma config FPLLIDIV = DIV_1        // PLL Input Divider (12x Divider)
#pragma config FPLLMUL = MUL_24        // PLL Multiplier (24x Multiplier)
//#pragma config UPLLIDIV = DIV_1        // USB PLL Input Divider (12x Divider)
//#pragma config UPLLEN = OFF             // USB PLL Enable (Disabled and Bypassed)
#pragma config FPLLODIV = DIV_1       // System PLL Output Clock Divider (PLL Divide by 256)
// DEVCFG1
#pragma config FNOSC = FRC              // Oscillator Selection Bits (Fast RC Osc (FRC))
#pragma config FSOSCEN = OFF             // Secondary Oscillator Disnable (Disabled)
#pragma config IESO = ON                // Internal/External Switch Over (Enabled)
#pragma config POSCMOD = OFF            // Primary Oscillator Configuration (Primary osc disabled)
#pragma config OSCIOFNC = OFF           // CLKO Output Signal Active on the OSCO Pin (Disabled)
#pragma config FPBDIV = DIV_1           // Peripheral Clock Divisor (Pb_Clk is Sys_Clk/1)
#pragma config FCKSM = CSECMD           // Clock Switching and Monitor Selection (Clock Switch Disable, FSCM Disabled)
#pragma config WDTPS = PS1048576        // Watchdog Timer Postscaler (1:1048576)
//#pragma config WINDIS = OFF             // Watchdog Timer Window Enable (Watchdog Timer is in Non-Window Mode)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable (WDT Disabled (SWDTEN Bit Controls))
//#pragma config FWDTWINSZ = WISZ_25      // Watchdog Timer Window Size (Window Size is 25%)
// DEVCFG0
#pragma config JTAGEN = OFF             // JTAG Enable (JTAG Disabled)
#pragma config ICESEL = ICS_PGx1        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
#pragma config PWP = OFF                // Program Flash Write Protect (Disable)
#pragma config BWP = OFF                // Boot Flash Write Protect bit (Protection Disabled)
#pragma config CP = OFF                 // Code Protect (Protection Disabled)
//////////////////////////////////////////

#define EEPROM_WP PORTBbits.RB7
#define CLOCK   8000000
#define HIGH 1 //logic values declaration
#define LOW 0 //logic values declaration

char dataArr[8];
int controlWrite = 0b10100000; /*Control byte for writing to EEPROM*/
int controlRead = 0b10100001; /*Control byte for reading from EEPROM*/
int wordAddress = 0x00; /*Address of word in EEPROM*/

void init(void);
void readEeprom(void);
void readEepromSeq(void);
void writeEeprom(void);
void delayus(unsigned t); //1us delay
void delayms(unsigned k); //1ms delay

int main (void)
{
    init();
    delayms(10);
    writeEeprom();
    delayms(10);
    readEepromSeq();
} /*main*/

void init(void)
{
    SYSTEMConfigPerformance(CLOCK);
    /*I2C peripheral overrides states of respective interface pins - no need
     * to set state of SCLx and SDAx pins here.
     * I2C pins must be set to digital pins by clearing the respective ANSEL-SFR
     */
    ANSELB = 0x00; /*Configure port B as digital port, not analog*/

    /*Initialize I2C Peripheral*/    
    I2C1CONbits.DISSLW = HIGH; /*disable slew rate for 100 kHz*/
    I2C1BRG = 0x26; /*Set Baud Rate Generator - for PBCLK = 8 MHz, Fck = 100 kHz*/
    I2C1CONbits.ON = HIGH;

    int i = 0;
    for (i = 0; i < 10; i++)
    {
        dataArr[i] = '0';
    } /*for*/
} /*init*/

void writeEeprom(void)
{    
    wordAddress = 0x00;
    int data = 0x48; /*Character "H"*/
    int i = 0;

    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/     

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = controlWrite;

    /*Wait for transmit buffer empty - indicates that write is completed*/
    //while (I2C1STATbits.TBF == HIGH); 
    /*Wait for transmit process to end - bit clears once transmit not in progress*/
    while (I2C1STATbits.TRSTAT == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);

    /*Send address for read*/
    I2C1TRN = wordAddress;
    /*Wait for transmit process to end*/
    while (I2C1STATbits.TRSTAT == HIGH); 
    /*Wait for ACK signal from device*/
    while (I2C1STATbits.ACKSTAT == HIGH);

#if 0 /*Page write*/
    int i;
    /*24LC02 can only write up to 8 bytes at a time*/
    for (i = 0; i < 7; i++)
    {
        I2C1TRN = i;
        /*Wait for transmit buffer empty - indicates that write is completed*/
        while (I2C1STATbits.TBF == HIGH); 
        /*Generate ACK event*/        
        delayms(10);
        I2C1CONbits.ACKEN;
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 1 /*Byte write*/  
    I2C1TRN = data;
    /*Wait for transmit buffer empty - indicates that write is completed*/
    while(I2C1STATbits.TRSTAT == HIGH); /*Wait until transmit is completed*/
    delayms(10);
    /*wait for ACK from device*/       
    while (I2C1STATbits.ACKSTAT == HIGH);
    delayms(10);
    /*Send stop event*/
    I2C1CONbits.PEN;
    delayms(10);
#endif
} /*writeEeprom*/

void readEepromSeq()
{
    int i = 0;      
    wordAddress = 0x00;

    /*loop 8-times - the amount of bits in a byte*/
    for (i = 0; i < 8; i++)
    {
        /*Assert start condition*/
        I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

        /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
        while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

        /*Send device address and write indication - address = "1010xxx0"*/
        I2C1TRN = controlWrite;
        /*Wait for transmit buffer empty - indicates that write is completed*/
        while (I2C1STATbits.TBF == HIGH); 

        /*Wait for ACK signal from device - bit will clear when ACK is received*/
        while (I2C1STATbits.ACKSTAT == HIGH);
        delayms(10);

        /*Send address for read*/
        I2C1TRN = wordAddress; /*Lower 8 bits of address*/        
        while (I2C1STATbits.ACKSTAT == HIGH);
        delayms(10);

        /*Send Repeated start event again*/
        I2C1CONbits.RSEN = HIGH;

        /*Test if Repeated START condition is completed - test interrupt I2C1MIF in IFS1*/
        while (I2C1CONbits.RSEN == HIGH); /*wait until repeated start condition finishes*/ 

        /*Send device address and read indication*/
        I2C1TRN = controlRead;
        delayms(10);

        while (I2C1STATbits.ACKSTAT == HIGH);

        /*Enable receive mode - RCEN cleared after 8th bit is received*/
        I2C1CONbits.RCEN = HIGH; 
        while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
        dataArr[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
        while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
        /*Send stop event - no ACK event must be sent*/
        I2C1CONbits.PEN;
        wordAddress++;
    } /*for*/
} /*readEepromSeq*/

void readEeprom(void)
{
    int i = 0;      
    wordAddress = 0x00;
    /*Assert start condition*/
    I2C1CONbits.SEN = HIGH; /*This bit is automatically cleared by MCU*/

    /*Test if START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.SEN == HIGH); /*wait until start condition finishes*/ 

    /*Send device address and write indication - address = "1010xxx0"*/
    I2C1TRN = controlWrite;
    /*Wait for transmit buffer empty - indicates that write is completed*/
    while (I2C1STATbits.TBF == HIGH); 

    /*Wait for ACK signal from device - bit will clear when ACK is received*/
    while (I2C1STATbits.ACKSTAT == HIGH);
    delayms(10);

    /*Send address for read*/
    I2C1TRN = wordAddress; /*Lower 8 bits of address*/        
    while (I2C1STATbits.ACKSTAT == HIGH);
    delayms(10);

    /*Send Repeated start event again*/
    I2C1CONbits.RSEN = HIGH;

    /*Test if Repeated START condition is completed - test interrupt I2C1MIF in IFS1*/
    while (I2C1CONbits.RSEN == HIGH); /*wait until repeated start condition finishes*/ 

    /*Send device address and read indication*/
    I2C1TRN = controlRead;
    delayms(10);

    while (I2C1STATbits.ACKSTAT == HIGH);   

#if 1 /*Sequential read*/    
    for (i = 0; i < 8; i++)
    {
        /*Enable receive mode - RCEN cleared after 8th bit is received*/
        I2C1CONbits.RCEN = HIGH; 
        while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
        dataArr[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
        while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
        delayms(10);
        /*Generate ACK event - do not send ACK for last sequential read*/
        if (i < 8)
        {
            I2C1CONbits.ACKEN;
        } /*if*/        
    } /*for*/    
    /*Send stop event*/
    I2C1CONbits.PEN;
#endif

#if 0 /*Single read*/
    /*Enable receive mode - RCEN cleared after 8th bit is received*/
    I2C1CONbits.RCEN = HIGH; 
    while (I2C1STATbits.RBF == LOW); /*Wait for receive buffer full*/    
    dataArr[i] = I2C1RCV; /*Store receive buffer value in dataByte*/
    while (I2C1STATbits.RBF == HIGH); /*Wait for receive buffer to clear*/
    /*Send stop event - no ACK event must be sent*/
    I2C1CONbits.PEN;
#endif
} /*readEeprom()*/

void delayus(unsigned t)
{
    T1CONbits.ON = 1;                   //enable timer1
    while(t--)
    {
        TMR1 = 0;                       //reset timer1
        while(TMR1 < 8);                //delay of 1us: (1us)/(125ns) = 8
    } //while(t--)
    T1CONbits.ON = 0;                   //disable timer1 (power saving)
} //delayus

void delayms(unsigned k)
{
    T1CONbits.ON = 1;                   //enable timer1
    while(k--)
    {
        TMR1 = 0;                       //reset timer1
        while(TMR1 < 8000);                //delay of 1us: (1ms)/(125ns) = 8000
    } //while(t--)
    T1CONbits.ON = 0;                   //disable timer1 (power saving)
} //delayms

Kann sich bitte jemand die Mühe machen und einen Blick darauf werfen und mir zumindest einige Kommentare geben? Auch hier liegt das Problem in der Funktion "writeEeprom", die in main() aufgerufen wird.

Danke schön.

Haben Sie darüber nachgedacht, die chipKIT-Programmierumgebung anstelle des rohen PIC-Codes zu verwenden? Es hat volle I2C-Unterstützung, genau wie Arduino. Es erfordert eine enorme Plackerei, diese Art von Dingen zum Laufen zu bringen, und Sie können stattdessen mit dem Schreiben Ihres Codes fortfahren.
Nein, das habe ich nicht bedacht (kenne mich damit nicht aus). Ich ziehe es vor, rohen PIC-Code zu verwenden und ihn richtig zum Laufen zu bringen und alle Aspekte davon vollständig zu verstehen. Aus Entwicklungssicht denke ich nicht, dass es immer sinnvoll ist, auf eine andere Programmierumgebung umzusteigen, nur weil der Rohcode zu lange braucht, um ihn zum Laufen zu bringen. Es hängt natürlich davon ab, wie komplex die Implementierung ist, und I2C ist wirklich nicht so komplex, um die Verwendung einer anderen Programmierumgebung zu rechtfertigen. Wenn dies zB. eine Art USB-Host-Implementierung, dann würde ich einen Umzug in Betracht ziehen.
Das ist fair genug und eine vollkommen vernünftige Ansicht, die ich respektieren kann. Vielleicht könnten Sie sich jedoch die chipKIT-Implementierung von Wire.h (eigentlich ein Wrapper für DTWI) ansehen, um zu sehen, wie sie dort implementiert ist, und sehen, ob Sie in Ihrer Implementierung etwas übersehen haben. Es ist oft gut, Ihr Programm mit bekannt funktionierendem Code von anderswo zu vergleichen, um zu sehen, ob Sie etwas übersehen haben. Ich persönlich weiß nicht, wie man I2C direkt auf einem PIC32 implementiert, aber ich weiß, dass es einige Dinge gibt, auf die man achten muss.
Danke Majenko. Ich stimme Ihnen vollkommen zu, dass man sich ansehen kann, wie es in einer funktionierenden öffentlichen Bibliothek umgesetzt wird. Ich werde mir das mal anschauen und schauen, ob ich das Problem lösen kann.

Antworten (2)

Dein Code sieht gut aus. Das eigene Schreiben von Treibern kann jedoch zeitaufwändig und fehleranfällig sein. Microchip liefert auch grundlegende Bibliotheken und I2C EEPROM.

Sind Sie sicher, dass beide Leitungen Pull-ups (Widerstände gegen 3 V) haben? Ohne dies werden keine Bits von PIC generiert.

Hier ist ein Beispiel für einen funktionierenden I2C-EEPROM-Treiber, der sowohl plib als auch manuelles Hardware-I2C auf PIC32 oder PIC16/18 (HW_CFG_SENSOR) verwenden kann.

void i2cSetupMaster(unsigned int BaudRate)
{
#ifdef I2C_USE_PLIB
    #ifndef HW_CFG_SENSOR
            I2CEnable(I2C_MOD,0);
            I2CConfigure(I2C_MOD,0);
            I2CSetFrequency(I2C_MOD,GetPeripheralClock(), BaudRate);
            I2CEnable(I2C_MOD,1);
    #else
            ANSELC = 0;
            TRISC3 = 1;
            TRISC4 = 1;
            SSP1ADD =   39; // 39 @ 16Mhz  = 100khz        SCL pin clock     period = ((ADD<7:0> + 1) *4)/FOSC
            OpenI2C1(MASTER,SLEW_OFF);
    #endif
#else

    I2C_CONbits.ON = 0;
    idleI2C();

     //BRG
     //   I2C_BRG = BaudRate; // 0x0C2; //( (sourceClock/i2cClock)/2 ) - 2; // 100Khz at 40Mhz PBCLK
     //  I2C3ADD =   0x09;//( (_XTAL_FREQ/100000) /4 )-1;

    I2CConfigure(I2C_MOD,   I2C_ENABLE_SMB_SUPPORT);  //I2C_ENABLE_SMB_SUPPORT
    I2CSetFrequency(I2C_MOD, GetPeripheralClock(), BaudRate);

    idleI2C();
    //I2C_CONbits.ACKDT = 0; //send ACK on recieved byte
    I2C_CONbits.STRICT = 0;
    I2C_CONbits.SMEN = 1;  //SMB bus compliant

    //enable, master, no collision
    I2C_CONbits.DISSLW = 1;  //Slew rate control disabled for Standard Speed mode (100 kHz)
    I2C_STATbits.I2COV = 0;

    I2C_CONbits.ON = 1;

     DelayMs(2);
#endif

}


bool i2cSendByte(unsigned char byte)
{
#ifdef I2C_USE_PLIB
    #ifndef HW_CFG_SENSOR
            if (I2CTransmitterIsReady(I2C_MOD))
            {
               return I2CSendByte( I2C_MOD, byte );
            }
    #else
            putcI2C(byte); 
            while(SSPSTATbits.R_NOT_W){}
            return 1;
    #endif

#else
   I2C_TRN = byte;
   int timeout = 0;
   msspWait(); //wait until byte is latched
   while (     I2C_STATbits.TRSTAT == 1) {
        timeout++;
        if ( timeout > MAX_WAIT_CYCLES) {
            return 0x00;
        }
   };
   if (  msspOVF() ||   msspBWcol() )  {  return 0; } //send failed
   else { return 1; } //success
#endif


}



 /**********  Write fixed length in page portions   *****************/
void seqWriteEE (byte deviceAddr, word Addr,  word  bytes, byte* buff)
{
#ifdef MEM_I2C_HARDWARE

    i2cSetupMaster( I2C_BRG_100kHz  ); //concurrency enable

    /*If the  master should transmit more than 64 bytes prior to
    generating the Stop condition, the address counter will
    roll over and the previously received data will be overwritten.*/

    CurrentDeviceAddr = deviceAddr;
    int pages = (int)(bytes / i2cMemPageSize);
    int singleBytes = (int) (bytes % i2cMemPageSize);

    word writeAddr = Addr;
    int pageInc = 0;

    if ( bytes >= i2cMemPageSize)
    {
        word BufferPos;
        for (pageInc = 0; pageInc < pages; pageInc++)
        {
            writeAddr += pageInc > 0 ? i2cMemPageSize :0 ;
            BufferPos = pageInc*i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],i2cMemPageSize);
        }
        if (singleBytes > 0){
            BufferPos = pages*i2cMemPageSize;
            writeAddr += i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],singleBytes);
        }
    }
    else
    {
        WriteSectorBytesAtAddr(Addr,buff,bytes);
    } 
#else
    i2cSetupMaster( I2C_BRG_100kHz  ); //concurrency enable

    /*If the  master should transmit more than 64 bytes prior to
    generating the Stop condition, the address counter will
    roll over and the previously received data will be overwritten.*/

    CurrentDeviceAddr = deviceAddr;
    int pages = (int)(bytes / i2cMemPageSize);
    int singleBytes = (int) (bytes % i2cMemPageSize);

    word writeAddr = Addr;
    int pageInc = 0;

    if ( bytes >= i2cMemPageSize)
    {
        word BufferPos;
        for (pageInc = 0; pageInc < pages; pageInc++)
        {
            writeAddr += pageInc > 0 ? i2cMemPageSize :0 ;
            BufferPos = pageInc*i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],i2cMemPageSize);
        }
        if (singleBytes > 0){
            BufferPos = pages*i2cMemPageSize;
            writeAddr += i2cMemPageSize;
            WriteSectorBytesAtAddr(writeAddr,&buff[BufferPos],singleBytes);
        }
    }
    else
    {
        WriteSectorBytesAtAddr(Addr,buff,bytes);
    }
#endif

}

void WriteSectorBytesAtAddr(word Addr, byte* buff, word bytes){
if ( IsWriteOnSectorBoundries(Addr,bytes) ){
    word buffPos;
    word SecEndAddr = GetSectorEndForWriteAddr(Addr);
    word SecBytesToEnd = SecEndAddr-Addr;
    int binc = 0;
    StartWriteAtAddr(Addr);
    for(binc=0; binc< SecBytesToEnd; binc++)
    {
        i2cSendByte(buff[binc]);
    }
    FinishSectorWrite();

    StartWriteAtAddr(Addr+SecBytesToEnd);
    word BytesToEnd = bytes - SecBytesToEnd;
    buffPos = SecBytesToEnd;
    for(binc=0; binc< BytesToEnd; binc++)
    {
        i2cSendByte(buff[buffPos+binc]);
    }
    FinishSectorWrite();
}else{
    StartWriteAtAddr(Addr);
    int binc = 0;
    for(binc=0; binc<bytes; binc++)
    {
        i2cSendByte(buff[binc]);
    }
    FinishSectorWrite();
}
}

Ohne selbst die einfachsten DSO werden Sie jedoch nicht weit kommen. Es gibt einfach zu viele Dinge, die schief gehen können.

Ich habe Arbeitsroutinen angehängt, die ich in einem PIC32 verwendet habe, indem ich die Funktionsaufrufe der Legacy-Bibliothek in plib verwende. Es dient zum zufälligen Lesen oder Schreiben aus dem EEPROM.

Wenn Sie sich den Quellcode ansehen möchten, wie plib diese Funktionen implementiert, finden Sie sie in Ihrem Mikrochip-Installationsverzeichnis des Compilers:

C:\Programme (x86)\Microchip\xc32\v1.34\pic32-libs\peripheral\i2c\legacy

(möglicherweise eine andere Version auf Ihrem Computer)

void i2c1Write(unsigned char dev_addr, unsigned char addr,unsigned char data){
    StartI2C1();
    IdleI2C1();

    MasterWriteI2C1(dev_addr); // Write control byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    MasterWriteI2C1(addr); // address byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    MasterWriteI2C1(data); // Read Command
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    StopI2C1();
    IdleI2C1();
}

unsigned char i2c1Read(unsigned char dev_addr, unsigned char addr){
    unsigned char data;

    StartI2C1();
    IdleI2C1();

    MasterWriteI2C1(dev_addr | 0); // Write control byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    MasterWriteI2C1(addr); // write address byte
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?


    //initiate repeated start and read data
    StartI2C1();
    IdleI2C1();

    MasterWriteI2C1(dev_addr | 1); // Issue Read Command
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    data = MasterReadI2C1(); // Read the data
    IdleI2C1();
    if (I2C1STATbits.ACKSTAT) return; // NACK'ed by slave ?

    StopI2C1();
    IdleI2C1();

    return data;
}