ESP8266 Урок 12. SPI. Драйвер индикатора MAX7219



Продолжаем изучать возможности контроллера ESP8266 и учиться пользоваться данными возможностями в своём коде.

На данном занятии мы познакомимся с интерфейсом SPI, который поддерживается аппаратно в микроконтроллере ESP8266

 

 

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

В ESP8266 есть два модуля SPI.

Первый называется просто General SPI (SPI общего назначения)

 

 

Данный интерфейс может работать максимально со скоростью до 80 мегагерц, в режиме ведомого — 20 мегагерц.

Второй модуль называется HSPI

 

 

Хотя в скобках и стоит приписка Slave, данный модуль прекрасно справляется и с работой в режиме MASTER (ведомого), в чём мы на данном уроке убедимся. Здесь максимальная скорость работы — 20 мегагерц.

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

Регистры модулей SPI, а также их биты не совсем подробно описаны в технической документации на контроллер, как мы привыкли видеть у других контроллеров. Поэтому пришлось воспользоваться некоторыми другими ресурсами для изучения работы с ними (сторонние проекты, заголовочные и файлы исходных кодов SDK). Работать с модулем SPI, как, впрочем, и с другой периферией, можно, используя возможности готового функционала SDK, так и прямого доступа к регистрам. Сегодня мы в основном поработаем по 2 варианту, так виднее процесс.

Работать на данном уроке с шиной SPI мы будем в режиме MASTER, так как он гораздо проще в программировании, с режимом SLAVE мы познакомимся в будущих уроках. Также для ещё большей простоты программирования мы будем работать с шиной SPI только в режиме передачи. В качестве ведомого устройства, подключаемого по шине, мы возьмём восьмиразрядный семисегментный индикатор, динамическая индикация которого реализована на микросхеме-драйвере MAX7219. Данная микросхема общается с контроллером именно по шине SPI. Мы неоднократно уже работали с данной микросхемой с использованием других контроллеров, поэтому весь процесс работы с ней нам знаком.

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

На нашей плате ножки, которые мы будем использовать, будут следующие:

 

MOSID7

CLKD5

CSD8

 

Также для лучшего мониторинга передачи данных по шине мы подключим к данным ножкам логический анализатор.

И теперь наша схема будет выглядеть следующим образом

 

 

Проект мы сделаем из проекта урока 10 с именем I2C_LCD2004 и назовём его LED7219.

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

Произведём в папке с проектом следующие переименования файлов:

 

i2с_user.h -> spi_user.h

i2с_user.c -> spi_user.c

lcd.h -> max7219.h

lcd.c -> max7219.c

 

Откроем наш проект в Eclipse и точно такие же переименования внесём и в Makefile в местах, где встретятся аналогичные файлы.

Можно было бы, конечно создать проект с нуля, но, как мне кажется, это было бы ещё дольше, так как пришлось бы ещё настраивать свойства проекта, и заново писать Makefile. Впрочем, решать вам, как вам легче.

В файлах main.c и max7219.c изменим также имя подключаемой библиотеки

 

#include "max7219.h"

 

В файлах max7219.c и spi_user.c изменим также имя другой подключаемой библиотеки

 

#include "spi_user.h"

 

Теперь у нас проект скорее всего соберётся.

В файлах max7219.c и spi_user.c также удалим весь полностью код кроме подключения библиотек.

А в файлах max7219.h и spi_user.h также удалим вообще весь код и наполним их пока следующим содержимым

 

 

 

В файле main.c удалим подключение библиотеки

 

#include «driver/i2c_master.h»

 

В функции user_init удалим объявление символьного массива.

 

 

Также удалим вот этот код

 

i2c_master_gpio_init();

I2C_MASTER_SDA_LOW_SCL_LOW();

LCD_ini();

ets_delay_us(100000);

LCD_String(«String 1»);

LCD_SetPos(3,1);

LCD_String(«String 2»);

LCD_SetPos(6,2);

LCD_String(«String 3»);

LCD_SetPos(9,3);

LCD_String(«String 4»);

ets_delay_us(1000000);

system_soft_wdt_feed();

ets_delay_us(1000000);

system_soft_wdt_feed();

LCD_SetPos(9,3);

LCD_String(» «);

 

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

 

 

Подключим заголовочный файл для SPI, а также наш пользовательский заголовочный файл

 

 

В файле spi_user.c добавим функцию инициализации SPI

 

 

В одноимённом заголовочном файле создадим для данной функции прототип и вызовем её в функции user_init файла main.c

 

 

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

 

 

В файле spi_user.h подключим библиотеку для SPI, а также добавим макросы для делителей

 

 

Вернёмся в файл spi_user.c и в функции spi_init в случае использования делителя проинициализируем также свою переменную для делителя

 

 

Произведём также настройку ножек GPIO, используемых в SPI

 

 

Как мы видим, наша функция универсальная и мы можем её использовать также и для инициализации первого модуля.

Настроим тактирование модуля

 

 

Вообщем, здесь происходит занесение значений различных делителей в соответствующие биты регистра SPI_CLOCK соответствующего модуля.

Вкратце битовые поля данного регистра описаны в technical reference на контроллер почти в самом конце документации

 

 

Настроим также порядок следования байтов от старшего к младшего для буферов чтения и записи

 

 

Здесь уже используется регистр SPI_USER, краткое описание которого есть там же

 

 

Установим режим использования ножки выбора

 

 

Кстати, про данные биты регистра в документации умалчивается. Остаётся только догадываться, что скорее всего SPI_CS_SETUP — это бит установки аппаратного управления ножкой CS, а — SPI_CS_HOLD — это включение режима удержания ножки при приёме, когда шина занята, хотя это тоже не факт, обычно такие задачи возлагаются на ведомое устройство.

Далее отключаем режим FLASH сбросом соответствующего бита в том же регистре, который также не обозначен в документации

 

 

Вот и вся инициализация.

Теперь нам нужно будет написать функцию отправки в шину 16-битного значения, так как именно с таким значением оптимальнее всего работать с драйвером индикатора. Такой функции готовой в библиотеке нет, поэтому будем писать.

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

 

 

В файле spi_user.h добавим макрос проверки занятости SPI, а заодно и прототип на нашу функцию передачи

 

 

Здесь мы уже обращаемся к регистру SPI_CMD, проверяя в нём бит SPI_USR.

Вот описание данного регистра, которое состоит из описания только одного бита

 

 

Как видим, сбрасывается данный бит аппаратно, за этим мы и будем следить, чтобы не обращаться лишний раз к периферии, когда она занята.

Причем в заголовочном фале находится также макрос только для этого бита.

 

 

Мне удалось найти некоторую информацию по другим битам данного регистра, а также по битам других регистров и не только периферии SPI в файле esp8266_peri.h из библиотеки для Arduino. Вот макросы некоторых других битов данного регистра

 

//SPI CMD

#define SPICMDREAD (1 << 31) //SPI_FLASH_READ

#define SPICMDWREN (1 << 30) //SPI_FLASH_WREN

#define SPICMDWRDI (1 << 29) //SPI_FLASH_WRDI

#define SPICMDRDID (1 << 28) //SPI_FLASH_RDID

#define SPICMDRDSR (1 << 27) //SPI_FLASH_RDSR

#define SPICMDWRSR (1 << 26) //SPI_FLASH_WRSR

#define SPICMDPP (1 << 25) //SPI_FLASH_PP

#define SPICMDSE (1 << 24) //SPI_FLASH_SE

#define SPICMDBE (1 << 23) //SPI_FLASH_BE

#define SPICMDCE (1 << 22) //SPI_FLASH_CE

#define SPICMDDP (1 << 21) //SPI_FLASH_DP

#define SPICMDRES (1 << 20) //SPI_FLASH_RES

#define SPICMDHPM (1 << 19) //SPI_FLASH_HPM

#define SPICMDUSR (1 << 18) //SPI_FLASH_USR

#define SPIBUSY (1 << 18) //SPI_USR

 

Вернёмся в файл spi_user.c подождём, пока шина будет свободна

 

 

Отключим пока не требующиеся режимы и использование ножек сбросом соответствующих битов в регистре SPI_USER

 

 

Установим требуемую длину посылки в битах

 

 

Цифра 15 у нас используется, потому что счёт количества битов в посылке идёт от нуля, то есть bit_length — 1.

Включим ножку MOSI

 

 

Далее мы нам нужно будет занести в буфер передачи данные для их последующей передачи в шину.

Вообще передавать по шине SPI с помощью нашего контроллера ESP8266 мы можем до 64 байт (512 бит). То есть буфер содержит 64 байта и разделен на 16 регистров по 4 байта. Как правило, первые 8 регистров (SPI_W0-SPI_W7) используются для передачи, а следующие (SPI_W8-SPI_W15) — для приёма данных.

Подготовим наши байты, загрузив их в самый первый регистр буфера (в старшую его часть, так как передача и приём начинается со старшего байта регистров буфера)

 

 

И напоследок дадим команду передачи

 

 

Вообщем, в принципе, драйвер шины SPI для нашего сегодняшнего урока мы написали.

Теперь осталось написать драйвер микросхемы, но это не проблема, так как мы с ней уже очень много работали.

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

 

 

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

 

 

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

 

 

Далее добавим функции отображения на индикаторе разнообразных цифровых данных

 

 

Все эти функции нами давно написаны и в объяснении не нуждаются. Тем не менее они снабжены комментариями, гласящими о том что в данный момент происходит в коде.

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

 

 

В заголовочном файле max7219.h добавим прототипы на некоторые требуемые извне функции

 

 

Вернёмся в main.c и в функции user_init вызовем функцию инициализации индикатора и попробуем вывести на него большое число

 

 

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

 

 

Подождём пару секунд и очистим индикатор

 

 

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

 

 

В бесконечном цикле добавим тест, в результате которого примерно 10 раз в секунду в правой половине индикатора будут увеличиваться выводимые числа от 0 до 9999, а в правой уменьшаться, задержка у нас уже есть

 

 

Посмотрим, как работает наш индикатор теперь, собрав код и прошив контроллер

 

 

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

 

 

Хотя в коде мы используем для передачи 16-разрядный режим, но здесь настроим 8-разрядный, так лучше видно передачу регистров и данных.

Вот так выглядит процесс передачи данных

 

 

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

Итак, на данном уроке мы начали знакомиться с работой модуля SPI в контроллере ESP8266, пока используя его только для передачи данных в режиме MASTER. Также мы не использовали другие режимы полярности и фазы. В дальнейшем мы обязательно познакомимся с работой SPI в ESP8266 и на приём, а также и в режиме ведомого (SLAVE).

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

 

 

 

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

 

Исходный код

 

 

Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU

Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266

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

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

 

 

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

 

ESP8266 Name

0 комментариев на “ESP8266 Урок 12. SPI. Драйвер индикатора MAX7219
1 Отклики /Обратные ссылки для "ESP8266 Урок 12. SPI. Драйвер индикатора MAX7219"
  1. […] Предыдущий урок Программирование МК ESP8266 Следующий урок […]

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

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

*