Como funciona uma faixa de led de endereço?


Provavelmente, essa pergunta "como funciona" parece tola para muitos. A resposta é quase óbvia: uma faixa de LED endereçável consiste em uma pluralidade de "LEDs inteligentes" conectados em série. Isso pode ser visto simplesmente olhando para o dispositivo de fita. Você pode ver microcircuitos individuais soldados em um loop flexível, você pode ver as conexões: os microcircuitos são conectados em série com apenas três fios e dois deles são de potência e terra. Apenas um fio transmite dados de cores de pixel. Como é isso? O que é um LED inteligente?

A seguir, falarei sobre o protocolo de transferência de dados usado na faixa de LEDs com base no WS2812B e, além disso, quase criarei meu próprio “chip de faixa de LED” no chip FPGA.

Portanto, a fita usa transmissão serial através de um único sinal de dados.

O bit zero é transmitido como um impulso positivo curto e uma pausa aproximadamente duas vezes maior que o impulso. A unidade de bit é transmitida como um amplo pulso positivo e uma curta pausa:



se não houver transmissão superior a 50 microssegundos, a fita retornará ao seu estado original, pronta para aceitar pixels a partir do primeiro.

A cada 24 bits em uma sequência são 3 bytes para três cores RGB. E, de fato, a sequência será GRB. A parte alta do G7 vem em primeiro lugar.

A sequência dos primeiros 24 bits é de um pixel, que receberá o primeiro LED da fita. Até o primeiro LED ficar saturado, ele não transfere mais os dados para o próximo LED. Depois que o primeiro LED recebe sua porção de 24x bits RGB, ele abre a transmissão para o próximo. Primitivamente, pode-se imaginar uma sequência de LEDs como uma cascata de jarros que são sucessivamente enchidos com água: o



primeiro, o segundo, o terceiro e assim por diante serão preenchidos.

Assim, acredito que o protocolo de transferência foi resolvido.

É possível tentar projetar um "LED inteligente" você mesmo? Obviamente, isso faz pouco sentido prático, mas para a autoeducação e a ampliação dos horizontes, essa é uma tarefa interessante. Vamos tentar descrever a lógica do chip na linguagem de programação Verilog HDL. Claro, isso não será um design de chip real, haverá limitações. Uma das limitações mais importantes - vou precisar de um relógio externo para o meu microcircuito. Em um LED inteligente real, esse gerador também existe, mas já está integrado ao chip.

Vamos começar o módulo Verilog assim:

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

Acho que tudo está claro aqui: a frequência do relógio clk, os sinais de entrada e saída do "LED inteligente" entrando e saindo e, é claro, os sinais de saída r, g, b através dos quais controlarei os LEDs externos reais em vermelho, verde e azul.

Capturarei o sinal de entrada em um registro de deslocamento de dois bits e, a partir do estado atual desses bits capturados, posso determinar o início da borda positiva do sinal em:

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);

Além disso, é importante determinar o status da redefinição da fita quando o controlador de controle faz uma pausa antes de iniciar uma nova transmissão:

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);

Além disso, a partir de uma margem positiva em_pos_edge, é necessário suportar uma pausa para obter o momento de corrigir um novo bit:

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);

O número de bits já recebidos no chip é considerado da seguinte maneira:

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;

Um sinal de passagem importante é introduzido aqui, que apenas determina o redirecionamento do fluxo de entrada para a saída. Depois de aceitar o bit de 24x pixels, o sinal de passagem é definido como um:

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;

A saída de entrada é multiplexada para a saída de saída quando o sinal pass_final é um.

Bem, é claro, precisamos de um registro de deslocamento, no qual os 24 bits recebidos do pixel são acumulados:

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] };

Após o recebimento de todos os 24 bits, eles também são copiados para o registro final de 24 bits.

Agora o assunto permanece pequeno. É necessário implementar um sinal PWM (Latitudinal Pulse Modulation) para transmitir brilho aos LEDs externos reais de acordo com os bytes RGB recebidos:

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

Isso parece ser tudo.

Um pequeno detalhe permanece - como experimentar tudo isso?

Peguei algumas placas-mãe simples com o FPGA MAX II (estas são as placas da série Mars rover) e mostrei todas elas com o projeto com este código Verilog. Já havia 8 LEDs nas placas, mas todos eram amarelos. Em cada uma das placas, substituí 3 LEDs por R, G, B. Conectei as placas em série e, além disso, as conectei a uma faixa de LED real. Assim, ampliei a fita real com meus LEDs caseiros.

Essa conexão acabou assim:



Na realidade, é assim:



Agora, aplicando uma certa imagem à fita, vejo que meus "LEDs inteligentes" se comportam exatamente da mesma forma que os reais da fita:


Acontece que a lógica que eu implementei no FPGA é totalmente funcional! Como primeira aproximação, eu pude fazer algo semelhante a um chip de LED inteligente real.

Na verdade, eu gosto de tiras de LED. Basicamente, todos podem inventar algo próprio: iluminação inteligente, telas, efeitos ambilight. Uma vez eu implementei música colorida em uma fita LED executando FPGA. Mas isso é outra história .

All Articles