Bryan Posted March 25, 2005 Share Posted March 25, 2005 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 Quote Link to comment Share on other sites More sharing options...
classics Posted March 25, 2005 Share Posted March 25, 2005 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 Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 25, 2005 Author Share Posted March 25, 2005 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 Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 25, 2005 Author Share Posted March 25, 2005 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 Quote Link to comment Share on other sites More sharing options...
classics Posted March 25, 2005 Share Posted March 25, 2005 I wrote some code that does 600bps via a PIA pin but the only way I could get it to not jitter like mad was to turn off antic. Can you have your code just produce a square wave and then check that with a scope? Steve Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 25, 2005 Author Share Posted March 25, 2005 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 Quote Link to comment Share on other sites More sharing options...
Sheddy Posted March 26, 2005 Share Posted March 26, 2005 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? Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 26, 2005 Author Share Posted March 26, 2005 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 Quote Link to comment Share on other sites More sharing options...
Sheddy Posted March 27, 2005 Share Posted March 27, 2005 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! Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 27, 2005 Author Share Posted March 27, 2005 Oh crap, you're right! I added the txa in to fix another problem and didn't notice what I'd done. I get tunnel vision when I code. Let me rearrange it and try again! -Bry Quote Link to comment Share on other sites More sharing options...
Sheddy Posted March 28, 2005 Share Posted March 28, 2005 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" Quote Link to comment Share on other sites More sharing options...
deathtrappomegranate Posted March 28, 2005 Share Posted March 28, 2005 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" Do you have "issues" with your body mass index...? Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 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" 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 Quote Link to comment Share on other sites More sharing options...
Sheddy Posted March 28, 2005 Share Posted March 28, 2005 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" Do you have "issues" with your body mass index...? Yeah, it is quite often a bit of a negative thing for us 6502 coders... Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 Oh yeah, this comment needs correcting: ;Each time through is 4 + 2 + 5*13 + 4 + 4 + 7 = 86 -Bry Quote Link to comment Share on other sites More sharing options...
Sheddy Posted March 28, 2005 Share Posted March 28, 2005 Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 Thanks man! -Bry Quote Link to comment Share on other sites More sharing options...
classics Posted March 28, 2005 Share Posted March 28, 2005 Very nice. Do you ever have to receive any data from the device? Steve Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 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 Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 (well, there are some status pins you can read) Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 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 Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 28, 2005 Author Share Posted March 28, 2005 Here's the whole package, including an MP3 of the test sentence. -Bry avox_test.zip Quote Link to comment Share on other sites More sharing options...
vdub_bobby Posted March 30, 2005 Share Posted March 30, 2005 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...? Quote Link to comment Share on other sites More sharing options...
Bryan Posted March 30, 2005 Author Share Posted March 30, 2005 Sorry, I should clarify. Yes, the AtariVOX has a readable EEPROM, but the SpeakJet does not. Right now my routine is designed for speech, but it could be expanded to use the EEPROM as well. -Bry Quote Link to comment Share on other sites More sharing options...
mos6507 Posted May 4, 2005 Share Posted May 4, 2005 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.