Entendendo o Vídeo Composto B&P
O sinal de vídeo composto utiliza três níveis de tensão: 1V corresponde a branco, 0,3V corresponde a preto e 0V indica um sinal de sincronismo. Tons de cinza podem ser representados por tensões entre 0,3 e 1V.A coisa complica um pouco quando começamos a falar nas temporizações, já que existem vários padrões. O Brasil segue as temporizações de sincronismo do padrão americano, o NTSC. No caso de vídeo branco e preto, o nosso sistema é igual ao americano. Para vídeo colorido o Brasil fez uma mescla entre o padrão NTSC (para ficar compatível com as TV b&p já existentes) e o padrão PAL (que possui uma codificação melhor para cores), criando o PAL-M.Como vamos ficar no b&p, podemos usar informações sobre o sistema americano, como aqui e aqui.
Uma tela é dividida em 525 linhas, que são enviadas em dois frames de 262,5 linhas a uma taxa de 60 frames por segundo. Na TV temos o chamado vídeo entrelaçado, onde um frame envia as linhas pares e o seguinte as linhas ímpares. Vamos trabalhar com vídeo não entrelaçado, enviando sempre as mesmas 262 linhas em cada frame.Destas 262 linhas, apenas as 20 últimas correspondem ao retraço vertical (quando o feixe está se movimentando rapidamente de baixo para cima).
O sinal para as primeiras 242 linhas começa com um pulso de sincronismo horizontal (sinal em 0V) com duração de 4,7 uS. Em seguida temos o "back porch", um período de 5,9 uS onde o sinal deve ser mantido em 0,3V. Chegamos então à parte visível da linha, com 51.5 uS, onde o sinal pode variar ente 0,3 e 1V. Fechando a linha temos o "front porch" onde o sinal deve ser mantido em 0,3V por 1.4uS. Somando todos estes tempos obtemos 63,5 uS. Na prática a nossa imagem deve ocupar da linha 30 até a linha 230, deixando margens apagadas em cima e em baixo.
Durante o retraço vertical o sinal de vídeo corresponde a linhas apagadas "inventidas": 4,7 uS no nível 0,3V seguindo de 58,8 uS no nível 0V.
Hardware
Para obter um sinal preciso é recomendado usar um clock de 20 MHz dividido por um timer de 16 bits. Com isto podemos gerar uma base de tempo de 63,55 dividindo o clock por 1271 (este tempo multiplicado por 262 ficará extremamente próximo dos 60 frames por segundo.A minha ideia inicial era usar um ATtinyx5 (de 8 pinos), porém ele não tem o timer de 16 bits. Optei então por um ATtiny44.
O sinal de vídeo é gerado por duas saídas digitais (PA0 e PA1) ligadas através de diodos a um divisor resistivo. Com isto conseguimos gerar os três níveis de interesse:
- 0V: PA0 e PA em 0
- 0,3V: PA0 em 1 e PA1 em 0
- 1,0V: PA0 e PA em 1
Software
A ideia básica é programar o timer para interromper a cada 63,5 uS; o sinal de vídeo será controlado dentro da rotina de interrupção. O primeiro passo da rotina é gerar o pulso de sincronismo horizontal. Se estivermos fora da região visível podemos encerrar a interrupção, caso contrário vamos gerar o sinal de vídeo conforme os pixels a apresentar (o que será feito em assembler para ter a velocidade e precisão necessárias).Para que o timing seja preciso e a imagem não tenha interferências, as interrupções durante as linhas visíveis deve acontecer quando o processador estiver dormindo. Com isto sobra só uma parte do tempo do "front porch" nas primeiras 242 linhas. Durante o retraço vertical podemos relaxar um pouco; teremos um pouco menos de 20 * (63,5 - 4,7) para gerar o próximo frame (ou seja, cerca de 1,1 ms a cada 16,7 ms).
O ATtiny44 não tem Ram suficiente para guardar uma imagem da tela. O exemplo da Cornell implementa uma resolução de 144 x 200 pontos, o que exige 3600 bytes. Para ficar no simples, vamos construir nossa imagem utilizando somente duas linhas repetidas várias vezes.
Para gerar um pixel, vamos manter PA0 em 1 e posicionar PA1 em 0 (pixel apagado) ou em 1 (pixel aceso). A sequência de instruções assembler gera o sinal correspondente ao bit b do byte contido no registrador R4, supondo que R30 contenha 1:
BST R4,b BLD R30,1 OUT 0x1B,R30 NOP NOP
A primeira instrução (bit store) move o bit b para o flag T. A segunda (bit load) move o flag T para o vbit de R30. A instrução OUT escreve o valor de R30 no registrador PORTA. Os dois NOPs finais são para dar o tempo exato de um pixel.
A macro videobits contem oito vezes esta sequência, para gerar o video correspondente a os oito bits de R4. A rotina byteblast utiliza 18 vezes a macro videobits para gerar o sinal de uma linha. Desta forma é obtida a velocidade e precisão necessárias, ao custo de um código longo (o meu programa ocupou 3262 bytes dos 4K disponíveis).
A rotina de interrupção ficou assim:
ISR (TIM1_COMPA_vect) { static uint8_t syncON = VID_0V; static uint8_t syncOFF = VID_03V; // Gera o pulso de sync VID_PORT = syncON; linhaAtual++; if (linhaAtual == iniSyncV) { // Sync vertical é invertido syncON = VID_03V; syncOFF = VID_0V; } if (linhaAtual == fimSyncV) { // Voltar ao sync normal syncON = VID_0V; syncOFF = VID_03V; } if (linhaAtual == fimFrame) { // Fim do frame linhaAtual = 1; } _delay_us(2); // Aguarda fim do tempo do pulso VID_PORT = syncOFF; // Gerar a imagem if ((linhaAtual <= ultLinha) && (linhaAtual >= primLinha)) { pontLinha = linhas[(linhaAtual-primLinha) & 3]; _delay_us(12); // tempinho para centrar a linha byteblast(); } }O programa principal é bem simples, já que a imagem é estática:
int main(void) { uint8_t i; // inicia as e/s digitais VID_DDR = VID_PINOS; VID_PORT = VID_0V; // começar na linha 1 linhaAtual = 1; // prepara as nossas duas linhas for (i = 0; i < nBytesLinha; i++) { linha1[i] = 0xFF; linha2[i] = 0x81; } // inicia o timer1 para interromper a cada linha // clock máximo, zera contador e interrompe quando // atinge a contagem em OCR1A OCR1A = tempoLinha; TCCR1B = 0x09; TCCR1A = 0x00; TIMSK1 = 0x02; // Habilitar interrupções e preparar para dormir sei(); set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); // O loop abaixo executa uma vez para cada linha for(;;) { // Precisa estar dormindo quando chegar a interrupção sleep_cpu(); if (linhaAtual == (ultLinha+2)) { // Retraço vertical // aqui temos um tempinho para gerar a próxima tela } } }O projeto completo pode ser baixado dos arquivos do blog, está em VidBP.zip.
Um comentário:
Ainda nem li o artigo, mas curti o tv :)
Postar um comentário