domingo, 30 de novembro de 2008

Expansão de dispositivos

Eis o resultado de mais alguns estudos sobre a expansão de dispositivos no MSX.


O MSX tem alguns dispositivos padrão, a saber: LPT - impressora, CRT - Tela de texto, GRP - Tela gráfica, e CAS - fita cassete.

Mas além destes, outros dispotitivos podem existir, pois os dispositivos são previstos na Bios do MSX como um mecanismo padronizado de buffers para ser fazer operações de entrada/saída de dados.

Um comando típico, para "abrir" um dispositivo personalizado é:

OPEN "MEUDISP:" FOR OUTPUT AS #1,

Quando o Basic recebe um comando como o abaixo, os seguintes eventos acontecem:

- Toda vez que o MSX tenta abrir um dispositivo que não seja padrão, ele chama uma rotina de procura de dispositivos, que analisa a tabela SLTATR à procura de entradas cujo sétimo bit (máscara 0x40) sejam diferentes de zero (Durante o 'boot' a Bios varreu todos os slots e setou estes bits toda vez que encontrou as posições 06 e 07 sejam diferentes de zero)

- Ao encontrar uma ROM que contém uma entrada de dispositivo válida, a BIOS chama esta ROM com o registro A=FF e o nome do dispositivo (no caso MEUDISP) vai estar no buffer PROCNM, terminado em zero.

- O código escrito dentro da ROM do dispositivo tem que, em primeiro lugar, ver se o valor do registrador A é FF. Se for, deve analisar o nome em PROCNAM (da mesma maneira que se faz para criar comandos chamáveis via CALL). Caso o nome não bata, deve-se retornar a flag de Carry 'setada', e a Bios vai procurar pelo 'MEUDISP' em outro slot.

- Mas vamos supor que a ROM tenha o dispositivo MEUDISP e ele seja o terceiro dispositivo (pois uma ROM pode ter até 4 dispositivos expandidos). Daí a rotina deve retornar em A o número 2 e a flag Carry deve estar em zero 'resetada'

- Em seguida a Bios converte a posição do slot em que o dispositivo foi encontrado mais o número do dispositivo em um "código interno" de dispositivo. Este código é colocado no quinto byte do FCB atual. É utilizando este código que a Bios sabe como chamar o dispositivo associado ao FCB.

- Em seguida, a BIOS chama o dispositivo novamente, mas desta vez o registrador A contém o número do dispositivo chamado, o par HL contém o endereço do FCB, o registrador D contém o "código interno" do dispositivo, e o registrador E contém o modo de abertura. O modo pode ser:

"FOR INPUT" (01H)
"FOR OUTPUT" (02H)
"FOR APPEND" (08H)
"RANDOM MODE" (04H), se nenhum modo for especificado


Não vou entrar em detalhes de como abrir o dispositivo, mesmo porque não experimentei ainda o suficiente. Mas uma das coisas necessárias, é mudar o valor do primeiro byte do FCB para o modo correspondente.


Já com o dispositivo aberto, a BIOS passa dados para o dispositivo (que nada mais é do que o manipulador de um buffer) utilizando o registrador C para o dado, o registrador A para a operação desejada e o dispositivo é identificado pela variável DEVICE.

por exemplo, ao se digitar

PRINT #1, "A"

Temos 3 chamadas para o dispositivo. Em todas elas o registrador A tem o valor 6, que significa saída sequencial, e a variável DEVICE guarda o número do dispositivo identificado na hora do "open". Na primeira chamada, o valor de C era 65, que corresponde ao A maiúsculo. Na segunda e terceira, C assumiu, respectivamente, o valor 13 e 10, que correspondem a um CR-LF.

Caso houvéssemos colocado um ponto e vírgula ao final da expressão, apenas o A seria enviado e apenas uma chamada seria feita.







sábado, 23 de fevereiro de 2008

Biblioteca SPI para porta de Joystick

A porta de Joystick pode ser utilizada como uma porta SPI, permitindo assim ligar um grande número de dispositivos, como memórias flash seriais, relógios RTC, conversores A/D e D/A, displays de celulares, cartões MMC/SD, etc.

Eis abaixo um código básico para comandar um dispositivo na porta B do joystick.

Uma desvantagem do protocolo SPI é necessitar de um sinal de Chip Select para cada dispositivo. Mas isso pode ser contornado, utilizando um duplo Flip-Flop, permitindo assim que uma cadeia de dispositivos seja conectada simultaneamente.

A velocidade de transmissão deve ser algo em torno de 1,7KBytes/segundo.

; Biblioteca SPI para a porta de Joystick do MSX
; Danjovic 2008 - danjovic@vespanet.com.br
; http://hotbit.blogspot.com
;
; Version: 0.1 : 18/02/2008
; Version: 0.2 : 22/02/2008 - Added 8 clock pulses after release of CS line.

; Caracteristicas:
; Modo 0 ->; CPOL=0, CPHA=0
; Sample in Rise, shift in Fall
;
; Pinout:
; MISO =>; 1 (UP)
; MOSI =>; 6 (TRGA)
; MSSL =>; 7 (TRGB)
; MSCK =>; 8 (PULSE)

;SPIUP - Init SPI port B
;SPIDW - Release SPI port
;SPITX - Transmit a byte
;SPIRX - Receive a byte
;SPIXF - Transfer a byte



; Bits do Registro 14 do PSG
;
BMISO EQU 1 ; UP
MSKSO EQU 0FEH

; Bits do Registro 15 do PSG
;
BMOSI EQU 2 ; TRG1
BMSSL EQU 3 ; TRG2
BMSCK EQU 5 ; PULSE
ABSEL EQU 6 ; A/B SELECT

; Registros do PSG
;
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H


SPIUP: ; Initialize SPI Port
; Inputs: None
; Outputs: A - Reg 15 state
; Changes: A,EI
DI
LD A,15
OUT [PSGAD],A
IN A,[PSGRD]
LD [PSGSAV],A
SET ABSEL,A
RES BMSSL,A ; Chip Select low
OUT [PSGWR],A
RET

SPIDW: ; Release SPI Port
; Inputs: A - Reg 15 State
; Outputs: None
; Changes: A,EI
LD B,A ; Save Reg 15 State
; Release /CS line off
LD A,15
OUT [PSGAD],A
LD A,B
SET BMSSL,A
OUT [PSGWR],A

; Dummy RX - 8 clock pulses
SCF
CALL SPIRX

; Restore PSG reg 15 State
LD A,[PSGSAV]
OUT [PSGWR],A
EI
RET

SPITX: ; Transmit a byte
; Inputs: A - Reg 15 State
; C - Byte to transmit
; PSG Reg 15 already selected
; Outputs: None
; Changes: AF,B,C
LD B,8
TXBIT: RL C ; MSB -> CY Flag
SET BMOSI,A
JR C,TPUTB
RES BMOSI,A
TPUTB: OUT [PSGWR],A
; CLOCK()
SET BMSCK,A
OUT [PSGWR],A
RES BMSCK,A
OUT [PSGWR],A
;
DJNZ TXBIT


SPIRX: ; Receive a byte
; Inputs: A - Reg 15 State
; CY - MOSI line state while receiving
; PSG Reg 15 already selected
; Outputs: C - Byte received
; Changes: AF,B,C,D

; Set MOSI line state
SET BMOSI,A
JR C,RXHIGH
RES BMOSI,A
RXHIGH: OUT [PSGWR],A

LD B,8
RXBIT: ; CLOCK HI
SET BMSCK,A
OUT [PSGWR],A
LD D,A ; Save Reg 15 State
; Read bit
LD A,14
OUT [PSGAD],A
IN A,[PSGRD]
AND MSKSO
NEG ; Bit MSKSO->CY
RL C ; LSB<-CY
; CLOCK LO
LD A,15
OUT [PSGAD],A
LD A,D ; Restore Reg15 state
RES BMSCK,A
OUT [PSGWR],A
;
DJNZ RXBIT


SPIXF: ; Transfer a byte
; Inputs: A - Reg 15 State
; C - Byte to transmit
; PSG Reg 15 already selected
; Outputs: E - Byte received
; Changes: AF,B,C,D,E

LD B,8

XFBIT: ; Write bit
RL C ; MSB -> CY Flag
SET BMOSI,A
JR C,XFPUTB
RES BMOSI,A
XFPUTB: OUT [PSGWR],A
; CLOCK HI
SET BMSCK,A
OUT [PSGWR],A
LD D,A ; Save Reg 15 State
; Read bit
LD A,14
OUT [PSGAD],A
IN A,[PSGRD]
AND MSKSO
NEG ; Bit MSKSO->CY
RL E ; LSB<-CY
; CLOCK LO
LD A,15
OUT [PSGAD],A
LD A,D ; Restore Reg15 state
RES BMSCK,A
OUT [PSGWR],A
;
DJNZ XFBIT

terça-feira, 19 de fevereiro de 2008

RX232 - Primeira versão compilável

Integrei hoje a rotina de recepção de um único byte na rotina de recepçao de buffer, e já tenho uma estimativa do tamanho do 'driver' de recepção após compilado: 122 bytes.
Agora tenho que passar um pente fino na lógica, no uso dos registradores e da pilha. Mas eventuais correções não vão alterar sensivelmente o tamanho do código gerado.

Tenho ainda que construir o adaptador RS232 (com um MAX232) para poder testar o hardware.

Segue abaixo o código:
;
; Recepcao serial via
; porta de Joystick do MSX
;
; danjovic@hotmail.com
; http://hotbit.blogspot.com
;
; Versao 0.1 18/02/2008
;
; Licenca de uso: GNU GPL
;
;
; Compilado no ASMSX
; http://www.robsy.net/asmsx.htm

ORG 0E000H

.BASIC
.START RX232

;
; Bits do Registro 14 do PSG
;
BRTS EQU 0 ; UP
BRXD EQU 1 ; DOWN
MRXD EQU 0FDH ; mask for bit BRXD
;
; Bits do Registro 15 do PSG
;
BTXD EQU 2 ; TRG1
BCTS EQU 5 ; TRG2
ABSEL EQU 6 ; A/B Port select

;
; Registros do PSG
;
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H

; Variaveis em RAM
PSGSAV EQU 0F974H ; RS232 putback
; Not used in MSX
;
; Constantes

; BaudRates
;RBAUD EQU 6 ; 19200 Bauds, (6)
;RBAUD EQU 10 ; 14400 Bauds, (10)
RBAUD EQU 18 ; 9600 Bauds, (17-19)
;RBAUD EQU 42 ; 4800 Bauds, (41-43)
;RBAUD EQU 92 ; 2400 Bauds, (90-93)
;RBAUD EQU 190 ; 1200 Bauds, (188-191)

ERFUL EQU 0FFH ; Buffer cheito
ERFRM EQU 0FEH ; Framing error
ERBRK EQU 0FDH ; RTS off antes startbit


RX232:
; Entradas: HL = Ender Buffer em RAM
; C = Tam maximo do buffer
; Saicas : D = Bytes recebidos
; CY = 0, OK
; CY = 1, Error; A=Codigo erro
;
LD A,15
OUT [PSGAD],A
IN A,[PSGRD]
LD [PSGSAV],A
SET ABSEL,A
LD E,A
LD D,0
NEWBYTE: LD A,14
OUT [PSGAD],A
IN A,[PSGRD]
AND A ; Clear carry
BIT BRTS,A
LD A,D
JR NZ,EXIT ; RTS off

LD A,D
CP C
LD A,ERFUL
JR C,EXIT ; Buffer full

PUSH BC
PUSH HL
CALL RECEIVE
POP HL
POP BC
JR C,EXIT ; Error

LD [HL],A ; Save byte
INC HL
INC D ; Incr counter
JR NEWBYTE ; Next byte

EXIT: PUSH AF
LD A,15
OUT [PSGAD],A
LD A,[PSGSAV]
OUT [PSGWR],A
POP AF
RET


RECEIVE:
; Recebe um único caractere
; E - State of PSG register 15
; Currently selected PSG rgister 14
; Return Byte received in Register A

; init local variables
LD B,10 ; bits to receive
LD H,RBAUD ; Baud rate delay
LD L,H
AND A ; Clear CY
RR L ; L= L\2, Half bit timer
SET BCTS,E ; CTS ON

; CTS=ON
; Set PSG register 15
LD A,15
OUT [PSGAD],A
LD A,E
RES BCTS,E ; Reg 15 with CTS OFF
OUT [PSGWR],A

; Set PSG register 14
LD A,14
OUT [PSGAD],A

WAITSTRT: ; Awaits Start Bit
IN A,[PSGRD]
BIT BRXD,A
JR Z,MEIOBIT ;
BIT BRTS,A
JR NZ,WAITSTRT

;Break: RTS went off before
; Start bit
LD A,ERBRK
SCF
RET

; Receive 10 bits
; First is discarded,
; last is the Stop Bit
RXBIT: LD L,H ; Reload delay time

; Delay for bit time
MEIOBIT: DEC L
JR NZ,MEIOBIT

RR C
IN A,[PSGRD]
AND MRXD ; Mask RXD bit
NEG ; RXD to Carry Flag
DJNZ RXBIT ;
; Here Carry contains Stop Bit

; CTS=OFF
; Set PSG register 15
LD A,15
OUT [PSGAD],A
LD A,E ; Reg E has bit CTS off
OUT [PSGWR],A

LD A,ERFRM
CCF ; invert CY to indicate
; Framing error
RET C

LD A,C ; Se sucesso, retorna
RET ; NC, A=byte recebido

segunda-feira, 18 de fevereiro de 2008

Código base RS232

Eis o código da rotina de recepção de "buffer". Agora é preciso adaptar o código da rotina anterior para criar a rotina RXBYTE. Também é preciso acrescentar o código que chaveia do registro 14 para o registro 15 do PSG. Essa operação é necessária devido à arquitetura do PSG

RX232:
; Entradas: HL = Ender Buffer em RAM
; C = Tam maximo do buffer
; Saicas : D = Bytes recebidos
; CY = 0, OK
; CY = 1, Error, A=Codigo erro
;
LD A,15
OUT [PSGAC],A
IN A,[PSGRD]
LD [PSGSAV],A
SET ABSEL,A
LD E,A
LD D,0
NEWBYTE: LD A,14
OUT [PSGAD],A
IN A,[PSGRD]
AND A ; Clear carry
BIT RTS,A
LD A,D
JR NZ,EXIT ; RTS off

LDA A,D
CP C
LD A,ERFUL
JR C,EXIT ; Buffer full

PUSH BC
PUSH HL
CALL RXBYTE
POP HL
POP BC
JR C,EXIT ; Error

LD [HL],A ; Save byte
INC HL
INC D ; Incr counter
JR NEWBYTE ; Next byte

EXIT: PUSH AF
LD A,15
OUT [PSGAD],A
LD A,[PSGSAV]
OUT [PSGWR],A
POP AF
RET

Delineando a rotina de recepção

Após alguns tropeços enquanto escrevia a rotina de recepção de um "buffer", resolvi definir melhor o funcionamento do código que chama a rotina de recepção de dados, do post anterior.

Eis abaixo o fluxograma da rotina, que deve ser chamada com 2 parâmetros:
- Endereço do buffer que vai receber os dados
- Tamanho do buffer de recepção

Uma simplificação importante que fiz, foi que considerar que o buffer está vazio na inícion da chamada da rotina. Isso evita a necessidade de uma chamada de inicialização do buffer e simplifica o tratamento de erros.

Outra vantagem é não depender diretamente de um buffer em RAM para receber temporariamente os caracteres da RS232, o que gerava a necessidade de um LDIR para o destino dos bytes. Com o esquema atual, basta apontar para a região de memória que deve receber os dados e dizer qual o tamanho máximo do buffer de dados.

Caso tudo a recepção tenha se processado corretamente, a quantidade de bytes recebidos é retornada. Caso contrário, um dos códigos de erro é retornado:
  • ERFUL - Buffer Cheiro
  • ERFRA - "Framing error", ou stop bit recebido incorretamente
  • ERBRK - Sinal RTS foi desativado pelo PC antes que o "Start" Bit fosse enviado.


sexta-feira, 15 de fevereiro de 2008

Código para a recepção RS232

Estive trabalhando no código para a recepção RS232 na porta de joystick. .

Eis um trecho da rotina de recepção de dados, que aguarda pelo Start Bit, tão logo ele seja detectado, recebe os 10 bits da palavra de dados, dentro de um só loop, para simplificar a temporização. Ao final da rotina, flag Carry contém o estado do Stop bit. Note que start bit é descartado, pois ele já havia sido detectado.
Outro detalhe importante é que o primeiro delay é de meio bit, e os subsequentes de 1 bit inteiro. Isso faz com que a amostragem seja feita no meio do tempo de bit, diminuindo assim a taxa de erro. Após o stop bit ser amostrado, ainda temos meio tempo de bit disponível, o que é importante, pois é necessário mudar registro do PSG antes de levantar novamente o sinal CTS, para fazer o PC esperar o MSX processar o dado antes de enviar outro.

;...
WAITSTART: IN A,(PSGRD)
BIT RXD,A ; Start bit?
JR Z,MEIOBIT ;yes, wait 1/2 bit before start
; to acquire samples
BIT RTS,A ; PC stopped TX ?
JR Z,WAITSTART ; No, sample again
JP BREAKERROR

MEIOBIT: LD L,BITTIME ;
SRL L ; divide by two
LD B,10 ; Ten bits.
PROXBIT: CALL DELAYBIT ; Wait Bit Time
RR C ; CY->7...0->CY
IN A,(PSGRD) ; Sample bit
AND RXD
NEG ; Bit RXD->CARRY
LD L,BITTIME ; Reload delay preset
DJNZ PROXBIT ; Wait full bit time before
; get another sample
LD A,(15)
OUT (PSGAD),A ; Select Register 15
LD A,E ; Previous state of reg 15
SET RTS,A
OUT (PSGWR),A ; deassert RTS
LD E,A ; Save state of reg15

JR NC,FRAMERR ; If stop bit=0 an framing
; error has occoured
;...
PROCESSABIT:

quinta-feira, 14 de fevereiro de 2008

Recepção serial na porta de Joystick

Fiz uns testes para determinar se o controle de fluxo por RTS/CTS poderia ser utilizado para fazer o PC esperar o MSX atender o pedido de solicitação de transmissão, e também para ver se a transmissão pode ser interrompida a qualquer momento. Os resultados do teste demonstraram que sim.

A correspondência entre os pinos da porta de joystick do MSX e a porta de PC pode ser vista na figura abaixo. Entre os dois deve ser utilizado um conversor de nível, tipo um MAX232.

MSX – Porta Joystick Dir PC – Porta Serial
Função Pino RS232 - Pino RS232
DOWN 2 RxD <- 3 TxD
UP 1 RTS <- 7 RTS
TRGA 6 TxD -> 2 RxD
TRGB 7 CTS -> 8 CTS
GND 9 GND - 5 GND

WiznetX (correção do circuito)

Algumas pessoas já me questionaram sobre como fazer a ligação de um módulo Wiznet WIZ810MJ no MSX.



Este módulo de rede é baseado no chip WM5100 e tem dois modos de interligação: SPI e memória. No modo memória, o chipa aparece para o 'host' como uma área endereçável de 32Kbytes, de acordo com o mapa abaixo (vide data sheet):




O WM5100 é alimentado por uma tensão de 3,3Volts, mas tem tolerância a sinais TTL, o que torna bem fácil a conexão ao MSX. Além disso, os sinais de controle têem a mesma polaridade (nível ativo) do Z80.

Então, todo o hardware necessário para conectar este módulo ao MSX se resume a um decodificador e um regulador de tensão LDO, que possa fornecer ao menos 183mA.

O circuito abaixo é de uma placa de protótipo. O decodificador é um LS138, que permite mapear a placa no intervalo 0000-7FFF. A temporização dos sinais /RD e /WR teve que ser adaptada para o chip W5100 pois difere em alguns pontos do Z80, em especial o sinal /WR, que fica ativo 1 ciclo de clock após o sinal MREQ do Z80. Segundo o "data sheet" do W5100 os sinais /RD e /WR têm que acontecer simultaneamente ao sinal /CS. Eu fiz umas perguntas sobre a temporização destes sinais no site do fabricante do CHIP, pois achei meio crótica a temporização "oficial" que diz que o sinal de /RD ou de /WR deve acontecer em, no máximo 1ns após o sinal de /CS, e deve retornar a nível alto 1ns antes do sinal de /CS. Mas caso seja assim mesmo, um latch controlado pelo clock do Z80 deve resolver a situação.

O regulador é o TC1108, que tem capacidade de fornecer até 300mA.




Abaixo está uma sugestão de placa para o protótipo. O módulo Wiznet deve ser montado do lado de baixo da placa.



Como eu não tenho um módulo desses, não devo montar uma placa dessas tão cedo, mas quem se aventurar a montar, seguem dois conselhos:

-O data sheet do WM5100 estipula um tempo máximo de 1ns entre o sinal de Chip Select e o READ ou Write, o que para mim significa que os sinais têem que ser simultâneos. O decodificador do meu circuito induz um certo atraso entre o sinal SLCTSLT e o CS, que eu estimo entre 30 a 40ns. Para a leitura isso não deve ser problema, pois já que o Data sheet não estipula tempo mínimo eu suponho que o sinal de RD Possa iniciar antes do sinal CS. Já para a escrita, o Z80 atrasa em 1 ciclo de clock (280ns) o sinal de WR em relaçao ao sinal MREQ. Pode ser que isso não traga problema algum, mas sempre é bom ficar e olho.

-Quando o circuito endereça na faixa de 4000-BFFF, o pino A14 está em nível alto entre - 4000-7FFF e em nível baixo entre 8000-BFFF. Isso significa que o mapa de memória vai aparecer trocado, ou seja, as áreas do TX buffer e RXbuffer vêm primeiro, entre 4000-7FFF, e os registros vêm depois, na faixa de 8000-BFFF.

sexta-feira, 18 de janeiro de 2008

Recepção RS-232 na porta de Joystick

Tenho uma estratégia para poder fazer a parte de recepção, utilizando os sinais RTS e CTS.

O Sinal RTS serve para indicar ao dispositivo de recepção, que o dispositivo de transmissão quer enviar dados. Já o sinal CTS diz é a resposta que o dispositivo de recepção dá ao dispositivo de transmissão de que já pode receber os dados.

Pois bem, utilizando estes sinais é possível sincronizar o MSX com o PC criando assim uma rotina de recepção mais inteligente, de forma a sinalizar ao PC quando este deve aguardar antes de enviar os dados. Desta maneira pode-se perder um tempo salvando o caractere, ou mesmo movendo um buffer.

É possível, por exemplo redirecionar a entrada (de teclado) para ler a partir da RS232 (como no apple) utilizando o hook da interrupção externa do Z80, gerada pelo VDP, que ocorre a 60Hz. O funcionamento é o seguinte:

Quando o VDP gera uma interrupção, a BIOS chama o Hook HTIMI no endereço 0FD9Fh. Neste momento pode-se checar a entrada de joystick para ver se o PC ativou o sinal RTS. Se o sinal RTS não estiver ativo, então não há caracteres a serem enviados e a rotina termina, devolvendo o controle à BIOS.

Mas se o sinal RTS estiver ativo, as interrupções são desabilitadas, e a rotina de recepção de um caractere é chamada. Esta rotina ativa o sinal CTS para indicar ao PC que o MSX está pronto para receber os dados.

O MSX então aguarda pelo start bit, e em seguida recebe os 8 bits do dado, e o stop bit. Depois ela desativa novamente o sinal CTS e vai processar o caractere recebido.

O Stop bit é checado para garantir que é válido. Se for inválido (“0”), então o caractere recebido é ignorado, caso contrário, ele é colocado no buffer do teclado, que é incrementado. Se o buffer estiver cheio, então a rotina termina. Se não estiver, o MSX checa se o sinal RTS ainda está ativo, e se estiver, ele recebe o próximo caractere, caso contrário, retorna

segunda-feira, 14 de janeiro de 2008

Conversor TTL-232 testado

Acabei de testar com sucesso o circuito de conversão TTL para RS-232 do post anterior. Agora o projeto está completo.

LPRINT na porta de Joystick - Código em BASIC

Acabei de testar a impressão via 'hook' na porta de joystick. O código tinha um pequeno erro mas já corrigi.

O programa ocupa apenas 83 na memória e é carregado a partir do endereço &HE000

A listagem abaixo foi capturada utilizando o lprint para o PC, após o programa ter sido executado:


5 '
10 ' Imprime na porta de Joystick B
20 ' via protocolo rs-232, 9600,N,8,1
30 '
40 ' danjovic@hotmail.com
50 '
60 FOR E=0 TO 82
70 READ B$:POKE &HE000+E,VAL("&H"+B$)
80 NEXT E
90 '
100 DEFUSR=&HE047: B=USR(0)
110 '
200 DATA F3,F5,C5,E5,4F,26,12,3E
210 DATA 0F,D3,A0,DB,A2,CB,F7,D3
220 DATA A1,CD,1C,E0,E1,C1,F1,A7
230 DATA FB,33,33,C9,6C,CD,34,E0
240 DATA 06,08,6C,CB,09,DC,3D,E0
250 DATA D4,34,E0,10,F5,2E,12,CD
260 DATA 3D,E0,47,C9,CB,97,D3,A1
270 DATA 2D,C2,38,E0,C9,CB,D7,D3
280 DATA A1,2D,C2,41,E0,C9,00,21
290 DATA 00,E0,22,B7,FF,3E,C3,32
300 DATA B6,FF,C9

domingo, 13 de janeiro de 2008

Conversor TTL-RS232

Fiz o layout de um conversor de nível RS232 para TTL a partir de um esquema que encontrei. Aproveitei apenas a parte de transmissão, que resultou no circuito abaixo.


Fiz o "layout" de uma placa de circuito impresso em face simples, de forma que ficasse o menor possível. Segue abaixo uma imagem em 300 dpi




E a disposiçao dos componentes na placa fica como a figura abaixo:




Os dois conectores são do tipo para cabo (solda) mas são soldados diretamente na placa, um virado para cima e outro virado para baixo. Assim só foi necessário um Jumper para ligar o pino 5 do conector de joystick do MSX (Vcc) ao circuito.

LPRINT na porta de Joystick

Estou trabalhando numa rotina para capturar o Hook de impressão e redirecionar o caractere à porta de joystick. O código, até o presente momento, consome 86 bytes.



;
; Impressao serial via
; porta de Joystick do MSX
;
; danjovic@hotmail.com
; http://hotbit.blogspot.com
;
; Versao 1.0 14/01/2008
;
; Licenca de uso: GNU GPL
;
;
; Compilado no ASMSX
; http://www.robsy.net/asmsx.htm


ORG 0E000H

.BASIC
.START INSTALA



; Bits do Registro 15 do PSG
BTXD EQU 2
ABSEL EQU 6

; Registros do PSG
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H


; BaudRates
;BAUD EQU 6 ; 19200 Bauds, (6)
;BAUD EQU 10 ; 14400 Bauds, (10)
BAUD EQU 18 ; 9600 Bauds, (17-19)
;BAUD EQU 42 ; 4800 Bauds, (41-43)
;BAUD EQU 92 ; 2400 Bauds, (90-93)
;BAUD EQU 190 ; 1200 Bauds, (188-191)



;
; Envia o Caractere no reg A
; para a porta de B (Joystick)
; 9600,8,n,1

PRNTJ232:
;CALL 0a2h
DI
PUSH AF
PUSH BC
PUSH HL

LD C,A ; Caractere a ser impresso
LD H,BAUD ; define taxa Baud

LD A,15 ; Registro 15
OUT [PSGAD],A
IN A,[PSGRD]
;LD [PSGSAV],A
SET ABSEL,A ; Porta Joystick B
OUT [PSGWR],A
;LD B,A ; salva conteudo reg 15

CALL SND232
;LD A,[PSGSAV]
;OUT [PSGWR],A

POP HL
POP BC
POP AF
AND A
EI
INC SP ; descarta stack
INC SP
RET




SND232:
; Entradas:
; C: Byte a ser transmitido
; A: Estado atual do registrador 15 do PSG
; H: Constante para Baud Rate
;

;
; Envia Start bit (txd=0)
;
LD L,H ; 4+1
CALL SND0 ; 17+1 + (SEND0)

;
; 8 bits do dado, LSbit primeiro
;
LD B,08H ; 7+1
S20:
LD L,H ; 4+1
RRC C ; 8+2
CALL C,SND1 ; 17+1 + (SEND0)/ 10+1 F
CALL NC,SND0 ; 17+1 + (SEND0)/ 10+1 F
DJNZ S20 ; 13+1 b


;
; Stopbit - retorna linha txd para IDLE
;
LD L,BAUD ; 8
CALL SND1 ; 17+1 + (SEND1)
LD B,A ; 4+1
RET ; 10+1


;
; Envia um bit 0
;
SND0:
RES BTXD,A ; txd=0 8+2
OUT [PSGWR],A ; 11+1
S01: DEC L ; 4+1
JP NZ,S01 ; 10+1 ;
RET ; 10+1

;
; Envia um bit 1
;
SND1:
SET BTXD,A ; txd=1 8+2
OUT [PSGWR],A ; 11+1
S11: DEC L ; 4+1
JP NZ,S11 ; 10+1 ;
RET ; 10+1


PSGSAV:
DS 1


;
; Instala subrotina no
; HOOK da impressora
;
; Do livro +50 dicas para o MSX
;
HLPT EQU 0FFB6H
;
INSTALA:
LD HL,PRNTJ232
LD [HLPT+1],HL
LD A,0C3H
LD [HLPT],A
RET

sábado, 12 de janeiro de 2008

Serial Bitbang a 19200 bauds na porta de Joystick

Fiz funcionar a rotina de transmissão serial na porta de joystick. Removidos alguns erros de lógica, consegui transmitir para o PC nas seguintes velocidades:

19200 Bauds, (6)
14400 Bauds, (10)
9600 Bauds, (17-19)
4800 Bauds, (41-43)
2400 Bauds, (90-93)
1200 Bauds, (188-191)

Toda a temporização é feita por software. Os números em parênteses são o parâmetro de temporização. As velocidades de 14400 e 19200 são meio críticas, mas funcionam bem.

A conexão com o PC é através do pino 6 da porta de Joystick B. Eu utilizei um MAX232, alimentado pelo pino 5 (Vcc), mas há outras alternativas[1], [2], embora eu ainda não as tenha testado.

O código fonte encontra-se abaixo.

;
; Rotinas de impressão na porta
; de Joystick do MSX
;
; danjovic@hotmail.com
; http://hotbit.blogspot.com
;
; Versao 0.5 12/01/2008
;
; Licenca de uso: GNU GPL
;
;


ORG 09000H

; Compilado no ASMSX
; http://www.robsy.net/asmsx.htm
.BASIC
.START PRNTJ232

;
; Bits do Registro 15 do PSG
;
BTXD EQU 2
BPLS EQU 5
ABSEL EQU 6

;
; Registros do PSG
;
PSGAD EQU 0A0H
PSGWR EQU 0A1H
PSGRD EQU 0A2H


;
; Constantes

; BaudRates
;BAUD EQU 6 ; 19200 Bauds, (6)
;BAUD EQU 10 ; 14400 Bauds, (10)
BAUD EQU 18 ; 9600 Bauds, (17-19)
;BAUD EQU 42 ; 4800 Bauds, (41-43)
;BAUD EQU 92 ; 2400 Bauds, (90-93)
;BAUD EQU 190 ; 1200 Bauds, (188-191)


;
; Rotina de teste de impressão
; na porta de Joystick
;



PRNTJ232:
DI
LD A,15
OUT [PSGAD],A
IN A,[PSGRD]
LD [PSGSAV],A

SET ABSEL,A ; JOY B
SET BTXD,A ; SDA=1

SYNC:
SET BPLS,A ; start sync
OUT [PSGWR],A
NOP
NOP
NOP
NOP
RES BPLS,A ; stop sync
OUT [PSGWR],A
LD B,A ; B=conteudo reg 15

MUDABAUD:
LD H,BAUD
LD DE,MENSAGEM
REPETE:
LD A,[DE]
INC DE
OR A
JR Z,FIM
LD C,A
CALL SND232
JR REPETE

FIM:
EI
RET


MENSAGEM:
DB "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 0123456789 ",0

PSGSAV:
DS 1


SND232:
; Entradas:
; C: Byte a ser transmitido
; B: Estado atual do registrador 15 do PSG
; H: Constante para Baud Rate
;
; Modifica A,F,B,C,L

LD A,B ; B=Estado registro 15 PSG

;
; Start bit (txd=0)
;
LD L,H ; 4+1
CALL SND0 ; 17+1 + (SEND0)

;
; 8 bits do dado, LSbit primeiro
;
LD B,08H ; 7+1
S20:
LD L,H ; 4+1
RRC C ; 8+2
CALL C,SND1 ; 17+1 + (SEND0)/ 10+1 F
CALL NC,SND0 ; 17+1 + (SEND0)/ 10+1 F
DJNZ S20 ; 13+1 b<>0/ 8+1 b=0

;
; Stopbit - retorna linha txd para IDLE
;
LD L,BAUD ; 8
CALL SND1 ; 17+1 + (SEND1)
LD B,A ; 4+1
RET ; 10+1


;
; Envia um bit 0
;
SND0:
RES BTXD,A ; txd=0 8+2
OUT [PSGWR],A ; 11+1
S01: DEC L ; 4+1
JP NZ,S01 ; 10+1 ;
RET ; 10+1

;
; Envia um bit 1
;
SND1:
SET BTXD,A ; txd=1 8+2
OUT [PSGWR],A ; 11+1
S11: DEC L ; 4+1
JP NZ,S11 ; 10+1 ;
RET ; 10+1