quinta-feira, 22 de maio de 2014

Emulador de teclado genérico - Parte 5

Parte 5: Interface PS/2 e firmware

Para ler o teclado PS/2 o caminho mais natural (pelo menos para mim) é utilizar um microcontrolador. A quantidade de pinos de I/O necessária é de 2 pinos para o teclado mais 3 pinos para os sinais dos registradores de deslocamento (Dados, Clock e Transfer). Isso abre bastante o leque de possibilidades, pois inclui até mesmo dos pequenos microcontroladores de 8 pinos.

Existem inúmeras bibliotecas prontas para ler a interface PS/2 disponíveis na Internet, para diversas linhas de microcontroladores.  Porém grande parte das bibliotecas que vi eram orientadas a fornecer o código ASCII de uma tecla pressionada, abstraindo o mecanismo dos 'make codes' e 'break codes'. Isso pode ser adequado para transmitir os caracteres através de uma linha serial, mas para emular uma matriz de teclado isso não serve pois precisamos reproduzir o estado da tecla na matriz do teclado emulado, e não o evento de seu pressionamento.

Escolhi utilizar um ATTiny85 pois tenho alguns de estoque aqui. Além disso eles são muito baratos, mas também poderia ter utilizado um PIC ou HC908.

Para a prova de conceito eu utilizei um Arduino com a biblioteca 'ps2' da autoria de Chris J. Kiick pois ela fornece na saída os scancodes enviados pelo teclado.

O estado da matriz do teclado foi mapeada bit a bit num vetor de 8 bytes inicializado com 0xFF, pois as teclas pressionadas estão em nível zero.

char Keymap[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

Os bit 0..4 de cada um dos elementos da matriz keymap correspondem às linhas D0..D4 do teclado, enquanto que as linhas de endereço A8..A15 correspondem aos elementos 0..7 da matriz.

Dessa forma a tecla 'CAPS SHIFT' está mapeada no bit 0 do elemento 0, a tecla '5' está no bit 4 do elemento 3 e assim por diante.

O proximo passo foi associar os scancodes do PC nas linhas e colunas da matriz do TK. Para isso eu utilizei uma tabela de equivalências no seguinte formato:



Os bits 0-2 correspondem à linha. Os bits 3-5 correspondem à coluna (tecla).

Exemplo: A tecla 'A' fica no bit 0 da linha 1, portanto quando eu receber o make code da tecla A do teclado PS2 eu vou zerar o bit 0 do elemento 1. Já a tecla 'R' fica no bit 3 do elemento 2
Tecla  SCANCODE  Keymap (binário)
'A'    0x1C      00.000.001 ou 0x01
'R'    0x2D      00.011.010 0u 0x1A

Os bits 6 e 7 correspondem ao pressionamento conjunto das teclas CAPS SHIFT e SYMBOL SHIFT. Isso foi feito para permitir mapear teclas compostas.

Exemplo: Quando eu receber o Scancode da tecla 'Backspace' eu devo ativar ao mesmo tempo CAPS SHIFT  que está no bit 0 da linha 0 e também a tecla '0' (zero) que está no bit 0 da linha 4. Dessa forma a associação fica: 
Tecla  SCANCODE  Keymap (binário)
BKSP   0x66      10.000.100 ou 0x84


As teclas estendidas são tratadas em separado, pois não não muitas (basicamente as setas).

Finalmente, o algoritmo de funcionamento é o seguinte:

  • Aguarda um Scancode
  • Usa o scancode como entrada numa tabela de 'scancodes x keymaps'
  • Se for um make code zera o(s) bit(s) correspondende na matriz
  • Se for um break code liga o(s) bit(s) correspondende na matriz
  • Envia a matriz serialmente para o registrador de deslocamento

Que em código equivale ao seguinte trecho




Emulador de teclado genérico - Parte 4 (atualizado)

Parte 4: Implementando a matriz.

O primeiro projeto de matriz é do ZX Spectrum e utiliza 8 registradores de deslocamento. Apesar desse arranjo ter capacidade para 64 teclas, apenas 50 são utilizadas (5 bits de cada registrador). As saídas dos registradores são ligados num 'bus' de 5 linhas que é lido pelo Z80.


zoom


Como os sinais de /OE (Output enable) dos registradores vêm direto do Z80 (linhas A8-A15) certamente vai acontecer de mais de uma linha de endereços estar em nível zero ao mesmo tempo e consequentemente sempre vai haver mais de um Hc595 ativo. Para evitar que isso cause uma contenção que poderia queimar os HC595, foi necessário utilizar um diodo em série com cada saída para simular um 'open collector'.

Para ativar os registradores de deslocamento são necessários 3 sinais:
  • Dados
  • Clock
  • Transfer

O funcionamento é simples. Basta enviar os 64 bits pela linha de dados, pulsando o sinal CLOCK a cada bit. Depois que todos os bits forem transferidos basta pulsar o sinal Transfer.

O layout da placa protótipo encontra-se abaixo.


A placa ficou com disposição dos conectores K1 e K2 é propositalmente idêntica à dos conectores dos flats do TK.

Emulador de teclado genérico - Parte 3

Parte 3: Considerações sobre o Hardware

Uma característica crucial do projeto é o tempo de resposta. Este tempo é que vai definir se a implementação da matriz pode ser feita em software ou se precisa ser feita em hardware.

A leitura de um teclado de matriz pode ser feita de forma instantânea, ou seja, ao se selecionar uma linha o estado das colunas já está disponível. Em termos de linguagem de máquina, não é necessário esperar nenhum tempo entre a instrução que seleciona a linha para a que lê a coluna (teclas).

...
out (xx) ; seleciona linha
in (xx) ; lê coluna
... 

Isso significa que para se emular uma matriz de teclado, o tempo de resposta é fundamental. Por exemplo para o MSX, esse  tempo é na melhor das hipóteses da ordem de 3,7us, mas se considerarmos a leitura de uma mesma linha repetidamente, este tempo é de aproximadamente 700ns.
Para o ZX Spectrum, a seleção da linha ocorre na mesma instrução de leitura, pois é utilizada a parte alta da linha de
endereços durante a instrução IN A,(xx), e o tempo de resposta necessário é também por volta de 700ns.

;; KEY-LINE
L0296:  IN      A,(C)           ; read the port to A - bits will be reset
                                ; if a key is pressed else set.


Considerando o tempo que um microcontrolador gasta para atender a uma interrupção, mais o tempo que ele gasta para decodificar a linha, chega-se à conclusão de que é necessário utilizar um microcontrolador muito rápido. Um AVR com 'overclock' ou mesmo um ARM com o 'core' operando a algumas dezenas de MHz deve ser suficiente para atender este tempo.

Por outro lado, se considerarmos o uso de hardware, é possível utilizar uma solução mais simples e modular é ligar em cascata alguns registradores de deslocamento 74HC595. Estes registradores possuem uma característica importantíssima para o projeto em questão que é a presença de um latch com saídas tri-state.  

Também é possível utilizar um CPLD, porém cabe lembrar que para cada tecla vai ser necessária uma macro-célula. Então seriam necessárias no mínimo 40+5 para emular um teclado de ZX, ou de umas 88+8 para emular um de MSX (número de teclas + número de pinos de saída).





quarta-feira, 21 de maio de 2014

Emulador de teclado genérico - Parte 2

Parte 2: Teclados de PC

Existem dezenas de páginas sobre o funcionamento dos teclados de PC, portanto vou fazer apenas um resumo do funcionamento. Quem quiser saber mais detalhes pode consultar alguns links no final deste post.

Os teclados de PC também possuem matrizes de linhas e colunas, porém eles contam com um microcontrolador dedicado para cuidar da varredura da matriz e prover de forma serial as informações sobre o estado das teclas.

Em linhas gerais, quando uma tecla é pressionada controlador do teclado transmite um código correspondente à tecla, o chamado 'make code'. Quando a tecla é liberada, é enviado um código (0xf0) em seguida do código da tecla que foi liberada, o chamado 'break code'.

Exemplo: ao se pressionar a tecla 'A' o teclado envia o valor 0x1C. Quando se solta a tecla 'A', o teclado envia o valor 0xF0 e em seguida o valor 0x1C

Existem também as teclas chamadas estendidas, cujo 'make code' é precedido pelo valor 0xE0, como por exemplo as teclas de cursor. De modo semelhante, o 'break code' desta tecla é precedido pelo valor 0xE0

Exemplo: Ao se pressionar a seta para cima, o teclado envia o valor 0xE0 e em seguida o valor 0x75. Quando se solta a tecla para cima, o teclado envia os valores 0xE0, 0xF0, 0x75.

Por último existem as teclas 'alienígenas' que são o 'Print Screen' e o 'Pause/Break'.

O 'make code' do Print Screen é composto por 5 caracteres 0xE0, 0x12, 0xE0, 0x7c e o 'break code' é composto de 0xE0, 0xF0, 0x7C, 0xE0, 0xF0, 0x12

Já o Pause/Break é o mais bizarro de todos, porque não possui 'break code'. Em vez disso, quando se pressiona esta tecla o teclado transmite simplesmente 0xE1, 0x14, 0x77, 0xE1, 0xF0, 0x14, 0xF0, 0x77 que pode ser entendido como uma combinação de make code e break code juntos

Será que algum dia alguém vai ser capaz de dar uma razão convincente para esta bagunça toda no protocolo? Seria tão mais simples utilizar um código por tecla...

Uma outra característica é a auto-repetição das teclas. Quando se deixa uma tecla pressionada por um tempo maior de que uns 500ms (1/2 segundo) o teclado começa a transmitir repetidamente o make code da(s) tecla(s) pressionadas. Quando se solta a tecla, o teclado emite o break code.

Exemplo: Ao se pressionar e manter pressionada a tecla 'B' o teclado transmite o código 0x32 que corresponde ao B. 500ms depois o teclado transmite os valores 0x32, 0x32, 0x32... a cada 92ms (aproximadamente) enquanto o a tecla estiver pressionada. Ao se soltar a tecla 'B' o teclado transmite 0xF0, 0x32

No caso de ser uma tecla estendida, o raciocínio é o mesmo. o make code 'composto' é transmitido repetidamente.

Exemplo: Ao se pressionar e manter pressionada a tecla UP serão transmitidos os códigos 0xE0, 0x75 seguidos de uma pausa de 500ms, depois novamente 0xE0, 0x75 seguidos de uma pausa de 92ms, depois 0xE0, 0x75, pausa de 92ms .... até a tecla ser liberada (quando então é transmitida a sequência 0xE0, 0xF0, 0x75)

O último aspecto a se considerar é que os símbolos das teclas não possuem códigos próprios. Isso significa que não existe por exemplo um código para a exclamação, em vez disso o teclado simplesmente transmite o código da tecla SHIFT e o da tecla '1'. O mesmo vale para as teclas maiúsculas ou as demais teclas de símbolos.

Existem ainda outros detalhes sobre o protocolo como o 'handshake' inicial, onde o teclado dá seu status de funcionamento e recebe parâmetros como o estado inicial dos LEDs e a taxa de repetição dos caracteres, e outras coisas, mas isto está devidamente explicado nos links abaixo.

Referências:
[1] Interfacing the AT keyboard - Beyond Logic
[2] The PS/2 Mouse/Keyboard Protocol - Computer-Engineering.org 

segunda-feira, 19 de maio de 2014

Emulador de teclado genérico - Parte 1

Parte 1: Matrizes de teclado

A maioria dos computadores da década de 80 utilizava uma matriz de teclado, disposta numa matriz de linhas e colunas, comumente acessada pelo microprocessador, mas algumas vezes através de algum periférico (PIA, PPI, etc). Como os computadores desta época eram em sua maioria de 8 bits, as matrizes de teclado também eram, em sua maioria, múltiplas de 8 teclas

Um exemplo é a matriz de teclado do TRS-80


Já o ZX Spectrum usava apenas 5 bits de dados.


Independente da disposição das teclas, a técnica de  utilizada pela BIOS é a mesma, ou seja, para
Para varrer o teclado, as linhas são acionadas uma por vez e é feita uma leitura para saber qual (ou quais) teclas pertencentes àquela linha foram acionadas. Outra característica comum nos projetos de lógica digital desta época era utilizar o nível lógico baixo como nível ativo. Assim "acionar a linha" significa colocar um nível baixo nela. e as teclas acionadas correspondem aos bits em nível zero obtidos na leitura realizada.

As características das matrizes de alguns computadores mais comuns se encontram na tabela abaixo

Microcomputador
Teclas
Linhas
Colunas
Acesso
ZX81 / ZX Spectrum
40
8
5
Direto
MSX
Até 88
Até 11
8
PPI
TRS-80
53
8
8
Direto
TRS-Color
53
7
8
PIA
Commodore 64
64
8
8
CIA