
Пролог
SPI это цифровой, последовательный, относительно высокоскоростной, полнодуплексный, синхронный физический интерфейс передачи данных в пределах одной электронной платы PCB. Этот интерфейс служит для обмена данными между микросхемами в пределах одной электронной платы. Ранее в эпоху AVR микроконтроллеров интерфейс SPI и вовсе использовался для перепрошивки микроконтроллеров вместо SWD, как сейчас. По SPI обычно подключают внешние ASIC-и. Это могут быть ADC, акселерометры, дисплеи, DAC, Flash память, CAN трансиверы и прочее. SPI много надежнее, чем его собрат I2C. I2C может зависать, в то время в как SPI просто нечему зависать.
При разработке электроники практически на всех платах нужно передавать данные по интерфейсу SPI.
Во всех микроконтроллерах заложен аппаратный SPI трансивер. Трансивер - это прибор, который может отправлять и принимать бинарные массивы. Полный дуплекс - это когда передача и прием происходят одновременно.
Постановка задачи
Настроить SPI2 трансивер на работу в режиме DMA. Сделать функцию передачи данных в режиме полного дуплекса. В качестве отладочной платы использовать учебно-тренировочную электронную плату JZ-F407VET6. Выбрать GPIO пины PB10, PC2, PC3.
Pin |
MCU pin |
GPIO |
Dir |
SCK |
47 |
PB10 |
out |
MISO |
17 |
PC2 |
in |
MOSI |
5 |
PC3 |
out |
Реализация
Настройка SPI передачи данных - это комплекс мер. Надо настроить регистры тактирования, GPIO, SPI, DMA и прерывания.
Настроить тактирование (clock)
--Подать тактирование на используемые GPIO пины.
--Подать тактирование на SPI трансивер.
--Подать тактирование на DMA.

Активировать прерывания (NVIC)
1--Активировать прерывания глобально на уровне процессорного ядра.
2--Определить приоритет прерывания SPI. В случае с SPI2 NVIC номер равен 36
3--Активировать прерывания для каналов DMA (14 и 15).
Поток |
IRQn |
DMA |
stream |
channel |
SPI2_TX |
15 |
DMA1 |
stream_4 |
channel_0 |
SPI2_RX |
14 |
DMA1 |
stream_3 |
channel_0 |
4--Определить функции обработчики прерываний для DMA каналов. Тут важный момент. Как сделать так, чтобы и отправка по SPI2 и прием по SPI2 работали в режиме DMA одновременно (полный дуплекс режим)? Ведь у них один и тот же корневой DMA: DMA1. У каждого DMA потока должен быть свой собственный и отдельный экземпляр структуры DMA_HandleTypeDef. Для каждого потока надо вызывать DMA_Init для каждого экземпляра потока. Даже вопреки тому, что они ссылаются на один DMA1.
5--Определить функцию обработчик прерываний для SPI.
Активировать GPIO
--Надо физически подключить SPI блок к GPIO пинам микроконтроллера. Для этого надо сконфигурировать 3 GPIO пина на альтернативную функцию SPI2. Переключить внутренний мультиплексор.
Pin |
MCU pin |
GPIO |
Dir |
PinMux |
Pull |
Connector |
SCK |
47 |
PB10 |
out |
5 |
air |
P3.5 |
MISO |
17 |
PC2 |
in |
5 |
up |
P3.7 |
MOSI |
5 |
PC3 |
out |
5 |
up |
P3.6 |
Активировать SPI
1--Подать тактирование на SPI трансивер.
2--Активировать прерывание для конкретного SPI трансивера
3--написать обработчик прерывания для SPI
4--Задать приоритет SPI прерывания
5--Выбрать роль трансивера: master или slave.
6--Задать битовую скорость.
7--Задать фазу тактирования.
8--Задать размер сдвигового регистра: 8 бит или 16 бит.
9--Задать порядок передачи бит.
10--Задать событие захвата бита: положительный перепад или отрицательный перепад.
Активировать DMA
DMA хорош тем, что позволяет уменьшить количество прерываний при работе SPI и тем самым снизить нагрузку на центральный процессор. Поэтому, по возможности, надо использовать SPI трансивер именно в режиме DMA.
Надо подать тактирование на DMA c которым будет работать SPI. В моем случает это DMA1
Активировать DMA каналы
--Выбрать Номер DMA, поток и канал на конкретный экземпляр поток передачи. Это указано в спецификации на микроконтроллер.
Поток |
IRQn |
DMA |
stream |
channel |
SPI2_TX |
15 |
DMA1 |
stream_4 |
channel_0 |
SPI2_RX |
14 |
DMA1 |
stream_3 |
channel_0 |
--Активировать канал DMA ассоциированный с SPI отправкой
--Ассоциировать SPI трансивер с DMA каналом отправки
__HAL_LINKDMA(&Node->handle,hdmatx,(DmaCh->dma_h));
--Активировать канал DMA ассоциированный с SPI приёмом
--Ассоциировать SPI трансивер с потоком DMA отправки.
__HAL_LINKDMA(&Node->handle,hdmarx,DmaCh->dma_h);
--Активировать два прерывания DMA для работы SPI в режиме DMA.
Поток |
IRQn |
DMA_stream |
SPI2_TX |
15 |
DMA1_stream_4 |
SPI2_RX |
14 |
DMA1_stream_3 |
--Назначить разный приоритет всем каналам DMA.
--настроить источник канала: адрес, выравнивание, инкремент.
--настроить приемник канала: адрес, выравнивание, инкремент.
--Указать сколько байт будем передавать по DMA.
Опрос SPI трансивера
Когда SPI уже сконфигурирован, то можно периодически вычитывать статусный регистр и следить за здоровьем SPI трансивера. Так можно выявить события аварий и принять меры. Например пере инициализировать SPI-трансивер.
Комбинаторика такова, что у SPI драйвера помимо init должно быть еще минимум 9 функций.
operation |
move mode |
move mode |
move mode |
operation |
polling |
interrupts |
DMA |
read |
spi_read_polling |
spi_read_interrupt |
spi_read_dma |
write |
spi_write_polling |
spi_write_interrupt |
spi_write_dma |
write_read |
spi_write_read_polling |
spi_write_read_interrupt |
spi_write_read_dma |
Модульное тестирование SPI трансивера
Я подготовил набор модульных тестов для верификации SPI трансивера
Механизм |
тип теста |
Название теста |
CLI команда пуска теста |
polling |
write |
spi1_write_polling |
tr spi1_write_polling |
polling |
read |
spi1_read_polling |
tr spi1_read_polling |
polling |
write_read |
spi1_write_read_polling |
tr spi1_write_read_polling |
interrupt |
write |
spi1_write_interrupt |
tr spi1_write_interrupt |
interrupt |
read |
spi1_read_interrupt |
tr spi1_read_interrupt |
read |
spi1_miso |
tr spi1_miso |
|
interrupt |
write_read |
spi1_write_read_interrupt |
tr spi1_write_read_interrupt |
dma |
write |
spi1_write_dma |
tr spi1_write_dma |
dma |
read |
spi1_read_dma |
tr spi1_read_dma |
dma |
write_read |
spi1_write_read_dma |
tr spi1_write_read_dma |
Тестирование приёма по SPI
Тест SPI приёма может быть таким:
1--Отключить провод от SPI пинв MISO .
2--Установить на пине MISO Pull Up.
3--Прочитать байт по SPI.
4--В приёмном регистре должно быть 0xFF.
5--Установить на пине MISO Pull Down.
6--Прочитать байт по SPI.
7--В приёмном регистре должно быть 0x00.
Если так, то тест пройден. Если нет, то приём по SPI не работает.

Тестирование отправки по SPI
1--В обработчике прерываний по окончании отправки увеличивать счетчик отправленных байт.
2--Запустить SPI отправку
3--Подождать прерывания окончания отправки
4--Убедиться что счетчик отправленных байт увеличился на нужное значение.
Если прерывание произошло, то тест пройден. Если прерывания не было, то интерфейс не работает.

Тестирование полнодуплексной операции по SPI
--Можно взять проводную перемычку, соединить пин MOSI и MISO, выполнить полно дуплексную запись-чтение и проверить, что микроконтроллер принял то же самое, что и отправил. Если массив совпал, значит тест пройден.

Тест DMA
Что касается модульного теста DMA, то тут можно просто реализовать функцию memcpy() на основе DMA и прогнать её для всех свободных потоков. Если массив прописался по новому адресу и совпал по значению байт в байт, значит тест пройден.

Итог
Удалость научиться отправлять и принимать массивы по интерфейсу SPI на микроконтроллерах семейства STM32F4x во всех трёх режимах: опрос, прерывания и DMA. Как видите запуск SPI это достаточно громоздкая работа. Надо было настроить CLK, GPIO, NVIC, SPI и DMA. Зато теперь это открывает прямую дорогу для подключения к микроконтроллеру всяческих внешних ASICов: SPI NAND-Flash памяти, микросхем с ADC, RF трансиверы, CAN-трансиверы, SD карты, акселерометры и прочее.
Словарь
Сокращение |
Расшифровка |
PCB |
printed circuit board |
ASIC |
application-specific integrated circuit |
DMA |
Direct Memory Access |
MCU |
microcontroller unit |
SPI |
Serial Peripheral Interface |
MISO |
Master In Slave Out |
MOSI |
Master Out Slave In |
Ссылки
При наличии работающего SPI трансивера можно смело подключать к микроконтроллеру разнообразное периферийное оборудование: Flash память, джойстики, SD карты памяти, генераторы сигналов, акселерометры и прочее.
Текст |
URL |
SPI-NOR Flash на примере MX25R6435F |
|
Подключение PlayStation2 Джойстика к Микроконтроллеру (или Переходник между человеком и компьютером) |
|
Подключение SD карты по SPI (Капсула памяти) |
|
Пульт от «Dendy» в любительских конструкциях |
|
Обзор генератора сигналов AD9833 |
|
Обзор учебно-тренировочной платы JZ-F407VET6 (или электронная парта) |
|
Обзор Акселерометра LIS3DH |
|
Serial Peripheral Interface |
Вопросы
1--На шине SPI 2 разных чипа. На оба подали CS-0 вольт и начали читать. Что произойдет: Сгорит/не сгорит/другое?
Albert2009Zi
Мощнейшая статья. Такое комментировать, только портить...
HardWrMan
Зачем комментировать ИИшницу, которая проанализировала букварь на чипс?