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
示波器截图
写入操作波形

读取操作波形


代码实现
读写函数基于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
相关产品推荐
相关产品推荐

