STM Урок 152. LL. SPI. Драйвер индикатора MAX7219. Часть 2

 

 

 

В предыдущей части занятия мы познакомились с аппаратной реализацией шины SPI в контроллере STM32F1 и настроили проект урока.

И по нашей славной традиции посмотрим, каким образом происходит у нас инициализация шины SPI.

Для этого зайдём в функцию MX_SPI1_Init и посмотрим, что же там происходит.

Сначала, как обычно, объявляются структуры, включается тактирование на шины и настраиваются ножки портов.

Затем заполняется определёнными значениями из наших настроек структура шины SPI_InitStruct.

Далее идёт вызов LL_SPI_Init, в которую мы зайдём и посмотрим код там.

Там сначала, как всегда, проверяется наличие параметров, а затем при условии, что шина у нас ещё не включена, заполняется управляющий регистр CR1. В нём сначала с помощью маски SPI_CR1_CLEAR_MASK обнуляются все биты, кроме SPE, а затем эти биты включаются или не включаются в зависимости от настроек в параметрах структуры

 

 

В результате наших настроек у нас включатся биты SSM, SSI, а поле BR примет двоичное значение 011, что означает деление частоты на 16, как мы и настраивали.

Далее идёт инициализация регистра CR2

 

 

У нас не включится ни один бит в данном регистре, так как прерывания мы никакие не включали, и NSS у нас программный.

Настройка CRC пропускается, так как мы этот механизм не задействовали.

Вот, в принципе, и вся инициализация шины. То есть шина у нас настроена, но ещё не включена, так как бит SPE в регистре CR1 сброшен. Поэтому нам затем надо будет не забыть его включить.

Уберём сначала все глобальные макросы в файле main.c.

Затем добавим локальную переменную для счёта в функции main()

 

 

Также удалим инициализацию ножек

 

LED1_OFF();LED2_OFF();LED3_OFF();LED4_OFF();LED5_OFF();
LED6_OFF();LED7_OFF();LED8_OFF();LED9_OFF();LED10_OFF();

 

Удалим ещё весь пользовательский код из бесконечного цикла.

Обнулим переменную, немножко подождём, дёрнем ножкой CS, и запустим нашу шину SPI

 

 

Далее нам потребуется библиотека для индикатора. Чтобы нам ничего лишнего заново не сочинять, то мы возьмём файлы max7219.c и max7219.h из проекта урока 115 по NRF для первого приёмника с именем NRF24_RX_00 и скопируем их в подобающие папки нашего проекта.

Подключим файл max7219.c к нашему проекту и подключим нашу библиотеку в файле main.c

 

 

В функции main() вызовем сразу инициализацию нашего дисплея

 

 

Перейдём в файл max7219.h и удалим подключение файла библиотеки HAL

 

#include «stm32f1xx_hal.h»

 

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

 

 

Затем перейдём в файл и удалим буфер, а также подключение структуры шины

 

uint8_t aTxBuf[1]={0};

extern SPI_HandleTypeDef hspi2;

 

Следующие директивы также приведём в подобающий вид

 

#define cs_set() LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4)

#define cs_reset() LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4)

 

В теле функции Send_7219 удалим код передачи данных

 

aTxBuf[0]=rg;

HAL_SPI_Transmit (&hspi2, (uint8_t*)aTxBuf, 1, 5000);

aTxBuf[0]=dt;

HAL_SPI_Transmit (&hspi2, (uint8_t*)aTxBuf, 1, 5000);

 

Вместо этого мы сначала дождёмся готовности шины путём проверки установки флага TXE в регистре SR

 

 

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

При установке флага мы проваливаемся по коду вниз и передадим сначала адрес регистра микросхемы

 

 

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

 

 

Читаем регистр DR вникуда (на самом деле он прочитается в регистр АЛУ r1)

 

 

Аналогичным образом, как и адрес регистра микросхемы, передадим данные в этот регистр

 

 

Соберём код, прошьём контроллер и посмотрим результат нашего труда пока в программе логического анализа, так как мы ещё ничего не выводили на индикатор.

В программе настроим шину SPI следующим образом

 

 

Триггер установим на ножку CS (хотя можно и на любую, также характер изменения сигнала неважен, так как все равно диаграмма выводится с запасом)

 

 

Запустим анализ и перезагрузим контроллер. Результат будет вот такой

 

Наша шина отлично работает.

Теперь идём в файл main.c и в функции main() сначала очистим дисплей, а затем попробуем вывести какое-нибудь длинное число

 

 

Соберём код, прошьём контроллер и посмотрим результат теперь уже не в программе, а на настоящем индикаторе

 

 

Вернёмся в файл max7219.c и немного подправим функцию вывода числа в левую половину индикатора NumberL_7219, чтобы не выводились лидирующие нули при малых значениях

 

 

 

Добавим аналогичную функцию вывода числа в правую половину индикатора

 

 

Создадим для данной функции прототип в заголовочном файле, перейдём в файл main.c в функцию main() и после вывода цифры на экран подождём 2 секунды. Дисплей нам очищать не надо, так как мы всё лишнее теперь гасим в самих функциях вывода чисел в тетрады индикатора

 

 

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

 

 

Соберём код, прошьём контроллер и посмотрим результат работы кода на индикаторе

 

 

Всё отлично!

Казалось бы, пора уже и закругляться, но вы же знаете, я ж без бонусов не могу никак.

Меня постоянно напрягал промежуток времени между передачами старшего и младшего байта и я этот вопрос урегулировал следующим образом.

Заходим в Cube MX и выставим теперь разрядность передаваемых (соответственно, и принимаемых) данных 16 бит

 

 

Сгенерируем проект, откроем его в Keil вернёмся в файл max7219.c и в функции Send_7219 закомментируем код передачи данных (теперь уже для истории)

 

 

А вместо него у нас теперь будет передача 16-битного числа в сразу в один приём

 

 

Если мы посмотрим в отладке регистр CR1 шины, то увидим, что кроме тех битов, которые у нас устанавливались и ранее, у нас установился также бит DFF.

Соберём код, прошьём контроллер и увидим на индикаторе, что у нас также всё работает, как и ранее.

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

 

 

Вот так мы оптимизировали и передачу данных. Попробуем ещё передать данные несколько в другом режиме работы шины. Сейчас мы передаём в режиме SPI 0:0, попробуем передать в режиме SPI 1:1. Для этого закроем проект в Keil, и в Cube MX в настройках шины изменим полярность и фазу

 

 

Сгенерируем проект, откроем его в Keil, соберём проект, прошьём контроллер и увидим, что у нас также будет всё отлично работать.

Только вот программа логического анализа нас не поймёт

 

 

А всё потому, что в ней также надо настроить режим 1:1

 

 

Теперь после сохранения у нас будет всё снова прекрасно определяться

 

 

Таким образом, на данном уроке мы научились работать с шиной SPI при помощи возможностей библиотеки LL, также мы подробно изучили её аппаратную реализацию в контроллере STM32F1.

Благодарю всех за внимание!

 

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

 

Исходный код

 

 

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

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

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

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

 

 

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

 

STM Name

Один комментарий на “STM Урок 152. LL. SPI. Драйвер индикатора MAX7219. Часть 2
  1. Евгений:

    А в SW4STM32 не получается бонуса. После установки DATA SIZE 16 Bits генерируем проект, собираем и файл .elf меняет паука на треугольник и становится в 10 раз меньше. Отладчик не запускается, говорит Error in final launch sequence
    Failed to execute MI command:
    load D:\\WorkCube\\Indicator1\\Debug\\Indicator1.elf
    Error message from debugger back end:Load failed

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

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

*