Светодиодная лента состоит из множества последовательно соединенных микросхем WS2812B. Каждая такая микросхема представляет собой intelligent control LED light source - то есть интеллектуально управляемый светодиодный источник света, в моем вольном переводе. Каждая такая микросхема не только управляемый контроллер, но и три светодиода: красный, зеленый, синий. Каждую микросхему в ленте можно индивидуально зажечь в свой собственный цвет, комбинируя три базовых цвета.
Описание чипа можно взять здесь:
Там ничего сложного. Микросхемы соединены цепочкой всего одним проводом, выход одной микросхемы на вход другой, ее выход на вход следующей, и так далее:
Кодирование сигнала простое: интервал времени "бит" условно можно разделить на три равные части, первая часть всегда единица, третья часть - всегда ноль. Часть по середине - это и есть передаваемый бит. Каждый пиксель передается 24-мя битами ( 8R-8G-8B ), каждый бит по три части. Пиксели передаются один за другим без интервалов.
Когда передано достаточное количество пикселей (в моей в ленте 300 микросхем), то чтобы переданные пиксели загорелись в те цвета, которые им были переданны нужно передать еще небольшую паузу. В смысле передать "паузу" - это значит ничего не передавать некоторое время.
Тактовая частота на ленту 2,4МГц. Соответственно один бит передается 1,25 микросекунды. Пауза по активации пикселей 50 микросекунд или больше.
Сделаю такой Verilog модуль:
`timescale 1ns / 1ps
module LED_tape(
input wire clk,
input wire [23:0] RGB,
output reg data,
output wire[15:0]num,
output reg sync,
output reg req
);
parameter NUM_LEDS = 8;
parameter NUM_RESET_LEDS = 2;
localparam NUM_TOTAL = (NUM_LEDS+NUM_RESET_LEDS);
//3 tick counter
reg [1:0] cnt3 = 2'b0;
always @(posedge clk)
if (cnt3 == 2'b10)
cnt3 <= 2'b0;
else
cnt3 <= cnt3+1;
//24 tick counter
reg [4:0] cnt24 = 5'b0;
always @(posedge clk)
if (cnt3 == 2'b10)
cnt24 <= ( cnt24 == 23 ) ? 5'b0 : cnt24 +1'b1;
reg _req = 1'b0;
reg req_ = 1'b0;
always @(posedge clk)
begin
_req <= (cnt3 == 2'b10) & (cnt24 == 22);
req <= _req;
req_ <= req;
end
reg [15:0]cntN = 0;
always @(posedge clk)
if(_req)
begin
if( cntN==(NUM_TOTAL) )
cntN <= 0;
else
cntN <= cntN + 1;
end
assign num = cntN;
reg [23:0]shift_r24;
always @(posedge clk)
if(req_)
shift_r24 <= RGB;
else
if( cnt3==2'b10 )
shift_r24 <= { 1'b0, shift_r24[23:1] };
wire hide; assign hide = (cntN>NUM_LEDS & cntN<=(NUM_TOTAL));
always @(posedge clk)
sync <= hide;
always @(posedge clk)
if( hide )
data <= 1'b0;
else
data <= (cnt3==2'b00) ? 1'b1 :
(cnt3==2'b01) ? shift_r24[0] : 1'b0;
endmodule
В этом модуле два входных сигнала: clk - это тактовая частота, 24 бита RGB - это цвет пикселя, который будет передаваться. Я предлагаю, чтобы модуль выдавал выходной сигнал [15:0]num - это порядковый номер пикселя, который будет передаваться следующим. Выходной сигнал req - запрос на смену пикселя. Таким образом, внешний модуль получает информацию о позиции текущего выводимого пикселя и сигнал, когда требуется смена пикселя на следующий.
Модуль параметризуемый. Можно задавать, сколько светодиодов будут управляться NUM_LEDS и какова будет длительность сигнала reset NUM_RESET_LEDS. Название reset мне не очень нравится, так как обычно это что-то другое, но в документации на микросхему написано именно так. Reset - это пауза между передачами бит пикселей, и эта пауза активирует цвет переданный на пиксели.
Если хотите посмотреть, как может работать этот модуль в симуляторе Verilog, то вот вам тестбенч:
`timescale 1ns / 1ns
module LED_tape_TB;
reg clk = 0;
always
begin
#5;
clk = ~clk;
end
wire data;
wire [15:0] w_num;
wire w_req;
wire w_sync;
reg [23:0]rgb = 0;
always @(posedge clk )
if( w_req )
rgb <= w_sync ? 0 : { {8{w_num[2]}}, {8{w_num[1]}}, {8{w_num[0]}} };
// Instantiate the Unit Under Test (UUT)
LED_tape #( .NUM_LEDS(7), .NUM_RESET_LEDS(4) )uut (
.clk(clk),
.RGB(rgb),
.data(data),
.num(w_num),
.sync(w_sync),
.req(w_req)
);
initial
begin
$dumpfile("out.vcd");
$dumpvars(0,LED_tape_TB);
#1000000;
$finish(0);
end
endmodule
Тестбенч смотрит запрашиваемый номер пикселя, его младшие три бита и на их основании формирует цвета. Результат работы модуля в симуляторе - передача последовательно только восьми пикселей: черный, зеленый, красный, желтый, синий, бирюзовый, фиолетовый, белый.
Вот диаграммы из GtkWave, передача нескольких пикселей и "пауза", активирующая пиксели на ленте:
Вот передача одного пикселя:
Счетчик cnt3 считает от нуля до 2х - это фазы передачи одного бита. Счетчик cnt24 - номер передаваемого бита пикселя. Счетчик cntN - номер передаваемого пикселя. Сигнал req - запрос внешнему модулю на смену пикселя, RGB - новый пиксель, который нужно передать в ленту.
Этот же модуль Verilog управления светодиодной лентой я хочу вставить в проект цветомузыки, только там уже цвета будут задаваться согласно спектра сигнала и я надеюсь в такт музыке.
Чтобы испытать модуль в реальной ПЛИС платы Марсоход3bis я сделал отдельный проект в САПР Intel Quartus Prime. Топ модуль этого проекта выглядит вот так:
Весь проект можно взять на GitHub: https://github.com/marsohod4you/Led-control-WS2812B
Ну а демонстрация его работы - на видео в начале статьи.
Следующий этап - это вставить модуль управления светодиодной лентой в проект цветомузыки.
Подробнее...