Как работает адресная светодиодная лента?


    Наверное этот вопрос «как работает» очень многим покажется глупым. Ответ почти очевиден: адресная светодиодная лента состоит из множества последовательно соединенных «умных светодиодов». Это можно увидеть просто рассматривая устройство ленты. Видны отдельные микросхемы, припаянные к гибкому шлейфу, видны соединения: микросхемы соединены последовательно всего тремя проводами, при этом два из них это питание и земля. Только один провод передает данные о цвете пикселей. Как же это? Что такое «умный светодиод»?

    Дальше я расскажу о протоколе передачи данных, используемом в светодиодной ленте на базе WS2812B, и, более того, я почти создам свою «микросхему светодиодной ленты» в микросхеме ПЛИС.

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

    Бит ноль передается, как короткий положительный импульс и пауза, которая примерно в два раза шире импульса. Бит единица передается как широкий положительный импульс и короткая пауза:



    При отсутствии передачи более 50 микросекунд лента переходит в исходное состояние, готова принимать пиксели начиная с первого.

    Каждые 24 бита в последовательности — это 3 байта для трех цветов RGB. Причем на самом деле последовательность будет G-R-B. Старший бит G7 идет первым.

    Последовательность из первых 24х бит представляет из себя один пиксель, который получит самый первый светодиод в ленте. Пока первый светодиод не насытится он не передает данные дальше к следующему светодиоду. После того, как первый светодиод получит свою порцию из 24х бит RGB он открывает передачу следующему. Примитивно можно последовательность светодиодов представить, как каскад из кувшинов, последовательно наполняемых водой:



    Заполнится первый, потом второй, потом третий и так все по очереди.

    Таким образом, я считаю, что с протоколом передачи разобрались.

    Можно ли попробовать самому спроектировать такой «умный светодиод»? Практического смысла в этом конечно мало, но для самообразования и расширения кругозора — задача интересная. Попробуем описать логику чипа на языке проектирования аппраратуры Verilog HDL. Конечно, это будет не настоящий дизайн микросхемы, будут ограничения. Одно из самых важных ограничений — мне для моей микросхемы будет нужен внешний тактовый генератор. В настоящем умном светодиоде такой генератор тоже есть, но он встроен уже в чип.

    Модуль на Verilog начнем вот так:

    module WS2812B(
    	input wire clk,
    	input wire in,
    	output wire out,
    	output reg r,
    	output reg g,
    	output reg b
    );

    Здесь думаю все понятно: тактовая частота clk, входной и выходной сигналы «умного светодиода» in и out, ну и, конечно, выходные сигналы r, g, b через которые я буду управлять реальными внешними светодиодами красным, зеленым и синим.

    Входной сигнал я буду захватывать в двухбитный сдвиговый регистр и по текущему состоянию в этих захваченных битах смогу определить начало положительного фронта сигнала in:

    reg [1:0]r_in = 0;
    always @( posedge clk )
    	r_in <= { r_in[0],in };
    
    wire in_pos_edge; assign in_pos_edge = (r_in==2'b01);

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

    localparam reset_level = 3000;
    reg [15:0]reset_counter = 0;
    always @( posedge clk )
    	if( r_in[0] )
    		reset_counter <= 0;
    	else
    	if( reset_counter<reset_level )
    		reset_counter <= reset_counter+1;
    
    wire reset; assign reset = (reset_counter==reset_level);

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

    localparam fix_level   = 50;
    reg [7:0]bit_length_cnt;
    always @( posedge clk )
    	if( in_pos_edge )
    		bit_length_cnt <= 0;
    	else
    	if( bit_length_cnt<(fix_level+1) && !pass )
    		bit_length_cnt <= bit_length_cnt + 1;
    
    wire bit_fix; assign bit_fix = (bit_length_cnt==fix_level);
    

    Количество уже принятых бит в чипе считаем так:

    reg pass = 0;
    reg [5:0]bits_captured = 0;
    
    always @( posedge clk )
    	if( reset )
    		bits_captured <= 1'b0;
    	else
    	if( ~pass && bit_fix )
    		bits_captured <= bits_captured+1'b1;

    Здесь вводится еще важный сигнал pass, который как раз и определяет перенаправление входного потока на выход. После принятия 24х бит пикселя сигнал pass устанавливается в единицу:

    always @( posedge clk )
    	if( reset )
    		pass <= 1'b0;
    	else
    	if( bits_captured==23 && bit_fix )
    		pass <= 1'b1;
    		
    reg pass_final;
    always @( posedge clk )
    	if( reset )
    		pass_final <= 1'b0;
    	else
    	if( r_in!=2'b11 )
    		pass_final <= pass;
    		
    assign out = pass_final ? in : 1'b0;

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

    Ну и, конечно, нужен сдвиговый регистр, где накапливаются принятые 24 бита пикселя:

    reg [23:0]shift_rgb;
    always @( posedge clk )
    	if( bit_fix )
    		shift_rgb <= { in, shift_rgb[23:1] };
    
    reg [23:0]fix_rgb;
    always @( posedge clk )
    	if( bits_captured==23 && bit_fix )
    		fix_rgb <= { in, shift_rgb[23:1] };

    По приему всех 24х бит они переписываются в итоговый так же 24х битный регистр.

    Теперь остается дело за малым. Нужно реализовать ШИМ (Широтно Импульсную Модуляцию) сигнала для передачи яркости реальным внешним светодиодам согласно принятым байтам RGB:

    wire [7:0]wgreen; assign wgreen = { fix_rgb[0 ], fix_rgb[1 ], fix_rgb[2 ], fix_rgb[3 ], fix_rgb[4 ], fix_rgb[5 ], fix_rgb[6 ], fix_rgb[7 ] };
    wire [7:0]wred;   assign wred   = { fix_rgb[8 ], fix_rgb[9 ], fix_rgb[10], fix_rgb[11], fix_rgb[12], fix_rgb[13], fix_rgb[14], fix_rgb[15] };
    wire [7:0]wblue;  assign wblue  = { fix_rgb[16], fix_rgb[17], fix_rgb[18], fix_rgb[19], fix_rgb[20], fix_rgb[21], fix_rgb[22], fix_rgb[23] };
    
    reg [7:0]pwm_cnt;
    
    always @( posedge clk )
    begin
    	pwm_cnt <= pwm_cnt+1;
    	r <= pwm_cnt<wred;
    	g <= pwm_cnt<wgreen;
    	b <= pwm_cnt<wblue;
    end

    Вот кажется и все.

    Остается маленькая деталь — как это все испытать?

    Я взял несколько простых плат с ПЛИС MAX II (это платы серии Марсоход) и прошил их все проектом с вот этим Verilog кодом. На платах уже было 8 светодиодов, но они были все желтые. На каждой из плат я заменил 3 светодиода на R, G, B. Платы соединил последовательно и более того подключил их к настоящей светодиодной ленте. Таким образом, я удлинил настоящую ленту своими самодельными светодиодами.

    Получилось вот такое соединение:



    В реальности это выглядит вот так:



    Теперь, подавая на ленту некоторое изображение я вижу, что мои «умные светодиоды» ведут себе точно так же, как и настоящие из ленты:


    Получается, что реализованная мною в ПЛИС логика вполне работоспособна! Я смог в первом приближении сделать нечто похожее на реальный чип «умного светодиода».

    Вообще, мне нравятся светодиодные ленты. На их основе каждый может изобрести что-то свое: интеллектуальное освещение, экраны, амбилайт эффекты. Однажды я даже реализовал цветомузыку на светодионой ленте под управлением FPGA. Но это уже другая история.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 50

      +2
      AlexGyver, перелогиньтесь =)
      PS. Мне действительно было интересно как это реализовано.
      Все оказывается просто.
      Спасибо!
        +1
        получается когда первый светодиод получил первый пакет, он его не передает дальше, а оставляет себе? а дальше он передает уже все остальные пакеты? я почему-то всегда думал что они как сдвиговые регистры работают.
          0
          Аналогично, тоже думал что как hc595 работают, почитал даташит, оказывается нет, работают как автор описал, по очереди заполняются. Получается, светодиоды в начале ленты сменяют цвет раньше тех, что идут за ними? Или они все же передают цвет на сами диоды только после ресета, т.е. одновременно?
            0
            Опс… посмотрел свою реализацию, действительно у меня получается, что первый светодиод раньше получает информацию. А правильнее будет, как вы написали — по сбросу, чтобы одновременно.
              0
              Да наверное правильно будет «как в 2812», для единообразия — а вот как именно у них сделано, непонятно.
          0
          Это можно увидеть просто рассматривая устройство ленты. Видны отдельные микросхемы, припаянные к гибкому шлейфу, видны соединения: микросхемы соединены последовательно всего тремя проводами, при этом два из них это питание и земля
          судя по описанию, это не последовательное, а параллельное соединение (последовательное расположение и последовательное соединение — разные вещи)
            +2
            Никак нет. Именно последовательное. Сигнал заходит в первую микросхему и потом через нее идет во вторую (когда первая получит свою порцию данных 24 бита).
              +2
              Согласен, однако, здесь имеет смысл уточнить, что по питанию подключение параллельное, а по управлению — последовательное
            0

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

              –1
              Автор, объясните, вот какой смысл изобретать какой-то отдельный пропиетарный протокол обмена данными, вместо того чтобы использовать какой-нибудь стандартный i2c?
              А то потом пользователи должны голову ломать, как сеё поделье запустить на каком-нибудь stm32f100 через DMA чтобы процессорного времени не тратить на передачу.
                +2
                Ну так-то это не совсем ко мне вопрос. Это вопрос к китайцам. Я просто повторяю их протокол в своем «реверс инжиниренге»…
                  +2
                  в i2c проводов больше, а скорость меньше. Не очень он подходит для такого применения)
                    +3
                    У I2C:
                    1. В 2 раза больше проводов для сигналов. Для узкой ленты это критично.
                    2. Имеет меньшую скорость.
                    3. В добавок к предыдущему ещё и накладные расходы на передачу адреса устройства (при передаче по 3 байта на устройство будет как минимум 25% пропускной способности уходить на адреса).
                    3. Ограниченное и не очень большое количество адресов (127, 255 или 1023, причём последний вариант дополнительно повысит накладные расходы на передачу адресов). Светодиодов в ленте может быть больше.
                    4. Эти адреса нужно как-то конфигурировать. Каждый светодиод джамперами не обвесишь, потребуется какой-то велосипед для автоконфигурации адресов и я даже с ходу не могу его придумать. Насколько надёжным будет такой велосипед — тоже большой вопрос.
                    5. Сигнал мастера должен проходить всю длину светодиодной ленты, со всеми её паразитными ёмкостями и индуктивностями, что накладывает на эту самую длину ограничения и ощутимо повышает чувствительность ко всяким наводкам и помехам, либо выдвигает существенные требования и к мастеру, и к самим светодиодам.
                    6. От светодиодов требуется немножко более сложная логика, что потенциально может повысить их стоимость, а поскольку в лентах могут быть тысячи светодиодов это критично. Логичнее перенести это удорожание на необходимость поставить более мощный МК или даже дополнительный МК в помощь основному, преобразующий UART/SPI/I2C в этот протокол. Ведь он будет 1 на всё устройство, а не тысяча.
                    7. К тому же более сложная логика повышает и вероятность глюков. Я встречал I2C устройства, которые при некорректных сигналах I2C могли притянуть к земле SCL и уже больше никогда не отпустить до перезагрузки по питанию, парализовав всю шину. На многометровой шине вероятность ошибочных сигналов сильно выше из-за помех и т. д. (не забываем, что мастеру нужно управлять всей длинной шины)

                    Текущий же протокол не содержит явных ограничений ни на количество светодиодов (адресов нет, можно влить сколько-угодно бит), ни на длину ленты (ведь каждый светодиод по сути выступает ретранслятором). Можно хоть миллионами светодиодов так управлять, озаботится придётся только подводом питания, ну и частота обновления упадёт. В данном конкретном приложении использовании нестандартного протокола вполне обоснованно.
                      0
                      1. В 2 раза больше проводов для сигналов. Для узкой ленты это критично.

                      Да ладно. В том же ws2815 две линии сигнала. И ничего, на ленту влезают, никто не жаловался.

                      image

                      2. Имеет меньшую скорость.

                      0.9 + 0.35us = 1.25us -> 800khz /bit
                      i2с — позволяет работать на 3.4Мгц

                      3. В добавок к предыдущему ещё и накладные расходы на передачу адреса устройства (при передаче по 3 байта на устройство будет как минимум 25% пропускной способности уходить на адреса).

                      что? не вижу проблемы передавать в bulk режиме:
                      |address| data_led1 | data_led2 | data_led3 |… data_led_100500|
                      передать один раз адрес и пачкой данные.

                      4. Эти адреса нужно как-то конфигурировать.

                      Зачем? они также будут соеденены последовательно. mcu -> led1 -> led2 -> led3… -> led100500 пусть будут на одном же адресе. Тут без разницы.

                      5. Сигнал мастера должен проходить всю длину светодиодной ленты,


                      См. предыдущий ответ про последовательное соединение.

                      6. От светодиодов требуется немножко более сложная логика, что потенциально может повысить их стоимость

                      Вот тут частично согласен, но не думаю что от доп. нескольких тысяч транзисторов существенно возрастет цена. она больше от техпроцесса зависит а не от количества pn-переходов.

                      Скорее тут китайцам было лень лицензию на i2c покупать у филипса.
                        0
                        |address| data_led1 | data_led2 | data_led3 |… data_led_100500|
                        передать один раз адрес и пачкой данные.

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

                        Вот тут частично согласен, но не думаю что от доп. нескольких тысяч транзисторов существенно возрастет цена. она больше от техпроцесса зависит а не от количества pn-переходов.

                        Скорее тут китайцам было лень лицензию на i2c покупать у филипса.

                        + ещё 2 резистора в вашей схеме для i2c на каждый светодиод
                        И правильно сделали, текущий протокол очень не сложный, можно битбагн сделать, можно SPI, можно DMA
                        Но не без минусов конечно, 2х проводной лучше, только не тот, который у WS2815 (там просто защита он выгоревшего пикселя). А тот, который у APA102, синхронный, так как с ним в холоде стабильно работает, а WS2812B глючат, так как кварцевого генератора в них нет

                          0
                          А адрес то чего вначале? какого устройства?

                          Вы прикалываетесь? Это в даташите обычно пишут.

                          как первый после передаст второму? без адреса?

                          Каждый предыдущий будет master для последующего. И передавать на тот же адрес, что в даташите.

                          + ещё 2 резистора в вашей схеме для i2c на каждый светодиод

                          Их можно прямо в светодиод встроить как pullup. Там токи не большие

                          можно DMA

                          Та реализацию, которую я видел здесь память жрет как свинья. И не факт что в какой-нибудь stm32f100 вообще этот буфер влезет.
                          Если у вас есть более элегантное решение, я готов его выслушать.
                            0
                            Каждый предыдущий будет master для последующего. И передавать на тот же адрес, что в даташите.

                            и это сразу оверхед на шине, так как передаются куча одинаковых адресов. Снижает скорость. А ведь и так у большинства устройств скорость i2c 400 kbit/s

                            Их можно прямо в светодиод встроить как pullup. Там токи не большие

                            1. On the STM32F77xxx/F76xxx/F72xxx/F73xxx devices, the I2C I/Os support the 20mA drive needed in Fast-mode Plus.

                            плюс ещё 40 mA, если я правильно понимаю) (ну временами конечно) Если на 1 mbit/s использовать.
                            open-drain всё таки

                            Если у вас есть более элегантное решение, я готов его выслушать.

                            we.easyelectronics.ru/STM32/upravlenie-svetodiodnoy-lentoy-na-ws2812b-s-stm32f10x.html

                              0
                              А вот за APA102 отдельное спасибо. Почти то, что надо. А есть ли аналоги на 12 вольт? а то ток большой получается на 5 в.
                                0

                                Лента на ws2811, но вряд ли она вам понравится;)

                    0
                    При отсутствии передачи более 50 микросекунд лента переходит в исходное состояние, готова принимать пиксели начиная с первого.

                    Что означает «лента переходит»? У нее же нет общего «мозга», на сколько я понял. Тут имеется ввиду первый светодиод?

                    Еще такой вопрос: контроллер может как-то определить сколько светодиодов в ленте?
                      +1
                      Общего мозга конечно нет. Каждый светодиод сам по себе решает. Если данные не приходят в течении какого-то времени, то каждый из них сам решает, что видимо начинается новый кадр и нужно быть готовым его принять.

                      Контроллер не может определить количество светодиодов. Нет для этого никаких возможностей.
                        0
                        Хм, получается чтоб сделать на ленте какой-то световой эффект, нужно в программу зашить количество светодиодов в ней? Такое себе решение…
                          0
                          Ну можно же каким то образом сказать программе, сколько светодиодов в ленте)
                          Либо завести на контроллер другую сторону ленты, тогда можно определить сколько светодиодов в ней)
                            0
                            Можно конечно, но это уже усложнение. А вообще странно что не предусмотрели какого-то опрашивающего сигнала для этих целей, для простоты светодиод может «отвечать» на запрос замыканием сигнального провода, например.
                              0

                              Это тоже усложнение)

                                0
                                Небольшое усложнение прошивки чипа, без изменений в аппаратной части.
                                  0
                                  да, но если логику переносить в светодиод который в ленте, то будет усложнение
                                    0
                                    Я думаю, что у светодиода нет прошивки и там протокол реализован «в железе», он же очень простой. И в таком случае любой доп. функционал — дорого.
                                0
                                Зажигать по одному, измерять ток. Ток не меняется — светодиоды кончились. Заодно и контроль повреждения ленты.
                                  +1
                                  Интересный метод. Наверное даже будет работать.
                                    0
                                    Можно совместить с двоичным поиском, тогда можно будет гораздо быстрее считать светодиоды.
                              0
                              Еще такой вопрос: контроллер может как-то определить сколько светодиодов в ленте?

                              Если только закольцевать сигнал с последнего светодиода обратно на контроллер
                              0

                              Прикольно, но интереснее было бы реализовать передачу по двум проводам вместо трёх (данные по линии питания).

                                +1
                                Там с питанием и так жесть полная. Ленте нужен очень большой ток.
                                К примеру, я питал ленту от компьютерного блока питания и полную яркость с трудом удавалось зажечь — начинала глючить.
                                  0
                                  А сколько у вас диодов в ленте? Если не включать белый свет на максимальной яркости, то не так уж много лента потребляет. У меня на карнизе 90 диодов, питается все от полутораамперной зарядки от телефона. Как бы стрелочные часы (60 диодов, все горят одновременно) — вообще напрямую от Digitalspark.
                                    0
                                    Для длинных осветительных светодиодных лент встречал совет: подавать питание на оба конца ленты, т.к. падение напряжения вдоль ленты заметно уже на трехметровых.
                                      0
                                      Да и посередине не помешает.
                                      Каждый светодиод в кластере кушает 12 мА. Учитываем худший вариант — белый свет при максимальной яркости, т.е. 36 мА на светодиод.
                                      Для пятиметровой ленты 60 LED/m это 10,8 А при 5 В.
                                      Для пятиметровой ленты 144 LED/m это уже 26 А.
                                      Там дорожки и разъемы столько не вытянут.
                                      0
                                      стоит попробовать запитать ленту с 2х сторон, или подавать питание в середину.
                                        0
                                        Несомненно, это поможет.
                                          0
                                          По-моему, там желательно во все места подавать. Уж очень эти 5 вольт проседают. Когда делал MIDI-гирлянду на ёлку, попробовал включить все диоды белым светом, и было очень заметно, что чем дальше от питания — тем желтее, вплоть до оранжевого, причём ток был ниже, чем мог выдать БП. С лентами получше, но тоже к концу желтее (144 LED/m).
                                    0
                                    На их основе каждый может изобрести что-то свое:

                                    Эрон дон дон:D
                                    image

                                      +1
                                      А уровни TTL логики WS2812B и FPGA не требуют согласования?
                                        0
                                        Я ничего не согласовывал.
                                          +4
                                          а так вообще законно?)
                                            0
                                            Если ножка FPGA работает только на выход, то вполне законно.
                                            А вот если бы работала на вход, то без согласования уровней было бы уже ой-ёй-ёй
                                              +2
                                              Если ножка FPGA работает только на выход, то вполне законно.

                                              а у WS2812B какое напряжение логической единицы минимальное?
                                        +1
                                        Можете, пожалуйста, объяснить как цвета меняются одновременно? Например, если нужно всю ленту зажечь одним цветом. Если светодиод меняет свой цвет после того, как получил свою порцию данных, то одновременное переключение не получится
                                          0
                                          Глаз — слишком инерционная штука. Вся пятиметровая лента включается менее чем за 5 мсек — это нереально заметить.
                                            0
                                            Возможно активация нового принятого цвета происходит именно по сигналу Reset (это на самом деле не сигнал, а пауза в передаче более 50 микросекунд). Тогда светодиоды будут включаться примерно в одно время. У меня в коде это не сделано, но сделать легко.
                                              0
                                              Получается что светодиоды меняют цвет последовательно, но происходит это достаточно быстро чтобы глаз не заметил.
                                              Я раньше думал, что в лентах управление идет по какой-нибудь параллельной шине, по которой передается что-то вроде адреса светодиода и команда. Но такой способ оказался намного проще и универсальнее (в теории можно подключить любое количество светодиодов)

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

                                          Самое читаемое