Having issues with EEPROM storage. External EEPROM acks data transfer, but only returns 255 when read

214 Views Asked by At

I’m working on a project and for part of it I am trying to use the Harmony I2C driver library in order to send data to and from the eeprom using the SDA and SCL lines.

When reading the SDA and SCL lines with an oscilloscope, the correct sequence of bits is passed to the EEPROM, and the EEPROM acks the data. However, when trying to read from the EEPROM, it sends back all 1s. Additionally, when calling the built in I2C function DRV_I2C_BytesTransferred, it returns 0 bytes for both the read and the write.

I’ve been troubleshooting the past few days, but I can’t seem to find what is causing this.

I'm using the PIC32MZ1024ECM144-I/PL microcontroller and Harmony V2.06 on the MPLAB X IDE. The EEPROM that I’m working with is the M24C02-RMN6TP.

Here is the oscilloscope when writing to the EEPROM:

Oscilloscope when writing

Here is the oscilloscope when reading from the EEPROM:

enter image description here

enter image description here

Here are the functions for the EEPROM read and write. The call to the eepromWrite and eepromRead are called in a separate function not listed here, and there is an added delay between the read and the write function calls.

SYS_MODULE_OBJ objectHandle;

uint8_t deviceAddressSlave;

uint8_t numOfBytes;

uint8_t         TXbuffer[32];

/* I2C driver RX Buffer */
uint8_t         RXbuffer[32];

DRV_I2C_BUFFER_EVENT APP_Check_Transfer_Status(DRV_HANDLE drvOpenHandle, DRV_I2C_BUFFER_HANDLE drvBufferHandle);

uint32_t    APP_Number_Of_Bytes_Transferred(DRV_HANDLE drvOpenHandle, DRV_I2C_BUFFER_HANDLE drvBufferHandle);



DRV_HANDLE drvI2CMasterHandle; //Returned from DRV_I2C_Open for I2C Master
DRV_I2C_BUFFER_HANDLE bufHandle_M1; //Returned from calling a Data Transfer function
uintptr_t i2cOpStatus; //Operation status of I2C operation returned from callback
DRV_HANDLE drvI2CSlaveHandle; //Returned from DRV_I2C_Open for I2C Slave
DRV_I2C_BUFFER_HANDLE bufHandle_S1; //Returned from calling a Data Transfer function
DRV_I2C_BUFFER_HANDLE bufHandle_S2; //Returned from calling a Data Transfer function

typedef enum {
    
        TxRx_OPEN = 0,
        TxRx_TO_EXTERNAL_SLAVE,
        TxRx_EXTERNAL_SLAVE_STATUS_CHECK_1,
        TxRx_STATUS_CHECK,
        TxRx_COMPLETED

} APP_EEPROM_WR_STATES;

static APP_EEPROM_WR_STATES appWriteState = TxRx_OPEN;

DRV_I2C_BUFFER_EVENT Transaction;


bool APP_Write_Tasks(void)
{
    switch (appWriteState)
    {
        case TxRx_OPEN:
        {;
            /* Open the I2C Driver for Master */
            appData.drvI2CHandle_Master = DRV_I2C_Open( DRV_I2C_INDEX_0,
                                                     DRV_IO_INTENT_READWRITE );

            if(appData.drvI2CHandle_Master != DRV_HANDLE_INVALID)
            {
                
                appWriteState = TxRx_TO_EXTERNAL_SLAVE;
            }
            else
            {
                appData.state = APP_STATE_ERROR;
            }

            break;
        }
        case TxRx_TO_EXTERNAL_SLAVE:
        {    
            /* Number of bytes to transfer */
            numOfBytes = 3;

            deviceAddressSlave = 0xA0;
            
            
            if ( (appData.appI2CWriteBufferHandle[0] == DRV_I2C_BUFFER_HANDLE_INVALID) || 
                    (APP_Check_Transfer_Status(appData.drvI2CHandle_Master,     appData.appI2CWriteBufferHandle[0]) == DRV_I2C_BUFFER_EVENT_COMPLETE) ||
                        (APP_Check_Transfer_Status(appData.drvI2CHandle_Master, appData.appI2CWriteBufferHandle[0]) == DRV_I2C_BUFFER_EVENT_ERROR) )
            {
                
           
                appData.appI2CWriteBufferHandle[0] = DRV_I2C_Transmit (appData.drvI2CHandle_Master,deviceAddressSlave, &TXbuffer[0], numOfBytes, NULL);

                
            }
             
            if (APP_Check_Transfer_Status(appData.drvI2CHandle_Master, appData.appI2CWriteBufferHandle[0]) == DRV_I2C_BUFFER_EVENT_ERROR){
            }

            appWriteState = TxRx_EXTERNAL_SLAVE_STATUS_CHECK_1;
            
            break;
        }   
        case TxRx_EXTERNAL_SLAVE_STATUS_CHECK_1:
        {
            Transaction = APP_Check_Transfer_Status(appData.drvI2CHandle_Master, appData.appI2CWriteBufferHandle[0]);
            appWriteState =TxRx_STATUS_CHECK;
            if  ( Transaction == DRV_I2C_BUFFER_EVENT_COMPLETE)
            {
                appWriteState =TxRx_STATUS_CHECK;
            }
             else if  (Transaction == DRV_I2C_BUFFER_EVENT_ERROR)  //Useful for error checking
            {
                appWriteState =TxRx_STATUS_CHECK;
            }
            
            break;
        }        
        case TxRx_STATUS_CHECK:
        {
            
// Only defined for dynamic driver.            
            #ifdef DRV_I2C_CLIENTS_NUMBER            
extern const DRV_I2C_INIT drvI2C0InitData;
            DRV_I2C_Close( appData.drvI2CHandle_Master );
            DRV_I2C_Deinitialize (sysObj.drvI2C0);
            #endif
            
            DelayMs(800);
            #ifdef DRV_I2C_CLIENTS_NUMBER            
            sysObj.drvI2C0 = DRV_I2C_Initialize(DRV_I2C_INDEX_0, (SYS_MODULE_INIT *)&drvI2C0InitData);
            #endif
            
            /* to run the application only once,  
             * set next state to TxRx_COMPLETED */
//            appWriteState = TxRx_COMPLETED;
            
            /* to run the application in a continuous loop,  
             * set next state to TxRx_OPEN */
            #ifdef DRV_I2C_CLIENTS_NUMBER            
            appWriteState = TxRx_COMPLETED;
            #else
            appWriteState = TxRx_TO_EXTERNAL_SLAVE;
            #endif
            break;
        }
        case TxRx_COMPLETED:
        {
            return true;
            break;
        }
    }
    
    return false;
}




void writeEEPROM(void) {
    TXbuffer[0] = 0xF0;
    TXbuffer[1] = ((unsigned short)300 >> 8); //1
    TXbuffer[2] = (char) 300; //44
    
    
    
    while (!APP_Write_Tasks());
    
    DRV_I2C_Close( appData.drvI2CHandle_Master );
}




void readEEPROM(void) {
    appData.drvI2CHandle_Master = DRV_I2C_Open( DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE );
    /*memset(TXbuffer, 0, sizeof TXbuffer);  //Used when not calling write function
    deviceAddressSlave = 0xA0;
    numOfBytes = 3;  
    TXbuffer[0] = 0xF0;
    TXbuffer[1] = ((unsigned short)300 >> 8); //1
    TXbuffer[2] = (char) 300; //44*/
    
    appData.appI2CReadBufferHandle[0] = DRV_I2C_TransmitThenReceive(appData.drvI2CHandle_Master, 0xA0, &TXbuffer[0], 1, &RXbuffer, 2, NULL);

    DRV_I2C_Close(appData.drvI2CHandle_Master);
}



DRV_I2C_BUFFER_EVENT APP_Check_Transfer_Status(DRV_HANDLE drvOpenHandle, DRV_I2C_BUFFER_HANDLE drvBufferHandle)
{
    return (DRV_I2C_TransferStatusGet (appData.drvI2CHandle_Master, drvBufferHandle));
}

uint32_t APP_Number_Of_Bytes_Transferred(DRV_HANDLE drvOpenHandle, DRV_I2C_BUFFER_HANDLE drvBufferHandle)
{
    return (DRV_I2C_BytesTransferred (appData.drvI2CHandle_Master,drvBufferHandle));
}

These are functions are based off the driver example code that comes with Harmony. I have been testing sending the value 300 split into 2 bytes to the EEPROM. However no matter what address I try or what values I send, the EEPROM only every sends back 255, I.E. all bits set to 1. There is write control on the EEPROM that block write, however I have confirmed that the write block is currently disabled.

2

There are 2 best solutions below

0
On

So I found a solution. I'm not sure exactly what the problem was, but I think the I2C drivers I was using weren't sending the I2C stop condition correctly, which caused the EEPROM not to start the internal write cycle.

The solution I found involves turning on the Bit Bang I2C implementation in the Harmony configuration settings and setting the Errata Method the BIT_BANG_STOP. After that I no longer had any errors reading or writing, and the above code worked as it should.

1
On

In might be coze EEPROM need some delay to write data.

First step - try to use delay after the write function 200 ms. If you'll read your wrote data the next step is checking if data writing process finished: enter image description here

Ex:

/**
 * @brief  Check if device present or ready
 * @param  [in] i2c_addr I2C devices address
 * @retval true if ok or ready
 */
bool i2c_is_bevice_present (uint8_t i2c_addr) {
    _tx_buf_len = 0;
    if (i2c_transmit(i2c_addr, true) != I2C_SUCCESS) {
        return false;
    }
    return true;
}


static bool is_m24c02_ready (void) {
    return i2c_is_bevice_present(M42C02_I2C_ADDRES_MEMORY);
}

/**
 * @brief  M24C02 write byte
 * @param  [In] addres Addres
 * @param  [In] data byte to write
 * @retval none
 */
void m24c02_write_byte(uint16_t addres, uint8_t data) {
    while (is_m24c02_ready() == false);
    m24c02_i2c_write(addres, &data, 1);
    while (is_m24c02_ready() == false);
}