Определить причину NACK от ведомого устройства I2C

#microcontroller #i2c

#микроконтроллер #i2c

Вопрос:

Я довольно новичок в I2C, поэтому, пожалуйста, извините за недостаток знаний. Я пытаюсь считывать данные с датчика PAC1710, используя микроконтроллер Stm32H743ZI с HAL-библиотекой и генератором кода cubemx.

Я могу отправить первую часть своего сообщения, но я не получаю подтверждения после отправки адреса. Я использую резистор 2700 Ом для заземления на выводе ADDR_SEL, ОПОВЕЩЕНИЕ переходит на землю через резистор 10 Ком.

Что касается моего кода, это моя инициализация:

 void MX_I2C2_Init(void)
{
  hi2c2.Instance = I2C2;
  hi2c2.Init.Timing = 0x307075B1;
  hi2c2.Init.OwnAddress1 = 0;
  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c2.Init.OwnAddress2 = 0;
  hi2c2.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(amp;hi2c2) != HAL_OK) {
    Error_Handler();
  }
  /** Configure Analogue filter */
  if (HAL_I2CEx_ConfigAnalogFilter(amp;hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK) {
    Error_Handler();
  }
  /** Configure Digital filter */
  if (HAL_I2CEx_ConfigDigitalFilter(amp;hi2c2, 0) != HAL_OK) {
    Error_Handler();
  }
}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if (i2cHandle->Instance == I2C2) {
  /* USER CODE BEGIN I2C2_MspInit 0 */

  /* USER CODE END I2C2_MspInit 0 */
  
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C2 GPIO Configuration    
    PB11     ------> I2C2_SDA
    PF1     ------> I2C2_SCL 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
    HAL_GPIO_Init(GPIOF, amp;GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
    HAL_GPIO_Init(GPIOB, amp;GPIO_InitStruct);

    /* I2C2 clock enable */
    __HAL_RCC_I2C2_CLK_ENABLE();
  }
}
  

Моя реализация очень упрощена:

 uint8_t i2cbuffer[8];
uint16_t val = 0;
HAL_StatusTypeDef ret;
  

и в основном цикле у меня есть следующий код:

         i2cbuffer[0] = 254;
        ret = HAL_I2C_Master_Transmit(amp;hi2c2, PAC1710Address << 1, i2cbuffer, 1, HAL_MAX_DELAY);   
        if (ret == HAL_OK) {
            ret = HAL_I2C_Master_Receive(amp;hi2c2, PAC1710Address << 1 , i2cbuffer, 2, HAL_MAX_DELAY);
            if (ret == HAL_OK) {
                val = i2cbuffer[0];
            }
        }
        HAL_Delay(500);
  

Я выбрал 254, потому что я думал, что ведомое устройство должно быть в состоянии ответить на это независимо от его измерения. Однако я даже не дошел до отправки регистра, изучив его с помощью осциллографа, я отправляю адрес и получаю NACK.

Есть ли что-нибудь очевидное, чего мне не хватает?

Комментарии:

1. Вы получите NAK, если датчик отключен, не включен или не по этому адресу. Я думаю, что запись / передача выше должна быть (PAC1710Address << 1) 1 . Что именно находится в вашей трассировке осциллографа (какие биты, как быстро, что-нибудь странное, часы выглядят нормально?), И как ADDR_SEL устанавливается на датчике?

2. Мой датчик включен и подключен, oszi показывает 0x54 W ~ a, поэтому адрес должен быть в порядке. Oszi показывает Start 1 0 1 0 1 0 0 0 1 Stopp. Что касается часов, есть небольшое влияние на емкость, но все выглядит нормально.

3. 1010_100 не соответствует ни одному из адресов в техническом описании датчика.

4. Разве это не адрес (7 бит 101 0100), запись (0), NACK?

5. Я думаю, вы можете поместить пробел или _ куда угодно, но эта последовательность битов не отображается в листе данных. Существует 0101_010, с которым вы, возможно, перепутали его (это означало бы, что вы не <<1 должны)?

Ответ №1:

После некоторых комментариев появилось больше полезной информации, большая часть которой была показана осциллографом Start 1010100 0 1 Stop . Хотя 1010100 это адрес 0x54, W бит также необходимо подсчитать, поэтому 8-битные данные были фактически 10101000 , а не ожидались 01010100 . Адрес не должен был сдвигаться влево, поскольку он уже был правильным.

Это довольно распространенная ошибка с I2C. Необходимо обратить внимание на точный адрес и R/!W биты, так как в некоторых документах и API они сдвинуты влево, в некоторых — нет.

Очень полезной информацией здесь была трассировка осциллографа, которая действительно помогла показать, что именно происходит.