EEPROM协议误解

Posted

技术标签:

【中文标题】EEPROM协议误解【英文标题】:EEPROM protocol misconception 【发布时间】:2021-06-07 09:32:21 【问题描述】:

我目前正在使用通过 i2c 与 stm32f4 (11RET) 连接的微芯片 eeprom (24cw160)。配置和连接似乎工作正常,因为我的逻辑分析器打印了一些 i2c 消息(带有 ACK),我可以发送数据和接收数据。在阅读reference manual(尤其是第 13 页和第 18 页,其中包含我正在执行的两个操作的示意图)之后,我期望下面的代码将数据 0,1,2... 依次发送到 x10 之后的地址,然后接收相同的数据并打印出来:

while(true)

    HAL_Delay(1000);
    std::array<uint8_t,100> arr;
    int counter=0;
    for(auto&i :arr)
      i=counter;
      counter++;
    
    auto ret1 = HAL_I2C_Mem_Write_DMA(&hi2c1 , 0xa0 , 0x10 , 1 ,arr.data() , arr.size());
    HAL_Delay(1000);
    std::array<uint8_t,100> arr2;
    arr2.fill(1);
    auto ret2 = HAL_I2C_Mem_Read( &hi2c1 , 0xa1 , 0x10 , 1 , arr2.data() , arr2.size(),100);
    printf("arr2:\n");
    for(auto i:arr2)
      printf("%d,",(int)i);
    
    printf("\nWrite ret status: %d\nRead ret status: %d\n",ret1,ret2);
  

相反,我在终端上得到的是:

arr2:
70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
Write ret status: 0
Read ret status: 0
arr2:
68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
Write ret status: 0
Read ret status: 0

注意,第一行打印与第二行有一些差异,第二行是重复出现的(所以第一次打印的时候确实与其他打印有点不同)老实说,我认为我已经将自己与我给HAL_I2C_Mem_Writeread 提供的常量参数,我也想对此进行一些解释。 有关更多信息,请评论我,我将提供所有必要的诊断/初始化等。

【问题讨论】:

你试过非DMA写版本吗?你没有得到实际写入的结果,只是写入设置。 HAL_I2C_Mem_Write_DMA() 是非阻塞的。开始 DMA 传输后仅等待 1 秒是不够的。而是等到HAL_I2C_MemTxCpltCallback() 被调用。 另外,MemAddSize 是否以比特为单位?您使用具有 11 位字的设备将 16 传递给它。我认为这不是问题所在,即使它根本不正确,因为它无论如何都会发送两个字节,但要记住这一点。 另外,这些写入是否作为单次写入发生?如果是这样,那么您只能写入单个页面,不能跨越 32 字节的边界。 据我了解的示例,HAL 调用自己将 7 位设备地址转换为 8 位读/写命令。尝试在两个调用中使用 0x50(而不是 0xa0 和 0xa1)。 【参考方案1】:

感谢 cmets,我设法在我想要的任何地址发送一个字节。上一个代码中一个注意到的错误是MemAddress 参数(HAL_I2C_Write_Mem 的第三个参数),因为我的 eeprom 是 11 位可寻址的,我应该向 hal 声明它是 16 而不是 8,因为 5 个额外的位被忽略了,但少于 11 个可能会发生故障。

第二个问题是我试图写入超过 32 个字节,而我只读取前 32 个字节,因为协议不接受一次写入或读取超过一个 32 字节的页面。因此,这里是修改后的代码,其中包含一些 cmets 的更改:

std::array<uint8_t,32> arr0; //32 bytes instead of something silly
unsigned counter=0;
for(auto&i :arr)
    i=counter;
    counter++;

// 0x20 is a start of a page so it can write all 32 bits
// I2C_MEMADD_SIZE_16BIT is the value 2 instead of 1 I had
// The extra 5 bits are ignored
// For the testing I call the blocking write
auto ret1 = HAL_I2C_Mem_Write(&hi2c1 , 0xa0 , 0x20 , I2C_MEMADD_SIZE_16BIT , arr.data() , arr.size(),4);
HAL_Delay(4);
std::array<uint8_t,32> arr20;
arr2.fill(1);
auto ret2 = HAL_I2C_Mem_Read( &hi2c1 , 0xa1 , 0x20 , I2C_MEMADD_SIZE_16BIT , arr2.data() ,arr2.size(),4);
HAL_Delay(4);
printf("arr2: ");
for(auto i:arr2)
   printf(" %d,",(int)i);
printf("\nWrite ret status: %d\nRead ret status: %d\n",ret1,ret2);

【讨论】:

std:: 是 C++ 语句,不是 C 的一部分 @user3629249 我知道,但这并不重要,因为与硬件相关的问题大多与 c 而不是 c++ 相关。如果我可以添加超过 5 个标签,我会添加 c++,但这是我的问题中最不重要的事情,因为 std::array 在这里所做的任何事情都可以使用传统数组完成(例如,您可以迭代数组而不是 fill) .

以上是关于EEPROM协议误解的主要内容,如果未能解决你的问题,请参考以下文章

FPGAer:EEPROM读写实战

ZYNQ之FPGA学习----EEPROM读写测试实验

硬件实现IIC协议读取EEPROM

单片机: EEPROM和串口通信

用STM32 中的 I2C读写EEPROM 基础知识(二)

Arduino EEPROM读写实例