You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PIC32+Harmony I2C驱动读写M24C02 EEPROM返回全1故障求助

I2C驱动EEPROM读写异常问题排查

问题描述

使用Harmony I2C驱动库通过SDA、SCL与M24C02 EEPROM通信,示波器观测到发送的比特序列正确且EEPROM有应答,但读取时返回全1(0xFF);调用DRV_I2C_BytesTransferred时,读写操作均返回0字节。测试写入数值300(拆分为两个字节),无论地址或数值如何,读取结果始终为0xFF,已确认EEPROM写保护关闭。

硬件与软件环境

  • 微控制器:PIC32MZ1024ECM144-I/PL
  • 开发环境:MPLAB X IDE + Harmony V2.06
  • EEPROM型号:M24C02-RMN6TP

示波器截图

写入操作波形

写入EEPROM时的示波器波形

读取操作波形

读取EEPROM时的示波器波形1
读取EEPROM时的示波器波形2

代码实现

读写函数基于Harmony驱动示例编写,writeEEPROM和readEEPROM独立调用,读写间已添加延时:

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));
}

问题分析与解决建议

1. 读取操作的核心错误

readEEPROM函数调用DRV_I2C_TransmitThenReceive后立即关闭I2C句柄,未等待传输完成。I2C传输是异步操作,调用函数仅提交请求,此时数据还未完成接收就关闭驱动,导致RXbuffer未被正确填充,返回全1(未初始化或无效数据)。

修改readEEPROM,添加传输状态等待逻辑:

void readEEPROM(void) {
    appData.drvI2CHandle_Master = DRV_I2C_Open( DRV_I2C_INDEX_0, DRV_IO_INTENT_READWRITE );
    if(appData.drvI2CHandle_Master == DRV_HANDLE_INVALID) {
        return; // 处理打开失败
    }

    TXbuffer[0] = 0xF0; // EEPROM内部存储地址(M24C02地址范围0x00~0xFF,0xF0合法)
    
    appData.appI2CReadBufferHandle[0] = DRV_I2C_TransmitThenReceive(
        appData.drvI2CHandle_Master, 
        0xA0, 
        &TXbuffer[0], 
        1, 
        &RXbuffer, 
        2, 
        NULL
    );

    // 等待传输完成或出错
    while(APP_Check_Transfer_Status(appData.drvI2CHandle_Master, appData.appI2CReadBufferHandle[0]) == DRV_I2C_BUFFER_EVENT_PENDING);

    DRV_I2C_Close(appData.drvI2CHandle_Master);
}

2. DRV_I2C_BytesTransferred返回0的原因

该函数需在传输完成后调用,若在传输未完成时调用会返回0;同时要确保传入的bufHandle有效(不是DRV_I2C_BUFFER_HANDLE_INVALID)。

3. EEPROM写入的潜在问题

  • 确认I2C设备地址:M24C02的7位设备地址为1010A2A1A0,A2/A1/A0对应硬件引脚电平。你使用的0xA0是1010000左移1位(写地址),若硬件引脚A2/A1/A0不全为低,地址会错误,导致写入未生效,读取返回默认全1。可通过示波器确认发送的设备地址是否与硬件匹配。
  • 当前写入后800ms延时足够覆盖M24C02最大5ms的写周期,也可优化为查询EEPROM应答的方式(发送设备地址,等待ACK)。

4. 驱动初始化的冗余操作

APP_Write_Tasks的TxRx_STATUS_CHECK中反复关闭、重新初始化I2C驱动完全没必要,会增加系统复杂度,建议删除该部分逻辑,保持驱动持续打开即可。

5. 硬件与波形验证

  • 检查I2C引脚的上拉电阻是否合适(M24C02需上拉,一般选4.7kΩ)。
  • 确认微控制器I2C外设配置(时钟频率、采样时间等)符合M24C02要求(支持最高100kHz标准模式、400kHz快速模式)。
  • 读取波形需验证:发送内部地址后是否发送了重复起始条件+读地址、EEPROM是否发送数据字节、主机是否发送ACK确认接收。

内容的提问来源于stack exchange,提问作者bbeeb8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 16:08:07