Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2741
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

SPI

442

15.2. Модуль HAL_SPI

Чтобы запрограммировать периферийное устройство SPI, HAL объявляет структуру Си SPI_HandleTypeDef, которая определена следующим образом5:

typedef struct __SPI_HandleTypeDef {

 

 

 

SPI_TypeDef

*Instance;

/*

Базовый адрес регистров SPI

*/

SPI_InitTypeDef

Init;

/*

Параметры SPI-связи

*/

uint8_t

*pTxBuffPtr; /*

Указатель на буфер Tx-передачи SPI

*/

uint16_t

TxXferSize;

/*

Размер Tx-передачи SPI

*/

__IO uint16_t

TxXferCount; /*

Счетчик Tx-передачи SPI

*/

uint8_t

*pRxBuffPtr; /*

Указатель на буфер Rx-передачи SPI

*/

uint16_t

RxXferSize;

/*

Размер Rx-передачи SPI

*/

__IO uint16_t

RxXferCount; /*

Счетчик Rx-передачи SPI

*/

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, который мы будем исполь-

зовать. Например, SPI1 является дескриптором первого периферийного устройства SPI.

Init: это экземпляр структуры Си SPI_InitTypeDef, используемой для конфигура-

ции периферийного устройства. Мы рассмотрим ее более подробно в ближайшее время.

pTxBuffPtr, pRxBuffPtr: указатель на внутренние буферы, используемые для вре-

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

hdmatx, hdmarx: указатели на экземпляры структуры DMA_HandleTypeDef, используе-

мые при работе периферийного устройства SPI в режиме DMA.

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

typedef struct {

 

 

uint32_t Mode;

/* Задает режим работы SPI.

*/

uint32_t Direction;

/* Задает состояние двунаправленного режима SPI.

*/

uint32_t DataSize;

/* Задает размер данных SPI.

*/

uint32_t CLKPolarity;

/* Задает установившееся состояние

 

 

тактового сигнала последовательной шины.

*/

uint32_t CLKPhase;

/* Задает активный фронт тактового сигнала

 

 

для захвата битов.

*/

uint32_t NSS;

/* Определяет, управляется ли сигнал NSS аппаратно

 

5 Некоторые поля были опущены для простоты. Обратитесь к исходному коду CubeHAL для того, чтобы увидеть точное определение структуры SPI_HandleTypeDef.

SPI

 

443

 

(вывод NSS) или программно

*/

uint32_t BaudRatePrescaler;

/* Задает значение предделителя скорости передачи

 

 

в бодах, который будет использоваться для

 

 

конфигурации тактового сигнала SCK.

*/

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 (направление): определяет, работает ли ведомое устройство в 4-х провод-

ном (две отдельные линии для I/O) или в 3-х проводном режиме (всего одна линия для I/O). Может принимать значение SPI_DIRECTION_2LINES для конфигурации полнодуплексного 4-проводного режима; значение SPI_DIRECTION_2LINES_RXONLY для конфигурации полудуплексного 4-проводного режима; значение SPI_DIRECTION_1LINE для конфигурации полудуплексного 3-проводного режима.

DataSize: конфигурирует размер передаваемых данных по шине SPI и может при-

нимать значения SPI_DATASIZE_8BIT и SPI_DATASIZE_16BIT.

CLKPolarity: конфигурирует параметр CPOL линии SCK и может принимать зна-

чения SPI_POLARITY_LOW (соответствует CPOL = 0) и SPI_POLARITY_HIGH (соответ-

ствует CPOL = 1).

CLKPhase: конфигурирует фазу тактового сигнала и может принимать значения

SPI_PHASE_1EDGE (соответствует CPHA = 0) и SPI_PHASE_2EDGE (соответствует

CPHA = 1).

NSS: это поле обрабатывает поведение вывода NSS. Может принимать значения SPI_NSS_SOFT для конфигурации сигнала NSS в программном режиме; значения

SPI_NSS_HARD_INPUT и SPI_NSS_HARD_OUTPUT для конфигурации сигнала NSS во вход-

ном или выходном аппаратном режиме соответственно.

BaudRatePrescaler: конфигурирует предделитель тактового сигнала шины APB и

устанавливает максимальную тактовую частоту SCK. Может принимать значения

SPI_BAUDRATEPRESCALER_2, SPI_BAUDRATEPRESCALER_4,…, SPI_BAUDRATEPRESCALER_256 (все

степени двойки от 21 до 28).

FirstBit: задает порядок передачи данных и может принимать значения

SPI_FIRSTBIT_MSB и SPI_FIRSTBIT_LSB.

TIMode: используется для включения/отключения режима TI и может принимать

значения SPI_TIMODE_DISABLE и SPI_TIMODE_ENABLE.

CRCCalculation и CRCPolynomial: периферийное устройство SPI во всех микро-

контроллерах STM32 поддерживает аппаратную генерацию контрольной суммы (CRC). Значение CRC может передаваться последним байтом в режиме Tx, или может быть произведена автоматическая проверка на ошибку CRC с последним принятым байтом. Значение CRC вычисляется с использованием нечетного программируемого полинома на каждом бите. Расчет выполняется на определяемом конфигурациями CPHA и CPOL фронте тактовой частоты дискретизации. Вычисленное значение CRC проверяется автоматически в конце блока данных, а также

SPI

444

для передачи, управляемой ЦПУ или DMA. Когда обнаруживается несоответствие между CRC, рассчитанным внутри для принятых данных, и CRC, отправленным передатчиком, устанавливается условие ошибки. Функция CRC недоступна, если SPI работает в циклическом режиме DMA. Для получения дополнительной информации об этих параметрах обратитесь к справочному руководству по рассматриваемому микроконтроллеру STM32.

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

HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi);

которая принимает указатель на экземпляр структуры SPI_HandleTypeDef, рассмотренной ранее.

15.2.1.Обмен сообщениями с использованием периферийного устройства SPI

После конфигурации периферийного устройства SPI мы можем начать обмен данными с ведомыми устройствами. Так как спецификация SPI не описывает конкретный протокол связи, нет никакой разницы между процедурами CubeHAL при использовании периферийного устройства SPI в режиме ведомого или ведущего. Единственная разница заключается в конфигурации соответствующего параметра Mode структуры

SPI_InitTypeDef.

Как обычно, CubeHAL предоставляет три способа обмена данными по шине SPI: режимы

опроса, прерываний и DMA.

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

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

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

мах SPI_DIRECTION_1LINE или SPI_DIRECTION_2LINES. Для получения нескольких байт в ре-

жиме опроса, мы используем функцию:

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

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

Если ведомое устройство поддерживает полнодуплексный режим, тогда мы можем использовать функцию:

HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,

uint32_t Timeout);

SPI

445

которая позволяет передавать заданное количество байт при одновременном получении того же количества байт. Очевидно, что она работает, только если для параметра SPI

Direction установлено значение SPI_DIRECTION_2LINES.

Для обмена данными через SPI в режиме прерываний CubeHAL предоставляет функции:

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);

Процедуры CubeHAL для обмена данными через SPI в режиме DMA идентичны предыдущим трем, за исключением того факта, что они заканчиваются на _DMA.

После использования процедур, основанных на прерываниях и DMA, мы должны быть подготовлены к получению уведомлений о завершении передачи, поскольку она выполняется асинхронно. Это означает, что нам нужно разрешить соответствующее прерывание на уровне NVIC и вызвать функцию HAL_SPI_IRQHandler() из ISR. Существует шесть различных обратных вызовов, которые мы можем реализовать, как показано в

таблице 3.

Таблица 3: Доступные обратные вызовы CubeHAL при работе периферийного устройства SPI в режимах прерываний или DMA

Обратный вызов

Описание

 

 

HAL_SPI_TxCpltCallback()

Оповещает о том, что передано заданное количество байт

HAL_SPI_RxCpltCallback()

Оповещает о том, что принято заданное количество байт

HAL_SPI_TxRxCpltCallback()

Оповещает о том, что заданное количество байт было пере-

 

дано и получено

HAL_SPI_TxHalfCpltCallback()

Оповещает о том, что передача SPI через DMA наполовину

 

завершена

HAL_SPI_RxHalfCpltCallback()

Оповещает о том, что прием SPI через DMA наполовину за-

 

вершен

HAL_SPI_TxRxHalfCpltCallback()

Оповещает о том, что процесс передачи и приема SPI через

 

DMA наполовину завершен

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

HAL_StatusTypeDef HAL_SPI_DMAPause(SPI_HandleTypeDef *hspi);

HAL_StatusTypeDef HAL_SPI_DMAResume(SPI_HandleTypeDef *hspi);

HAL_StatusTypeDef HAL_SPI_DMAStop(SPI_HandleTypeDef *hspi);

При работе SPI в циклическом режиме DMA применяются следующие ограничения: