¿Cómo funciona una tira de dirección led?


Probablemente esta pregunta "cómo funciona" parece tonta para muchos. La respuesta es casi obvia: una tira de LED direccionable consiste en una pluralidad de "LED inteligentes" conectados en serie. Esto se puede ver simplemente mirando el dispositivo de cinta. Puede ver microcircuitos individuales soldados a un bucle flexible, puede ver las conexiones: los microcircuitos están conectados en serie con solo tres cables, y dos de ellos son de alimentación y tierra. Solo un cable transmite datos de color de píxeles. ¿Como es eso? ¿Qué es un LED inteligente?

A continuación, hablaré sobre el protocolo de transferencia de datos utilizado en la tira de LED basada en WS2812B y, además, casi crearé mi propio "chip de tira de LED" en el chip FPGA.

Entonces, la cinta utiliza la transmisión en serie a través de una sola señal de datos.

El bit cero se transmite como un impulso positivo corto y una pausa que es aproximadamente dos veces más ancha que el impulso. La unidad de bits se transmite como un pulso positivo amplio y una pausa breve:



si no hay transmisión de más de 50 microsegundos, la cinta vuelve a su estado original, lista para aceptar píxeles a partir del primero.

Cada 24 bits en una secuencia son 3 bytes para tres colores RGB. Y, de hecho, la secuencia será GRB. La parte alta de G7 es lo primero.

La secuencia de los primeros 24 bits es de un píxel, que recibirá el primer LED en la cinta. Hasta que el primer LED esté saturado, no transfiere datos al siguiente LED. Después de que el primer LED recibe su porción de bits RGB 24x, abre la transmisión al siguiente. Primitivamente, uno puede imaginar una secuencia de LED como una cascada de jarras que se llenan sucesivamente de agua: la



primera, luego la segunda, luego la tercera, y así sucesivamente, se llenarán.

Por lo tanto, creo que el protocolo de transferencia ha sido resuelto.

¿Es posible intentar diseñar un "LED inteligente" usted mismo? Por supuesto, esto tiene poco sentido práctico, pero para la autoeducación y la ampliación de los horizontes, esta es una tarea interesante. Intentemos describir la lógica del chip en el lenguaje de programación Verilog HDL. Por supuesto, este no será un diseño de chip real, habrá limitaciones. Una de las limitaciones más importantes: necesitaré un reloj externo para mi microcircuito. En un LED inteligente real, dicho generador también existe, pero ya está integrado en el chip.

Comencemos el módulo Verilog así:

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

Creo que todo está claro aquí: la frecuencia de reloj de clk, las señales de entrada y salida del "LED inteligente" dentro y fuera, y, por supuesto, las señales de salida r, g, b a través de las cuales controlaré los LED externos reales en rojo, verde y azul.

Capturaré la señal de entrada en un registro de desplazamiento de dos bits y desde el estado actual en estos bits capturados puedo determinar el comienzo del borde positivo de la señal en:

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

Además, es importante determinar el estado del restablecimiento de la cinta cuando el controlador de control hace una pausa antes de comenzar una nueva transmisión:

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

Además, desde un borde positivo en_pos_edge es necesario soportar alguna pausa para obtener el momento de arreglar un nuevo 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);

El número de bits ya recibidos en el chip se considera de la siguiente manera:

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;

Aquí se introduce una señal de paso importante, que solo determina la redirección del flujo de entrada a la salida. Después de aceptar el bit de píxeles de 24x, la señal de paso se establece en uno:

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;

La salida de entrada se multiplexa a la salida cuando la señal pass_final es una.

Bueno, por supuesto, necesitamos un registro de desplazamiento, donde se acumulan los 24 bits del píxel recibidos:

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

Al recibir los 24 bits, también se copian en el registro final de 24 bits.

Ahora el asunto sigue siendo pequeño. Es necesario implementar una señal PWM (Latitudinal Pulse Modulation) para transmitir el brillo a los LED externos reales de acuerdo con los bytes RGB recibidos:

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

Eso parece ser todo.

Queda un pequeño detalle: ¿cómo experimentarlo todo?

Tomé algunas placas base simples con FPGA MAX II (estas son las tarjetas de la serie Mars rover) y las flasheé todas con el proyecto con este código Verilog. Ya había 8 LED en los tableros, pero todos eran amarillos. En cada una de las placas, reemplacé 3 LED con R, G, B. Conecté las placas en serie y, además, las conecté a una tira de LED real. Por lo tanto, alargué la cinta real con mis LED caseros.

Esta conexión resultó así:



en realidad, se ve así:



ahora, aplicando una determinada imagen a la cinta, veo que mis "LED inteligentes" se comportan exactamente igual que los reales de la cinta:


¡Resulta que la lógica que implementé en el FPGA es completamente funcional! Como primera aproximación, pude hacer algo similar a un chip LED inteligente real.

En realidad, me gustan las tiras de LED. Sobre su base, todos pueden inventar algo propio: iluminación inteligente, pantallas, efectos ambilight. Una vez incluso implementé música en color en una cinta LED con FPGA. Pero esa es otra historia .

All Articles