Bi-Directional User Port Code

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Bi-Directional User Port Code

Post by chysn »

I'm trying to grasp the general theory behind bi-directional asynchronous communication with the VIC-20 user port. Obviously, I know it can be done because VICmodem exists. So far, all of my serial port projects have involved either output from the VIC or input from another source into the VIC, or either by use of a manual switch.

I've read the VIC-20 Programmer's Reference Guide section on the user port a bunch of times. It breaks the user port operation into several Peripheral Control Register (PCR) modes, each of which is either an input or output mode.

For output, I'm using the Handshake Output Mode (p. 231). When I write to the port, CB2 goes low in this mode. My receiving device (Arduino) is listening for that, and when CB2 goes low, it reads the data lines, does whatever with them, and then sets CB1 high then low. This transition causes the CB2 to go high again, and now both parties know that we're ready for another byte of data to go out.

For input, I'm using the Interrupt Input mode (p. 231). When the Arduino has set the data lines appropriately, it sets CB2 from high to low, which sets the CB2 interrupt flag on the VIC-20 and fires an interrupt. My software on the VIC-20 checks the interrupt for the CB2 flag and, if set, reads the port and does whatever. Reading the port clears the CB2 flag, and we're ready for another byte of data to come in.

I'm usually using all 8 data lines. I know that I can use the DDR to divide them up into, say, four in/four out, then shift them into useful bytes. My confusion (or ignorance?) lies in the apparent mutual exclusivity in the PCR modes.

The only solution that comes to mind is that I might normally use the interrupt mode, and then switch over to the Handshake Output Mode when sending data, switching back to input mode when acknowledged or timed out. But then, data can't be received via interrupt while the sending is in progress (CB2 interrupt is disabled). This seems (to me) to nullify the advantage of dividing up the DDR. I feel like I need a "CB3" line!

TLDR; Does anyone have any sample code that does bi-directional in/out with the user port? Or, if not that, then a description of the theory of such communication, so I can piece it together?
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5

WIP: MIDIcast BASIC extension

he/him/his
groepaz
Vic 20 Scientist
Posts: 1188
Joined: Wed Aug 25, 2010 5:30 pm

Re: Bi-Directional User Port Code

Post by groepaz »

Not for VIC20 - but the "PC64" userport cable (for the C64) worked like this, ie bidirectional, 4bit per direction. I don't know if this was ever adapted to the VIC20 - but there is quite some code around for it that you could look at. Eg the "over5" utility supports it
I'm just a Software Guy who has no Idea how the Hardware works. Don't listen to me.
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Bi-Directional User Port Code

Post by chysn »

groepaz wrote: Wed Nov 29, 2023 10:06 am Not for VIC20 - but the "PC64" userport cable (for the C64) worked like this, ie bidirectional, 4bit per direction. I don't know if this was ever adapted to the VIC20 - but there is quite some code around for it that you could look at. Eg the "over5" utility supports it
Thanks! It looks like the PC64 does support VIC-20, so I'll look closely at that. (Follow-up: Sadly, the link to the Commodore-side code is no good)

VIC Revealed goes into more detail on the 6522 shift register than the P.R.G. does, although I'll need to read it a half dozen more times to be able to put it into practice.
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Bi-Directional User Port Code

Post by chysn »

I'd still like to get this figured out at some point, but for now I have a "good enough" solution for my immediate need, which is building a Bluetooth MIDI interface. It was a delicate dance of listening for transitions and doing things in the proper order, but I developed a functioning "role switching" strategy.

(1) The VICside software starts in Interrupt Input mode, waiting for incoming data as MIDI IN. All eight data lines are set for input.
(2) When the VICside software needs to send MIDI OUT, it switches to Handshake Output mode, sets data lines for output, and writes the port. Then it waits of acknowledgement or timeout, at which point it switches the PCR back to Interrupt Input mode.
(3) The Arduino software starts by watching for the CB2 pin to go low. When this happens, it reads the user port and sends MIDI OUT to its own serial TX pin, along to the Bluetooth MIDI module.
(4) When the Arduino sees serial data available (MIDI IN from the Bluetooth module), it switches the data pins and the CB2 pin to OUTPUT, sets the data pins, and brings CB2 low to trigger the VICside interrupt.
(5) Here's the cool part. Remember when I said I wanted a "CB3?" I'm connecting CB2 to a second Arduino pin that's always set to INPUT. So when the Arduino has received serial data and CB2 goes high (which the VIC-20 does when the data port is read) then the Arduino starts listening for MIDI OUT from the VIC again. (Update: but see below...)

Are conflicts possible with this configuration? Yes. But typically you won't be sending and receiving at the same time with MIDI. It's not a necessarily asynchronous use case. As long as the VIC and the Arduino software can do the dance, this switching method seems to be pretty seamless.

Update: I've abandoned #5 for now, in favor of switching after a fraction of a second of no activity on the MIDI IN. Trying to quickly change the pin mode in the Arduino isn't reliable with lots of MIDI data, like the kind you get from a system exclusive dump.
Post Reply