
Пролог
SPI это цифровой, последовательный, относительно высокоскоростной, полнодуплексный, синхронный физический интерфейс передачи данных в пределах одной электронной платы PCB. Этот интерфейс служит для обмена данными между микросхемами в пределах одной электронной платы. Ранее в эпоху ARV микроконтроллеров интерфейс 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 вольт и начали читать. Что произойдет: Сгорит/не сгорит/другое?
ссылка на оригинал статьи https://habr.com/ru/articles/1043452/