sábado, 23 de agosto de 2014

Mais testes com o emulador de teclado

Depois de um longo tempo sem mexer no circuito do emulador de teclado por causa de compromissos profissionais, hoje finalmente consegui avançar mais um pouco.

Depois de acertar alguns parâmetros do software de controle vi que o circuito ainda não estava gerando o acionamento das teclas. Desconfiei então que pudesse estar acontecendo retenção do barramento, de modo semelhante ao que acontece com o TK85 quando se usa a interface JOY81 do Kelly Murta. Fiz algumas medições para investigar. Nas figuras abaixo o sinal laranja corresponde ao sinal de leitura da ULA enquanto o sinal azul representa a linha D0. Sem nenhuma tecla pressionada, a tensão na linha D0 no momento da leitura é de aproximadamente 4,0 Volts.

Tecla "A" solta.
Quando se pressiona a tecla "A", as linhas A9 e DD5 são conectadas, fazendo com que o sinal da linha D0 caia para aproximadamente 0,16 Volts, puxado para baixo pelo LS365 interno ( o o conector interno (ligando as linhas A9 e DD5) .

Tecla "A" pressionada





Por outro lado, quando se ativa a mesma linha de um um driver externo (74LS365) acontece a retenção pois ao mesmo tempo que o 365 externo tenta abaixar o nível da linha, o interno tenta jogar um nível alto. Com isso a tensão resultante é por volta dos 1,44 Volts que o Z80 entende como nível alto.

Linhas A9 e DD0 externas pressionadas - contenção de barramento.

A conclusão é que infelizmente, para que meu circuito funcione vai ser necessária uma adaptação interna no TK90 que consiste na inclusão de 5 diodos, novamente de modo semelhante à modificação do JOY81.  Talvez sejam necessários também resistores de pullup, mas tenho que dar uma estudada melhor no assunto.



sábado, 21 de junho de 2014

Emulador de Teclado - fotos e testes com o protótipo

Fiz hoje alguns testes com o emulador de teclado conectado ao TK.


Alguns problemas se apresentaram, a começar pela contenção da linha A13 por parte do AVR (vide post anterior).

Outro problema que eu tive foi com a rotina de interrupção em assembly. Em alguns momentos eu notava que o AVR parava de responder às interrupções e o TK travava com o sinal /wait em nível baixo. Por enquanto retornei o atendimento à interrupção de leitura de teclado para uma interrupção padrão do Arduino e mesmo com o overhead o TK parou de travar.

Ainda estou com dois problemas que tenho que resolver. Um deles é que de vez em quando o TK demora a iniciar ou não inicia, mas isso não é mais problema de contenção. Desconfio que ainda esterja relacionado ao acionamento incorreto do sinal que libera a linha de /WAIT.

Outro problema é que apesar da matriz estar sendo preenchida corretamente quando se pressionam as teclas (o circuito imprime o estado dos bits na serial) nenhum bit muda de estado na entrada do LS367. Vou precisar debugar esta rotina em separado (fora da interrupção) para descobrir o problema.

Por último, pode ser que eu precise colocar uns resistores em série com as linhas D0 a D4 do LS365 interno do TK a fim de evitar a contenção do barramento de dados quando o LS367 do emulador de teclado estiver ativo.




Treta no A13

Como nada nessa vida é fácil, a primeira vez que liguei o circuito do emulador de teclado no TK ele não inicializou.

Passei um tempo conferindo o circuito, retirei o decodificador e o buffer da placa, mas a coisa continuava na mesma.

Daí foi que lembrei que eu não tinha programado o AVR para colocar como entrada os pinos que vão ligados às linhas de endereço A8-A15! Eu comprovei isso retirando o AVR da placa.

Depois de um bom tempo procurando uma fonte de alimentação que servisse no meu adaptador RS232-TTL eu finalmente programei o AVR com o seguinte 'sketch':

void setup() {
  // put your setup code here, to run once:
  DDRB=0x00;
  PORTB=0xff;
  DDRC=0x00;
  PORTC=0x00;
  DDRD=0x00;
  PORTD=0xc0;
}

void loop() {
  // put your main code here, to run repeatedly: 
  
}

Daí o TK bootou!!

Mas como diz o meu amigo Ferraz, "nessa vida tudo tem que ser com dor", só o primeiro boot deu certo. No segundo o TK ficou com a tela cheia de artefatos, no terceiro ficou branca, no quarto ficou ok. Em resumo, a operação estava de forma intermitente!

Tentei em vão descobrir algo de errado com o osciloscópio mas sem muito sucesso. Daí segui um expediente que embora trabalhoso foi o que me levou a descobrir o problema.

Eu retirei todas as conexões das linhas A8-A15 e espetei a placa no TK. Funcionou (óbvio ne?).

Daí eu removi a placa e fiz a ligação do sinal A8. Recoloquei a placa no TK e funcionou.

Fiz o mesmo com as outras linhas até chegar na linha A13. Com a linha A13 no lugar o TK fica funcionandode modo intermitente.

Removi a ligação da linha A13 e continuei o procedimento com as linhas A14 e A15 . Tudo OK.

De fato tinha alguma treta na linha A13! Esta linha está ligada ao pino PB5 do AVR (sinal SCK).


Como o AVR tem um bootloader, desconfiei que alguma coisa poderia estar acontecendo durante o boot. Daí instalei um resistor de 4K7 entre a linha A13 e o pino PB5 do AVR e o TK bootou normalmente (todas as vezes ).

Medindo com o osciloscópio eu verifiquei que o AVR mantém esta linha em nível baixo por um pouco mais de um segundo durante o 'startup' do bootloader. Eu creio que isso seja um erro de implementação do bootloader, mas por enquanto vou deixar o resistor e prosseguir com os testes. Depois eu dou uma olhada no código fonte do bootloader e/ou entro em contato com o desenvolvedor, pois não considero isso um comportamento normal.

Laranja: PB5 do AVR  / Azul: A13 do Z80




quinta-feira, 19 de junho de 2014

Emulador de teclado - Protótipo com AVR

Terminei de montar e conferir as ligções do protótipo do adaptador de teclado. Ainda faltam 2 capacitores para soldar e uma modificação para fazer a fim de poder usar o tanto o 74LS365 quanto o 74LS367 como buffer. É que o circuito foi projetado para o LS365 mas não consegui encontrar este chip. 

Emulador montado. Falta uma modificação para poder usar o LS367 no lugar do LS365.

O extensor não é necessário e só foi montado para o protótipo.
O bom de ter o protótipo em mãos é perceber alguns detalhes que devem ser corrigidos ou mesmo melhorados, como a ligação do botão de RESET que deveria ter passado por baixo da placa para não fechar curto com o metal da armação do botão.

Ali na placa, logo abaixo do 74HC74 tem um conector para o adaptador RS232 para testes e debug. O ATMega88 foi gravado com o bootloader do Arduino.

sexta-feira, 13 de junho de 2014

Rotina de interrupção em Assembly dentro do Arduino

A sintaxe do Assembly Inline do GCC é meio confusa, e isso me deu bastante trabalho para conseguir embutir um pouco de código Assembly dentro da IDE do Arduino. Mas finalmente consegui.

Eis o código para tratar a interrupção:

asm volatile ( 
   "in __tmp_reg__,__SREG__ \n\t"   // Salva registrador de Status  
   
   "ldi r26,lo8(mapa) \n\t"         // Ponteiro X = endereço de Keymap
   "ldi r27,hi8(mapa)\n\t"          //
   
   "ldi r18,0x1f \n\t"              // Mascara inicial => bits 0..5 em 1
   
   "in r19,%0 \n\t"                 // Amostra bits PB 0..5 (A8..A13)
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[0] 
   "sbrs R19,0 \n\t"                // Bit [0] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[0] para R18
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[1] 
   "sbrs R19,1 \n\t"                // Bit [1] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[1] para R18   
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[2] 
   "sbrs R19,2 \n\t"                // Bit [2] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[2] para R18
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[3] 
   "sbrs R19,3 \n\t"                // Bit [3] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[3] para R18   

   "ld r20,X+ \n\t"                 // R20 = Keymap[4] 
   "sbrs R19,4 \n\t"                // Bit [4] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[4] para R18   

   "ld r20,X+ \n\t"                 // R20 = Keymap[5] 
   "sbrs R19,5 \n\t"                // Bit [5] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[5] para R18

   "in r19,%1 \n\t"                 // Amostra bits PD 6..7 (A14..A15)

   "ld r20,X+ \n\t"                 // R20 = Keymap[6] 
   "sbrs R19,4 \n\t"                // Bit [6] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[6] para R18   

   "ld r20,X+ \n\t"                 // R20 = Keymap[7] 
   "sbrs R19,5 \n\t"                // Bit [7] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[7] para R18
   
   "out %2,r18 \n\t"                // Escreve resultado nos bits D0-D4 do LS365 e libera Wait State
   "nop \n\t"
   "sbi %2,5 \n\t"                  // libera flip flop
   
   "out __SREG__,__tmp_reg__ \n\t"  // restaura registrador de Status
    
   :: "I" (_SFR_IO_ADDR(PINB)), "I" (_SFR_IO_ADDR(PIND)) , "I" (_SFR_IO_ADDR(PORTC)) );
}


Cabe observar que eu tentei antes incluir uma função externa em assembly e incluir no projeto, mas o Arduino não compila.

Pelas minhas contas são necessários 32 ciclos de clock entre a interrupção e a liberação do Wait, o que significa 1,6us a 20MHz ou 4us a 8MHz (clock interno).

quarta-feira, 11 de junho de 2014

Tabelas de Scancodes para teclados ABNT

Com o auxílio de um Arduino e um pequeno 'sketch' levantei a tabela de scancodes para teclados ABNT pois não havia conseguido encontrar esta tabela em lugar algum.

Aproveitei o embalo e organizei os scancodes em uma tabela com  132 entradas correspondentes aos códigos das teclas entre 0 e 0x83.

O valor _NONE corresponde a um código que não tem ação. Para popular a tabela basta substituir a entrada _NONE pelo código correspondente à posição da tecla na matriz do teclado.

Tomando por exemplo a tecla "Q". Na matriz do TK90 ela corresponde ao bit 2 da linha 0 de varredura (conforme explicado no post anterior).

Assim, a linha da tecla "Q" fica:

0x02,      // 0x14  Q 


Para simplificar mais ainda, basta definir as constantes das teclas:


#define _Q    0x02  // Tecla  Q 

E na tabela usar o valor definido

_Q      // 0x14  Q 

Segue abaixo a tabela 'virgem', ou seja, não preenchida.


const uint8_t PS2Keymap_Normal[] PROGMEM = { 
_NONE,     // 0x00   
_NONE,     // 0x01  F9
_NONE,     // 0x02  
_NONE,     // 0x03  F5
_NONE,     // 0x04  F3
_NONE,     // 0x05  F1
_NONE,     // 0x06  F2
_NONE,     // 0x07  F12           
_NONE,     // 0x08                
_NONE,     // 0x09  F10           
_NONE,     // 0x0A  F8            
_NONE,     // 0x0B  F6            
_NONE,     // 0x0C  F4            
_NONE,     // 0x0D  TAB           
_NONE,     // 0x0E  APOSTROPHE    '
_NONE,     // 0x0F                
_NONE,     // 0x10                
_NONE,     // 0x11  L ALT         
_NONE,     // 0x12  L SHFT        
_NONE,     // 0x13  L CTRL        
_NONE,     // 0x14  Q             
_NONE,     // 0x15  1             
_NONE,     // 0x16                
_NONE,     // 0x17                
_NONE,     // 0x18                
_NONE,     // 0x19                
_NONE,     // 0x1A  Z             
_NONE,     // 0x1B  S             
_NONE,     // 0x1C  A             
_NONE,     // 0x1D  W             
_NONE,     // 0x1E  2             
_NONE,     // 0x1F                
_NONE,     // 0x20                
_NONE,     // 0x21  C             
_NONE,     // 0x22  X             
_NONE,     // 0x23  D             
_NONE,     // 0x24  E             
_NONE,     // 0x25  4             
_NONE,     // 0x26  3             
_NONE,     // 0x27                
_NONE,     // 0x28                
_NONE,     // 0x29  SPACE         
_NONE,     // 0x2A  V             
_NONE,     // 0x2B  F             
_NONE,     // 0x2C  T             
_NONE,     // 0x2D  R             
_NONE,     // 0x2E  5             
_NONE,     // 0x2F                
_NONE,     // 0x30                
_NONE,     // 0x31  N             
_NONE,     // 0x32  B             
_NONE,     // 0x33  H             
_NONE,     // 0x34  G             
_NONE,     // 0x35  Y             
_NONE,     // 0x36  6             
_NONE,     // 0x37                
_NONE,     // 0x38                
_NONE,     // 0x39                
_NONE,     // 0x3A  M             
_NONE,     // 0x3B  J             
_NONE,     // 0x3C  U             
_NONE,     // 0x3D  7             
_NONE,     // 0x3E  8             
_NONE,     // 0x3F                
_NONE,     // 0x40                
_NONE,     // 0x41  COMMA         ,
_NONE,     // 0x42  K             
_NONE,     // 0x43  I             
_NONE,     // 0x44  O             
_NONE,     // 0x45  0             
_NONE,     // 0x46  9             
_NONE,     // 0x47                
_NONE,     // 0x48                
_NONE,     // 0x49  DOT           .
_NONE,     // 0x4A  SEMICOLON     ;
_NONE,     // 0x4B  L             
_NONE,     // 0x4C  CCCEDIL       Ç
_NONE,     // 0x4D  P             
_NONE,     // 0x4E  MINUS         -
_NONE,     // 0x4F  
_NONE,     // 0x50  
_NONE,     // 0x51  SLASH         /
_NONE,     // 0x52  TILDE         ~
_NONE,     // 0x53  
_NONE,     // 0x54  ACUTE         `
_NONE,     // 0x55  EQUAL         =
_NONE,     // 0x56  
_NONE,     // 0x57  
_NONE,     // 0x58  CAPS
_NONE,     // 0x59  R SHFT
_NONE,     // 0x5A  ENTER
_NONE,     // 0x5B  OPENBRACKET   [
_NONE,     // 0x5C  
_NONE,     // 0x5D  CLOSEBRACKET  ]
_NONE,     // 0x5E  
_NONE,     // 0x5F  
_NONE,     // 0x60  
_NONE,     // 0x61  BACKSLASH     \
_NONE,     // 0x62  
_NONE,     // 0x63  
_NONE,     // 0x64  
_NONE,     // 0x65  
_NONE,     // 0x66  BKSP
_NONE,     // 0x67  
_NONE,     // 0x68  
_NONE,     // 0x69  KP1
_NONE,     // 0x6A  
_NONE,     // 0x6B  KP4
_NONE,     // 0x6C  KP7
_NONE,     // 0x6D  KPDOT         .
_NONE,     // 0x6E  
_NONE,     // 0x6F  
_NONE,     // 0x70  KP0
_NONE,     // 0x71  KPCOMMA       ,
_NONE,     // 0x72  KP2
_NONE,     // 0x73  KP5
_NONE,     // 0x74  KP6
_NONE,     // 0x75  KP8
_NONE,     // 0x76  ESC
_NONE,     // 0x77  NUM
_NONE,     // 0x78  F11
_NONE,     // 0x79  KPPLUS        +
_NONE,     // 0x7A  KP3
_NONE,     // 0x7B  KPMINUS       -
_NONE,     // 0x7C  KPTIMES       *
_NONE,     // 0x7D  KP9
_NONE,     // 0x7E  SCROLL
_NONE,     // 0x7F  
_NONE,     // 0x80  
_NONE,     // 0x81  
_NONE,     // 0x82  
_NONE      // 0x83  F7
};  
  

Pode-se replicar esta tabela para as teclas ativadas com a  tecla SHIFT, como por exemplo as teclas sobre os números e as teclas de acentuação, colhetes, etc

Também é possível utilizar uma tabela para as teclas de códigos estendidos (como as setas de cursor), mas como estas teclas não são muitas é mais fácil tratar cada uma caso a caso. O mesmo se aplica à tecla F7. Caso esta tecla seja tratada separadamente dá para deixar a tabela com menos de 128 entradas.

       

domingo, 8 de junho de 2014

Placa para o Emulador de teclado com AVR (atualizado)

Uma vez que o gerador de /WAIT funcionou corretamente, projetei uma placa de circuito impresso para o circuito, com as seguintes funcionalidades:
  1. Botão de Reset (que reseta não só o Z80 mas também o AVR)
  2. Header Serial para a reprogramação do circuito (com suporte a Auto-Programação, como no Arduino Severino)
  3. Montagem em conector EDGE ou com headers para encaixar na Interface M1 do Edu Luccas (assim que pretendo utilizar a minha). Nesse caso tem que serrar a parte de baixo da placa e soldar os headers diretamente nas ilhas.
  4. Jumper para habilitar/desabilitar a interface
  5. Três opções para montagem do conector para o teclado:
  • Mini-DIN 6 pinos
  • USB (alguns teclados revertem para o modo PS/2 quando não conseguem estabelecer comunicação via USB)
  • Header para montagem do conector para painel (esta opção vai ser útil para montagem dentro da M1). 

Eu cheguei a pensar em manter apenas o conector USB pois o conector Mini-DIN é mais caro e mais difícil de ser encontrado. Porém mas acabei deixando desse jeito mesmo.

Também pensei (caso dispensasse o mini-din) foi colocar um bootloader USB e usar um cabo USB A-A para reprogramar o circuito usando um bootloader baseado em V-USB compatível com USBASP, mas acabei deixando a serial mesmo, por conta da facilidade que ela traz na hora de se fazer o Debug do circuito.




A placa ficou com aproximadamente 76 x 55 mm

As fotos abaixo são da placa do protótipo assim que terminou de ser corroída.