Jump to content
IGNORED

Bit-Bang Serial (RS232) Output via Joystick Pin (PORTA-Bit 0)


mytek

Recommended Posts

OK I wasn't far off on the idea that the data was inverted. Problem was when I took out the data inversion the first time I had forgotten to reverse both the STOP and START bits which were also inverted. So I went in and made those changes, and then stuff started to work... well sort of. It seems that when I send a listing as in LIST "R:" from within BASIC (or LIST #R: from within ASSEMBLER/EDITOR) the first 8 characters are garbled, but everything afterwards is fine :?

 

ttl-timing.PNG

 

So I got this on a scope and fed it a continuous stream of alternating bits 10101010 which is a capital 'U' in ASCII (ASCII 85 = 'U') . This was the same as used in the diagram above. So on the scope each bit including START and STOP were registering as 3.3 ms in duration which appears to be correct for 300 baud. And it rendered the same on the scope as on the diagram. But also just like when I sent the listing, the first few characters received were garbled, and then all is perfect thereafter. Very strange indeed.

 

Here is the BASIC test program I used...

10 OPEN $1,12,0,"R:"
20 PUT #1,85
30 GOTO 20

I'm once again confused :(

 

So here are the code changes thus far...

0850 ; SERIALOUT - FIRST INVERT DATA
0860 ;
0870 SEROUT
0880  NOP  ;*** REMOVED EOR #$FF
0885  NOP  ;*** NO INVERSION OF DATA
0890  STA BUFFER
0900 ;
0910 ; DISABLE INTERRUPTS
0920 ;
0930  SEI
0940  LDA #0
0950  STA NMIEN
0960  STA DMACTL
0970 ;
0980 ; SEND STARTBIT
0990 ;
1000  LDA #0  ;*** REMOVED INVERSION
1010  STA PORTA
1020  JSR BITWAIT
1030 ;
1040 ; SEND CHARACTER DATA
1050 ;
1060  LDY #8
1070  STY COUNT
1080 ;
1090 SENDBYTE
1100  LDA BUFFER
1110  STA PORTA
1130  ROR BUFFER
1140  JSR BITWAIT
1150  DEC COUNT
1160  BNE SENDBYTE
1170 ;
1180 ; SEND STOPBIT
1190 ;
1200  LDA #1  ;*** REMOVED INVERSION
1210  STA PORTA
1220  JSR BITWAIT

- Michael

 

 

EDIT: the listing problem was worse in the ASSEMBLER/EDITOR environment as can be seen below...

 

frc0qrq.png

 

The first line got pretty much toasted, and probably also put out some sort of weird control code that indented the second line of the listing. But if I press break and then reissue the command to list to the R: device, I get an identical result as above. Go figure?

 

3 friggin days spent on this project thus far :mad: but at least I'm making headway and seeing stuff appear in the terminal that is getting close to being right :grin: .

Edited by mytekcontrols
Link to comment
Share on other sites

Couple of caveats: I haven't looked at the .PDF or found my original book so I don't know what they are doing with the subroutine BITWAIT. I recall writing something to do a transfer from 8-bit to ST or IBM via J/S port. There is no doubt in my mind that I added a 1/2 bit delay to get the data to transfer properly. This insured that the receiver was synced to the middle of the data sent. I can't remember how I did it, it could have been as simple as having my BITWAIT type subroutine adjusted and called 3 times for start bit and twice for actual data. Anyway, it worked fine after that up to 19k BAUD. Old age is hitting me with a vengeance but I think you want 1.5 BITWAIT for the start bit and 1 BITWAIT for everything after that.

  • Like 1
Link to comment
Share on other sites

Couple of caveats: I haven't looked at the .PDF or found my original book so I don't know what they are doing with the subroutine BITWAIT. I recall writing something to do a transfer from 8-bit to ST or IBM via J/S port. There is no doubt in my mind that I added a 1/2 bit delay to get the data to transfer properly. This insured that the receiver was synced to the middle of the data sent. I can't remember how I did it, it could have been as simple as having my BITWAIT type subroutine adjusted and called 3 times for start bit and twice for actual data. Anyway, it worked fine after that up to 19k BAUD. Old age is hitting me with a vengeance but I think you want 1.5 BITWAIT for the start bit and 1 BITWAIT for everything after that.

 

Thanks. I'll let you know what I find out. Also wondering if something isn't right with the 'handler' aspect, possibly stomping on my one byte data buffer initially and then some how clearing up later. I'm so close at this point to having what I want.

 

- Michael

Link to comment
Share on other sites

I promise, I will download the book so I can get out of the dark. ☺

 

Could be a STATUS being issued by the Atari. If the first chr is a @ or A, B, C, it is looking for a printer or [P, Q, R, S] it's looking for serial device R1-R4. If that is the case, you would just need something in the handler to respond w/o doing anything on the j/s port.

Link to comment
Share on other sites

I promise, I will download the book so I can get out of the dark. ☺

 

Could be a STATUS being issued by the Atari. If the first chr is a @ or A, B, C, it is looking for a printer or [P, Q, R, S] it's looking for serial device R1-R4. If that is the case, you would just need something in the handler to respond w/o doing anything on the j/s port.

 

No worries I figured it out :grin:

 

The PACTL commands were incorrect. It was amazing it even worked at all, although obviously not right.

 

Here is the complete (fixed) R: Handler assembly listing...

10 ;*********************************
20 ;*           R-Handler           *
30 ;*     JOY PORTA-0 R: DEVICE     *
40 ;*    Adapted from Hackerbook    *
50 ;*           (Page 72)           *
60 ;*                               *
70 ;* INITIALIZE - BY CALLING $0689 *
80 ;*                               *
90 ;*********************************
0100 ;
0110 COUNT  = $0600
0120 BUFFER = $0601
0130 RSENTRY = $032C
0140 PACTL = $D302
0150 PORTA = $D300
0160 NMIEN = $D40E
0170 DMACTL = $D400
0180 EOL = $9B
0190 CR = $0D
0200 LF = $0A
0210 K = 150        110 & 300 BAUD
0220 L = 6          300 BAUD
0230 ;              L=18 FOR 110 BAUD
0240 ;
0250     *=$0602
0260 ;
0270 HANDLTAB
0280  .WORD OPEN-1
0290  .WORD CLOSE-1
0300  .WORD GETBYTE-1
0310  .WORD PUTBYTE-1
0320  .WORD STATUS-1
0330  .WORD SPECIAL-1
0340  .BYTE 0,0,0,0  FILL REST WITH 0
0350 ;
0360 ; THE OPEN ROUTINE
0370 ;
0380 OPEN = *
0390 INIT
0400  LDA #$38
0410  STA PACTL
0420  LDA #1         SELECT TXD BIT
0430  STA PORTA
0440  LDA #$3C
0450  STA PACTL
0460  LDA #1
0470  STA PORTA
0480 SUCCESS
0490  LDY #1
0500  RTS
0510 ;
0520 ; THE CLOSE DUMMY ROUTINE
0530 ; ONLY RETURN SUCCESS IN Y (1)
0540 ;
0550 CLOSE = SUCCESS
0560 NOTIMPL
0570  LDY #146      RETURN WITH Y=146
0580  RTS
0590 ;
0600 ; THE FOLLOWING COMMANDS ARE
0610 ; NOT IMPLEMENTED SO GET ERROR
0620 ; CODE 146
0630 ;
0640 GETBYTE = NOTIMPL
0650 STATUS  = NOTIMPL
0660 SPECIAL = NOTIMPL
0670 ;        THE PUTBYTE COMMAND
0680 ;        DATA IN ACCU
0690 ;        STATUS IN Y (=1)
0700 ;
0710 PUTBYTE
0720  CMP #EOL
0730  BNE NOEOL
0740 ;
0750 ; IF EOL GIVE CRLF TO DEVICE
0760 ;
0770  LDA #CR
0780  JSR SEROUT
0790  LDA #LF
0800 NOEOL
0810  JSR SEROUT
0820  LDY #1
0830  RTS
0840 ;
0850 ; SERIALOUT
0860 ;
0870 SEROUT
0880  STA BUFFER     PRESERVE ACC
0890 ;
0900 ; DISABLE INTERRUPTS
0910 ;
0920  SEI
0930  LDA #0
0940  STA NMIEN
0950  STA DMACTL
0960 ;
0970 ; SEND STARTBIT
0980 ;
0990  LDA #0
1000  STA PORTA
1010  JSR BITWAIT
1020 ;
1030 ; SEND CHARACTER DATA
1040 ;
1050  LDY #8
1060  STY COUNT
1070 ;
1080 SENDBYTE
1090  LDA BUFFER
1100  STA PORTA
1110  ROR BUFFER
1120  JSR BITWAIT
1130  DEC COUNT
1140  BNE SENDBYTE
1150 ;
1160 ; SEND 2 STOPBITS
1170 ;
1180  LDA #1
1190  STA PORTA
1200  JSR BITWAIT
1210  JSR BITWAIT
1220 ;
1230 ; ENABLE INTERRUPTS
1240 ;
1250  LDA #$22
1260  STA DMACTL
1270  LDA #$FF
1280  STA NMIEN
1290  CLI
1300  RTS            DONE SENDING
1310 ;
1320 ; THE BIT TIMING ROUTINE
1330 ; FOR AN EXACT BAUDRATE
1340 ;
1350 BITWAIT
1360  LDX #K
1370 LOOPK
1380  LDY #L
1390 LOOPL
1400  DEY
1410  BNE LOOPL
1420  DEX
1430  BNE LOOPK
1440  RTS
1450 ;
1460 ; ROUTINE FOR INSTALLING THE
1470 ; RS232 HANDLER
1480 ;
1490 INITHAN
1500  LDA #'R        DEVICE NAME
1510  STA RSENTRY
1520  LDA #HANDLTAB&255
1530  STA RSENTRY+1
1540  LDA #HANDLTAB/256
1550  STA RSENTRY+2
1560  JMP OPEN
1570  .END

Download Atari Compatible Assembly Code: JOYRHAND.ASM

 

To test under the ASSEMBLER/EDITOR CART do the following:

  1. ENTER #D:JOYRHAND.ASM<CR>
  2. ASM<CR>
  3. BUG<CR>
  4. G589<CR>
  5. X<CR>
  6. LIST #R:<CR>

You can also hop into BASIC by going to DOS and then load a disk based version so you don't need to yank out the cartridge (BASIC++). Enter the following code to send a CR/LF following by all the printable ASCII characters.

 

10 OPEN #1,12,0,"R:"

20 PUT #1,13:PUT #1,10

30 FOR NUM=0 TO 94

40 PUT #1,32+NUM

50 NEXT NUM

 

And of course LIST "R:" will send a BASIC listing via the joystick serial connection.

 

Later I'll put together a BASIC program that will automatically load the handler code and initialize it.

 

In order to actual use this as a 'real' RS232 connection you will need to add a simple circuit to level shift and invert the TTL signal coming from Pin 1 on joystick #1. The upper half of the circuit in the following diagram will do the trick.

 

simple-ttl-rs232-level-converter-using-t

 

Also it might be necessary to jumper pin 7 to 8 as well (you can try it without, but my computer terminal didn't do anything without it).

 

So basically this can be built inside the D-Sub 9F shell on the joystick side, with pin #1 as the TTL-TXD connection, pin #7 as +5V, and pin #8 as GND. The 10K resistor is optional since the Atari already has current limiting resistors inline with all of the joystick ports. If you can't find a BC557 transistor (I certainly couldn't), then substitute any general purpose PNP transistor such as the 2N2907.

 

And yes both connectors (Terminal and Joystick) use the same 9 pin D-Sub female connector so be sure to mark which end is which.

 

Enjoy :)

 

- Michael

 

 

EDIT: Oh yeah don't forget to set your RS232 Terminal to 1 start bit, 8 data bits, 2 stop bits, parity = none, no handshake, 300 baud. Any protocol should work (ANSI, ect.).

Edited by mytekcontrols
  • Like 4
Link to comment
Share on other sites

Could the Atari joystick ports communicate with an Arduino Mini pro by directly connecting the RX/TX pins (https://www.arduino.cc/en/Main/arduinoBoardProMini)?

 

I agree with Kyle, there should be no problem. I do stuff like this with PIC's all the time, and the Arduino has similar I/O characteristics. The only thing I would suggest is maybe using a 3K pull-up to +5V, since the Atari's PIA being TTL has a rather feeble logic high state. But you'll only need to do this if you are experiencing erratic behavior. I take it your going to use the Aruino's built-in UART.

 

Now I have a question of my own. Does anyone know of a good program to do a dump of Page 6 memory and create either BASIC data statements or maybe better yet a string variable equivalent for the data?

 

- Michael

Edited by mytekcontrols
Link to comment
Share on other sites

 

Now I have a question of my own. Does anyone know of a good program to do a dump of Page 6 memory and create either BASIC data statements or maybe better yet a string variable equivalent for the data?

 

 

I was compelled to see how rusty my brain is:

10 for i=1536 to 1791 step 8
30 print i;" data ";peek(i);
30 for j=1 to 7
40 print ",";peek(i+j);
50 next j:print
60 next i 
  • Like 2
Link to comment
Share on other sites

 

 

I was compelled to see how rusty my brain is:

10 for i=1536 to 1791 step 8
30 print i;" data ";peek(i);
30 for j=1 to 7
40 print ",";peek(i+j);
50 next j:print
60 next i 

 

I like that ;)

 

And it's very simple.

 

Thank you,

 

- Michael

Link to comment
Share on other sites

OK here's a simple BASIC loader and test routine.

10 REM ** LOAD R:HANDLER TO MEMORY **
20 FOR AD=1538 TO 1691
30 READ B
40 POKE AD,B
50 NEXT AD
60 N=USR(1673):REM ** INIT R:HAND **
70 REM 
80 REM ======= PROGRAM MAIN =======
100 REM setup input/output
110 REM 
120 OPEN #1,4,0,"K:"
130 OPEN #2,12,0,"R:"
140 REM 
150 REM clear screen & prompt input
160 REM 
170 GRAPHICS 0:? "READY "
180 REM 
190 REM get key and send to R: device
200 REM 
210 GET #1,KEY:PUT #2,KEY:GOTO 210
220 REM 
4000 DATA 17,6,37,6,40,6,43,6
4010 DATA 40,6,40,6,0,0,0,0
4020 DATA 169,56,141,2,211,169,1,141
4030 DATA 0,211,169,60,141,2,211,169
4040 DATA 1,141,0,211,160,1,96,160
4050 DATA 146,96,201,155,208,7,169,13
4060 DATA 32,61,6,169,10,32,61,6
4070 DATA 160,1,96,141,1,6,120,169
4080 DATA 0,141,14,212,141,0,212,169
4090 DATA 0,141,0,211,32,126,6,160
4100 DATA 8,140,0,6,173,1,6,141
4110 DATA 0,211,110,1,6,32,126,6
4120 DATA 206,0,6,208,239,169,1,141
4130 DATA 0,211,32,126,6,32,126,6
4140 DATA 169,34,141,0,212,169,255,141
4150 DATA 14,212,88,96,162,150,160,6
4160 DATA 136,208,253,202,208,248,96,104
4170 DATA 169,82,141,44,3,169,2,141
4180 DATA 45,3,169,6,141,46,3,76
4190 DATA 18,6
 

Download BASIC File: RHANDOUT.BAS

 

This little program essentially does 3 things...

  1. Loads R: Handler code into Page 6 memory
  2. Initializes the new handler
  3. Redirects keyboard input to the R: device

So what you have is a very simple RS232 terminal program running on your Atari. Now keep in mind that this is running the bare essentials, so it doesn't understand things like backspace or delete, which if pressed will send out some strange symbols. But it does recognize the RETURN key, and will send a <CR><LF>.

 

The purpose of this little program is to give someone a basis to build up on and develop their own unique twist.

 

Enjoy :)

 

- Michael

 

 

EDIT: Hey I think I'm getting my Atari programming legs back 8)

Edited by mytekcontrols
  • Like 4
Link to comment
Share on other sites

Question: Is there someway to read the 6520 PIA port to know what the output pin state is?

 

The reason I am asking, is that I would like to write a variation of this code that respects the other pins on the port that I'm using to send out the serial data. So let's say this code gets combined with someone's BASIC program that also manipulates bits as outputs. I don't want this routine to stomp all over it and change any of the other output pin logic states. I know I can implement masking to prevent this, but that assumes I can read the logic state of the port pins to begin with which I haven't figured out how that can be done for outputs.

 

- Michael

Link to comment
Share on other sites

The PORT register is read/write. If in the data direction mode you can use AND/OR to existing value to set which pins you want as input or output.

 

When it's in the default data mode, you can read it and use logic functions to perform output as needed and can do so without disturbing other pins.

If a pin is configured for input then obviously it's state reflects if it's grounded or not. But writing back either value is no problem.

Link to comment
Share on other sites

The PORT register is read/write. If in the data direction mode you can use AND/OR to existing value to set which pins you want as input or output.

 

When it's in the default data mode, you can read it and use logic functions to perform output as needed and can do so without disturbing other pins.

If a pin is configured for input then obviously it's state reflects if it's grounded or not. But writing back either value is no problem.

 

Hmmm... I think we might possibly be talking about two different things.

 

So here is the scenario. Let's say all outputs have been set to output mode like in the code below.

LDA #$38
STA PACTL
LDA #$FF   Set port bits to all outputs
STA PORTA
LDA #$3C
STA PACTL

And now we desire to have a ML program manipulating just one bit (or in other words, one output pin) of PORTA.

 

This code won't work as desired because it obviously will set bit 1 to a logic high, but it will also set all other bits (0,2-7) to a logic low.

LDA #%00000010
STA PORTA   all bits changed

However if I only want to set Bit 1 to high and leave all the other bits alone, I would normally want to do something like this.

LDA #%00000010
ORA PORTA   only bit 1 changes

And this would work great if it were a normal memory location in RAM. But unless I am doing something wrong, this doesn't seem to work for a PIA port. When the PIA bits are set to outputs, they don't appear to be readable --- only writable.

 

Now of course if my ML routine was in charge of everything, I could simply shadow the PIA Port in RAM and then use that as a mask to either OR (set specific bits) or AND (clear specific bits). But I don't have that luxury when a BASIC program may also be manipulating Port bits. So I guess what I am really asking, is there a way going through the Atari OS to have my ML routine only toggle a specific bit on a Port, without affecting others that a BASIC program is using for itself?

 

- Michael

Edited by mytekcontrols
Link to comment
Share on other sites

You just described what I said. The register is read/write, as in it will contain the output setting previously set. So all you need to do if only using 1 or 2 bits is to read the existing value, then use logic instructions to do your own bitsettings without disturbing the others.

 

But generally I doubt that any software using the ports would bother to try and coexist with other things in that way. When using the ports for custom I/O you generally have a purpose made interface cable and just plugging it in means you're obscuring all the other pins from possible use anyway.

 

Though of course you have 2 ports sharing the one register but that's why you set the data direction first. For bits that are set to input, it doesn't matter what value you store to the data register anyway.

Edited by Rybags
Link to comment
Share on other sites

You just described what I said. The register is read/write, as in it will contain the output setting previously set. So all you need to do if only using 1 or 2 bits is to read the existing value, then use logic instructions to do your own bitsettings without disturbing the others.

 

Rybags I apologize. Previous to my question I had run some tests that suggested that reading the port wasn't yielding the same information as what had been set. Well I don't know what I changed, but I just re-ran that test and yes just like you said the register is read/write and the info matches. So sorry for my confusion, and thank you for having the patience to explain, and then re-explain.

 

Best regards -- Michael

  • Like 2
Link to comment
Share on other sites

Just musing, if you don't know this off the top of your head, don't bother researching it as I will get to it eventually. More of an unnecessary software trick. Let's say you wanted to use bit 1 as the toggle for RS232 or SD type clock bit and pin 2 as data. Would a sequence like

 

INC PORT

DELAY

INC PORT

DELAY

 

be OK or would it lead to problems down stream,like switching port I/O configuration would still have the count value?

Link to comment
Share on other sites

Just musing, if you don't know this off the top of your head, don't bother researching it as I will get to it eventually. More of an unnecessary software trick. Let's say you wanted to use bit 1 as the toggle for RS232 or SD type clock bit and pin 2 as data. Would a sequence like

 

INC PORT

DELAY

INC PORT

DELAY

 

be OK or would it lead to problems down stream,like switching port I/O configuration would still have the count value?

 

I'm not sure what that would really do for you. Sure it would toggle Pin 1 (RS232 or a SPI clock line), but the data on pin 2 would simply be a divide-by-2 counter. Is that what you want? Of course I could be missing something :? .

 

- Michael

Link to comment
Share on other sites

Just eliminates the need for a

 

LDA #0

or

LDA #1

 

to set bit state and leaves A reg alone. First inc will set start port state for start bit for example. Next inc or a skip of the inc will set the data bit at a one or zero. Pointless in that saving a couple of bytes or running faster then the port can handle transitions is overkill. I forgot who did it, Maybe Guss or Hias, did a clock chip on a J/S port that used a clock bit. Between that and your hacks, it is enough to get me curious! :}

  • Like 1
Link to comment
Share on other sites

Just eliminates the need for a

 

LDA #0

or

LDA #1

 

to set bit state and leaves A reg alone. First inc will set start port state for start bit for example. Next inc or a skip of the inc will set the data bit at a one or zero. Pointless in that saving a couple of bytes or running faster then the port can handle transitions is overkill. I forgot who did it, Maybe Guss or Hias, did a clock chip on a J/S port that used a clock bit. Between that and your hacks, it is enough to get me curious! :}

 

Now I see the light :) .

 

Very interesting way to do that.

 

As for the actual end use I had in mind for the RS232 R:handler code... it was to take the place of the PWM feedback I had added to my Stepper Motor Control Program. Although the PWM to analog feedback worked very well, it was affected by ambient temperature changes as well as other factors that wasn't acceptable for my application. So I needed another method to feed the position data to my PC DasyLab program, and that came in the form of the following code which was altered to put the RS232 TXD bit on joystick port 2, and to not interfere with the motor control chip's (A4988) enable pin while transmitting (leave the chip disabled).

10 ;*********************************
20 ;*           R-Handler           *
30 ;*     JOY PORTA-0 R: DEVICE     *
40 ;*  Adapted for use with A4988   *
50 ;*  stepper motor chip on JOY#1  *
60 ;*                               *
70 ;* INITIALIZE - BASIC CALL $068F *
80 ;*                 ML CALL $0690 *
90 ;*********************************
0100 ;
0110 COUNT  = $0600
0120 BUFFER = $0601
0130 RSENTRY = $032C
0140 PACTL = $D302
0150 PORTA = $D300
0160 NMIEN = $D40E
0170 DMACTL = $D400
0180 EOL = $9B
0190 CR = $0D
0200 LF = $0A
0210 K = 150        110 & 300 BAUD
0220 L = 6          300 BAUD
0230 ;              L=18 FOR 110 BAUD
0240 ;
0250     *=$0602
0260 ;
0270 HANDLTAB
0280  .WORD OPEN-1
0290  .WORD CLOSE-1
0300  .WORD GETBYTE-1
0310  .WORD PUTBYTE-1
0320  .WORD STATUS-1
0330  .WORD SPECIAL-1
0340  .BYTE 0,0,0,0  FILL REST WITH 0
0350 ;
0360 ; THE OPEN ROUTINE
0370 ;
0380 OPEN = *
0390 INIT
0400  LDA #$38
0410  STA PACTL
0420  LDA #$FF       ALL BITS = OUT
0430  STA PORTA
0440  LDA #$3C
0450  STA PACTL
0460  LDA #$14          SET TXD = 1
0470  STA PORTA    SET A4988 EN = 1
0480 SUCCESS
0490  LDY #1
0500  RTS
0510 ;
0520 ; THE CLOSE DUMMY ROUTINE
0530 ; ONLY RETURN SUCCESS IN Y (1)
0540 ;
0550 CLOSE = SUCCESS
0560 NOTIMPL
0570  LDY #146      RETURN WITH Y=146
0580  RTS
0590 ;
0600 ; THE FOLLOWING COMMANDS ARE
0610 ; NOT IMPLEMENTED SO GET ERROR
0620 ; CODE 146
0630 ;
0640 GETBYTE = NOTIMPL
0650 STATUS  = NOTIMPL
0660 SPECIAL = NOTIMPL
0670 ;        THE PUTBYTE COMMAND
0680 ;        DATA IN ACCU
0690 ;        STATUS IN Y (=1)
0700 ;
0710 PUTBYTE
0720  CMP #EOL
0730  BNE NOEOL
0740 ;
0750 ; IF EOL GIVE CRLF TO DEVICE
0760 ;
0770  LDA #CR
0780  JSR SEROUT
0790  LDA #LF
0800 NOEOL
0810  JSR SEROUT
0820  LDY #1
0830  RTS
0840 ;
0850 ; SERIALOUT
0860 ;
0870 SEROUT
0880  STA BUFFER     PRESERVE ACC
0890 ;
0900 ; DISABLE INTERRUPTS
0910 ;
0920  SEI
0930  LDA #0
0940  STA NMIEN
0950  STA DMACTL
0960 ;
0970 ; SEND STARTBIT
0980 ;
0990  LDA #$04       TXD = 0
1000  STA PORTA
1010  JSR BITWAIT
1020 ;
1030 ; SEND CHARACTER DATA
1040 ;
1050  LDY #8
1060  STY COUNT
1070 ;
1080 SENDBYTE
1090  LDA BUFFER
1091  ROL A      MOVE BIT TO JOY2
1092  ROL A
1093  ROL A
1094  ROL A
1095  ORA #$04     A4988 EN = 1
1100  STA PORTA
1110  ROR BUFFER
1120  JSR BITWAIT
1130  DEC COUNT
1140  BNE SENDBYTE
1150 ;
1160 ; SEND 2 STOPBITS
1170 ;
1180  LDA #$14       TXD = 1
1190  STA PORTA
1200  JSR BITWAIT
1210  JSR BITWAIT
1220 ;
1230 ; ENABLE INTERRUPTS
1240 ;
1250  LDA #$22
1260  STA DMACTL
1270  LDA #$FF
1280  STA NMIEN
1290  CLI
1300  RTS            DONE SENDING
1310 ;
1320 ; THE BIT TIMING ROUTINE
1330 ; FOR AN EXACT BAUDRATE
1340 ;
1350 BITWAIT
1360  LDX #K
1370 LOOPK
1380  LDY #L
1390 LOOPL
1400  DEY
1410  BNE LOOPL
1420  DEX
1430  BNE LOOPK
1440  RTS
1450 ;
1460 ; ROUTINE FOR INSTALLING THE
1470 ; RS232 HANDLER
1480 ;
1490 INITHAN
1500  PLA      BASIC ENTRY POINT
1510  LDA #'R        DEVICE NAME
1520  STA RSENTRY
1530  LDA #HANDLTAB&255
1540  STA RSENTRY+1
1550  LDA #HANDLTAB/256
1560  STA RSENTRY+2
1570  JMP OPEN
1580  .END

It works great!

 

I also needed to have my BASIC code break the position number into individual ASCII digits before sending to the R:device, so this subroutine worked quite well for doing that (enter with TEMP = the number you wish to decimalize as I call it).

 

Note: First set-up channel for R:device: OPEN #2,12,0,"R:"

3010 REM <DECIMALIZE ROUTINE>
3020 REM 
3030 D3=INT(TEMP/100)
3040 D2=INT((TEMP-(D3*100))/10)
3050 D1=INT((TEMP-(D3*100))-(D2*10))
3060 PUT #2,D3+48:PUT #2,D2+48:PUT #2,D1+48:PUT #2,13
3070 RETURN

Here's the BASIC loader to put the R:handler code into play.

910 REM <LOAD R: HANDLER CODE>
911 FOR AD=1538 TO 1697
912 READ B:POKE AD,B
913 NEXT AD
914 N=USR(1679):REM ** INIT R:HAND **
915 REM
4000 DATA 17,6,37,6,40,6,43,6
4010 DATA 40,6,40,6,0,0,0,0
4020 DATA 169,56,141,2,211,169,255,141
4030 DATA 0,211,169,60,141,2,211,169
4040 DATA 20,141,0,211,160,1,96,160
4050 DATA 146,96,201,155,208,7,169,13
4060 DATA 32,61,6,169,10,32,61,6
4070 DATA 160,1,96,141,1,6,120,169
4080 DATA 0,141,14,212,141,0,212,169
4090 DATA 4,141,0,211,32,132,6,160
4100 DATA 8,140,0,6,173,1,6,42
4110 DATA 42,42,42,9,4,141,0,211
4120 DATA 110,1,6,32,132,6,206,0
4130 DATA 6,208,233,169,20,141,0,211
4140 DATA 32,132,6,32,132,6,169,34
4150 DATA 141,0,212,169,255,141,14,212
4160 DATA 88,96,162,150,160,6,136,208
4170 DATA 253,202,208,248,96,104,169,82
4180 DATA 141,44,3,169,2,141,45,3
4190 DATA 169,6,141,46,3,76,18,6

The only annoyance, although it's minor, is that data sent to the R:device requires a momentary blanking of the screen DMA. Perhaps in a future version of this routine a way can be worked out to somehow do the timing loops during the horizontal and vertical blank period and not disrupt anything. Also I noticed that Turbo Basic did not like the repetitive DMA disables, and would eventually go crazy with rolling jibberish on screen. Other BASIC's did not do this.

 

And here's a demo of it in action (Atari on the left --- sending RS232 data to --- PC on the right).

https://www.youtube.com/watch?v=EAaRgbd5EkA&feature=em-upload_owner

 

 

- Michael

Edited by mytekcontrols
  • Like 2
Link to comment
Share on other sites

You just described what I said. The register is read/write, as in it will contain the output setting previously set. So all you need to do if only using 1 or 2 bits is to read the existing value, then use logic instructions to do your own bitsettings without disturbing the others.

Actually, no. The story of the PIA is that it has two different ports, port A and B, and they are really electrially different. For one of the ports, a READ on an output register returns the last value written into the output, i.e. it reads from the buffer. I believe this is port A. Port A has tri-state outputs that can drive the output line low or high. Port B is different: It has open collector outputs that can only drive the output low, but requires a pull-up externally to drive it high. If you READ from a port-B output register, it returns the true electrical state on the pin, unbuffered. That is, if you drive the output high, but pull it low externally (which you can do, due to the open collector), then the read will return low, not high.

  • Like 1
Link to comment
Share on other sites

OK, I didn't have that info in my datasheets. The Rockwell one seems to have better info than the MOS one http://archive.6502.org/datasheets/rockwell_r6520_pia.pdf

 

But from a programming POV it shouldn't matter as 400/800 has external pullups on all the port bits. For XL/XE PORTB is sort of inconsequential since it's devoted to driving MMU inputs for memory control. Although the Atarimax 32in1 OS does utilize the output of PB7 as a serial data channel to receive commands to enquire or change which OS is active.

Edited by Rybags
Link to comment
Share on other sites

Actually, no. The story of the PIA is that it has two different ports, port A and B, and they are really electrially different. For one of the ports, a READ on an output register returns the last value written into the output, i.e. it reads from the buffer. I believe this is port A. Port A has tri-state outputs that can drive the output line low or high.

 

So basically if I understand this right, any bit of PortA that was set as an output would have it's logic state reflected in the output buffer which is readable. And I would think that should yield the same data as if the outputs were directly readable? I can't think of a situation other than over loading the output pins (forced to GND or to VDD) where this wouldn't be true.

 

Any bits that were set as inputs should still have their logic state read directly, and not be buffered?

 

- Michael

Edited by mytekcontrols
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...