Урок 177. CMSIS. STM32F1. SPI. Interrupt



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

Такую задачу мы с вами уже выполняли, только использовали мы при этом возможности других библиотек — HAL и LL. Чтобы получить ещё большую гибкость и контроль над передачей, мы теперь воспользуемся библиотекой CMSIS.

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

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

Схема будет использоваться та же, что и в уроке 175

 

 

И займёмся мы сначала ведущим устройством, проект для которого мы сделаем из проекта того же урока с именем CMSIS_SPI_MASTER и назовём его CMSIS_SPI_MASTER_INT.

Подключим к ПК наше ведущее устройство, ведомое пока не подключаем.

Откроем наш проект в Keil и в файле main.c добавим два буфера, один для передачи, другой для приёма, а также несколько глобальных переменных для счёта и отслеживания событий

 

 

В функции SPI1_Init поднимем в самое начало функции включение тактирования порта

 

 

Включим глобальные прерывания от модуля SPI1

 

 

С локальными прерываниями мы будем заниматься уже в функции main(), в которой мы сначала изменим имя локальной переменной

 

uint16_t i, n;

 

Удалим вызов макроса старта модуля

 

SPI1_ENABLE();

 

Заполним буфер передачи инкрементирующимися значениями

 

 

После 2-секундной задержки опустим ножку выбора и запустим модуль

 

 

Включим пока прерывания только по ошибке передачи

 

 

Дальше работаем в бесконечном цикле, из которого пока удалим весь код.

Заполним буфер следующими значениями

 

 

Затем передадим самое первое полуслово буфера

 

 

Включим прерывания по заполнению приёмного и опустошению передающего буферов

 

 

Добавим в самом низу файла обработчик прерываний от модуля SPI1

 

 

В теле данного обработчика добавим три вида условий, соответствующим флагам событий, обработку прерываний которых мы включили

 

 

Так как мы не будем писать никакие реакции на события ошибки передачи, то в тело данного условия мы добавили только инструкцию nop.

 

 

В случае, если мы попали в обработчик по событию опустошению буфера передачи, то проинкрементируем сначала позицию передачи в пакете

 

 

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

 

 

А если ещё не достигли, то передадим следующее полуслово

 

 

Теперь обработаем заполнение приёмного буфера.

В теле данного условия мы заберём принятое число из буфера приёма и запишем его в соответствующую позицию приёмного буфера

 

 

Проинкрементируем приёмную позицию

 

 

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

 

 

Вернёмся в бесконечный цикл функции main(), в котором дождёмся установки пользовательского флага и обнулим его

 

 

Покажем принятые и переданные числа на индикаторе

 

 

Подождём 1 секунду

 

 

Вообщем, передавать и принимать мы будем пакеты по 128 полуслов, таких пакетов у нас будет 64, числа в каждом следующем пакете будут инкрементироваться дальше и так до 8191, поэтому, если мы достигнем такого значения, то обнуляем счётчик и после этого передача продолжится, но числа будут опять идти с нуля

 

 

Обнулим счётчик позиций приёма и опустим ножку выбора

 

 

Вот и весь код для ведущего устройства. Соберём проект и прошьём контроллер.

Индикатор начнёт показывать передаваемые числа, принимаемых пока нет, так как у нас ведомый даже не включен, поэтому слева будет 0

 

 

Казалось бы, почему мы в каждой итерации бесконечного цикла включаем прерывания по заполнению приёмного буфера, а нигде их потом не запрещаем, как в случае с буфером передачи? А потому что в самой первой итерации мы должны их включить именно здесь. Вот поэтому остальные итерации тоже страдают. Но а из-за того, что данное действие много времени не займёт, мы не стали проверять, что это именно первая итерация, заводить какой-то флаг, так что не факт, что на проверку уйдёт времени не меньше. Поэтому пока оставим так.

 

 

Отключим от ПК программатор ведущего устройства, запитаем его от независимого источника, а к ПК подключим ведомое.

Для ведомого устройства проект сделаем из проекта того же урока 175 с именем CMSIS_SPI_SLAVE и назовём его, соответственно, CMSIS_SPI_SLAVE_INT.

Откроем данный проект в Keil и также добавим 2 буфера и несколько глобальных переменных

 

 

В функции SPI1_Init также включим глобальные прерывания

 

 

В функции main() также изменим имя локальной переменной

 

uint16_t i, n;

 

Инициализацию локальных переменных удалим

 

i=0; n=0;

 

Включим сразу все 3 вида локальных прерываний

 

 

Также пока удалим вызов макроса старта периферии

 

SPI1_ENABLE();

 

Удалим задержку

 

delay_ms(2000);

 

Запустим модуль SPI1

 

 

Из бесконечного цикла пока всё удалим

Добавим обработчик прерываний от модуля SPI1 в самом низу файла сразу с кодом, так как код подобен коду ведущего устройства

 

 

Также добавим вот такой код в бесконечный цикл функции main()

 

 

Здесь мы сначала ждём установки пользовательского флага, обнуляем его, затем готовим буфер значениями, вычтенными из 8192, чтобы отличался от приёмного, потом отображаем принятые и переданные числа на индикаторе, обнуляем счётчик, отправляем в буфер передачи первое число пакета и включаем прерывания по событию опустошению буфера передачи.

Соберём код, прошьём контроллер.

Посмотрим, как идёт обмен, по показаниям индикаторов

 

 

Показания приёмного индикатора на ведущем будут всегда отставать на 128 от ведомого, так как мы там отображаем предыдущий пакет.

Посмотрим теперь обмен в программе логического анализа

 

 

Мы видим, что передаваемые числа следуют в пакетах друг за другом непрерывно.

А здесь мы видим, что у нас ничего не пропускается и не выпадает

 

 

А вот здесь мы видим, что ножке по окончанию пакета теперь поднимается вовремя, хотя мы не использовали никаких задержек, оказывается, её нужно было поднимать в теле условия по событию приёма, а не передачи

 

 

Таким образом, в данном уроке мы произвели обмен между двумя устройствами на контроллерах STM32F1 посредством шины SPI, используя возможности библиотеки CMSIS, а также механизм прерываний по событиям передачи и приёма по интерфейсу SPI, что позволило нам добиться лучшего контроля за обменом данных по данному интерфейсу.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код для ведущего устройства (MASTER)

Исходный код для ведомого устройства (MASTER)

 

 

Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

Индикатор светодиодный семиразрядный с драйвером MAX7219

Логический анализатор 16 каналов можно приобрести здесь

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM CMSIS. STM32F1. SPI. Interrupt

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*