I2C в STM32 HAL

В данной статье рассмотрим функции HAL для работы с I2C в STM32. Так же разберем небольшой пример для лучшего понимания работы функций. В статье, все примеры представлены для режима «Ведущий». Это значит, что инициатором обмена данными является «Мастер».

Общее описание

Для каждой серии микроконтроллеров STMicroelectronics предлагает встроенный пакет библиотек, которые включают в себя драйвер аппаратного абстрагированного уровня (HAL). Этот драйвер предоставляет разработчикам набор API-интерфейсов. Что позволяет абстрагироваться от сложности микроконтроллера и его периферийных устройств. Интерфейс I 2 C является одним из таких периферийных устройств.  Драйвер HAL поддерживает три модели программирования для своих функций обработки данных: опрос, прерывание и DMA. Функции опроса работают в режиме блокировки. Это режим, когда управление основной программе передается после завершения работы функции. Для исключения зависания, такие функции в качестве параметра принимают время ожидания, после которого будет принудительный выход из функции. Функции прерывания и DMA работают в неблокирующем режиме. В этом режиме наша программа будет работать не ожидая завершения окончания передачи по I2C. Для таких функций необходимо реализовать функцию Callback. Сюда передается управление. после завершения работы функции в неблокирующем режиме.

При работе в качестве ведущего I 2 C в режиме блокировки доступны четыре функции API для связи с ведомым устройством:

  • HAL_I2C_Master_Transmit()
  • HAL_I2C_Master_Receive()
  • HAL_I2C_Mem_Write()
  • HAL_I2C_Mem_Read()
  • HAL_I2C_Master_TransmitIT()
  • HAL_I2C_Master_ReceiveIT()
  • HAL_I2C_Master_TransmitDMA()
  • HAL_I2C_Master_ReceiveDMA()

Для неблокирующей функциональности режимы прерывания и DMA имеют эквивалентные функции.

HAL I2C: передача данных

Отправка данных с ведущего устройства на ведомое с помощью функций HAL достаточно проста. Можно использовать либо функции HAL_I2C_Master_Transmit(), либо HAL_I2C_Mem_Write().

HAL_I2C_Master_Transmit()

Вид прототипа для этой функции API показан ниже. Первый параметр — это просто структура конфигурации, которая содержит настройки параметров I2C. Второй параметр — это адрес ведомого устройства (который необходимо сдвинуть влево на единицу). Третий и четвертый параметры — это указатель на буфер данных и объем данных из буфера, которые должны быть отправлены на ведомое устройство соответственно. Последний параметр — это время ожидания в миллисекундах. Обратите внимание, что пользователь может предоставить HAL_MAX_DELAY в качестве аргумента отключение тайм-аута и бесконечную блокировку до тех пор, пока функция не выполнит свою работу.


ВНИМАНИЕ! В функции адрес необходимо сдвинуть на единицу, так как первый бит указывает, что мы собираемся делать, читать данные или записывать.


ВНИМАНИЕ! Задержку HAL_MAX_DELAY использовать не желательно, так как если вы укажите например неверный адрес или устройство будет не доступно, то ваша программа зависнет на функции передачи.

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, 
										  uint16_t DevAddress, 
										  uint8_t *pData, 
										  uint16_t Size, 
										  uint32_t Timeout);

Последовательность I 2 C, полученная в результате вызова функции, находится ниже по тексту. Заштрихованные области показывают, где сигнал управляется ведомым устройством. Во время передачи ведомое устройство подтверждает свой собственный адрес (плюс бит записи) и любые последующие байты данных. Напомним, что количество отправляемых байтов данных определяется аргументом, Size предоставленным вызову функции.

Описание пакета передачи данных  stm32 hal i2c

В качестве примера использования этой функции рассмотрим приведенный ниже код, в котором содержимое буфера отправляется на ведомое устройство с адресом 0x40. На рисунке ниже можно увидеть форму сигнала во время передачи I 2 C. Эту форму можно получить с помощью логического анализатора.

uint8_t dataBuffer[10] = {0x03, 0x01};
HAL_I2C_Master_Transmit(&hi2c1, (0x40 << 1), dataBuffer, 2, HAL_MAX_DELAY);
расшифровка передачи данных по i2c  в Stm32

HAL_I2C_Mem_Write()

Эта функция чаще всего используется для записи данных в память. Примером может быть энергонезависимая память stm32 eeprom i2c. Или же для конфигурации датчиков. Прототип этой функции выглядит следующим образом.

HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, 
									uint16_t DevAddress, 
									uint16_t MemAddress, 
									uint16_t MemAddSize, 
									uint8_t *pData, 
									uint16_t Size, 
									uint32_t Timeout);

Функция отличается от HAL_I2C_Master_Transmit двумя дополнительными параметрами. Параметр MemAddress — начальный адрес памяти в ведомом устройстве, куда будет записано содержимое буфера. Параметр  MemAddSize — размер адреса внутренней памяти. Принимает одно из двух значений I2C_MEMADD_SIZE_8BIT или I2C_MEMADD_SIZE_16BIT. Последовательность I 2 C теперь будет выглядеть, как показано ниже:

Передача данных STM32 i2c

Как видим, все идентично функции HAL_I2C_Master_Transmit(). Отличие только в передаче аргумента MemAddress. Он отправляется после адреса подчиненного устройства. В следующем примере HAL_I2C_Mem_Write() используется для записи значения 0x01 в регистр с адресом памяти 0x03. 

uint8_t dataBuffer[10] = {0x01};
HAL_I2C_Mem_Write(&hi2c1, (0x40 << 1), 0x03, I2C_MEMADD_SIZE_8BIT, dataBuffer, 1, HAL_MAX_DELAY);
Расшифровка пакета передачи i2c в stm32

HAL I2C: прием данных

HAL_I2C_Master_Receive()

Эта функция API используется для простого запроса данных с ведомого устройства. Обратите внимание, что в приведенном ниже прототипе его параметры идентичны параметрам HAL_I2C_Master_Transmit(). Однако в этом случае буфер данных используется для хранения входящих данных, а Size параметр указывает, сколько байтов данных необходимо получить перед отправкой NAck.

HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, 
										 uint16_t DevAddress, 
										 uint8_t *pData, 
										 uint16_t Size, 
										 uint32_t Timeout);

Диаграмма последовательности, описывающая работу этой функции, представлена ​​ниже. Обратите внимание, что она принципиально отличается от любой из рассмотренных выше функций передачи данных. Для приема данных нам необходимо настроить бит направления в адресе на прием. для этого нужно сдвинуть адрес влево на 1 и установить единицу в первый бит адреса. Мастер сообщает подчиненному устройству прекратить отправку данных, отправив Nack, за которым следует условие Stop.

диаграмма приема данных I2C Stm32

В приведенном ниже примере кода показано, как мастер запрашивает три байта данных у ведомого устройства с адресом 0x40. Мы можем видеть, наблюдая за захватом логического анализатора, что после завершения операции буфер данных будет содержать значения {0x00, 0x68, 0xF0}.

HAL_I2C_Master_Receive(&hi2c1, (0x40 << 1)|0x01, dataBuffer, 3, HAL_MAX_DELAY);

HAL_I2C_Mem_Read()

Эта функция API используется для запроса данных от ведомого устройства с определенного адреса памяти . Опять же, рассмотрим датчик I 2 C, в котором измерения хранятся в определенном регистре ведомого устройства, а ведущее устройство должно считывать данные из этого регистра. Как показано ниже, прототип функции содержит те же аргументы, что и HAL_I2C_Mem_Write() функция.

HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, 
								   uint16_t DevAddress, 
								   uint16_t MemAddress, 
								   uint16_t MemAddSize, 
								   uint8_t *pData, 
								   uint16_t Size, 
								   uint32_t Timeout);

Основное отличие данной функции от большинства, это повторный запуск в режиме блокировки. Функция сначала выполняет операцию передачи I 2 C. Сообщая ведомому устройству, из какого адреса памяти следует получать данные. Затем делает повторный запуск для приема данных. Полная последовательность I 2 C показана на рисунке ниже. 

Следующий пример кода получает два байта данных от ведомого устройства с адресом 0x40, начиная с адреса памяти 0x01. Обратите внимание на захват логического анализатора, что буфер будет содержать {0x68, 0x90}, когда операция завершится.

HAL_I2C_Mem_Read(&hi2c1, (0x40 << 1), 0x01, I2C_MEMADD_SIZE_8BIT, dataBuffer, 2, HAL_MAX_DELAY);

Где купить

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
2 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
MimoProhodil
MimoProhodil
5 месяцев назад

HAL_I2C_Master_Receive(&hi2c1, (0x40 << 1)&0x01, dataBuffer, 3, HAL_MAX_DELAY);
Опечатка в (0x40 << 1)&0x01? В результате будет 00000000, а не 10000001.