SPI HAL в STM32

Сегодня поговорим о таком протоколе передачи данных как SPI. Посмотрим какие функции нам предоставлены в рамках SPI HAL в STM32. Подробно о интерфейсе SPI можно прочитать в нашей статье.

SPI HAL модуль

Для начала работы с SPI в HAL содержится структура которую необходимо объявить. Ниже представлена эта структура в сокращенном виде, мы оставили только те параметры на которые необходимо обратить внимание:

typedef struct __SPI_HandleTypeDef {
  SPI_TypeDef  *Instance;  /* Адрес регистров SPI по умолчанию  */
  SPI_InitTypeDef  Init;  /* Настройка SPI протокола для начала передачи  */
  uint8_t  *pTxBuffPtr; /* Tx-передача SPI. Указатель на буфер данных  */
  uint16_t  TxXferSize;  /* Размер буфера Tх данных для передачи по SPI  */
  __IO uint16_t  TxXferCount; /* Счетчик Tx передач SPI  */
  uint8_t  *pRxBuffPtr; /* Rx прием по SPI. Указатель на буфер принимаемых данных  */
  uint16_t  RxXferSize;  /* Размер буфера Rx для приема данных по SPI  */
  __IO uint16_t  RxXferCount; /* Счетчик Rx-приема данных  */
  DMA_HandleTypeDef  *hdmatx;  /* Значения дескриптора DMA для Tx SPI  */
  DMA_HandleTypeDef  *hdmarx;  /* Значения дескриптора DMA для Rx SPI  */
  HAL_LockTypeDef  Lock;  /* Блокировка модуля SPI  */
  __IO HAL_SPI_StateTypeDef  State;  /* Флаг состояния работы SPI.  */
  __IO uint32_t  ErrorCode;  /* Содержит код возникшей ошибки SPI  */
} SPI_HandleTypeDef;

Рассмотрим подробнее наиболее важные элементы структуры:

  • Instance или экземпляр: является  указателем на физический модуль SPI. Для примера, если мы используем третий модуль SPI, то переменная Instance будет равна SPI3.
  • Init: эта переменная является указателем на экземпляр структуры SPI_InitTypeDef, которая хранит настройки протокола SPI.
  • pTxBuffPtr, pRxBuffPtr: указатели на буферы передачи и приема данных. Их необходим указать, если вы используете SPI в режиме прерываний и в режиме DMA.
  • hdmatx, hdmarx: указатели на экземпляры структуры DMA_HandleTypeDef,  которые использутся во время работы модуля SPI в режиме DMA.

Настройка протокола SPI

Теперь рассмотрим структуру InitTypeDef. С ее помощью настраивается модуль SPI для приема и передачи данных. Выглядит она следующим образом:

typedef struct {
uint32_t Mode;  /* Содержит настройки режима работы SPI.  */
uint32_t Direction;  /* Задает режим направления данных SPI.  */
uint32_t DataSize;  /* Установка размера передаваемых данных.  */
uint32_t CLKPolarity;  /* Установка состояния для тактового сигнала.  */
uint32_t CLKPhase;  /* Установка фронта сигнала для чтения битов  */
uint32_t NSS;  /* Выбор управления сигналом NSS  */
uint32_t BaudRatePrescaler; /* Установка предделителя для настройки скорости передачи. */
uint32_t FirstBit;  /* Настройка очередности передачи данных MSB- или LSB.  */
uint32_t TIMode;  /* Установка режима TI.  */
uint32_t CRCCalculation;  /* Настройка использования CRC */
uint32_t CRCPolynomial;  /* Задает полином, используемый для расчета CRC.  */
} SPI_InitTypeDef;
  • Mode: настройка режима работы модуля SPI. Выбирается режим ведущего или ведомого устройства. Данные режима описаны константами SPI_MODE_MASTER и SPI_MODE_SLAVE.
  • Direction: настройка режима направления для передачи данных. Есть несколько режимов:
    • четырех проводной полнодуплексный режим SPI_DIRECTION_2LINES. При таком режиме ведущее устройство и подчиненное принимают и отправляют данные по четырем проводам.
    • четырех проводной полудуплексный режим SPI_DIRECTION_2LINES_RXONLY. В этом случае ведущее устройство передает, а ведомое только принимает.
    • полудуплексный режим по трем проводам SPI_DIRECTION_1LINE. Ведущее устройство отправляет, ведомое принимает по трем проводам.
  • DataSize: настраивает размер передачи данных. Передача может быть побайтно или за раз 2 байта. Принимает значение передаваемых данных SPI_DATASIZE_8BIT или SPI_DATASIZE_16BIT.
  • CLKPolarity: настраивает регистр CPOL. Принимает такие значения как SPI_POLARITY_LOW  (CPOL  = 0) и  SPI_POLARITY_HIGH  (CPOL = 1).
  • CLKPhase: настраивает регистр CPHA. Принимает такие значения как SPI_PHASE_1EDGE  (CPHA  = 0) и  SPI_PHASE_2EDGE  (CPHA = 1).
  • NSS: здесь мы настраиваем управление сигналом NSS (сигнал выбора устройства).  Может управляться программно SPI_NSS_SOFT  или аппаратно.  Если управление аппаратное, то необходимо настроить вывод на вход или выход, указав значение SPI_NSS_HARD_INPUT или SPI_NSS_HARD_OUTPUT.
  • BaudRatePrescaler: настраиваем скорость передачи данных установкой предделителя тактовой частоты шины APB, на которой находится модуль SPI. Принимает следующие значения: SPI_BAUDRATEPRESCALER_1,…, SPI_BAUDRATEPRESCALER_256.
  • FirstBit:  Определяет очередность передачи данных в рамках одной передачи. Устанавливаем старший байт(полубайт) или младший будет отправлен первым. Может быть SPI_FIRSTBIT_MSB или SPI_FIRSTBIT_LSB.
  • TIMode: включение отключение режима TI. Принимает следующие значения SPI_TIMODE_DISABLE или  SPI_TIMODE_ENABLE. Режим TI это режим, при котором после установки сигнала CS начинается непрерывная передача данных до момента поднятия сигнала CS. первым отправляется старший бит.
  • CRCCalculation  и  CRCPolynomial: данные настройки относятся к контролю передаваемых данных. Микроконтроллеры STM32 имеют встроенный блок по расчету CRC.

Для того чтобы применить настройки к модулю SPI, необходимо вызвать функцию:

HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)

и передать указатель на структуру SPI_HandleTypeDef.

Прием и передача данных по SPI в STM32

После того, как мы настроили наш SPI, можно начинать обмен данных между ведущим и ведомым устройством. У нас есть три варианта организации приема передачи:

  • Простой опрос;
  • Прием и передача с использованием прерываний;
  • Прием и передача с использованием DMA;

STM32 SPI HAL в режиме опроса

Когда мы работаем с SPI в режиме опроса для приема/передачи необходимо использовать следующие функции:

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size, uint32_t Timeout)

отправляет Size байт на устройство по SPI.

*hspi — указатель на структуру SPI, которая содержит все настройки и дескрипторы SPI. Это может быть например hspi1, hspi2 и ваше объявление.

*pData — указатель а массив данных для отправки

Size — количество байт в массиве данных, которые хотим отправить

Timeout — время ожидания завершения отправки данных на  устройство. Если Timeout будет превышен, HAL с генерирует исключение и поместит его код в структуру HAL_StatusTypeDef.

ВНИМАНИЕ! Данная функция применяется в с такими режимами как SPI_DIRECTION_1LINE или SPI_DIRECTION_2LINES.

HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size, uint32_t Timeout);

Функция получает Size байт по SPI от устройства.

Отличием от предыдущей функции является *pData — здесь это указатель на приемный буфер.

Эта функция применяется во всех режимах Direction.

Если модуль SPI сконфигурирован на работу в полнодуплексном режиме то можно применить такую функцию:

HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout);

Данная функция отправляет и принимает данные одновременно. Как вы уже поняли работает только в режиме SPI_DIRECTION_2LINES

STM32 SPI HAL в режиме прерываний

Когда мы используем SPI в режиме прерываний, то для приема передачи у HAL описаны следующие функции:

HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_IT(SPI_HandleTypeDef *hspi,uint8_t *pTxData, uint8_t *pRxData,uint16_t Size);

Их описание идентичны функциям из предыдущего раздела. Для того что бы использовать SPI в режиме прерываний, их необходимо разрешить, вызвав функцию HAL_SPI_IRQHandler() в момент инициализации модуля, после всех настроек.

STM32 SPI DMA

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

HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size);
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size);
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi,uint8_t *pTxData, uint8_t *pRxData,uint16_t Size);

Важно знать несколько ограничений в работе SPI через DMA:

Важно знать несколько ограничений в работе SPI через DMA:

  • В случае, когда SPI модуль настроен на работу в режиме только приема, мы не можем использовать циклический режим DMA;
  • если DMA работает в циклическом режиме, мы не можем использовать расчет контрольной суммы CRC;
  • функции остановки, приостановки (HAL_SPI_DMAPause()/HAL_SPI_DMAStop()) работы DMA, можно использовать только в функция CallBack (функции обратного вызова)

В следующей статье мы поговорим как настроить работу SPI HAL в STM32 с использованием CubeMX.

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