Controlador DIY do painel de LED no CPLD usando modulação BAM

Há algum tempo, ele participou de uma discussão sobre o projeto DIY de um relógio LED de matriz.
E o que me surpreendeu - a antiga matriz monocromática de LED 8x8 com um passo de 5 milímetros foi usada como um dispositivo de exibição. Além disso, placas de circuito impresso complexas foram criadas para eles, uma indicação dinâmica suave foi feita. E isso ocorre em um momento em que os painéis LED de 64x32 em cores, prontos para uso, com passo de 3 mm, estão disponíveis há muito tempo a um preço de US $ 10 a 20. E a variedade geral desses painéis é muito grande e tem uma densidade de pixels de 2 a 10 mm e quase qualquer tamanho.

Ao mesmo tempo, o uso desses painéis em projetos de bricolage é bastante difícil - os controladores prontos custam muito dinheiro e não possuem uma API normal. É bastante difícil fazer uma varredura bastante rápida do painel em microcontroladores comumente usados ​​em bricolage. Além disso, os intervalos de tempo devem ser mantidos com alta precisão - caso contrário, uma irregularidade visível do brilho começa.

Existem boas soluções na Adafruit , mas todas são bastante caras e complexas.

Depois de pensar um pouco, o pensamento surgiu - por que não fazer uma placa extremamente barata que será uma ponte entre uma placa de centavo comum como um arduino e um painel de LED? Depois de alguns meses de confusão, nasceu algo que funcionava.

Este artigo descreve a segunda versão aprimorada do controlador.

Desafio


Como tarefa básica, eu queria poder controlar um painel com um tamanho total de pelo menos 64x64, além de poder trabalhar pelo menos em Highcolor (RGB565), mantendo uma taxa de atualização de tela aceitável (pelo menos 50Hz). Na primeira versão do controlador, a tarefa básica foi totalmente implementada, mas surgiu a idéia de implementar a tarefa por outro método muito promissor, a partir do qual a segunda versão nasceu.

Explicação básica do design de um painel LED típico


Interface de entrada HUB75:


Em cada entrada de cor, há uma cadeia de registros do tipo HC595 (mas versões especiais de 16 canais para LEDs). Existem tantos registros suficientes para a largura do painel. Permissões de fragmentação, inicialização paralela e saída são comuns a todos os registros. As entradas ABCDE - essa é a escolha de uma série - vão para um decodificador convencional.

Princípio de funcionamento:

  • Para definir os dados como entradas RGB, clique no botão CLK. Repita até carregarmos toda a linha
  • desligue as saídas OE = 1 (para que não haja interferência)
  • atribuir ao decodificador o número da linha carregada
  • clique em carregamento paralelo LAT - os dados da linha são transferidos para os registros de saída
    ativar saídas OE = 0
  • repita para a próxima linha

Essa é uma indicação dinâmica clássica. É claro que, com esse método em um desses ciclos, podemos ligar / desligar apenas cada LED específico.

Para obter gradações de brilho com o PWM clássico, esse ciclo deve ser repetido N-1 vezes, onde N é o número de gradações de brilho (256 para RGB888). E, considerando que, ao mesmo tempo, ele ainda pisca - tudo isso deve ser feito muito, muito rapidamente.

Existe uma solução alternativa - BAM (Bit Angle Modulation). Nesse caso, o tempo de brilho em cada ciclo é proporcional ao peso do bit exibido. Ou seja, para RGB888, você precisa de apenas 8 ciclos de exibição. Um pouco mais detalhado aqui .

A primeira versão do controlador usava o PWM clássico, que impunha um limite estrito no número de ciclos de varredura. Na segunda versão, o BAM é implementado, o que deu um enorme ganho de velocidade.

Implementação


Era óbvio que um microcontrolador convencional puxa apenas pequenos painéis - os grandes simplesmente não têm velocidade suficiente. Portanto, o CPLD ou o FPGA é indispensável aqui - é fisicamente impossível produzir dezenas de MB / s em microcontroladores de baixo custo.

Como memória, fui recomendado no fórum IXBT pela muito interessante memória FIFO Averlogic AL422B, que possui aproximadamente 400kbytes de memória e pode operar em frequências de até 50MHz.

Considerando que meu principal requisito era o baixo custo máximo dos componentes, para que o cachecol acabado fosse acessível aos fabricantes caseiros, foi escolhido o Altera EPM3064 - CPLD com 64 macrocélulas. Ao mesmo tempo, um número tão pequeno de macrocélulas não permite criar uma placa configurável dinamicamente - a configuração deve ser compilada diretamente no CPLD.

→ O circuito resultante está aqui

Detalhes:

  • CPLD EPM3064ATC44-10 - o preço de Ali é de US $ 13 a 15 por uma dúzia
  • FIFO RAM AL422B - o preço de Ali é de cerca de US $ 15 por dúzia
  • Oscilador de cristal de 50MHz. A placa fornece a instalação nos gabinetes DIP14 / DIP8 / 7050. O preço de Ali é de cerca de US $ 6-7 por dúzia
  • Estabilizador de 3.3V no pacote SOT223. Preço em Chip and Dip - 40r cada
  • Conector IDC-10MS. Preço em Chip & Dip - 3 p / peça
  • Conector IDC-16MS. Preço em Chip & Dip - 8 r / peça
  • Conector IDC-14MS. Preço em Chip & Dip - 7 r / peça
  • Capacitores 1 microfarad 0805 - 8 peças de cerca de 1 r / peça
  • Capacitor 0.1uF 0805 - cerca de 1 r / peça
  • Resistor 10k 0805 - um centavo

O total em detalhes é obtido 1,5 + 1,5 + 0,7 = US $ 3,7 e 40 + 3 + 8 + 7 + 8 * 1 + 1 = 67 p. Todos juntos dentro de US $ 5 - um centavo.

→ A imagem original do quadro está aqui

Arquivos gerber preparados para pedidos

O conselho está preparado para a primeira versão, na qual não havia controle de ER. Para usá-lo com a segunda versão, você deve cortar o jumper entre os terminais 23 e 24 do AL422B e lançar os fios do terminal 28 do EPM3064 (que é levado ao bloco de terminais) para o terminal 24 do AL422B.

Ao soldar a placa, não se esqueça de soldar os jumpers na parte traseira da placa.





Cálculos


Os cálculos dos parâmetros necessários são bastante complicados.

O fato é que, no controlador, dois processos são executados em paralelo - carregando os dados da próxima linha / indicando uma linha já carregada.

Os processos iniciam simultaneamente, mas terminam em momentos diferentes; portanto, um processo mais rápido aguarda a conclusão de um processo mais longo.

→ Um tablet Excel foi feito para o cálculo

Dados de origem:

  • CRYSTAL_FRQ (MHz) - frequência do gerador (50 MHz)
  • PIXEL_COUNT - o número de pixels na barra de download. Mais detalhes na seção de comutação.
  • RGB_INPUTS - o número de entradas RGB usadas na interface HUB75E do painel usado. 1 ou 2
  • BYTES_PER_PIXEL - bytes por pixel. No nosso caso, sempre 3 - RGB888
  • SCAN_LINES - número de linhas de varredura no painel usado. 16/08/32

Parâmetros selecionados:

  • PRE_DELAY - atraso do sinal LAT até que o OE seja ligado, definido em ticks
  • PRESCALER - pré-calibrador para o contador principal. Ou seja, se a lista de preços for 8 e o peso do bit atual for 4, o OE será ativado por 8 * 4 = 32 ciclos
  • POST_DELAY - atraso mínimo de desligar o OE para o próximo sinal LAT, definido em ticks

Por exemplo, temos um painel 32x32 com 8 linhas de digitalização e 2 entradas RGB. Esse painel possui dois conectores HUB75E, ou seja, fisicamente, são dois painéis 32x16. Conectamos esses painéis em série, ou seja, logicamente esse painel será semelhante a 64x16.

PRE_DELAY e POST_DELAY são intervalos de apagamento antes e depois da ativação da saída (OE), para que os multiplexadores possam alternar as saídas e as teclas abrir / fechar. Sem eles, haverá "truques" da queima de pixels para as linhas adjacentes. Os valores são selecionados experimentalmente para um painel específico. Geralmente 15 medidas são suficientes (definidas em medidas).

Isso levanta a questão de escolher pré-calibrador - como escolher.

Um valor baixo do pré-calibrador fornece um tempo de exibição de quadro curto, mas reduz o brilho geral. O alto valor do pré-calibrador aumenta o tempo de exibição do quadro, ou seja, quando enumera, treme na tela.

Vamos tentar PRESCALER = 1

Temos:

OE_EFFICIENCY - 8,3%, ou seja, o painel funcionará apenas 8,3% do brilho máximo possível
FRAMES_PER_SECOND - 2034 fps - mas a taxa de atualização da imagem será enorme - mais de 2000 fps.

A perda de brilho já é muito grande.

Vamos tentar PRESCALER = 16

Temos:

OE_EFFICIENCY - 72,9%, ou seja, o painel funcionará com 72,9% do brilho máximo possível
FRAMES_PER_SECOND - 1117 - e a taxa de atualização da imagem é muito boa - mais de 1000 qps.
Bem, é bastante normal - uma eficiência de mais de 50% é bastante normal e a taxa de quadros é muito boa.

A regra geral é PRESCALER é cerca de 8 vezes menor que o produto PIXEL_COUNT * RGB_INPUTS

Bem, continue a contar e verificar.

Comutação de painéis de LED


Todos os painéis são conectados em série. Diagrama de conexão: primeiro da direita para a esquerda e depois de baixo para cima. Ou seja, primeiro conectamos as horizontais em série, depois a saída da linha inferior à entrada da segunda linha a partir da parte inferior, etc. para a linha superior.

O controlador se apega ao painel inferior direito.

Existem painéis que possuem dois conectores de entrada e dois de saída. Esses painéis são essencialmente apenas uma montagem mecânica de dois painéis verticalmente. Comutado como dois painéis independentes.

Após a montagem, precisamos calcular o comprimento total da cadeia em pixels - para isso olhamos - quantos painéis totais estavam na cadeia e multiplicar esse número pela largura do painel em pixels. Esse número precisará ser direcionado para o valor PIXEL_COUNT durante a configuração do CPLD e para a calculadora de tempo.

Firmware FPGA


Todos os arquivos necessários estão no github . Você precisa fazer o download diretamente com a pasta

Após o registro, você deve baixar e instalar o Quartus II 13.0sp1 no site da Altera. Você precisa baixar EXATAMENTE ESTA versão - as versões mais recentes não são mais compatíveis com a série MAX3000. Não é necessário quebrá-lo - a versão da Web (gratuita) é suficiente. Ao fazer o download, verifique as caixas de suporte para MAX3000 e Programmer. Só por precaução, aviso - o pacote é grande, cerca de dois shows. Você também precisará do Altera USB Blaster - o preço normal para todos é de cerca de US $ 3.

Abra o projeto al422_bam.qpf. À esquerda, abra a guia arquivo e abra o arquivo al422_bam.v - este é o arquivo principal do projeto. Nele, você precisa configurar os parâmetros:

Quantas entradas RGB em um painel - em painéis com uma entrada HUB75, pode haver 1 ou 2 entradas RGB. Para descobrir exatamente quantas entradas são possíveis dessa maneira - pegamos o número de pixels no painel verticalmente. Divida pelo número de linhas de digitalização (indicadas na designação do painel como 8S, por exemplo). Divida pelo número de conectores de entrada (1 ou 2). Por exemplo - eu tenho um painel 32x32, varredura 8S e dois conectores de entrada - 32/8/2 = 2 - o que significa duas entradas RGB.

`define RGB_outs 2 

Quantas linhas de digitalização no painel - como o padrão HUB75E é suportado, ele pode ter até 32x. O número de linhas de digitalização geralmente está no nome do painel na forma de 8S / 16S / 32S, respectivamente.

Apenas uma linha deve ser descomentada:

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

O número total de pixels horizontais na cadeia. Os pixels são considerados em toda a cadeia de painéis - consulte a seção acima “Alternando painéis de LED”

 `define PIXEL_COUNT 64 

As fases dos sinais de saída. A configuração mais típica é a seguinte: o OE está ativo em um nível baixo (comentários removidos), o CLK está em execução na frente (os comentários estão ativados), o LAT está ativo em um nível alto (os comentários estão ativados). Todos os tipos de opções estranhas são possíveis. Descubra qual você possui apenas experimentalmente ou removendo o circuito e procurando folhas de dados para os chips usados).

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

Pré e pós-atraso do sinal OE em relação ao LAT e pré-calibrador para o contador principal. Veja acima.

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

Tudo, pressione ctrl-L - o projeto é compilado. Se você não estragou tudo, haverá vários avisos, mas não deve haver erros. Em seguida, conectamos a placa soldada ao USB Blaster e aplicamos energia à placa. No Quartus, vá para ferramentas - programador. Selecione USB-blaster na configuração de hardware, clique em Iniciar. É isso aí, o CPLD está programado.

Peça do microcontrolador


A saída de dados para o controlador, em geral, é extremamente simples - redefinimos o endereço de gravação e, em seguida, emitimos bytes de dados sequencialmente, acariciando-os com o sinal WCLK. E parece que até um arduinka banal é suficiente para o trabalho. Mas há dois problemas:

a) É preciso muita memória. Mesmo um pequeno painel de 32x32 no modo RGB888 requer 3kBytes de memória para um buffer de tela. O Atmega328 baseado em Arduino comum contém apenas 2kbytes de RAM. Obviamente, você pode usar uma placa Mega baseada no Atmega2560, que contém até 8 kB de RAM, mas mesmo isso não é suficiente para painéis de tamanho normal - um painel de 128x64 no modo RGB565 requer 16kB de memória.

b) No processo de trabalho com o AL422B, ocorreu uma falha que não foi documentada em nenhum lugar - ao gravar dados a uma velocidade inferior a 2 MB / s, o contador de endereços não funciona corretamente e grava os dados "não existem". Talvez seja uma falha da minha festa. Talvez não. Mas essa falha deve ser contornada. Dado que o AVR8 opera em 16 MHz, é quase impossível obter dados dele nas velocidades desejadas.

A solução proposta é optar por lenços baratos com base no controlador STM32F103C8T6 de 32 bits. Esse cachecol custa Ali cerca de US $ 2,5 por peça, ou US $ 1,7 na compra de uma dúzia, ou seja, ainda mais barato que um Arduino Nano. Ao mesmo tempo, temos um microcontrolador de 32 bits completo operando a 72 MHz e com 20 kB de RAM e 64 kB de flash (compare com o Atmega328 de 2kB / 8kB, que está no Nano).

Ao mesmo tempo, essas placas são programadas com bastante êxito no ambiente do Arduino. Sobre isso, há um bom artigo sobre o relógio , então não o duplicarei. Em geral, faça tudo como descrito no artigo.

Em um ambiente arduino, escolha a placa genérica STM32F103C, variante STM32F103C8. Os dados passam pelo DMA, para que você possa usar qualquer opção de otimização.

A troca ocorre da seguinte maneira:

Pregou firmemente na biblioteca:
A0..A7 → DI0..DI7 AL422B
B0 → WCLK AL422B
B1 → WRST AL422B

Atribuído em um esboço ao controlador:
B10 → NÓS AL422B

Fio comum:
G → GND

Bem, não esqueça de fornecer energia de 5V / GND a partir do painel para os pinos correspondentes do controlador.

Retire a pinagem do conector no controlador do circuito .



Parte do software


Como a tarefa era tornar tudo o mais simples e acessível possível, todo o software foi feito para o ambiente Arduino e foi projetado como uma biblioteca LED_PANEL .

A biblioteca LED-PANEL usa ativamente a biblioteca Adafruit GFX , portanto, ela precisa ser instalada.

Eu recomendo não colocar a biblioteca LED_PANEL no diretório de bibliotecas, mas deixá-la na pasta de esboço. O fato é que existem muitos parâmetros ligados a ferro e, se você deseja transferir o trabalho para um microcontrolador mais "gordo", precisará alterar muitas coisas no próprio código.

A inicialização está aproximadamente no seguinte formato:

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

isto é, criamos uma instância da classe LED_PANEL, para a qual especificamos os parâmetros:

width - a largura total do painel em pixels (total)
height - a altura total do painel em pixels (total)
bpp - byte por pixel, 3 para RGB888. A versão BAM funciona apenas em RGB888
scan_lines - o número de linhas de varredura é 16/8/32. Deve corresponder ao modo piscado no controlador.
RGB_inputs - o número de entradas RGB no conector HUB75 é 1/2. Deve corresponder ao modo piscado no controlador.
we_out_pin - pino ao qual a saída WE está conectada

Observe que durante a inicialização, apenas o pino WE é especificado. Todos os outros pinos são registrados rigidamente no código, uma vez que estão vinculados aos canais de timer e DMA usados ​​e sua alteração implicará alterações significativas no código.

Iniciando e limpando a tela na seção de configuração:

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

begin inicializa os pinos necessários na saída, conecta um timer e DMA
limpar limpa o buffer

Para desenhar, você pode usar todos os procedimentos padrão da biblioteca Adafruit GFX - desde o drawPixel mais simples até a saída de texto. Para gerar os procedimentos extraídos para o buffer, são utilizados:

 led_panel.show(); 

Neste formulário, o show inicia a transferência de dados para o controlador via DMA e retorna imediatamente o controle. Descubra se a transferência foi finalizada com a ajuda da função led_panel.OutIsFree () - se for verdadeira, a transferência foi finalizada. Existe um recurso - se você ligar para show quando a transferência ainda não tiver sido concluída - ele será simplesmente ignorado.

 led_panel.show(false); 

análogo de show (), mas se você chamar show (false) e a transferência ainda não tiver sido concluída, o procedimento aguardará a conclusão da transferência e inicie um novo controle de transferência e retorno:

 led_panel.show(true); 

análogo de show (false), mas se você chamar show (true), após o início de uma nova transferência, o procedimento não retornará o controle até que a transferência seja concluída.

Em geral, isso é tudo.



Algumas notas sobre o software:

a) A correção gama é introduzida ao recalcular a cor do RGB565 (que a biblioteca usa) com a função ExpandColor. Em todos os outros casos, é utilizada uma função de transferência linear, ou seja, o brilho é diretamente proporcional ao valor.
b) O software permite conectar vários controladores de LED a uma placa de microcontrolador. Para fazer isso, envie as linhas de barramento de dados, RST e CLK para os controladores em paralelo. O controlador desejado é selecionado através da linha WE. No software, você precisa criar uma instância separada da classe LED_PANEL para cada controlador e cada instância deve ter linhas WE diferentes (o último parâmetro) durante a inicialização.

A FAZER


- Lide com a "coleta" de flores nas fileiras vizinhas. Parece uma fiação ruim do próprio painel (as teclas estão desarrumadas), mas você precisa verificar. Acabou de chegar um novo painel - vou verificar;
- Crie uma nova versão da placa - com ER já divorciado e a adição de conversores de nível de saída em 5V;
- Faça a classe META_LED_PANEL, que permitirá combinar vários LED_PANELs em uma tela virtual - isso permitirá criar telas muito grandes com vários controladores;
- No futuro, vá para uma série de CPLD mais poderosa, por exemplo, o CycloneIV. Isso aumentaria significativamente os recursos, mantendo um custo baixo (o EP4CE6E22 custa cerca de 5 $ para os chineses, enquanto há 100 vezes mais macrocélulas e cerca de 32 kB de memória interna). Mas farei isso algum dia depois. Se eu quiser. Uma vez que tais desenvolvimentos levam muito tempo.

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


All Articles