Вторая часть про настройку NUCLEO-F746ZG для работы по интерфейсу I2C. В предыдущей части был создан, настроен проект в STM32CubeMX, после чего сгенерирован исходный код для STM32CubeIDE. Основные файлы хранятся в этом репозитории.
Основной файл, с которым будем работать, называется main.c.
В этой части будет решены следующие задачи:
1. Поиск устройств на шине I2C
2. Отправка данных slave-устройству
3. Получение данных от slave-устройства
Формальная организация
На этапе создания проекта в Кубе мы оставили галку на "Keep User Code when re-generating ". Однако, чтобы написанный код сохранялся, нужно его размещать внутри блоков:
/* USER CODE BEGIN I2C2_Init 2 */
/* USER CODE END I2C2_Init 2 */
, где вместо I2C2_Init 2 может быть другое название другого блока кода.
Поиск устройств по шине
Следующая команда проверяет наличие устройств на шине I2C. Следует помнить, что значение искомого адреса перед отправкой нужно сдвинуть влево согласно даташиту.
* @param DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
Адрес у нас 7 битный, а значит количество возможных адресов у нас ограничено 127. В результате получаем следующий алгоритм:
for (uint16_t i = 0x00; i < 127; i++)
{
if(HAL_I2C_IsDeviceReady(&hi2c2,(i<<1),1,100) == HAL_OK)
Что-то делаем, если нашли
else
Нужно что-то делать, если не нашли
}
1. hi2c2 -- структура управления I2C
Примечание: (i<<1) -- это сдвиг влево адреса
Интерфейс I2C использует сигнал Acknowledgement (Подтверждение) для идентификации наличия устройства на опрашиваемом адресе. Ниже приведены примеры отсутствия и наличия ответа от опрашиваемого устройства
Отправка данных устройству
Если мы нашли что-либо на шине устройства, то следующим шагом будет передача данных на это устройство.
HAL_I2C_Master_Transmit(&hi2c2, (TargetI2Cdevice<<1), ptI2Cbuffer2transmit, 4, 10);
1. TargetI2Cdevice -- адрес устройства
2. ptI2Cbuffer2transmit -- буфер с 4 значениями, которые необходимо передать
3. Последнее значение, равное 10, указывает промежуток ожидания между отправкой данных
Результат отправки данных приведен ниже: сначала отправлен адрес, а потом четыре байта данных. На каждую итерацию отправки информации было получено подтверждение.
Получение данных от устройства
Чтобы получить данные, нужна похожая команда:
HAL_I2C_Master_Receive(&hi2c2, (TargetI2Cdevice<<1), ptI2Cbuffer4receive, I2C_RECEIVE_CNT, 10);
1. ptI2Cbuffer4receive -- буффер, в который будут записаны данные
2. I2C_RECEIVE_CNT -- макрос, указывающий количество данных для получения
В моем случае, я получаю 80 значений по шине, поэтому график получается немного ненаглядный.
Стоит отметить, что устройство предполагает отправку большего количества данных. Поэтому последний байт сопровождается отправкой NACK.
На самом в устройстве этот разрыв приведен к ошибке типа Acknowledge Failure.
Немного о скорости стандартной библиотеки HAL и I2C. Изначально, поставим задачу: сколько можно передать данных за 10 мс, иначе при частоте отправке пачек 100 Гц?
Опытным путем было получено, что наиболее стабильная передача данных получается на данной частоте при следующих характеристиках:
1. Режим I2C: Fast mode (400 кГц)
2. Количество данных в пачке: 390
2. Промежуток ожидания(последний параметр функции) 10
Возникает вопрос: Можно ли ускорить передачу данных, запрограммировав на регистрах?
Визуализация передачи при таких характеристиках можно наблюдать ниже.
Уточненное время передачи равно 9.7 мс.
Сравнение с Arduino
Часто к преимуществам Arduino относят минимальное количество кода, которого надо написать для решения задачи. Рассмотрим количество кода на примере I2C (функция передачи данных).
Arduino
Wire.begin();
Wire.beginTransmission(address);
for(int j = 0; j < 3; j++)
{
Wire.write(value);
}
Wire.endTransmission(true);
STM32 HAL
HAL_I2C_Master_Transmit(&hi2c2, (TargetI2Cdevice<<1), ptI2Cbuffer2transmit, 4, 10);
В обоих случаях, это ровно то, что необходимо написать для успешной отправки данных. В Ардуино получается даже немного больше. В целом, сейчас все преимущество Ардуино это связка расширений и библиотек. Это лично мое мнение.
Более того, я считаю, что графический интерфейс Куба гораздо лучше того, чего предлагает Ардуино (а Ардуино предложить собственно и нечего).
Лайк?