[Из песочницы] Использование конфигурируемых логических ячеек PIC микроконтроллеров для управления WS2812

Эта статья про управление светодиодами WS2812b, немного о синтезе логических схем и реализации их внутри микроконтроллера. Статья с небольшими отступлениями и двумя бонусами. Первый бонус основывается на том факте, что когда мы пишем, то одновременно читаем (разве нет?). Второй бонус поможет начать программировать микроконтроллеры и за 10 минут самим повторить реализацию, описанную в статье.
Трехцветные «SPI светодиоды» WS2812b (рис. 1) с драйвером и их предшественники WS2811/WS2812 включаются последовательно и управляются по однопроводной (последовательной) шине (отсюда иногда ошибочно называются «SPI светодиодами», хотя в описываемом случае, особенно для «бонуса #1», интерфейс SPI играет ключевую роль). Каждый бит цветности RGB (24 бита, по 8 бит на канал) кодируется ШИМ сигналом (см. рис. 2), с периодом около 1.25 мкс. Светодиоды WS2812 часто применяются в управляемых светодиодных лентах и экранах, так как имеют быстрый и простой интерфейс, а количество светодиодов легко наращивается. Так, например, при частоте 25 кадров в секунду видео экран может содержать одну линейку из (40 мс — 50 мкс)/(0.125 мкс x 24) ~= 1300 RGB светодиода. Это не так много, но для рекламных вывесок, табло или бегущей строки может быть вполне достаточно.

a8996727fea344f48dadd1c28b75a02c.jpg
Рис. 1. Светодиодная лента с цифровым последовательным интерфейсом

4f04e5ac879a43299e59f2e611e5915c.png
Рис. 2. Параметры кодирования битовой последовательности

Применение дешевых микроконтроллеров для формирования таких коротких сигналов (см. рис. 2) представляет определенные трудности. Так, например, для контроллера PIC16 с тактовой частотой 16МГц одна команда выполняется за 250нс. Таким образом, для программного управления драйвером WS2812 нужно затратить практически 100% быстродействия ядра.

Синтез интерфейса
Для решения задачи можно было бы использовать аппаратные возможности микроконтроллера, например SPI интерфейс. Часто используют такой трюк, когда для передачи «нуля» передают последовательность »11100000», а для «единицы» — »11111000», т.е. один бит кодируется байтом (или полубайтом).

Другой путь — использование SPI интерфейса и логических элементов. В заметках по применению [1] и [2] опубликованы примеры, на которых в основном базируется описываемая реализация.

Итак, если взять сигналы SPI интерфейса и инвертировать сигнал SCK (сигнал синхронизации) и объединить с SDO (выходные данные) логической функцией И, то получим закодированные «Единицы» (рис. 3).

fd239d1744e8449babddcc5cd4d00aef.png
Рис. 3. Кодирование «единиц»

Для кодирования «Нулей» нужен другой сигнал с меньшей длительностью. Для этого можно использовать ШИМ микроконтроллера. «Нули» кодируются сигналом, описываемым логическим выражением n (SDO) * n (SCK) * PWM (n это инверсия). Именно такое выражение приведено в [1] и [2], но, как можно заметить из итоговой диаграммы (рис 5), или вывести при синтезе логической схемы с помощью таблицы истинности и карт Карно, выражение можно записать как nSCK * PWM.

bcb895e8112e46c4a3760104f3a108d7.png
Рис. 4. Кодирование «нулей»

Остается объединить потоки «Нулей» и «Единиц» функцией ИЛИ, и получить нужную ШИМ последовательность управления драйвером WS2811/WS2812.

a65df247632b4e4384d20b719d083a3f.png
Рис. 5. Результат кодирования потока

В виде логического выражения сигнал управления записывается как:
(nSCK * SDO) + (nSDO * nSCK * PWM) {1}

Применяя теоремы булевой алгебры (см., например, замечательный учебник [3]) можно показать, что выражение {1} преобразуется к эквивалентным выражениям:
n (SCK + nSDO) + n (SDO + SCK + nPWM) {2}
(nSCK * PWM) + (nSCK * SDO) {3}
n (SCK + nPWM) + n (SCK + nSDO) {4}
nSCK * (PWM + SDO) {5}

Многие младшие микроконтроллеры Microchip, например PIC16F1508, PIC16F1509 имеют встроенные Конфигурируемые Логические Ячейки (Configurable Logic Cell, CLC).

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

Входными сигналами для CLC могут быть входные сигналы микроконтроллера, выходы CLC, другие встроенные периферийные модули и внутренние генераторы. Выходы CLC могут выводиться на порты и использоваться совместно с другой периферией контроллеров.

Учитывая вышесказанное, связка SPI интерфейса и CLC выглядит как идеальный вариант для решения задачи формирования управляющего сигнала драйвера светодиодов WS2812 (WS2811).

Для визуального конфигурирования CLC и формирования кода предназначена утилита «CLC Designer», так же конфигурирование периферии микроконтроллеров можно осуществить через плагин «Mplab Code Configurator» (MCC) к среде разработки MPLAB X.

Не все комбинации входных сигналов присутствуют на входах логических ячейках. Поэтому необходимо найти такую комбинацию сигналов и ячеек, которые нужны для выполнения конкретной задачи. Для кодирования данных на ячейках CLC нам нужны сигналы SCK, SDO и PWM. Логическая ячейка CLC4 на своих входах может иметь сигналы от SCK, SDO, но не имеет сигнала от PWM, а CLC2 может на своих входах иметь PWM. Выход CLC2 можно соединить с входом CLC4. Поэтому CLC2 будет выступать в роли повторителя и транслировать ШИМ на вход CLC4, а CLC4 будет выполнять логическую функцию выражений {1}, {2}, … {5}.

55a9a915df03429ea934c12dd071c19b.png
Рис. 6. CLC2 транслирует PWM на выход. Gate2 — 4 имеют на выходе лог.1 и не влияют на итоговый результат

В действительности, функцию {1} в приведенном виде не реализовать на одной ячейке CLC, но её эквивалентные формы {2}…{5} — легко. (см.рис. 7).

33af0bbda3c74b51a3e8da7d1ac1ab3f.png
Рис. 7. CLC4 формирует ШИМ кодирование SPI сигнала через функцию n (SCK + SDA + nPWM) + n (SCK + SDA)

В данном случае применен дополнительно D-триггер, что позволяет входным сигналам быть рассинхронизированными относительно тактовой частоты контроллера и избежать ложных переключений выхода. Вообще, для конкретного случая D-триггер может быть не обязательным, но такая конфигурация дает более предсказуемые тайминги на выходе (синхронизация от тактовой частоты FOSC).

Отступление #1. Пять способов решения одной задачи
Реализация логических функций {2} … {5} приведены на рис. 7a… 7 г. Все выражения эквивалентны и дают ожидаемый результат (см. рис. 5).

255530025f6b4bf98f88361b3c11d494.PNG
Рис. 7а. (nSCK * PWM) + (nSCK * SDO)

b50393c1a19849ea9d7e174db4efc77a.PNG
Рис. 7 б. n (SCK + nPWM) + n (SCK + nSDO)

6bd8c4f34ef14a30a83ea120c1005524.PNG
Рис. 7в. nSCK * (PWM + SDO)

9f50cfba7c114b128ef925b8c1fda29d.PNG
Рис. 7 г. n (SCK + SDA + nPWM) + n (SCK + SDA)


Отступление #2. Паразитные импульсы в комбинационных логических схемах
Возможны ситуации когда изменение входного сигнала приводит к нескольким изменениям выхода, в результате чего формируется паразитный импульс (glitch). Это может случиться, если изменяющийся входной сигнал проходит к выходу несколькими путями и количество проходимых логических вентилей в разных путях разное. Тогда, за счет задержки каждого из логических элементов и разницы во времени прохождения по «кратчайшему» и «критическому» пути, возможно формирование паразитного импульса. Данный процесс хорошо описан в [3].
Для конкретного нашего примера, при реализации функций {1} … {5} таких ситуаций не возникает, но даже если бы и возникло, то проблему можно решить используя конфигурацию OR-D конфигурируемых ячеек. Тогда схему с рис. 7 г можно перерисовать как на рис. 7(д), где дополнительный D-триггер фиксирует значение на выходе по фронту сигнала тактовой частоты контроллера FOSC.

33af0bbda3c74b51a3e8da7d1ac1ab3f.png
Рис. 7д. Та же функция что и на рис. 7 г., но с защелкой по выходу

Итак, после того, как проведена конфигурация CLC, ШИМ и SPI, подготовительная часть окончена. Теперь если записать байт в регистр SSP1BUF, то на выходе CLC4 получим кодированный ШИМ сигнал в соответствии с форматом WS2812. Пока SPI модуль передает данные, микроконтроллер может выполнять какие-то другие задачи. Для каждого светодиода необходимо передать три байта. Схема подключения приведена на рис. 8.

f03894246aa84dd09b3c474b55a1a087.png
Рис. 8. Подключение ленты WS2812b к микроконтроллеру

Бонус #1. Увеличение памяти
В описанном способе конфигурируемая логика и её совместная работа с периферией микроконтроллера обеспечивает формирование временных параметров протокола в формате WS2812, от программы требуется только записать байт в буфер SPI, дальнейшую «магию» берут на себя конфигурируемые логические ячейки. Так как в описанном примере SPI используется только для записи, а входная линия SDI остается свободной, то предоставляется отличная возможность использования SPI не только для управления светодиодами, но и для одновременного получения внешних данных. Рассмотрим как одновременно с управлением светодиодами читать данные из микросхемы памяти с интерфейсом SPI.

SPI порт PIC микроконтроллера имеет два сдвиговых регистра (один для передачи, один для приема) с одним адресом. Запись в SSPBUF начнет передачу байта и сдвигает битики в линию SDO, но одновременно в этот же регистр сдвигаются данные с входной линии SDI. То есть передавая байт в SPI (SDO) мы одновременно принимаем данные с SPI (SDI).

4599aca9cae243a3b3a7804ddcd65afa.png

Таким образом, если подключить к модулю SPI микроконтроллера светодиоды WS2812 и, например, SPI память (SRAM 23LC512 или EEPROM 25LCxxx), то для пересылки данных из внешней памяти в светодиодную ленту программе необходимо лишь переписывать данные из SSPBUF в SSPBUF, т.е. читать байт из внешней памяти и следующей командой отсылать данные обратно в SPI (в светодиоды) и одновременно читать следующий байт и т.д.

ced6b6d4fb174ae5bac606f668695cd3.png
8c43fb2db7b649b09176a01cb2c464c7.png
Рис. 9. Подключение внешней памяти

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

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

Наличие буферизированного изображения во внешней памяти позволяет отображать движущиеся изображения путем сдвига начального адреса чтения памяти. При использовании SPI EEPROM памяти можно отображать заранее записанные изображения. Интерфейс SPI позволяет подключать несколько микросхем памяти, например, одну EEPROM для хранения знакогенератора, статических изображений, а во второй SRAM создавать дисплейный буфер для последующего вывода на LED-экран.

Бонус #2. Делаем сами
Для изучения исходников можно зайти на сайт Microchip (исходные коды примера AN1890 доступны на сайте

Но я предлагаю посмотреть короткое видео, где в пяти минутах показано, как всю вышеописанную магию сотворить своими руками.

Источники


1. AN1606. Using the Configurable Logic Cell (CLC) to Interface a PIC16F1509 and WS2811. LED Driver www.microchip.com
2. AN1890. Simple SRAM Buffering for Large LED Arrays. www.microchip.com
3. Д. Харрис, С. Харрис. «Цифровая схемотехника и архитектура компьютера» (http://habrahabr.ru/post/259505/)

© Habrahabr.ru