STM32 - Ошибка записи I2C - PullRequest
       50

STM32 - Ошибка записи I2C

0 голосов
/ 23 октября 2018

Я использую STM32 с EEPROM 512 КБ, я инициализировал проект, используя 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 подключены к земле

Ответы [ 4 ]

0 голосов
/ 23 июля 2019

Сразу после вызова 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, очень вероятно, что выиспользуя микроконтроллер с аппаратной ошибкой, вы можете проверить ошибки stm32f10xx8 на стр. 26, это произошло со мной с stm32f103c8t6 семейства STM32F10xx8 (если ваше устройство не принадлежит этому семейству, вы можетепопробуйте второе решение, указанное ниже).

решение перечислено с ошибками и является следующим:

Обходной путь Выход аналогового фильтра SCL и SDA обновляется послеПереход происходит по линии SCL и SDA соответственно.Переход SCL и SDA может быть вызван программным обеспечением, конфигурирующим входы / выходы I2C в режиме вывода.Затем, когда аналоговые фильтры разблокированы и выводят уровень линий SCL и SDA, флаг BUSY может быть сброшен с программным сбросом, и I2C может войти в основной режим.Поэтому необходимо применить следующую последовательность:

  1. Отключить периферийное устройство I2C, очистив бит PE в регистре I2Cx_CR1.
  2. Сконфигурируйте входы / выходы SCL и SDA как открытый выход общего назначения-Drain, High level (запись 1 в GPIOx_ODR)
  3. Проверка высокого уровня SCL и SDA в GPIOx_IDR.
  4. Конфигурирование ввода-вывода SDA в качестве выходного сигнала общего назначения с открытым стоком, низкий уровень (записьОт 0 до GPIOx_ODR).
  5. Проверка низкого уровня SDA в GPIOx_IDR.
  6. Сконфигурируйте вход / выход SCL как выход общего назначения с открытым стоком, низким уровнем (запись 0 в GPIOx_ODR).
  7. Проверка низкого уровня SCL в GPIOx_IDR.
  8. Настройка ввода / вывода SCL в качестве выходного сигнала общего назначения, открытый уровень, высокий уровень (запись 1 в GPIOx_ODR).
  9. Проверка высокого уровня SCL вGPIOx_IDR.
  10. Сконфигурируйте ввод / вывод SDA как выход общего назначения, открытый слив, высокий уровень (запись 1 в GPIOx_ODR).
  11. Проверка высокого уровня SDA в GPIOx_IDR.
  12. Настройте входы / выходы SCL и SDA в качестве альтернативной функции Open-Drain.
  13. Установить бит SWRST в регистре I2Cx_CR1.
  14. Очистить бит SWRST в регистре I2Cx_CR1.
  15. Включить периферийное устройство I2C, установив бит PE в регистре I2Cx_CR1.

другое решение добавляет

__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, но в моем случае и многие другие работают, хотя я бы не стал доверять это решение в продукте, это зависит от модели вашего микро, вы можете играть с задержкой, если2 не работает, это зависит от того, какой микроконтроллер вы используете.

0 голосов

Хорошо!Первый раз будет «true», но после записи в eeprom вам необходимо убедиться, что запись завершена и eeprom готов к следующему шагу.Вы не были и до hi2c1 в последней строке.И, может быть, для EEPROM 512 КБ вам нужно указать «I2C_MEMADD_SIZE_16BIT», а не «I2C_MEMADD_SIZE_8BIT»?

0 голосов

Как вы определяете, что запись, которая, по стандартам процессора, требует значительного времени, завершена?Для этого есть процедура HAL_I2C_IsDevitseReady.

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); 64 в «HAL_I2C_IsDeviceReady» - количество попыток.Иногда одного или нескольких раз недостаточно.Проверьте.Нужен & hi2c1, а не hi2c1

...