Jump to content
IGNORED

Trying to write an AtariVOX driver.


Bryan

Recommended Posts

Well, I got an AtariVOX and I'm trying to make the A8 talk to it. It isn't as easy as it is on the 2600 because you can never shut off all the things that steal cycles. The Speakjet is configured for 19.2Kbps, so that translates to 93 cycles per bit. What I do is send 10 bits every VBL, so I get an effective rate of 600 baud. I subtract some cycles so that the refresh cycles will put it closer to the correct timing, but usually with some error. I was hoping it would talk using this method, but so far I just get gibberish.

 

I was really hoping not to have to space out every bit with a fine-tuned delay...

 

;Simple AtariVOX driver for A8


;Memory Usage:
;Code starts at page 6 (1536)
;$67B contains the status of the READY pin
;$67C is the read position
;$67D is the write position
;$680-FF is the buffer. Write to here and update the pointer.





#INCLUDE "atari.h"	;Generic Atari equates


;Page 6

.ORG $0600


;Pull the extra argument



pla


;Set up the pointers:



lda #$00

sta $067C

sta $067D


;Set up PIA for reading pins 1&2



lda #$38;access DDR

sta PACTL

lda #$01;b0 is output

sta PORTA

lda #$3C;access PORTA

sta PACTL


;Set up our new vector



lda #6

ldx #(writebytes>>8 & $FF);MSB

ldy #(writebytes & $FF)	;LSB

jsr $E45C;use SETVBV to change VVBLKI


;And we're done!



rts


;Here's the communications routine.
;The SpeakJet is preconfigured for 19.2Kbps.
;Communicating at a high rate like this in software is difficult
;because of the other things happening on the bus (things the
;2600 doesn't have to worry about).
;What we're going to do is communicate during vertical blank,
;and make a crude attempt to compensate for refresh cycles.



writebytes


;See if there's anything to do



lda $067C;Get the position pointer

cmp $067D;Is there anything left to do?

beq writedone;nope! Jump to the OS.


;Process one byte



tax	;make an index

lda $0680,x;get the next byte

ldy #10	;Process 10 bits!

clc	;start bit...

rol a	;...into position 0 (& bit 7 in C)

inx	;move us to next read position

txa	;read position

and #$7F;buffer wraps at 128 entries

sta $067C;save it (for next time)

sta WSYNC;Do this so timing is always the same


;loop - this is the timing critical section:
;Perfect timing would be 93 cycles per bit, but we use 88 hoping
;a few stolen refresh cycles will bring us closer.



bitloop

sta PORTA;[4] Only affects bit 0 (data out)	


;timing loop
;Each time through is 4 + 4 + 5*13 + 4 + 4 + 7 = 88



ldx #13	;[2]

nop	;[2]



timeloop

dex	;[2]

bpl timeloop;[2/3]



dey	;[2] another bit done!

beq writedone;[2/3] all done?



ror a	;[2] position next bit

sec	;[2] roll in stop bits

bcs bitloop;[2/3] do it again! 



writedone


;Report the status:



lda PORTA;Read from the port

lsr a	;READY in b0

and #$01;only keep READY

sta $067B;save it


;Enter the VBlank routine.



jmp $E45F;SYSVBV - stage 1 Vblank



.END

 

The idea here is that you call 1536 to get the TSR part going, then put a number of bytes in the buffer at $680-6FF. Then set the write index to the number of bytes you wrote. The read index then outputs one byte per VBL until it catches up. You could keep writing to the buffer and wrap from an index of 7F to 00 and it should keep working as long as you never catch up to the read index.

 

Anyway, I'll mess with this again later unless someone else fixes it. :)

 

-Bry

Link to comment
Share on other sites

Hook it to the SIO port, set the baud rate to 19.2k and send. :)

 

If thats impossible for some reason, you should be able to get slower speed serial out of PIA if you turn off ANTIC and all interrupts. I dont think your going to get anywhere near 19.2k, but I'd love to be proven wrong.

 

Steve

Link to comment
Share on other sites

Steve,

 

I thought about SIO, but my objective is to use the AtariVOX in the intended way. My driver only sends during VBLANK, so there's really nothing else I can turn off. My next step is to drag out the scope. I really wish I had a logic analyzer.

 

-Bry

Link to comment
Share on other sites

You know what would have made this easier...

 

According to the datasheet, the SpeakJet can be set to any baud rate (by setting the right combination of pins, then sending it $55's). If it could be set to 15.7Kbps, then WSYNC could be used to time the bits.

 

-Bry

Link to comment
Share on other sites

I could probably do that but the routine has to do 19.2K or the AtariVOX won't work out of the box. The way I'm dealing with that is to do only one character per VBL, during the blanking period (which results in 60 bytes per second).

 

I pulled out my Antic timing chart and I think I know what I need to do to send it accurately.

 

After WSYNC, there are 34 cycles before we hit the 1st refresh cycle. There are 9 total, spaced every 4 cycles, so I need to see where every 93rd cycle falls, and subtract the refresh cycles from each bit's timing loop. It's more work, but I think the error is just too great with my 1st attempt.

 

-Bry

Link to comment
Share on other sites

Just skimming Bry, and I may not be understanding something, but, I can't see you restoring your data byte to A after setting up the next index position?

 

Well, I only load A once before the serial timing loop. I have to send 10 bits which are 0, followed by the byte, then 1.

 

PIA is set to only pay attention to bit 0, so... A is loaded, Carry is cleared, then I rotate the whole thing left so carry is in bit 0. From then on, I write the byte (meaning I update PORTA's bit 0), wait for the delay, rotate right, and set carry 10 times. This should put all 10 bits on pin 1.

 

I think I just need a more comprehensive timing method.

 

-Bry

Link to comment
Share on other sites

Ah, start and stop bits make up the 10 bits.

 

Sure you already found it, but this is what I was getting at:

 

 



;Process one byte



tax	;make an index

lda $0680,x;get the next byte

ldy #10	;Process 10 bits!

clc	;start bit...

rol a	;...into position 0 (& bit 7 in C)

inx	;move us to next read position

txa	;read position

and #$7F;buffer wraps at 128 entries

sta $067C;save it (for next time)

sta WSYNC;Do this so timing is always the same



 

that "txa" is bad news for your data?!

 



;Process one byte



tax	;make an index

lda $0680,x;get the next byte

ldy #10	;Process 10 bits!

clc	;start bit...

rol a	;...into position 0 (& bit 7 in C)

inx	;move us to next read position

       bmi saveindex

       ldx #0



saveindex



stx $067C;save it (for next time)

sta WSYNC;Do this so timing is always the same



?

 

Interesting project though - It'll be really cool to have a game or app chatting away!

Link to comment
Share on other sites

so easy to do that...

 

An error seems to have crept in during the massive changes I  made to your code - all 3 lines of it. The "bmi" should of course be a "bpl" :lolblue:

 

Here's my update. This one works!!

 

;Simple AtariVOX driver for A8


;Memory Usage:
;Code starts at page 6 (1536)
;$67B contains the status of the READY pin
;$67C is the read position
;$67D is the write position
;$680-FF is the buffer. Write to here and update the pointer.





#INCLUDE "atari.h"	;Generic Atari equates


;Page 6

.ORG $0600


;Pull the extra argument



pla


;Set up the pointers:



lda #$00

sta $067C

sta $067D


;Set up PIA for reading pins 1&2



lda #$38;access DDR

sta PACTL

lda #$01;b0 is output

sta PORTA

lda #$3C;access PORTA

sta PACTL


;Set up our new vector



lda #6

ldx #(writebytes>>8 & $FF);MSB

ldy #(writebytes & $FF)	;LSB

jsr $E45C;use SETVBV to change VVBLKI


;And we're done!



rts


;Here's the communications routine.
;The SpeakJet is preconfigured for 19.2Kbps.
;Communicating at a high rate like this in software is difficult
;because of the other things happening on the bus (things the
;2600 doesn't have to worry about).
;What we're going to do is communicate during vertical blank,
;and make a crude attempt to compensate for refresh cycles.



writebytes


;See if there's anything to do



lda $067C;Get the position pointer

cmp $067D;Is there anything left to do?

beq writedone;nope! Jump to the OS.


;Process one byte



tax	;make an index

clc	;clear carry (also becomes the start bit)

adc #1	;inc.

and #$7F;Wrap at index of 127

sta $067C;save it (for next time)



lda $0680,x;get the next byte

rol a	;Move C into position 0 (& bit 7 in C)



ldy #10	;Process 10 bits!

sta WSYNC;Do this so timing is always the same


;loop - this is the timing critical section:
;Perfect timing would be 93 cycles per bit, but we use 86 so the
;stolen refresh cycles will bring us closer.



bitloop

sta PORTA;[4] Only affects bit 0 (data out)	


;timing loop
;Each time through is 4 + 4 + 5*13 + 4 + 4 + 7 = 88



ldx #13	;[2]



timeloop

dex	;[2]

bpl timeloop;[2/3]



dey	;[2] another bit done!

beq writedone;[2/3] all done?



ror a	;[2] position next bit

sec	;[2] roll in stop bits

bcs bitloop;[2/3] do it again! 



writedone


;Report the status:



lda PORTA;Read from the port

lsr a	;READY in b0

and #$01;only keep READY

sta $067B;save it


;Enter the VBlank routine.



jmp $E45F;SYSVBV - stage 1 Vblank



.END

 

Right now it uses joystick port 1, but I imagine it would be more useful to use port 2. I'll post the BASIC test program as soon as I get it transferred over. It simply says the "Hello" phrase from the 2600 test code.

 

-Bry

Link to comment
Share on other sites

so easy to do that...

 

An error seems to have crept in during the massive changes I  made to your code - all 3 lines of it. The "bmi" should of course be a "bpl" :lolblue:

 

Do you have "issues" with your body mass index...?

 

Yeah, it is quite often a bit of a negative thing for us 6502 coders...

Link to comment
Share on other sites

New update! Now it works on joystick port 2!!

 

;Simple AtariVOX driver for A8 - Now uses Joystick port 2!!


;Memory Usage:
;Code starts at page 6 (1536)
;$67B contains the status of the READY pin
;$67C is the read position
;$67D is the write position
;$680-FF is the buffer. Write to here and update the pointer.





#INCLUDE "atari.h"	;Generic Atari equates


;Page 6

.ORG $0600


;Pull the extra argument



pla


;Set up the pointers:



lda #$00

sta $067C

sta $067D


;Set up PIA for reading pins 1&2



lda #$10;set b4 high (or we get an output glitch)

sta PORTA



ldx #$38;access DDR

stx PACTL



sta PORTA;b4 is output



ldx #$3C;access PORTA

stx PACTL


;Set up our new vector



lda #6

ldx #(writebytes>>8 & $FF);MSB

ldy #(writebytes & $FF)	;LSB

jsr $E45C;use SETVBV to change VVBLKI


;And we're done!



rts


;Here's the communications routine.
;The SpeakJet is preconfigured for 19.2Kbps.
;Communicating at a high rate like this in software is difficult
;because of the other things happening on the bus (things the
;2600 doesn't have to worry about).
;What we're going to do is communicate during vertical blank,
;and make a crude attempt to compensate for refresh cycles.



writebytes


;See if there's anything to do



lda $067C;Get the position pointer

cmp $067D;Is there anything left to do?

beq writedone;nope! Jump to the OS.


;Process one byte



tax	;make an index

clc	;clear carry (also becomes the start bit)

adc #1	;inc.

and #$7F;Wrap at index of 127

sta $067C;save it (for next time)



lda $0680,x;get the next byte

ror a

ror a

ror a

ror a	;Move C into bit 4



ldy #10	;Process 10 bits!

sta WSYNC;Do this so timing is always the same


;loop - this is the timing critical section:
;Perfect timing would be 93 cycles per bit, but we use 86 so the
;stolen refresh cycles will bring us closer.



bitloop

sta PORTA;[4] Only affects bit 0 (data out)	


;timing loop
;Each time through is 4 + 2 + 5*13 + 4 + 4 + 7 = 86



ldx #13	;[2]



timeloop

dex	;[2]

bpl timeloop;[2/3]



dey	;[2] another bit done!

beq writedone;[2/3] all done?



ror a	;[2] position next bit

ora #$08;[2] add in trailing stop bits

bne bitloop;[2/3] (branch always) do it again! 



writedone


;Report the status:



lda PORTA;Read from the port

lsr a	;READY in b0

and #$01;only keep READY

sta $067B;save it


;Enter the VBlank routine.



jmp $E45F;SYSVBV - stage 1 Vblank



.END

 

BASIC test program coming soon!!

 

-Bry

Link to comment
Share on other sites

Very nice. :)  

 

Do you ever have to receive any data from the device?

 

Steve

 

No. You can program the internal EEPROM to set it up and such, but you can't read anything back.

 

-Bry

Doesn't the AtariVox have readable memory....?

 

http://www.atariage.com/store/product_info...products_id=295

The AtariVox also includes 32K of non-volatile memory (EEPROM) that can be used to store high scores, saves, configuration settings, and more.

Or am I misunderstanding...?

Link to comment
Share on other sites

  • 1 month later...

At 60 characters per second, does that mean that if you used it for a game it would introduce some latency if you wanted to have it speak in sync with something happening on the screen in response to an event?

 

Wouldn't the effective speed be lower if you consider all the control information (pitch, speed, volume) that also needs to be transferred?

 

I'm just wondering whether it might be possible to write a display list interrupt routine that runs on every scanline.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...