STM Урок 154. LL. SPI. Соединяем два контроллера



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

Цель данного занятия у нас практически та же, но есть и отличие. Теперь мы для достижения данной цели будем уже использовать возможности библиотеки LL.

Схема урока остаётся полностью та же как и в прошлом занятии

 

 

Логический анализатор также подключим

 

 

И также мы начнём писать проект с устройства MASTER.

Проект мы сделаем из проекта урока 152 с именем LL_LED7219, а имя ему присвоим LL_SPI_MASTER.

Откроем проект в Cube MX и включим ещё SPI2, настроив его аналогичным образом, как и SPI1

 

 

У нас включатся следующие ножки

 

 

Включим ножку PB12 на выход, то будет ножка SS для нашей шины

 

 

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

 

 

 

Не забываем включить LL на SPI2

 

 

Сгенерируем проект, откроем его в Keil, подключим к дереву проекта файл max7219.c, настроим программатор на автоперезагрузку и отключим оптимизацию.

Так как индикатор у нас теперь подключен к SPI2, то в перейдём в файл max7219.c и первым делом поменяем ножку SS вот в этих макросах

 

#define cs_set() LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_12)

#define cs_reset() LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_12)

 

В функции Send_7219 изменим номер шины

 

while(!LL_SPI_IsActiveFlag_TXE(SPI2)) {}

LL_SPI_TransmitData16 (SPI2, (uint16_t)rg<<8 | dt);

while(!LL_SPI_IsActiveFlag_RXNE(SPI2)) {}

(void) SPI2->DR;

Перейдём в функцию main() файла main.c и включим там нашу шину SPI2

 

 

Соберём код прошьём контроллер и проверим работоспособность нашего индикатора

 

 

Индикатор отлично работает!

Теперь займёмся передачей данных ведомому устройству по шине SPI1. Передавать мы будем также инкрементирующиеся цифры.

Добавим ещё одну локальную переменную в main()

uint16_t i, r;

Проинициализируем её также нулём

 

i=0; r=0;

 

Вот эту строку удалим, пусть у нас ножка останется поднятой

 

LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4);

 

А ножку SS SPI2 тоже поднимем

 

 

В бесконечном цикле передадим число ведомому

 

 

И от него также примем число и запишем его во вторую переменную

 

 

 

И затем поднимем ножку выбора

 

 

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

 

 

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

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

Проект для ведомого сделаем из проекта ведущего и назовём его LL_SPI_SLAVE.

Откроем этот проект в Cube MX и отключим первым делом ножку PA4, так как контроль здесь будет аппаратный

 

 

У шины SPI1 переключим тип и включим аппаратный контроль, внизу никакие настройки больше не трогаем

 

 

Сгенерируем проект, откроем его в Keil, подключим к дереву проекта файл max7219.c, настроим программатор на автоперезагрузку и отключим оптимизацию.

В функции main() файла main.c удалим поднятие ножки PA4, так как она управляется теперь аппаратно

 

LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4);

 

В бесконечном цикле также уберём и опускание и поднятие данной ножки

 

LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_4);

LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_4);

 

Задержку в цикле также уберём, она не нужна, задержка есть у МАСТЕРа

 

LL_mDelay(100);

 

И здесь мы будем уже декрементировать значение переменной i.

Поэтому удалим сначала декрементирование

 

i++;

 

Здесь также исправим срабатывание

 

if(i<1) i=9999;

 

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

 

 

Здесь переменные тоже поменяем местами

 

NumberR_7219(r);

NumberL_7219(i);

 

И после этого уменьшим на один значение нашего счётчика

 

 

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

 

 

Судя по показаниям индикаторов, обмен у нас осуществляется правильно, данные между контроллерами передаются в обе стороны.

Посмотрим также обмен в программе логического анализа, сначала настроив её следующим образом

 

 

Мы включили SPI 1:1, так как у нас был именно такой режим, когда мы изучали шину на примере работы с микросхемой MAX7219, и мы его обратно в 0:0 не переводили.

Теперь нажмём кнопку START, соберём информацию с наших проводов и посмотрим, как у нас передаются данные

 

 

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

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

 

 

Отлично! Данные не пропускаются, на шине MOSI число инкрементируется, а на MISO — декрементируется.

Таким образом, мы сегодня поработали с шиной SPI в режиме SLAVE или ведомого устройства, применяя при этом уже библиотеку LL, тем самым обеспечив полнодуплексный обмен данными по шине SPI между двумя контроллерами.

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

 

 

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

 

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

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

 

 

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

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

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

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

 

 

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

 

STM LL. SPI. Соединяем два контроллера

4 комментария на “STM Урок 154. LL. SPI. Соединяем два контроллера
  1. Андрей:

    Здравствуйте, Владимир.

    А почему в Slave-е при разрешении SPI командой LL_SPI_Enable(SPI2) Вы предварительно не активируете биты RXNE и TXE командами LL_SPI_EnableIT_RXNE(SPI2) и LL_SPI_EnableIT_TXE(SPI2) ведь по умолчанию эти биты сброшены и Выша программа должна была бы сразу «зависнуть» на первой же строке while(!LL_SPI_IsActiveFlag_RXNE(SPI1))???

  2. Alexei DrevaLab:

    хотел-бы еще добавить, чего у Вас нету в коде. Это когда Master просто пытается прочитать данные от Slave.

    while(!LL_SPI_IsActiveFlag_TXE(SPI1)) {}
    //отпрвляем 0 чтобы выдать тактирование от master к slave . Т.к. ведмый будет ждать до
    //бесконечности, пока ему мастер не отправит
    //тактирование на SCK. А когда ведомый увидит такты,
    //то начнет передавать данные по MISO.
    LL_SPI_TransmitData8 (SPI1, 0);
    while(!LL_SPI_IsActiveFlag_RXNE(SPI1)) {}
    r = LL_SPI_ReceiveData8(SPI1);

  3. Олег:

    Добрый день, пытаюсь используя LL подключить TM1638. Не работает чтение кнопок то есть функция LL_SPI_ReceiveData8(SPI1); На HAL все работает, в чем может быть причина, куда копать? Спасибо!
    for (uint8_t i=0; i <5; i++)
    {
    r_data [i] = LL_SPI_ReceiveData8(SPI1);
    }

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

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

*