STM32-I2C写失败

时间:2018-10-23 11:21:04

标签: stm32 eeprom

我正在使用STM32和EEPROM 512KB,我使用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接地

5 个答案:

答案 0 :(得分:0)

尝试一下。首先致电设备准备检查,并确保设备已准备就绪。

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

根据处理器的标准,如何确定需要大量时间的记录已完成?为此,需要执行以下过程HAL_I2C_IsDevitseReady。

答案 3 :(得分:0)

在致电HAL_I2C_MspInit(&hi2c1)之后,您需要立即检查i2c的状态

    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的errata,发生在我STM32F10xx8系列的stm32f103c8t6上(如果您的设备不属于该系列,您仍然可以尝试下面列出的第二种解决方案)。

解决方案已在勘误表中列出,并且是这样:

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

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

另一种解决方案是添加

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

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推荐的解决方案,但就我而言,尽管我不相信产品中的这种解决方案,但许多others还是可行的,这取决于型号如果2个时钟不起作用,您可以在微控制器中播放延迟,这实际上取决于您所使用的微控制器。

答案 4 :(得分:0)

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

功能:

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

Library Link