terça-feira, julho 13, 2021

Raspberry Pi Pico: Gerando Vídeo Alfanumérico Colorido

Como mencionei algum tempo atrás, um dos meus projetos com o PiPico é fazer um terminal de vídeo alfanumérico, para usar com meus projetos com microprocessadores antigos (Z80, 6502, etc). Como parte deste projeto, eu preciso aprender como gerar um vídeo alfanumérico colorido (a meta é pelo menos 24 linhas de 80 colunas).

Minha ideia foi fazer algo semelhante ao que é feito no modo alfanumérico da CGA/EGA/VGA, armazenando os códigos dos caracteres e um byte de atributo para cada um, gerando em tempo real a sequência de pixeis correspondente. Pelo pouco que eu tinha lido sobre as rotinas (experimentais) de geração de vídeo VGA com o PiPico, me parecia algo viável. Mas eu acabei sofrendo bastante para fazer o básico funcionar e, por enquanto, tive que me conformar com 40 colunas...


Como dito no post anterior, as rotinas de geração de vídeo estão no repositório "pico extras"  e  os exemplos estão no "pico playground". A documentação é basicamente o que está nos fontes ("use the source, Luke!"). O código é complexo e está disperso em alguns fontes. Os exemplos são mais variados que propriamente instrutivos.

Eu optei por usar um gerador de caracteres 8x16, o que forneceria 30 linhas de 80 colunas com o vídeo no modo 640x480. Em retrospecto, eu escrevi corretamente a lógica para gerar os pontos nas cores certas a partir dos caracteres e atributos. Mas isso não foi suficiente.

Um "detalhe" na hora de escrever esta lógica é que o buffer de pontos que deve ser passado para as rotinas tem uma esquisitice (para suportar a compactação de sequências de pontos na mesmo cor). Para passar uma sequência de N pontos é necessário colocar no buffer (supondo N par e maior que três):

    | RAW_RUN | COLOR(1) | N-3 | COLOR(2) | COLOR(3) ... | COLOR(N) | EOL_SKIP_ALIGN

Onde cada item é um valor de 16 bits e RAW_RUN e EOL_SKIP_ALIGN são valores especiais. O formato (em binário) para a cor é:

    b b b b b g g g g g 0 r r r r r

Onde bbbbb, ggggg e rrrrr são as intensidades (entre 0 e 31) para azul, verde e vermelho.

O modo 640x480 se recusou a dar qualquer sinal de vida no começo, daí resolvi testar o modo 320x240 que funcionou, mas se recusava a apresentar as cores que eu achava que deviam aparecer. Após muito sofrimento, me atentei para um comentário que dizia que a última cor de uma linha deveria se preto (0). Bastou forçar isso para o texto de 15 linhas de 40 colunas funcionar!

Não me arrisquei ainda a mergulhar no código para entender porque a ausência deste ponto na cor 0 causa os efeitos estranhos que eu vi. Desconfio que é alguma regra de bruxaria.

Uma curiosidade é que o modo 320x240 utiliza os tempos do modo 640x480 porém duplica os pontos na horizontal e as linhas na vertical.

Depois de mais algumas horas de desespero, descobri que existe um define (PICO_SCANVIDEO_MAX_SCANLINE_BUFFER_WORDS) que determina o número de palavras de 32 bits no buffer para os pontos que as rotinas passam para preencher. O default é 180, o que é mais que suficiente para 320 pontos, mas insuficiente para 640 pontos. Isto não parece estar documentado em lugar nenhum. Acertado este define, o programa funcionou, mas somente para as primeiras linhas da tela. O problema agora é que o meu código é lento demais, não consigo gerar as linhas de pontos na velocidade necessária.

Eu desconfio que não vou conseguir deixar o meu código quatro vezes mais rápido, portanto para implementar vídeo 80 colunas eu vou ter que partir para uma solução diferente. Pesquisando na internet, já achei uma solução para implementar uma tela gráfica 640x480 16 cores, o que é uma possibilidade. Outra ideia é mudar o hardware (e toda programação, inclusive da PIO) para trabalhar com menos bits por cor e armazenar um ponto em um byte (e tirar o suporte a compactação).

O código atual (15 linhas de 40 caracteres) está em https://github.com/dquadros/pico-vgatext40

Nenhum comentário: