STM32F4与Microchip 24CW160 EEPROM I2C读写异常及HAL库参数疑问
Let's break down what's causing your unexpected read results and fix the problem step by step:
Key Issues Identified
- Incorrect Memory Address Mode
- Unreliable DMA Completion Handling
- Potential Page Boundary Misunderstanding
1. Fix the Memory Address Size Parameter
The 24CW160 uses an 11-bit memory address, which requires you to use 16-bit address mode in HAL's I2C functions. You're currently passing 1 (8-bit mode), which only sends the lower 8 bits of your start address and ignores the upper 3 bits—this leads to incorrect addressing for the EEPROM.
Update both your write and read calls to use I2C_MEMADD_SIZE_16BIT (defined as 2 in HAL headers):
// Write with 16-bit address mode auto ret1 = HAL_I2C_Mem_Write_DMA(&hi2c1, 0xa0, 0x10, I2C_MEMADD_SIZE_16BIT, arr.data(), arr.size()); // Read with 16-bit address mode auto ret2 = HAL_I2C_Mem_Read(&hi2c1, 0xa1, 0x10, I2C_MEMADD_SIZE_16BIT, arr2.data(), arr2.size(), 100);
2. Properly Wait for DMA Transfer + EEPROM Write Cycle
Using HAL_Delay(1000) is a lazy and unreliable way to handle asynchronous DMA transfers. You need to confirm the DMA transfer has finished first, then wait for the EEPROM's internal write cycle (max 10ms for 24CW160, per datasheet).
Option 1: Polling (Simple for Testing)
HAL_I2C_Mem_Write_DMA(&hi2c1, 0xa0, 0x10, I2C_MEMADD_SIZE_16BIT, arr.data(), arr.size()); // Wait until I2C peripheral is ready (DMA transfer complete) while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {} // Wait for EEPROM to finish internal write HAL_Delay(10);
Option 2: Interrupt Callback (Better for Production)
Enable the I2C TX DMA complete interrupt in your HAL initialization, then use a flag to track completion:
volatile uint8_t i2c_dma_tx_done = 0; // DMA transfer complete callback void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c) { if (hi2c->Instance == I2C1) { i2c_dma_tx_done = 1; } } // In your loop: i2c_dma_tx_done = 0; auto ret1 = HAL_I2C_Mem_Write_DMA(&hi2c1, 0xa0, 0x10, I2C_MEMADD_SIZE_16BIT, arr.data(), arr.size()); while (!i2c_dma_tx_done) {} HAL_Delay(10);
3. Account for EEPROM Page Boundaries
The 24CW160 has a 16-byte page size. While HAL's I2C functions handle multi-page writes correctly (via auto-increment), if your addressing was wrong, writes could wrap around to the start of a page and overwrite data. Fixing the address mode should resolve this, but you can test with a single page first to confirm:
// Test 1-page write/read std::array<uint8_t,16> test_arr{}; for(int i=0; i<16; i++) test_arr[i] = i; auto ret1 = HAL_I2C_Mem_Write_DMA(&hi2c1, 0xa0, 0x10, I2C_MEMADD_SIZE_16BIT, test_arr.data(), test_arr.size()); while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {} HAL_Delay(10); std::array<uint8_t,16> test_arr2{}; auto ret2 = HAL_I2C_Mem_Read(&hi2c1, 0xa1, 0x10, I2C_MEMADD_SIZE_16BIT, test_arr2.data(), test_arr2.size(), 100); printf("Test Data:\n"); for(auto val : test_arr2) printf("%d,", (int)val); printf("\n");
4. Double-Check Device Address
Ensure your 24CW160's A2/A1/A0 pins are tied to GND (matching your 0xA0/0xA1 device addresses). If any of these pins are floating or tied to VCC, the device address will change, leading to silent failures.
After applying these fixes, your read data should match the 0-99 sequence you're writing. If you still see issues, share your I2C initialization code for further debugging.
内容的提问来源于stack exchange,提问作者Spyros Mourelatos

