Controlador de bricolaje de panel LED en CPLD con modulación BAM

Hace algún tiempo, participó en una discusión sobre el proyecto de bricolaje de un reloj LED de matriz.
Y lo que me sorprendió: la antigua matriz monocromática de LED 8x8 con un paso de 5 milímetros se usó como dispositivo de visualización. Además, se crearon placas de circuito impreso complejas para ellos, se realizó una indicación dinámica suave. Y esto es en un momento en que los paneles LED 64x32 a todo color ya listos con un paso de 3 mm han estado disponibles durante mucho tiempo a un precio de $ 10-20. Y la variedad general de estos paneles es muy grande y tiene un paso de píxeles de 2 a 10 mm y casi cualquier tamaño.

Al mismo tiempo, el uso de tales paneles en diseños de bricolaje es bastante difícil: los controladores prefabricados cuestan bastante dinero y no tienen una API normal. Es bastante difícil hacer un escaneo bastante rápido del panel en microcontroladores comúnmente utilizados en bricolaje. Además, los intervalos de tiempo deben mantenerse con alta precisión; de lo contrario, comienza un notable desnivel del brillo.

Hay buenas soluciones en Adafruit , pero todas son bastante caras y complejas.

Después de pensarlo un poco, surgió el pensamiento: ¿por qué no hacer una placa extremadamente económica que será un puente entre una penique común como un arduino y un panel LED? Después de un par de meses de alboroto, nació algo que funciona.

Este artículo describe la segunda versión mejorada del controlador.

Desafío


Como tarea básica, quería poder controlar un panel con un tamaño total de al menos 64x64, mientras tenía la capacidad de trabajar al menos en Highcolor (RGB565) mientras mantenía una frecuencia de actualización de pantalla aceptable (al menos 50Hz). En la primera versión del controlador, la tarea básica se implementó por completo, pero surgió la idea de implementar la tarea por otro método muy prometedor, del cual nació la segunda versión.

Explicación básica del diseño de un panel LED típico.


Interfaz de entrada HUB75:


En cada entrada de color hay una cadena de registros del tipo HC595 (pero versiones especiales de 16 canales para LED). Hay tantos registros que son suficientes para el ancho del panel. Los permisos de trituración, arranque paralelo y salida son comunes a todos los registros. Las entradas ABCDE, esta es la elección de una serie, van a un decodificador convencional.

Principio de funcionamiento:

  • configure los datos en entradas RGB, haga clic en el botón CLK. Repite hasta que carguemos la línea completa
  • apague las salidas OE = 1 (para que no haya interferencia)
  • dar al decodificador el número de la fila cargada
  • haga clic en carga paralela LAT: los datos de línea se transfieren a los registros de salida
    habilitar salidas OE = 0
  • repetir para la siguiente fila

Esa es una indicación dinámica clásica. Está claro que con este método en uno de esos ciclos solo podemos encender / apagar cada LED específico.

Para obtener gradaciones de brillo con PWM clásico, dicho ciclo debe repetirse N-1 veces, donde N es el número de gradaciones de brillo (256 para RGB888). Y dado que al mismo tiempo todavía parpadea, todo esto debe hacerse muy, muy rápido.

Hay una solución alternativa: Modulación de ángulo de bit (BAM). En este caso, el tiempo de brillo en cada ciclo es proporcional al peso del bit mostrado. Es decir, para RGB888 solo necesita 8 ciclos de visualización. Un poco más detallado aquí .

La primera versión del controlador usó PWM clásico, que impuso un límite estricto en el número de ciclos de escaneo. En la segunda versión, se implementa BAM, que dio una gran ganancia en velocidad.

Implementación


Era bastante obvio que un microcontrolador convencional tira solo de paneles pequeños, los grandes simplemente no tienen suficiente velocidad. Por lo tanto, CPLD o FPGA son indispensables aquí: es físicamente imposible producir decenas de MB / s en microcontroladores de bajo costo.

Como memoria, fui recomendado en el foro IXBT por la muy interesante memoria FIFO Averlogic AL422B, que tiene aproximadamente 400kbytes de memoria y puede operar a frecuencias de hasta 50MHz.

Teniendo en cuenta que mi requisito principal era el bajo costo máximo de los componentes, para que la bufanda terminada fuera accesible para los fabricantes caseros, se eligió el Altera EPM3064 - CPLD con 64 macrocélulas. Al mismo tiempo, un número tan pequeño de macrocélulas no permite hacer una placa configurable dinámicamente; la configuración debe compilarse directamente en CPLD.

→ El circuito resultante se encuentra aquí

Detalles:

  • CPLD EPM3064ATC44-10: el precio de Ali es de aproximadamente $ 13-15 por una docena
  • FIFO RAM AL422B: el precio de Ali es de aproximadamente $ 15 por docena
  • Oscilador de cristal de 50MHz. La placa permite la instalación en cajas DIP14 / DIP8 / 7050. El precio de Ali es de aproximadamente $ 6-7 por docena
  • Estabilizador de 3.3V en el paquete SOT223. Precio en Chip and Dip - 40r cada uno
  • Conector IDC-10MS. Precio en Chip & Dip - 3 p / pieza
  • Conector IDC-16MS. Precio en Chip & Dip - 8 r / pieza
  • Conector IDC-14MS. Precio en Chip & Dip - 7 r / pieza
  • Condensadores 1 microfaradio 0805 - 8 piezas de aproximadamente 1 r / pieza
  • Condensador 0.1uF 0805 - aproximadamente 1 r / pieza
  • Resistencia 10k 0805 - un centavo

El total en detalle se obtiene 1.5 + 1.5 + 0.7 = $ 3.7 y 40 + 3 + 8 + 7 + 8 * 1 + 1 = 67 p. Todos juntos dentro de $ 5 - un centavo.

→ La imagen original del tablero está aquí

Archivos gerber preparados para ordenar

La placa está preparada para la primera versión, en la que no hubo control de RE. Para usarlo con la segunda versión, debe cortar el puente entre los terminales 23 y 24 de AL422B y tirar los cables desde el terminal 28 de EPM3064 (se lleva al bloque de terminales) al terminal 24 de AL422B.

Al soldar la placa, no olvide soldar los puentes de alimentación en la parte posterior de la placa.





Cálculos


Los cálculos de los parámetros requeridos son bastante complicados.

El hecho es que en el controlador se realizan dos procesos en paralelo: cargar los datos de la siguiente línea / indicar una línea ya cargada.

Los procesos comienzan simultáneamente, pero terminan en diferentes momentos, por lo que un proceso más rápido espera la finalización de un proceso más largo.

→ Se hizo una tableta Excel para el cálculo

Datos de origen:

  • CRYSTAL_FRQ (MHz) - frecuencia del generador (50 MHz)
  • PIXEL_COUNT: la cantidad de píxeles en la barra de descarga. Más detalles en la sección de cambio.
  • RGB_INPUTS: el número de entradas RGB utilizadas en la interfaz HUB75E del panel utilizado. 1 o 2
  • BYTES_PER_PIXEL: bytes por píxel. En nuestro caso, siempre 3 - RGB888
  • SCAN_LINES: número de líneas de escaneo en el panel utilizado. 16/08/32

Parámetros seleccionados:

  • PRE_DELAY - retraso de la señal LAT hasta que se enciende el OE, configurado en ticks
  • PRESCALER - preescaler para el contador principal. Es decir, si la lista de precios es 8 y el peso del bit actual es 4, entonces OE se activará durante 8 * 4 = 32 ciclos
  • POST_DELAY: retraso mínimo desde el apagado del OE a la siguiente señal LAT, configurada en ticks

Por ejemplo, tenemos un panel de 32x32 que tiene 8 líneas de escaneo y 2 entradas RGB. Dicho panel tiene dos conectores HUB75E, es decir, físicamente estos son dos paneles de 32x16. Conectamos estos paneles en serie, es decir, lógicamente este panel se verá como 64x16.

PRE_DELAY y POST_DELAY son intervalos de supresión antes y después de la habilitación de salida (OE) para que los multiplexores puedan cambiar las salidas y las teclas abrir / cerrar. Sin ellos, habrá "trucos" desde la grabación de píxeles hasta las líneas adyacentes. Los valores se seleccionan experimentalmente para un panel particular. Por lo general, 15 medidas son suficientes (establecidas en medidas).

Esto plantea la cuestión de elegir el preescalador: cómo elegirlo.

Un valor bajo de preescalador proporciona un tiempo de visualización de fotogramas corto, pero reduce el brillo general. El alto valor del preescalador aumenta el tiempo de visualización del cuadro, es decir, cuando enumera, parpadea la pantalla.

Probemos PRESCALER = 1

Obtenemos:

OE_EFFICIENCY: 8.3%, es decir, el panel solo funcionará 8.3% del brillo máximo posible
FRAMES_PER_SECOND - 2034 fps, pero la frecuencia de actualización de la imagen será enorme: más de 2000 fps.

La pérdida de brillo ya es muy grande.

Probemos PRESCALER = 16

Obtenemos:

OE_EFFICIENCY: es decir, el 72,9%, el panel funcionará al 72,9% del brillo máximo posible
FRAMES_PER_SECOND - 1117 - y la frecuencia de actualización de la imagen es muy buena: más de 1000 fps.
Bueno, es bastante normal: una eficiencia de más del 50% es bastante normal y la velocidad de fotogramas es muy buena.

La regla general es que PRESCALER es aproximadamente 8 veces más pequeño que el producto PIXEL_COUNT * RGB_INPUTS

Bueno, sigue contando y comprobando.

Cambiar paneles LED


Todos los paneles están conectados en serie. Diagrama de conexión: primero de derecha a izquierda, luego de abajo hacia arriba. Es decir, primero conectamos las horizontales en serie, luego la salida de la fila inferior a la entrada de la segunda fila desde la parte inferior, etc. a la fila superior.

El controlador se aferra al panel inferior derecho.

Hay paneles que tienen dos conectores de entrada y dos de salida. Tales paneles son esencialmente solo un conjunto mecánico de dos paneles verticalmente. Conmutado como dos paneles independientes.

Después del ensamblaje, necesitamos calcular la longitud total de la cadena en píxeles, para esto vemos cuántos paneles totales había en la cadena y multiplicar este número por el ancho del panel en píxeles. Luego, este número deberá introducirse en el valor PIXEL_COUNT durante la configuración de CPLD y en la calculadora de temporización.

Firmware FPGA


Todos los archivos necesarios están en github . Necesita descargar directamente con la carpeta.

Después del registro, debe descargar e instalar Quartus II 13.0sp1 desde el sitio web de Altera. Necesita descargar EXACTAMENTE ESTA versión: las versiones más nuevas ya no son compatibles con la serie MAX3000. No es necesario romperlo: la versión web (gratuita) es suficiente. Al descargar, asegúrese de marcar las casillas para MAX3000 y soporte para programadores. Por si acaso, te advierto: el paquete es grande, aproximadamente dos conciertos. También necesitará Altera USB Blaster: el precio habitual de Ali es de aproximadamente $ 3.

Abra el proyecto al422_bam.qpf. A la izquierda, abra la pestaña del archivo y abra el archivo al422_bam.v: este es el archivo principal del proyecto. En él necesitas configurar los parámetros:

Cuántas entradas RGB en un panel: en los paneles con una entrada HUB75 puede haber 1 o 2 entradas RGB. Para saber exactamente cuántas entradas son posibles de esta manera, tomamos la cantidad de píxeles en el panel verticalmente. Divídalo por el número de líneas de exploración (indicadas en la designación del panel como 8S, por ejemplo). Dividir por el número de conectores de entrada (1 o 2). Por ejemplo, tengo un panel de 32x32, escaneo 8S y dos conectores de entrada - 32/8/2 = 2 - lo que significa dos entradas RGB.

`define RGB_outs 2 

Cuántas líneas de escaneo en el panel, dado que el estándar HUB75E es compatible, puede ser de hasta 32x. El número de líneas de escaneo generalmente está en el nombre del panel en forma de 8S / 16S / 32S, respectivamente.

Solo una línea debe ser descomentada:

 `define SCAN_x8 1 //`define SCAN_x16 1 //`define SCAN_x32 1 

El número total de píxeles horizontales en la cadena. Los píxeles se consideran en toda la cadena de paneles; consulte la sección anterior "Cambio de paneles LED"

 `define PIXEL_COUNT 64 

Las fases de las señales de salida. La configuración más típica es la siguiente: OE está activo en un nivel bajo (comentarios eliminados), CLK se está ejecutando en el frente (los comentarios están activados), LAT está activo en un nivel alto (los comentarios están activados). Todo tipo de opciones extrañas son posibles. Averigüe cuál tiene solo experimentalmente o quitando el circuito y buscando hojas de datos para los chips usados).

 //`define LED_LAT_ACTIVE_LOW 1 `define LED_OE_ACTIVE_LOW 1 //`define LED_CLK_ON_FALL 1 

Retraso previo y posterior de la señal OE en relación con LAT y preescalador para el contador principal. Ver arriba

 `define OE_PRESCALER 16 `define OE_PREDELAY 31 `define OE_POSTDELAY 31 

Todos, presione ctrl-L: el proyecto se compila. Si no lo arruinaste en ninguna parte, habrá varias advertencias, pero no debería haber errores. A continuación, conectamos la placa soldada al USB Blaster, aplicamos energía a la placa. En Quartus, vaya a herramientas - programador. Seleccione USB-blaster en la configuración de hardware, haga clic en Inicio. Eso es todo, CPLD está programado.

Pieza de microcontrolador


La salida de datos al controlador, en general, es extremadamente simple: restablecemos la dirección de escritura y luego emitimos secuencialmente bytes de datos, acariciándolos con la señal WCLK. Y parece que incluso un arduinka banal es suficiente para el trabajo. Pero hay dos problemas:

a) Se necesita mucha memoria. Incluso un pequeño panel de 32x32 en modo RGB888 requiere 3kBytes de memoria para un búfer de pantalla. El Atmega328 ordinario basado en Arduino contiene solo 2kbytes de RAM. Por supuesto, puede usar una placa Mega basada en Atmega2560, que contiene hasta 8 kB de RAM, pero incluso esto no es suficiente para paneles de tamaño normal: un panel de 128x64 en modo RGB565 requiere 16kB de memoria.

b) En el proceso de trabajar con AL422B, surgió un problema técnico que no se documentó en ninguna parte: al escribir datos a una velocidad de menos de 2 MB / s, el contador de direcciones no funciona correctamente y escribe datos "no allí". Quizás este sea un fallo de mi fiesta. Quizás no. Pero esta falla tiene que ser evitada. Dado que el AVR8 funciona a 16 MHz, es casi imposible obtener datos a las velocidades deseadas.

La solución propuesta es buscar bufandas baratas basadas en el controlador STM32F103C8T6 de 32 bits. Tal bufanda le cuesta a Ali alrededor de $ 2.5 por pieza, o alrededor de $ 1.7 al comprar una docena, es decir, incluso más barato que un Arduino Nano. Al mismo tiempo, tenemos un microcontrolador completo de 32 bits que funciona a 72 MHz y tiene 20 kB de RAM y 64 kB de flash (compárelo con el Atmega328 de 2kB / 8kB, que está en Nano).

Al mismo tiempo, estas placas se programan con bastante éxito en el entorno Arduino. Sobre esto hay un buen artículo sobre el reloj , por lo que no lo duplicaré. En general, haga todo como se describe en el artículo.

En un entorno arduino, elija la placa genérica STM32F103C, variante STM32F103C8. Los datos pasan por DMA, por lo que puede usar cualquier opción de optimización.

El cambio ocurre de la siguiente manera:

Firmemente clavado en la biblioteca:
A0..A7 → DI0..DI7 AL422B
B0 → WCLK AL422B
B1 → WRST AL422B

Asignado en un boceto al controlador:
B10 → NOSOTROS AL422B

Cable común:
G → GND

Bueno, no olvide suministrar energía de 5V / GND desde el panel a los pines del controlador correspondientes.

Retira el pinout del conector del controlador del circuito .



Parte de software


Dado que la tarea era hacer que todo fuera lo más simple y asequible posible, todo el software se creó para el entorno Arduino y se diseñó como una biblioteca LED_PANEL .

La biblioteca LED-PANEL utiliza activamente la biblioteca Adafruit GFX , por lo que debe instalarse.

Recomiendo no poner la biblioteca LED_PANEL en el directorio de bibliotecas, sino dejarla en la carpeta de bocetos. El hecho es que hay muchos parámetros vinculados al hierro, y si desea transferir el trabajo a un microcontrolador más "gordo", tendrá que cambiar muchas cosas en el código mismo.

La inicialización es aproximadamente de la siguiente forma:

 #include "LED_PANEL.h" #define width 32 #define height 32 #define bpp 3 #define scan_lines 8 #define RGB_inputs 2 #define we_out_pin PB10 LED_PANEL led_panel = LED_PANEL(width, height, bpp, scan_lines, RGB_inputs, we_out_pin); 

es decir, creamos una instancia de la clase LED_PANEL, para la cual especificamos los parámetros:

ancho: el ancho total del panel en píxeles (total)
altura: la altura total del panel en píxeles (total)
bpp: byte por píxel, 3 para RGB888. La versión BAM solo funciona en RGB888
scan_lines: el número de líneas de exploración es 8/16/32. Debe corresponder al modo flasheado en el controlador.
Entradas_ RGB: el número de entradas RGB en el conector HUB75 es 1/2. Debe corresponder al modo flasheado en el controlador.
we_out_pin - pin al que se conecta la salida WE

Tenga en cuenta que durante la inicialización, solo se especifica el pin WE. Todos los demás pines se registran rígidamente en el código, ya que están vinculados al temporizador utilizado y los canales DMA y su cambio conllevará cambios significativos en el código.

Inicio y borrado de la pantalla en la sección de configuración:

  led_panel.begin(); led_panel.clear(); 

comenzar inicializa los pines necesarios a la salida, conecta un temporizador y DMA
clear limpia el búfer

Para dibujar, puede utilizar todos los procedimientos estándar de la biblioteca Adafruit GFX, desde el drawPixel más simple hasta la salida de texto. Para dar salida a los procedimientos dibujados al búfer se utilizan:

 led_panel.show(); 

De esta forma, show inicia la transferencia de datos al controlador a través de DMA e inmediatamente devuelve el control. Averigüe si la transferencia ha finalizado con la ayuda de la función led_panel.OutIsFree (): si dice verdadero, la transferencia ha finalizado. Hay una función: si llama a show cuando la transferencia aún no se ha completado, simplemente se ignorará.

 led_panel.show(false); 

análogo de show (), pero si llama a show (false) y la transferencia aún no se ha completado, el procedimiento esperará a que se complete la transferencia, luego comience una nueva transferencia y regrese el control:

 led_panel.show(true); 

análogo de show (falso), pero si llama a show (true), luego del inicio de una nueva transferencia, el procedimiento no devolverá el control hasta que se complete la transferencia.

En general, eso es todo.



Algunas notas sobre el software:

a) La corrección gamma se introduce al recalcular el color de RGB565 (que la biblioteca usa) con la función ExpandirColor. En todos los demás casos, se utiliza una función de transferencia lineal, es decir, el brillo es directamente proporcional al valor.
b) El software le permite conectar múltiples controladores LED a una placa de microcontrolador. Para hacer esto, envíe el bus de datos, las líneas RST y CLK a los controladores en paralelo. El controlador deseado se selecciona a través de la línea WE. En el software, debe crear una instancia separada de la clase LED_PANEL para cada controlador, y cada instancia debe tener diferentes líneas WE (el último parámetro) durante la inicialización.

Hacer


- Tratar con la "recogida" de flores en las filas vecinas. Parece un mal cableado del panel en sí (las teclas están ensuciando), pero debe verificarlo. Acabo de llegar un nuevo panel, lo comprobaré;
- Haga una nueva versión de la placa, con RE ya divorciada y la adición de convertidores de nivel de salida en 5V;
- Haga la clase META_LED_PANEL, que permitirá combinar varios LED_PANEL en una pantalla virtual; esto permitirá crear pantallas muy grandes con varios controladores;
- En el futuro, vaya a una serie CPLD más poderosa, por ejemplo CycloneIV. Esto ampliaría significativamente las capacidades mientras se mantiene un bajo costo (EP4CE6E22 cuesta alrededor de $ 5 para los chinos, mientras que hay 100 veces más macrocélulas y aproximadamente 32 kB de memoria interna). Pero lo haré algún día más tarde. Si yo quiero Dado que tales desarrollos toman demasiado tiempo.

Source: https://habr.com/ru/post/es409743/


All Articles