簡體   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