繁体   English   中英

STM32 - I2C 写入失败

[英]STM32 - I2C Write Failure

我正在使用带有 512KB EEPROM 的 STM32,我使用 STM32CubeMX 初始化了项目

PB7 作为 I2C_SDA PB6 作为 I2C_SCL

生成的函数

I2C_HandleTypeDef hi2c1;

/* I2C1 init function */
void MX_I2C1_Init(void)
{
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    GPIO_InitStruct.Pin = I2C_SCL_Pin|I2C_SDA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();

    /* I2C1 interrupt Init */
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{

  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */

  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();

    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    HAL_GPIO_DeInit(GPIOB, I2C_SCL_Pin|I2C_SDA_Pin);

    /* I2C1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
  /* USER CODE BEGIN I2C1_MspDeInit 1 */

  /* USER CODE END I2C1_MspDeInit 1 */
  }
} 

在主要我调用MX_I2C1_Init()然后HAL_I2C_MspInit(&hi2c1) ,但是当我调用

while(HAL_I2C_Mem_Write(hi2c,(uint16_t)DevAddress,(uint16_t)MemAddress,I2C_MEMADD_SIZE_8BIT,pData,(uint16_t)16-MemAddress,1000)!= HAL_OK && 1);

这个while循环永远不会返回HAL_OK,所以我无法处理读取写入的数据进行验证。 我的 EEPROM 是

CAT24C512WI-GT3OSCT-ND和A0->A2,WP接地

尝试这个。 首先调用设备就绪检查并确保设备已就绪。

while(HAL_I2C_IsDeviceReady(&hi2c1, I2C_EEPROM_ADDRESS, 64, HAL_MAX_DELAY)!= HAL_OK); 进而

while(HAL_I2C_Mem_Write(&hi2c1, I2C_EEPROM_ADDRESS, eeStart, I2C_MEMADD_SIZE_8BIT, pRamStart, num, HAL_MAX_DELAY)!= HAL_OK); “HAL_I2C_IsDeviceReady”中的 64 - 尝试次数。 有时一次或多次是不够的。 查看。 需要 &hi2c1,而不是 hi2c1

好的! 第一次会是“true”,但是在写入 eeprom 之后,您需要确保录制完成并且 eeprom 已准备好进行下一步。 在最后一行的 hi2c1 之前,您没有去过 & 。 而且,也许对于 EEPROM 512kb,您需要指定“I2C_MEMADD_SIZE_16BIT”而不是“I2C_MEMADD_SIZE_8BIT”?

您如何确定按照处理器的标准需要大量时间的录制已完成? 为此,有此过程 HAL_I2C_IsDevitseReady。

在调用HAL_I2C_MspInit(&hi2c1)您需要立即检查 i2c whit 的状态

    while(HAL_I2C_Mem_Write(
                       &hi2c1,
                       I2C_EEPROM_ADDRESS,
                       eeStart,
                       I2C_MEMADD_SIZE_8BIT,
                       pRamStart,
                       num,
                       HAL_MAX_DELAY) == HAL_BUSY);

如果程序卡在 while 循环中总是返​​回HAL_BUSY很可能您使用的是带有硬件错误的微控制器,您可以检查第 26 页中 stm32f10xx8 的勘误表,这发生在我身上,stm32f103c8t6 属于 STM32F10xx8系列(如果您的设备不属于该系列,您仍然可以尝试下面列出的第二种解决方案)。

解决方案列在勘误表中,是这样的:

解决方法SCL 和 SDA 模拟滤波器输出分别在 SCL 和 SDA 线上发生转换后更新。 SCL 和 SDA 转换可以通过软件在输出模式下配置 I2C I/O 来强制。 然后,一旦模拟滤波器解锁并输出 SCL 和 SDA 线电平,BUSY 标志可以通过软件复位来复位,I2C 可以进入主模式。 因此,必须应用以下顺序:

  1. 通过清除 I2Cx_CR1 寄存器中的 PE 位禁用 I2C 外设。
  2. 将 SCL 和 SDA I/O 配置为通用输出漏极开路,高电平(向 GPIOx_ODR 写入 1)
  3. 检查 GPIOx_IDR 中的 SCL 和 SDA 高电平。
  4. 将 SDA I/O 配置为通用输出漏极开路低电平(向 GPIOx_ODR 写入 0)。
  5. 检查 GPIOx_IDR 中的 SDA 低电平。
  6. 将 SCL I/O 配置为通用输出漏极开路低电平(向 GPIOx_ODR 写入 0)。
  7. 检查 GPIOx_IDR 中的 SCL 低电平。
  8. 将 SCL I/O 配置为通用输出漏极开路,高电平(向 GPIOx_ODR 写入 1)。
  9. 检查 GPIOx_IDR 中的 SCL 高电平。
  10. 将 SDA I/O 配置为通用输出漏极开路,高电平(向 GPIOx_ODR 写入 1)。
  11. 检查 GPIOx_IDR 中的 SDA 高电平。
  12. 将 SCL 和 SDA I/O 配置为备用功能漏极开路。
  13. 设置 I2Cx_CR1 寄存器中的 SWRST 位。
  14. 清除 I2Cx_CR1 寄存器中的 SWRST 位。
  15. 通过设置 I2Cx_CR1 寄存器中的 PE 位来启用 I2C 外设。

另一个解决方案是添加

__HAL_RCC_I2C1_FORCE_RESET();
HAL_Delay(2);
__HAL_RCC_I2C1_RELEASE_RESET();

HAL_I2C_MspInit(...)之后到HAL_I2C_MspInit(...) __HAL_RCC_I2C1_CLK_ENABLE(); 所以最终的解决方案是

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    GPIO_InitStruct.Pin = I2C_SCL_Pin|I2C_SDA_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
    //--------------added code :D -----------------------------------
    __HAL_RCC_I2C1_FORCE_RESET();
    HAL_Delay(2);
    __HAL_RCC_I2C1_RELEASE_RESET();
    //-------------end of added code---------------------------------

    /* I2C1 interrupt Init */
    HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
    HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
}

第二种解决方案可能适用也可能不适用于您,因为它不是 ST 推荐的解决方案,但在我的情况下和许多其他解决方案有效,尽管我不相信产品中的此解决方案,这取决于您可以玩的微型模型如果 2 不起作用,则延迟实际上取决于您使用的微控制器。

我开发了一个 EEPROM 库,您可以检查它并将其用于项目。

特征:

  • 支持所有具有自动数据控制的 AT24C 内存
  • 支持写保护
  • 支持多行地址
  • 可选引脚配置
  • 高速内存库
  • 支持 AVR 和 ARM Cortex M

图书馆链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM