Сканер I2C шины для STM32

Когда работаешь с I2C устройствами, особенно с китайскими платами без спецификации, нередко возникают проблемы с определением адреса. Причины могут быть разные, например, реверс-инжиниринг какого-нибудь ведомого устройства с МК на борту, в неведомой прошивке которого зашит неведомый нам адрес.

Сканер I2C — это простая программа, которая поможет просканировать весь диапазон адресов I2C и покажет активные адреса. Так можно узнать не только адрес, но и понять работают ли конкретные устройства в принципе, или нет.

Программу будем писать для отладочной платы BluePill с микроконтроллером STM32F103C8T6. Разумеется, она будет работать и для любого другого контроллера из семейства STM32.

Настройка STM32CubeIDE

Наша цель — сканировать I2C шину и о результатах докладывать пользователю при помощи интерфейса UART (по виртуальному COM-порту). Следовательно, активируем оба этих интерфейса на вкладке Connectivity. В разделе USART1 в поле Mode ставим Asynchronous. В разделе I2C1 в поле I2C выбираем I2C.

Никаких настроек у этих интерфейсов менять не нужно. Единственно, запомним скорость UART, обычно по-умолчанию она установлена в 115200 бод.

Настраиваем тактирование от внешнего резонатора, который штатно установлен на BluePill. Для этого на вкладке System Core, в разделе RCC в поле HSE выставляем: Crystal/Ceramic Resonator.

Также зарезервируем PA13 и PA14 за программатором. На той же вкладе, в раздел SYS в поле Debug выставляем Serial Wire. Схема настроенного микроконтроллера будет выглядеть так:

stm32 сканер i2c stm32cubeide

Затем, настраиваем схему тактирования. Тут тоже всё стандартно.

Тактирование STM32F103

Программа

Итак, идея в том, чтобы пробежаться по всем адресам от 0 до 127 и вызвать для каждого из них стандартную HAL функцию HAL_I2C_IsDeviceReady. Ну и вывести результаты этой проверки в UART, должным образом упорядочив вывод — для порядка.

В разделе пользовательских переменных добавляем всё, что нам может пригодиться:

/* USER CODE BEGIN PV */
uint8_t buf[8] = {0};
uint8_t separator[] = " . ";
uint8_t new_line[] = "\r\n";
uint8_t start_text[] = "Start scanning I2C: \r\n";
uint8_t end_text[] = "\r\nStop scanning";
/* USER CODE END PV */

Далее код самого алгоритма сканирования, тоже в соответствующий пользовательский блок кода:

  /* USER CODE BEGIN 2 */
  uint8_t row = 0, state;

  HAL_Delay(1000);

  // процедура сканирования
  HAL_UART_Transmit(&huart1, start_text, sizeof(start_text), 128);
  for( uint8_t i=1; i<128; i++ ){
      state = HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t)(i<<1), 3, 5);

      if ( state != HAL_OK ){ // нет ответа от адреса
          HAL_UART_Transmit(&huart1, separator, sizeof(separator), 128);
      }

      else if(state == HAL_OK){ // есть ответ
          sprintf(buf, "0x%X", i);
          HAL_UART_Transmit(&huart1, buf, sizeof(buf), 128);
      }

      if( row == 15 ){
    	  row = 0;
          HAL_UART_Transmit(&huart1, new_line, sizeof(new_line), 128);
      } else
    	  row ++;
  }
  HAL_UART_Transmit(&huart1, end_text, sizeof(end_text), 128);
  /* USER CODE END 2 */

Напоминаю, если что-то записать вне выделенного для пользователя места, то CubeIDE всё это почикает при компиляции программы.

Загружаем программу на stm32 через St-Link. Подключаем какое-нибудь I2C устройство, например, OLED дисплей 0.96. Затем через USB-UART соединяем всё это к ПК и открываем любой удобный терминал для COM порта. Например, подойдёт встроенный терминал в Arduino IDE.

Сканер I2C для STM32

Ага, попался! Вот он этот дисплей — 0x3D. Теперь можно смело использовать полученный адрес для работы с этим устройством.


Изменено:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.