Um amigo do trabalho pediu para eu dar uma olhada num cartucho de MSX dele que tinha parado de funcionar. O problema era só uma oxidação mais forte na placa do cartucho que foi removida com um lápis borracha.
Aproveitei e fiz umas fotos do cartucho, cuja marca e fabricante eu desconhecia, e
digitalizei o manual. Tanto o cartucho quanto o manual estão em ótimo
estado, dada a idade de ambos.
Um detalhe interessante é que quando o cartucho inicializa ele mostra
uma tela com o código que o fabricante usava para identificar o jogo (e
que consta na etiqueta).
Link para outras fotos, e para o download do manual.
quarta-feira, 25 de março de 2015
domingo, 22 de fevereiro de 2015
Pinagens dos VDPs do MSX1
Achei esta imagem num guia de programação dos VDPs da Texas. O que muda deu um processador para outro são os pinos 35 a 38.
quinta-feira, 30 de outubro de 2014
Recriando uma tábua digitalizadora para o MSX (update: código fonte)
Combinando o aprendido com o estudo das telas touchscreen resistivas e mais o funcionamento das tábuas digitalizadoras para o MSX, consegui recriar a minha própria. Eu recomendo fortemente a leitura dos artigos citados a fim de melhor compreender o que vai ser descrito aqui.
O circuito ficou a cargo de um PIC16F688, rodando com clock interno de 8MHz. A PORTA A ficou inteira para o digitalizador, enquanto a PORTA C ficou para a interface com o MSX.
O protótipo foi montado numa placa padrão. Os primeiros testes foram efetuados com um conjunto de potenciômetros, e posteriormente com o 'touchscreen'.
O conector do sensor resistivo é um componente SMD, e teve que ser adaptado para a montagem na placa padrão.
As abas do conector foram soldadas às ilhas e os terminais foram isolados com um pedaço de fita de kapton por baixo.
Eu notei que quando colocado sobre a mesa a detecção do toque não funcionou direito. Creio que será necessário incluir um delay entre o momento que eu ativo o resistor de pullup e a amostragem da tela.
Com o sensor resistivo sobre o MSX a detecção fica quase normal. Fora isso, a leitura das coordenadas ficou muito boa, e a auto-calibração também funciona muito bem (vide artigo sobre a leitura do sensor resistivo)
Em seguida fiz um programa para poder testar o funcionamento de uma forma mais visual.
E capturei o seguinte vídeo:
Ainda dá para melhorar um pouco a estabilidade da leitura, mas como prova de conceito já está OK. O protótipo já tem todos os elementos necessários. Agora é melhorar o firmware.
Mas antes disso, o próximo passo vai ser montar o circuito numa caixa ou base.
segunda-feira, 27 de outubro de 2014
Um estudo sobre o MSX Touchpad
Recentemente alguém publicou no MSX Wiki um material sobre as pranchetas digitalizadoras para o MSX. Estes periféricos nunca foram produzidos em terras tupiniquins, o que é uma pena, pois teria sido interessante ver programas como o Graphos III com suporte a ele.
O artigo, apesar de bem interessante ainda me deixou com algumas dúvidas, e resolvi esclarecê-las a partir de uma lida no código fonte da BIOS do MSX. Minhas observações podem ser vistas neste link.
Diante do esclarecido resolvi dar uma esboçada no circuito, que utiliza um DAC modelo uPD7001, velho conhecido meu, dos modulos controladores da válvula de saída das RD350 (YPVS).
Como tinha um chip desses em minha gaveta de componentes resolvi fazer uns testes, e usar pela primeira vez em minha vida a instrução PAD(x) do MSX Basic.
Eu aproveitei para capturar algumas formas de onda, de forma a ilustrar o funcionamento da função GTPAD da BIOS.
- O MSX faz uma primeira leitura ao Touchpad, provavelmente para "acordar" o circuito. O sinal SI, que seleciona o canal do ADC começa no valor 0.
- Em seguida vem uma segunda leitura para determinar se a tela está pressionada ou não, e também para selecionar o canal 0 do ADC. Caso a tela não esteja sendo pressionada, a rotina termina.
![]() |
| Sinais SI (Laranja) e /CS (Azul) na condição "Tela NÃO Pressionada" |
- Por outro lado, caso a tela esteja pressionada o MSX faz mais 4 leituras.
![]() |
| Sinais SI (Laranja) e /CS (Azul) na condição "Tela PRESSIONADA" |
- O MSX faz uma primeira leitura ao Touchpad, provavelmente para "acordar" o circuito;
- Em seguida vem uma segunda leitura para determinar se a tela está pressionada ou não, e também para selecionar o canal 0 do ADC;
- A terceira leitura é a do valor X0. Enquanto esta leitura acontece, o sinal SI fica em "1" para selecionar o canal 3 para a próxima leitura;
- Em seguida o valor de Y0 é lido com o sinal SI em zero, para selecionar o canal 0 para a próxima leitura;
- O MSX lê então o valor de X1 e coloca SI em "1" para a próxima leitura;
- Por último o valor de Y1 é lido e os sinais retornam ao estado normal. (faltou o "CH0" em vermelho ali na figura).
![]() |
| Sinais SI (Laranja) e /CS (Azul) na condição "Tela PRESSIONADA", detalhes. |
Alguns detalhes importantes:
- O processo de leitura dura por volta de 8ms.
- O ciclo de clock gerado pelo MSX dura 140us.
- O sinal de clock no código fonte parece estar invertido. O texto fala que está no estado "0" quando seta um bit, e vice versa. Talvez exista um inversor entre o sinal SCK do MSX e o mesmo sinal do uPD7001. De qualquer modo o circuito funcionou deste jeito.
- O texto do MSX Wiki fala de um inversor entre o sinal /EOC do uPD7001 e o MSX, mas eu suspeito que no circuito real exista um flip flop que é ativado pelo sinal /CS e resetado pelo sinal EOC do ADC.
domingo, 17 de agosto de 2014
Temporização dos paddles
Segue abaixo um pequeno estudo sobre a temporização do acionamento dos paddles do MSX.
A listagem abaixo contém o trecho exato da BIOS que lê os paddles. Os números marcados em azul / laranja correspondem à quantidade de ciclos de máquina que o Z80 leva para executar as instruções, já considerando o WAIT State inserido a cada ciclo M1 (padrão no MSX).
Para ler os paddles, o MSX gera um pulso no pino 8 e em seguida realiza uma contagem de tempo para ver quanto tempo o sinal do paddle permaneceu ativado. A contagem termina quando o sinal do paddle retorna a nível baixo, ou quando se atingem 255 contagens.
PDLP1:
128B LD A,PSG.PB
128D DI
128E CALL RDPSG ; get current port B content
1291 AND E
1292 OR D
1293 OR C
1294 12 OUT (PSG.DW),A ; set trigger high
1296 5 XOR C
1297 12 OUT (PSG.DW),A ; set trigger low again
1299 8 LD A,0EH
129B 12 OUT (PSG.LW),A
129D 8 LD C,0 ; initialize counter
PDL2:
129F 12 IN A,(PSG.DR)
12A1 5 AND B ; end of pulse?
12A2 13/8 JR Z,PDL3 ; yes
12A4 5 INC C ; bump counter
12A5 13/8 JP NZ,PDL2 ; no overflow yet
12A8 DEC C ; make it 255
PDL3:
12A9 EI
12AA LD A,C ; return counted value
12AB RET
Os números em azul são os ciclos gastos entre a subida do pulso de saída (pino 8 do conector de joystick) e a primeira leitura efetuada (para ser mais exato eu teria que reduzir os ciclos de clock referentes à busca e início da execução da instrução OUT que levanta o sinal de trigger, porém eu teria que acrescentar um tempo idêntico referente à primeira instrução IN do ciclo de leitura).
Num total são 57 ciclos, o que equivale a 15,92us num MSX rodando a 3,5795MHz. Se considerarmos apenas a borda de descida, são 17 ciclos a menos, o que resulta em 11,17us.
Os pulsos em laranja equivalem a uma contagem. Esta temporização já é velha conhecida pois consta no 'Livro Vermelho do MSX', mas como exercício não custa conferir.
Cada interação leva 43 ciclos, ou 12,01us (a 3,5795MHz). O tempo máximo para retornar da leitura do paddle é de 3,06ms (255 * 12,01us).
Com estes números em mente, surgem algumas idéias de emulação. Para isso eis um resumo do que se deve fazer:
A listagem abaixo contém o trecho exato da BIOS que lê os paddles. Os números marcados em azul / laranja correspondem à quantidade de ciclos de máquina que o Z80 leva para executar as instruções, já considerando o WAIT State inserido a cada ciclo M1 (padrão no MSX).
Para ler os paddles, o MSX gera um pulso no pino 8 e em seguida realiza uma contagem de tempo para ver quanto tempo o sinal do paddle permaneceu ativado. A contagem termina quando o sinal do paddle retorna a nível baixo, ou quando se atingem 255 contagens.
PDLP1:
128B LD A,PSG.PB
128D DI
128E CALL RDPSG ; get current port B content
1291 AND E
1292 OR D
1293 OR C
1294 12 OUT (PSG.DW),A ; set trigger high
1296 5 XOR C
1297 12 OUT (PSG.DW),A ; set trigger low again
1299 8 LD A,0EH
129B 12 OUT (PSG.LW),A
129D 8 LD C,0 ; initialize counter
PDL2:
129F 12 IN A,(PSG.DR)
12A1 5 AND B ; end of pulse?
12A2 13/8 JR Z,PDL3 ; yes
12A4 5 INC C ; bump counter
12A5 13/8 JP NZ,PDL2 ; no overflow yet
12A8 DEC C ; make it 255
PDL3:
12A9 EI
12AA LD A,C ; return counted value
12AB RET
Os números em azul são os ciclos gastos entre a subida do pulso de saída (pino 8 do conector de joystick) e a primeira leitura efetuada (para ser mais exato eu teria que reduzir os ciclos de clock referentes à busca e início da execução da instrução OUT que levanta o sinal de trigger, porém eu teria que acrescentar um tempo idêntico referente à primeira instrução IN do ciclo de leitura).
Num total são 57 ciclos, o que equivale a 15,92us num MSX rodando a 3,5795MHz. Se considerarmos apenas a borda de descida, são 17 ciclos a menos, o que resulta em 11,17us.
Os pulsos em laranja equivalem a uma contagem. Esta temporização já é velha conhecida pois consta no 'Livro Vermelho do MSX', mas como exercício não custa conferir.
Cada interação leva 43 ciclos, ou 12,01us (a 3,5795MHz). O tempo máximo para retornar da leitura do paddle é de 3,06ms (255 * 12,01us).
Com estes números em mente, surgem algumas idéias de emulação. Para isso eis um resumo do que se deve fazer:
- Responder a uma borda de subida no pino 8 do conector de joystick em até 15us (ou uma de descida em até 11us);
- Subir para nível alto o(s) pino(s) desejado(s) e mantê-los por um tempo entre 12us e 3ms;
- Ao final do tempo desejado, colocar o pino em nível baixo (ou mantê-lo em nível baixo por um tempo superior a uma iteração).
terça-feira, 1 de julho de 2014
Expansor de Slots em face simples - Exercício no Kicad
Num expansor de Slots de MSX praticamente todos os fios são interconectados desde o conector de entrada ao último Slot (com exceção é claro dos sinais /SLTSL). Por isso eu nunca entendi a razão pela qual todo expansor de slot tem os chips de decodificação no "meio do caminho", ou seja, entre o conector de entrada e o primeiro slot disponível, obrigando as trilhas a fazer um malabarismo para contornar os chips e chegar aos conectores dos Slots expandidos.
Não seria mais fácil colocar os chips no final, ou seja, depois do último slot expandido? Afinal de contas os únicos sinais gerados no circuito decodificador são os de seleção de Slots expandidos.
Pensando nisso eu fiz um exercício de layout utilizando o diagrama do expansor de slots do website do Luciano (MSXPRO). Como a placa ia ficar com mais do que 10 x 8cm eu acabei utilizando o Kicad. Eis o diagrama redesenhado.
E não é que no final deu pra fazer o expansor inteiro em face simples? Tudo bem que tem alguns jumpers - e metade deles são por causa da pinagem bizarra do LS273 - mas nada absurdo. E a placa nem ficou tão grande assim, ocupando aproximadamente 15 x 9cm. Se for usada como expansor interno, basta desconsiderar os conectores à direita de P5 e assim a placa vai ocupar apenas 7 x 9 cm.
Ainda falta fazer algumas coisas, como colocar os capacitores de desacoplamento, um LED de indicação de alimentação e alguns jumpers para permitir habilitar/desabilitar os slots (ou quem sabe usar o quadrado mágico). Mas já valeu o exercício.
![]() |
| Chips no meio do caminho das trilhas. |
Não seria mais fácil colocar os chips no final, ou seja, depois do último slot expandido? Afinal de contas os únicos sinais gerados no circuito decodificador são os de seleção de Slots expandidos.
![]() |
| Chips depois do último conector. |
![]() |
| Diagrama desenhado no Kicad (sem a parte dos Slots) |
E não é que no final deu pra fazer o expansor inteiro em face simples? Tudo bem que tem alguns jumpers - e metade deles são por causa da pinagem bizarra do LS273 - mas nada absurdo. E a placa nem ficou tão grande assim, ocupando aproximadamente 15 x 9cm. Se for usada como expansor interno, basta desconsiderar os conectores à direita de P5 e assim a placa vai ocupar apenas 7 x 9 cm.
![]() |
| Placa do expansor, desenhada no Kicad |
Ainda falta fazer algumas coisas, como colocar os capacitores de desacoplamento, um LED de indicação de alimentação e alguns jumpers para permitir habilitar/desabilitar os slots (ou quem sabe usar o quadrado mágico). Mas já valeu o exercício.
domingo, 29 de junho de 2014
PPI-Mega8 para o Hotbit - Matriz de diodos
Internamente o Hotbit possui um decodificador que converte os 4 bits da porta C da PPI para 10 linhas. A linha acionada corresponde ao valor em BCD.
Para se fazer um emulador de teclado que possa ser ligado ao conector interno de teclado do Hotbit torna-se necessário então converter de volta este valor para BCD.
Embora existam alguns chips para fazer isso, mas somente os consegui encontrar sob encomenda. Daí surge uma outra solução, que é fazer um codificador usando diodos, como o da figura abaixo, porém ele possui uma desvantagem que é a quantidade enorme de diodos necessária (21).
![]() |
| Codificador Decimal para BCD com diodos |
Contudo é possível simplificar esta matriz levando em conta algumas características do projeto:
- Apenas uma das saídas fica em nível baixo por vez.
- O HOTBIT usa apenas 9 sinais de seleção (em vez de 10 ou 11 como outros modelos de MSX).
- A porta C do ATMega8 que está sendo usado para ler a matriz do teclado ainda tem duas linhas disponíveis.
Sendo assim, podemos simplificar a matriz de diodos do codificador de forma que ela utilize apenas 8 diodos.
![]() |
| Matriz codificadora Decimal para 5 pinos. |
O funcionamento da matriz é bem simples:
- Quando o sinal Y0 é acionado, somente a linha PC0 é acionada;
- Quando o sinal Y1 é acionado, as linhas PC0 e PC1 são acionadas;
- Quando o sinal Y2 é acionado, somente a linha PC1 é acionada;
- Quando o sinal Y3 é acionado, as linhas PC1 e PC2 são acionadas;
- ... e assim por diante. .
E a tabela de entradas/saídas da matriz fica:
PC4 PC3 PC2 PC1 PC0 HEXA --------TECLAS--------
Y0 1 1 1 1 0 1E 7 6 5 4 3 2 1 0
Y1 1 1 1 0 0 1C Ç ¨ ´ \ = - 9 8
Y2 1 1 1 0 1 1D B A < / . , [ ~
Y3 1 1 0 0 1 19 J I H G F E D C
Y4 1 1 0 1 1 1B R Q P O N M L K
Y5 1 0 0 1 1 13 Z Y X W V U T S
Y6 1 0 1 1 1 17 F3 F2 F1 C0 CA GR CT SH
Y7 0 0 1 1 1 07 RE SL BS ST TA ES F5 F4
Y8 0 1 1 1 1 0F RT DW UP LT DE IN HO SP
O fato de ter sido utilizada uma linha a mais implica que a matriz que guarda o estado das teclas de cada linha vai precisar ter 32 entradas.
Dessa forma, a definição da variável que armazena a matriz de teclado fica:
static volatite unsigned char keymat [32] = {
0xff ; // 00
0xff ; // 01
0xff ; // 02
0xff ; // 03
0xff ; // 04
0xff ; // 05
0xff ; // 06
0xff ; // 07 - Teclas RE SL BS ST TA ES F5 F4
0xff ; // 08
0xff ; // 09
0xff ; // 0a
0xff ; // 0b
0xff ; // 0c
0xff ; // 0d
0xff ; // 0e
0xff ; // 0f - Teclas RT DW UP LT DE IN HO SP
0xff ; // 10
0xff ; // 11
0xff ; // 12
0xff ; // 13 - Teclas Z Y X W V U T S
0xff ; // 14
0xff ; // 15
0xff ; // 16
0xff ; // 17 - Teclas F3 F2 F1 C0 CA GR CT SH
0xff ; // 18
0xff ; // 19 - Teclas J I H G F E D C
0xff ; // 1a
0xff ; // 1b - Teclas R Q P O N M L K
0xff ; // 1c - Teclas Ç ¨ ´ \ = - 9 8
0xff ; // 1d - Teclas B A < / . , [ ~
0xff ; // 1e - Teclas 7 6 5 4 3 2 1 0
0xff ; // 1f
}
Quando (por exemplo) se pressiona a tecla "A" no teclado PS/2 a função principal do programa do emulador de teclado faz o seguinte:
keymat [0x1d] &= ~(1<<6 font="">6>
E na rotina em assembly, as mudanças são mínimas (em relação à versão que lê direto da PPI)
ISR (PCINT1_vect, ISR_NAKED) {
asm volatile ( // 7 até aqui
"in __tmp_reg__,__SREG__ \n\t" // 1 Salva registrador de Status
"ldi r26,lo8(Keymap) \n\t" // 1 Ponteiro X = endereço de Keymap
"ldi r27,hi8(Keymap)\n\t" // 1
"in r19,%0 \n\t" // 1 Amostra bits da porta C da PPI (PC0..PC4)
"andi r19,0x1f \n\t" // 1 limpa bits 5..7
"add r26,r19 \n\t" // 1 soma com ponteiro
"ld r19,X \n\t" // 1 lê coluna correspondente do mapa de teclas
"out %1,r19 \n\t" // 1 escreve na porta B da PPI
// até aqui 15 instruções
"out __SREG__,__tmp_reg__ \n\t" // restaura registrador de Status
"reti \n\t"
:: "I" (_SFR_IO_ADDR(PINC)), "I" (_SFR_IO_ADDR(PORTB)) );
}
Com isso, já dá pra definir o layout da placa do adaptador. Os dois conectores têm como objetivo manter o teclado interno funcionando junto com o emulador de teclado.
![]() |
| Adaptador interno para o teclado do Hotbit |
terça-feira, 17 de junho de 2014
PPI-Mega8 - Diagrama e tabelas de constantes
Depois de algum tempo estudando e fazendo alguns experimentos com o roteamento da placa cheguei ao circuito básico do emulador de teclado para ser colocado sobre a PPI.
Esta disposição de pinos permitiu fazer ligações praticamente retas entre o AVR e a PPI de forma que a placa de circuito impressso possa ser de face simples
As linhas PC0..PC3 da PPI foram direto aos pinos PINC0..3 do AVR. Com isso apenas as colunas trocaram um pouco de lugar (PB3 foi para o bit 0, etc)
Assim a matriz de teclado mudou para
// Matrix columns reorganized for optimizing PCB layout
7 6 5 4 3 2 1 0 BIT
+-----------------------------------------------+
¦ 4 ¦ 3 ¦ 2 ¦ 1 ¦ 0 ¦ 5 ¦ 6 ¦ 7 ¦ Row 0
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ \ ¦ = ¦ - ¦ 9 ¦ 8 ¦ ´ ¦ ¨ ¦ Ç ¦ Row 1
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ / ¦ . ¦ , ¦ [ ¦ ~ ¦ < ¦ A ¦ B ¦ Row 2
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ G ¦ F ¦ E ¦ D ¦ C ¦ H ¦ I ¦ J ¦ Row 3
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ O ¦ N ¦ M ¦ L ¦ K ¦ P ¦ Q ¦ R ¦ Row 4
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ W ¦ V ¦ U ¦ T ¦ S ¦ X ¦ Y ¦ Z ¦ Row 5
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦CODE ¦ CAP ¦GRAPH¦CTRL ¦SHIFT¦ F1 ¦ F2 ¦ F3 ¦ Row 6
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦STOP ¦ TAB ¦ ESC ¦ F5 ¦ F4 ¦ BS ¦ SEL ¦ CR ¦ Row 7
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦LEFT ¦ DEL ¦ INS ¦HOME ¦SPACE¦ UP ¦DOWN ¦RIGHT¦ Row 8
+-----------------------------------------------+
4 3 2 1 0 5 6 7 Column
E o endereço das teclas ficou:
// ROW 0 Hexa
#define _0 0x03
#define _1 0x04
#define _2 0x05
#define _3 0x06
#define _4 0x07
#define _5 0x02
#define _6 0x01
#define _7 0x00
// ROW 1
#define _8 0x0B
#define _9 0x0C
#define _MINUS 0x0D
#define _EQUAL 0x0E
#define _BACKSLASH 0x0F
#define _ACUTE 0x0A
#define _UBER 0x09
#define _CCEDIL 0x08
// ROW 2
#define _TILDE 0x13
#define _OPENBRACKET 0x14
#define _COMMA 0x15
#define _DOT 0x16
#define _SLASH 0x17
#define _LESSTHAN 0x12
#define _A 0x11
#define _B 0x10
// ROW 3
#define _C 0x1B
#define _D 0x1C
#define _E 0x1D
#define _F 0x1E
#define _G 0x1F
#define _H 0x1A
#define _I 0x19
#define _J 0x18
// ROW 4
#define _K 0x23
#define _L 0x24
#define _M 0x25
#define _N 0x26
#define _O 0x27
#define _P 0x22
#define _Q 0x21
#define _R 0x20
// ROW 5
#define _S 0x2B
#define _T 0x2C
#define _U 0x2D
#define _V 0x2E
#define _W 0x2F
#define _X 0x2A
#define _Y 0x29
#define _Z 0x28
// ROW 6
#define _SHIFT 0x33
#define _CONTROL 0x34
#define _GRAPH 0x35
#define _CAPS 0x36
#define _CODE 0x37
#define _F1 0x32
#define _F2 0x31
#define _F3 0x30
// ROW 7
#define _F4 0x3B
#define _F5 0x3C
#define _ESC 0x3D
#define _TAB 0x3E
#define _STOP 0x3F
#define _BACKSPACE 0x3A
#define _SELECT 0x39
#define _ENTER 0x38
// ROW 8
#define _SPACE 0x43
#define _HOME 0x44
#define _INSERT 0x45
#define _DELETE 0x46
#define _LEFT 0x47
#define _UP 0x42
#define _DOWN 0x41
#define _RIGHT 0x40
Finalmente, as tabelas de caracteres sem e com shift ficaram assim:
// Keys ordered by PS/2 Scancode
const uint8_t PS2Keymap_Normal[] PROGMEM = {
_NONE , // 0x00
_F9 , // 0x01 F9
_NONE , // 0x02
_F5 , // 0x03 F5
_F3 , // 0x04 F3
_F1 , // 0x05 F1
_F2 , // 0x06 F2
_STOP , // 0x07 F12
_NONE , // 0x08
_F10 , // 0x09 F10
_F8 , // 0x0A F8
_F6 , // 0x0B F6
_F4 , // 0x0C F4
_TAB , // 0x0D TAB
_APOSTROPHE , // 0x0E APOSTROPHE '
_NONE , // 0x0F
_NONE , // 0x10
_GRAPH , // 0x11 L ALT
_SHIFT , // 0x12 L SHFT
_NONE , // 0x13
_CONTROL , // 0x14 L CTRL
_Q , // 0x15 Q
_1 , // 0x16 1
_NONE , // 0x17
_NONE , // 0x18
_NONE , // 0x19
_Z , // 0x1A Z
_S , // 0x1B S
_A , // 0x1C A
_W , // 0x1D W
_2 , // 0x1E 2
_NONE , // 0x1F
_NONE , // 0x20
_C , // 0x21 C
_X , // 0x22 X
_D , // 0x23 D
_E , // 0x24 E
_4 , // 0x25 4
_3 , // 0x26 3
_NONE , // 0x27
_NONE , // 0x28
_SPACE , // 0x29 SPACE
_V , // 0x2A V
_F , // 0x2B F
_T , // 0x2C T
_R , // 0x2D R
_5 , // 0x2E 5
_NONE , // 0x2F
_NONE , // 0x30
_N , // 0x31 N
_B , // 0x32 B
_H , // 0x33 H
_G , // 0x34 G
_Y , // 0x35 Y
_6 , // 0x36 6
_NONE , // 0x37
_NONE , // 0x38
_NONE , // 0x39
_M , // 0x3A M
_J , // 0x3B J
_U , // 0x3C U
_7 , // 0x3D 7
_8 , // 0x3E 8
_NONE , // 0x3F
_NONE , // 0x40
_COMMA , // 0x41 COMMA ,
_K , // 0x42 K
_I , // 0x43 I
_O , // 0x44 O
_0 , // 0x45 0
_9 , // 0x46 9
_NONE , // 0x47
_NONE , // 0x48
_DOT , // 0x49 DOT .
_SEMICOLON , // 0x4A SEMICOLON ;
_L , // 0x4B L
_CCEDIL , // 0x4C CCCEDIL Ç
_P , // 0x4D P
_MINUS , // 0x4E MINUS -
_NONE , // 0x4F
_NONE , // 0x50
_SLASH , // 0x51 SLASH /
_TILDE , // 0x52 TILDE ~
_NONE , // 0x53
_ACUTE , // 0x54 ACUTE `
_EQUAL , // 0x55 EQUAL =
_NONE , // 0x56
_NONE , // 0x57
_CAPS , // 0x58 CAPS
_SHIFT , // 0x59 R SHFT
_ENTER , // 0x5A ENTER
_OPENBRACKET, // 0x5B OPENBRACKET [
_NONE , // 0x5C
_CLOSEBRACKET, // 0x5D CLOSEBRACKET ]
_NONE , // 0x5E
_NONE , // 0x5F
_NONE , // 0x60
_BACKSLASH , // 0x61 BACKSLASH
_NONE , // 0x62
_F7 , // 0x63 F7 (relocated from 0x83 to keep table under 128 chars
_NONE , // 0x64
_NONE , // 0x65
_BACKSPACE , // 0x66 BKSP
_NONE , // 0x67
_NONE , // 0x68
_1 , // 0x69 KP1
_NONE , // 0x6A
_4 , // 0x6B KP4
_7 , // 0x6C KP7
_DOT , // 0x6D KPDOT .
_NONE , // 0x6E
_NONE , // 0x6F
_0 , // 0x70 KP0
_COMMA , // 0x71 KPCOMMA ,
_2 , // 0x72 KP2
_5 , // 0x73 KP5
_6 , // 0x74 KP6
_8 , // 0x75 KP8
_ESC , // 0x76 ESC
_NONE , // 0x77 NUM
_SELECT , // 0x78 F11
_PLUS , // 0x79 KPPLUS +
_3 , // 0x7A KP3
_MINUS , // 0x7B KPMINUS -
_ASTERISK , // 0x7C KPTIMES *
_9 , // 0x7D KP9
_NONE , // 0x7E SCROLL
_NONE , // 0x7F
};
/*
_NONE , // 0x80
_NONE , // 0x81
_NONE , // 0x82
_F7 // 0x83 F7
};
*/
const uint8_t PS2Keymap_Shifted[] PROGMEM = {
_NONE , // 0x00
_F9 , // 0x01
_NONE , // 0x02
_F5 , // 0x03
_F3 , // 0x04
_F1 , // 0x05
_F2 , // 0x06
_SELECT , // 0x07
_NONE , // 0x08
_F10 , // 0x09
_F8 , // 0x0A
_F6 , // 0x0B
_F4 , // 0x0C
_TAB , // 0x0D
_QUOTE , // 0x0E QUOTE "
_NONE , // 0x0F
_NONE , // 0x10
_GRAPH , // 0x11
_SHIFT , // 0x12
_NONE , // 0x13
_CONTROL , // 0x14
_Q , // 0x15
_EXCLAMATION, // 0x16 EXCLAMATION !
_NONE , // 0x17
_NONE , // 0x18
_NONE , // 0x19
_Z , // 0x1A
_S , // 0x1B
_A , // 0x1C
_W , // 0x1D
_AT , // 0x1E AT @
_NONE , // 0x1F
_NONE , // 0x20
_C , // 0x21
_X , // 0x22
_D , // 0x23
_E , // 0x24
_DOLLAR , // 0x25 DOLLAR $
_NUMBER , // 0x26 NUMBER #
_NONE , // 0x27
_NONE , // 0x28
_SPACE , // 0x29
_V , // 0x2A
_F , // 0x2B
_T , // 0x2C
_R , // 0x2D
_PERCENT , // 0x2E PERCENT %
_NONE , // 0x2F
_NONE , // 0x30
_N , // 0x31
_B , // 0x32
_H , // 0x33
_G , // 0x34
_Y , // 0x35
_UBER , // 0x36 UBER ¨
_NONE , // 0x37
_NONE , // 0x38
_NONE , // 0x39
_M , // 0x3A
_J , // 0x3B
_U , // 0x3C
_AMPERSAND , // 0x3D AMPERSAND &
_ASTERISK , // 0x3E ASTERISK *
_NONE , // 0x3F
_NONE , // 0x40
_LESSTHAN , // 0x41 LESSTHAN <
_K , // 0x42
_I , // 0x43
_O , // 0x44
_CLOSEBRACE , // 0x45 CLOSEBRACE )
_OPENBRACE , // 0x46 OPENBRACE (
_NONE , // 0x47
_NONE , // 0x48
_GREATERTHAN, // 0x49 GREATERTHAN >
_COLON , // 0x4A COLON :
_L , // 0x4B
_CCEDIL , // 0x4C
_P , // 0x4D
_UNDERSCORE , // 0x4E UNDERSCORE _
_NONE , // 0x4F
_NONE , // 0x50
_QUESTION , // 0x51 QUESTION ?
_CIRCUMFLEX , // 0x52 CIRCUMFLEX ^
_NONE , // 0x53
_GRAVE , // 0x54 GRAVE `
_PLUS , // 0x55 PLUS +
_NONE , // 0x56
_NONE , // 0x57
_CAPS , // 0x58
_SHIFT , // 0x59
_ENTER , // 0x5A
_OPENKEY , // 0x5B OPENKEY {
_NONE , // 0x5C
_CLOSEKEY , // 0x5D CLOSEKEY }
_NONE , // 0x5E
_NONE , // 0x5F
_NONE , // 0x60
_PIPE , // 0x61 PIPE |
_NONE , // 0x62
_F7 , // 0x63 F7 (relocated from 0x83 to keep table under 128 chars
_NONE , // 0x64
_NONE , // 0x65
_BACKSPACE , // 0x66
_NONE , // 0x67
_NONE , // 0x68
_1 , // 0x69
_NONE , // 0x6A
_4 , // 0x6B
_7 , // 0x6C
_DOT , // 0x6D
_NONE , // 0x6E
_NONE , // 0x6F
_0 , // 0x70
_COMMA , // 0x71
_2 , // 0x72
_5 , // 0x73
_6 , // 0x74
_8 , // 0x75
_ESC , // 0x76
_NONE , // 0x77
_SELECT , // 0x78
_PLUS , // 0x79
_3 , // 0x7A
_MINUS , // 0x7B
_ASTERISK , // 0x7C
_9 , // 0x7D
_NONE , // 0x7E
_NONE , // 0x7F
};
Esta disposição de pinos permitiu fazer ligações praticamente retas entre o AVR e a PPI de forma que a placa de circuito impressso possa ser de face simples
As linhas PC0..PC3 da PPI foram direto aos pinos PINC0..3 do AVR. Com isso apenas as colunas trocaram um pouco de lugar (PB3 foi para o bit 0, etc)
Assim a matriz de teclado mudou para
// Matrix columns reorganized for optimizing PCB layout
7 6 5 4 3 2 1 0 BIT
+-----------------------------------------------+
¦ 4 ¦ 3 ¦ 2 ¦ 1 ¦ 0 ¦ 5 ¦ 6 ¦ 7 ¦ Row 0
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ \ ¦ = ¦ - ¦ 9 ¦ 8 ¦ ´ ¦ ¨ ¦ Ç ¦ Row 1
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ / ¦ . ¦ , ¦ [ ¦ ~ ¦ < ¦ A ¦ B ¦ Row 2
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ G ¦ F ¦ E ¦ D ¦ C ¦ H ¦ I ¦ J ¦ Row 3
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ O ¦ N ¦ M ¦ L ¦ K ¦ P ¦ Q ¦ R ¦ Row 4
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦ W ¦ V ¦ U ¦ T ¦ S ¦ X ¦ Y ¦ Z ¦ Row 5
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦CODE ¦ CAP ¦GRAPH¦CTRL ¦SHIFT¦ F1 ¦ F2 ¦ F3 ¦ Row 6
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦STOP ¦ TAB ¦ ESC ¦ F5 ¦ F4 ¦ BS ¦ SEL ¦ CR ¦ Row 7
+-----+-----+-----+-----+-----+-----+-----+-----¦
¦LEFT ¦ DEL ¦ INS ¦HOME ¦SPACE¦ UP ¦DOWN ¦RIGHT¦ Row 8
+-----------------------------------------------+
4 3 2 1 0 5 6 7 Column
E o endereço das teclas ficou:
// ROW 0 Hexa
#define _0 0x03
#define _1 0x04
#define _2 0x05
#define _3 0x06
#define _4 0x07
#define _5 0x02
#define _6 0x01
#define _7 0x00
// ROW 1
#define _8 0x0B
#define _9 0x0C
#define _MINUS 0x0D
#define _EQUAL 0x0E
#define _BACKSLASH 0x0F
#define _ACUTE 0x0A
#define _UBER 0x09
#define _CCEDIL 0x08
// ROW 2
#define _TILDE 0x13
#define _OPENBRACKET 0x14
#define _COMMA 0x15
#define _DOT 0x16
#define _SLASH 0x17
#define _LESSTHAN 0x12
#define _A 0x11
#define _B 0x10
// ROW 3
#define _C 0x1B
#define _D 0x1C
#define _E 0x1D
#define _F 0x1E
#define _G 0x1F
#define _H 0x1A
#define _I 0x19
#define _J 0x18
// ROW 4
#define _K 0x23
#define _L 0x24
#define _M 0x25
#define _N 0x26
#define _O 0x27
#define _P 0x22
#define _Q 0x21
#define _R 0x20
// ROW 5
#define _S 0x2B
#define _T 0x2C
#define _U 0x2D
#define _V 0x2E
#define _W 0x2F
#define _X 0x2A
#define _Y 0x29
#define _Z 0x28
// ROW 6
#define _SHIFT 0x33
#define _CONTROL 0x34
#define _GRAPH 0x35
#define _CAPS 0x36
#define _CODE 0x37
#define _F1 0x32
#define _F2 0x31
#define _F3 0x30
// ROW 7
#define _F4 0x3B
#define _F5 0x3C
#define _ESC 0x3D
#define _TAB 0x3E
#define _STOP 0x3F
#define _BACKSPACE 0x3A
#define _SELECT 0x39
#define _ENTER 0x38
// ROW 8
#define _SPACE 0x43
#define _HOME 0x44
#define _INSERT 0x45
#define _DELETE 0x46
#define _LEFT 0x47
#define _UP 0x42
#define _DOWN 0x41
#define _RIGHT 0x40
Finalmente, as tabelas de caracteres sem e com shift ficaram assim:
// Keys ordered by PS/2 Scancode
const uint8_t PS2Keymap_Normal[] PROGMEM = {
_NONE , // 0x00
_F9 , // 0x01 F9
_NONE , // 0x02
_F5 , // 0x03 F5
_F3 , // 0x04 F3
_F1 , // 0x05 F1
_F2 , // 0x06 F2
_STOP , // 0x07 F12
_NONE , // 0x08
_F10 , // 0x09 F10
_F8 , // 0x0A F8
_F6 , // 0x0B F6
_F4 , // 0x0C F4
_TAB , // 0x0D TAB
_APOSTROPHE , // 0x0E APOSTROPHE '
_NONE , // 0x0F
_NONE , // 0x10
_GRAPH , // 0x11 L ALT
_SHIFT , // 0x12 L SHFT
_NONE , // 0x13
_CONTROL , // 0x14 L CTRL
_Q , // 0x15 Q
_1 , // 0x16 1
_NONE , // 0x17
_NONE , // 0x18
_NONE , // 0x19
_Z , // 0x1A Z
_S , // 0x1B S
_A , // 0x1C A
_W , // 0x1D W
_2 , // 0x1E 2
_NONE , // 0x1F
_NONE , // 0x20
_C , // 0x21 C
_X , // 0x22 X
_D , // 0x23 D
_E , // 0x24 E
_4 , // 0x25 4
_3 , // 0x26 3
_NONE , // 0x27
_NONE , // 0x28
_SPACE , // 0x29 SPACE
_V , // 0x2A V
_F , // 0x2B F
_T , // 0x2C T
_R , // 0x2D R
_5 , // 0x2E 5
_NONE , // 0x2F
_NONE , // 0x30
_N , // 0x31 N
_B , // 0x32 B
_H , // 0x33 H
_G , // 0x34 G
_Y , // 0x35 Y
_6 , // 0x36 6
_NONE , // 0x37
_NONE , // 0x38
_NONE , // 0x39
_M , // 0x3A M
_J , // 0x3B J
_U , // 0x3C U
_7 , // 0x3D 7
_8 , // 0x3E 8
_NONE , // 0x3F
_NONE , // 0x40
_COMMA , // 0x41 COMMA ,
_K , // 0x42 K
_I , // 0x43 I
_O , // 0x44 O
_0 , // 0x45 0
_9 , // 0x46 9
_NONE , // 0x47
_NONE , // 0x48
_DOT , // 0x49 DOT .
_SEMICOLON , // 0x4A SEMICOLON ;
_L , // 0x4B L
_CCEDIL , // 0x4C CCCEDIL Ç
_P , // 0x4D P
_MINUS , // 0x4E MINUS -
_NONE , // 0x4F
_NONE , // 0x50
_SLASH , // 0x51 SLASH /
_TILDE , // 0x52 TILDE ~
_NONE , // 0x53
_ACUTE , // 0x54 ACUTE `
_EQUAL , // 0x55 EQUAL =
_NONE , // 0x56
_NONE , // 0x57
_CAPS , // 0x58 CAPS
_SHIFT , // 0x59 R SHFT
_ENTER , // 0x5A ENTER
_OPENBRACKET, // 0x5B OPENBRACKET [
_NONE , // 0x5C
_CLOSEBRACKET, // 0x5D CLOSEBRACKET ]
_NONE , // 0x5E
_NONE , // 0x5F
_NONE , // 0x60
_BACKSLASH , // 0x61 BACKSLASH
_NONE , // 0x62
_F7 , // 0x63 F7 (relocated from 0x83 to keep table under 128 chars
_NONE , // 0x64
_NONE , // 0x65
_BACKSPACE , // 0x66 BKSP
_NONE , // 0x67
_NONE , // 0x68
_1 , // 0x69 KP1
_NONE , // 0x6A
_4 , // 0x6B KP4
_7 , // 0x6C KP7
_DOT , // 0x6D KPDOT .
_NONE , // 0x6E
_NONE , // 0x6F
_0 , // 0x70 KP0
_COMMA , // 0x71 KPCOMMA ,
_2 , // 0x72 KP2
_5 , // 0x73 KP5
_6 , // 0x74 KP6
_8 , // 0x75 KP8
_ESC , // 0x76 ESC
_NONE , // 0x77 NUM
_SELECT , // 0x78 F11
_PLUS , // 0x79 KPPLUS +
_3 , // 0x7A KP3
_MINUS , // 0x7B KPMINUS -
_ASTERISK , // 0x7C KPTIMES *
_9 , // 0x7D KP9
_NONE , // 0x7E SCROLL
_NONE , // 0x7F
};
/*
_NONE , // 0x80
_NONE , // 0x81
_NONE , // 0x82
_F7 // 0x83 F7
};
*/
const uint8_t PS2Keymap_Shifted[] PROGMEM = {
_NONE , // 0x00
_F9 , // 0x01
_NONE , // 0x02
_F5 , // 0x03
_F3 , // 0x04
_F1 , // 0x05
_F2 , // 0x06
_SELECT , // 0x07
_NONE , // 0x08
_F10 , // 0x09
_F8 , // 0x0A
_F6 , // 0x0B
_F4 , // 0x0C
_TAB , // 0x0D
_QUOTE , // 0x0E QUOTE "
_NONE , // 0x0F
_NONE , // 0x10
_GRAPH , // 0x11
_SHIFT , // 0x12
_NONE , // 0x13
_CONTROL , // 0x14
_Q , // 0x15
_EXCLAMATION, // 0x16 EXCLAMATION !
_NONE , // 0x17
_NONE , // 0x18
_NONE , // 0x19
_Z , // 0x1A
_S , // 0x1B
_A , // 0x1C
_W , // 0x1D
_AT , // 0x1E AT @
_NONE , // 0x1F
_NONE , // 0x20
_C , // 0x21
_X , // 0x22
_D , // 0x23
_E , // 0x24
_DOLLAR , // 0x25 DOLLAR $
_NUMBER , // 0x26 NUMBER #
_NONE , // 0x27
_NONE , // 0x28
_SPACE , // 0x29
_V , // 0x2A
_F , // 0x2B
_T , // 0x2C
_R , // 0x2D
_PERCENT , // 0x2E PERCENT %
_NONE , // 0x2F
_NONE , // 0x30
_N , // 0x31
_B , // 0x32
_H , // 0x33
_G , // 0x34
_Y , // 0x35
_UBER , // 0x36 UBER ¨
_NONE , // 0x37
_NONE , // 0x38
_NONE , // 0x39
_M , // 0x3A
_J , // 0x3B
_U , // 0x3C
_AMPERSAND , // 0x3D AMPERSAND &
_ASTERISK , // 0x3E ASTERISK *
_NONE , // 0x3F
_NONE , // 0x40
_LESSTHAN , // 0x41 LESSTHAN <
_K , // 0x42
_I , // 0x43
_O , // 0x44
_CLOSEBRACE , // 0x45 CLOSEBRACE )
_OPENBRACE , // 0x46 OPENBRACE (
_NONE , // 0x47
_NONE , // 0x48
_GREATERTHAN, // 0x49 GREATERTHAN >
_COLON , // 0x4A COLON :
_L , // 0x4B
_CCEDIL , // 0x4C
_P , // 0x4D
_UNDERSCORE , // 0x4E UNDERSCORE _
_NONE , // 0x4F
_NONE , // 0x50
_QUESTION , // 0x51 QUESTION ?
_CIRCUMFLEX , // 0x52 CIRCUMFLEX ^
_NONE , // 0x53
_GRAVE , // 0x54 GRAVE `
_PLUS , // 0x55 PLUS +
_NONE , // 0x56
_NONE , // 0x57
_CAPS , // 0x58
_SHIFT , // 0x59
_ENTER , // 0x5A
_OPENKEY , // 0x5B OPENKEY {
_NONE , // 0x5C
_CLOSEKEY , // 0x5D CLOSEKEY }
_NONE , // 0x5E
_NONE , // 0x5F
_NONE , // 0x60
_PIPE , // 0x61 PIPE |
_NONE , // 0x62
_F7 , // 0x63 F7 (relocated from 0x83 to keep table under 128 chars
_NONE , // 0x64
_NONE , // 0x65
_BACKSPACE , // 0x66
_NONE , // 0x67
_NONE , // 0x68
_1 , // 0x69
_NONE , // 0x6A
_4 , // 0x6B
_7 , // 0x6C
_DOT , // 0x6D
_NONE , // 0x6E
_NONE , // 0x6F
_0 , // 0x70
_COMMA , // 0x71
_2 , // 0x72
_5 , // 0x73
_6 , // 0x74
_8 , // 0x75
_ESC , // 0x76
_NONE , // 0x77
_SELECT , // 0x78
_PLUS , // 0x79
_3 , // 0x7A
_MINUS , // 0x7B
_ASTERISK , // 0x7C
_9 , // 0x7D
_NONE , // 0x7E
_NONE , // 0x7F
};
Assinar:
Postagens (Atom)






















