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