6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 12:22 pm

All times are UTC




Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Wed Jan 24, 2018 4:56 am 
Offline

Joined: Wed Jan 24, 2018 4:05 am
Posts: 14
Hello all,

I was wondering if any of you had ever heard of, or had experience with, using a 6522 as a keyboard controller for a PS/2 keyboard? I don't wish to use a microcontroller in my design, but I also don't wish to design and build my own keyboard!
The PS2 keyboard protocol is kind of funky with an 11-bit packet and no common BAUD rate (it just pulses the clock "whenever it feels like it?" -- I see rates reported from 10kHz to 30kHz.) I can't wrestle that protocol with a typical UART. I'm not even sure it could be done with a 6522 but I thought I would ask.

My fall-back position is to maybe connect the keyboard data line to a single data line on a regular peripheral interface adapter (or some other kind of latch?). I need the keyboard clock falling low to signal an interrupt on the CPU, but it can't be tied directly -- it needs to just pulse, so the IRQ line can return to high. Keyboard data line is valid while the clock line is low, so I could in theory then try to bit-bang the keyboard's serial data directly from the CPU. I am all still new to the hardware side of this stuff so I expect there are obvious things that I am missing.

Your thoughts and comments are much appreciated!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 5:26 am 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
I don't know anything about implementing PS2, but if you're willing to code scanning and decoding the keyboard, you could use one of these.


Last edited by DerTrueForce on Wed Jan 24, 2018 5:33 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 5:27 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hi nerdy1, and welcome.

I had a look around, and I think I've found a couple of references to previous work (most people these days have used a microcontroller, but not everyone.) Hope you'll find it useful - but it would be great if you can succeed and publish your work too.

Daryl's SBC project has this:
http://sbc.rictor.org/io/pckb6522.html
(see also this thread)

And the late Lee Davison had this, using a GAL:
http://retro.hansotten.nl/lee-davison-w ... interface/
(also here, but with the pictures missing)

And Dieter managed something too, using some TTL shift registers to assist:
http://www.6502.org/users/dieter/drc2/drc2.htm

It seems the AT keyboard and PS/2 keyboard use the same protocol, just a different connector - if that's not so, please correct me! And, at least at one point, most USB keyboards also can use the PS/2 protocol and just need a trivial electrical adapter.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 6:17 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
http://www.computer-engineering.org/ps2protocol/ looks helpful. You can do it with a 65(c)22. There's not a baud rate in the sense that a UART uses it, because it's synchronous, not asynchronous. Instead it's similar to I²C but with a minimum clock-low and clock-high time of 30µs and maximum of 50µs, and with a parity bit at the end instead of an ACK bit.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 7:11 am 
Offline

Joined: Wed Jan 24, 2018 4:05 am
Posts: 14
Thank you everyone for those links -- that is very helpful!
I am thrilled that it not only looks possible to do with a VIA, but there is even source code for me to "borrow"! (I think I will want an interrupt-based version of Daryl's code, but hopefully that will just be a software-only modification.)
New 65C22 is on the way...and I have some studying to do!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 7:37 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
The VIA's CA1, CA2, CB1, and CB2 pins can be used as interrupt-on-change pins, suitable for an externally sourced clock signal. You can of course have a line connected to both that and one of the port pins at the same time, and then use the port pin to emulate an open-drain I/O by writing a 0 to its bit in the port's output register and then making the bit an output when you want to pull the line down, or an input when you want to read it or let it float up. Use an external pull-up resistor of course.

It isn't I²C, but very similar. I have an I²C-with-VIA part of the "circuit potpourri" page of the 6502 primer, at http://wilsonminesco.com/6502primer/pot ... ITBANG_I2C, and accompanying sample I²C bit-bang code that might give you some ideas, at http://wilsonminesco.com/6502primer/GENRLI2C.ASM .

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 2:41 pm 
Offline
User avatar

Joined: Wed Aug 17, 2005 12:07 am
Posts: 1250
Location: Soddy-Daisy, TN USA
This is very useful information. In my current "big board" SBC, I am using a VIA for a PS/2 keyboard, AY-3-8912 sound chip and a NES controller.

I'd love to learn more about those CA/CB pins. They are still a mystery to me. I'm planning on just bit-banging the VIA's for the moment. I will actually have two VIA's. One that I just mentioned and one for external ports.

_________________
Cat; the other white meat.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 5:44 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
The question is how much CPU bandwidth on the 6502 is necessary to decode the PS/2 protocol. 30KHz is kind of busy for a 1Mhz CPU. You'd have to be polling for bits pretty regularly, and I don't think you'd want the PS/2 clock to be hammering an interrupt.

In constrast to a keyboard scanner/decoder. You're dealing more with human terms and response rates, and can probably be a little more sloppy vs syncing up to a synchronous clock running at a random rate.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 6:51 pm 
Offline
User avatar

Joined: Wed Aug 17, 2005 12:07 am
Posts: 1250
Location: Soddy-Daisy, TN USA
Hmm. You got me thinking. It might be worth it to me to use a micro-controller tied to a 6522 now that I think about it. The micro-controller could handle the PS/2 and NES signals and just latch an 8 bit value on one of the VIA's ports.

_________________
Cat; the other white meat.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 11:22 pm 
Offline

Joined: Sat Jun 04, 2016 10:22 pm
Posts: 483
Location: Australia
Garth did suggest using CA1/2 or CB1/2 as change interrupt pins. If you did that, you wouldn't need to poll them until an IRQ hits.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 24, 2018 11:28 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
If you don't want interrupts, putting the clock line on bit 6 or 7 of one of the ports lets you test it with BIT and then branch on the N or V flag, without regard to what's in A. Put it in a loop. The VIA does have several capabilities that do not initially meet the eye though. When you don't want the keyboard interrupting, and you don't want to miss any keyboard events, just pull its clock line low to make it wait until you're ready.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 25, 2018 12:23 am 
Offline

Joined: Wed Jan 24, 2018 4:05 am
Posts: 14
Thanks again Garth. It's important to me that my keyboard should be interrupt driven. I don't mind if it takes me a while to nail down the software.
Just so I am clear though, we are not talking about using the VIA's shift registers at all correct? We are just talking about using it to take control of the two keyboard lines, so I can drive them (or not) as needed?
Just out of curiosity, how crazy would it be to try to squeeze a 16-bit shift register into the middle there?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 25, 2018 2:27 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
The odd frame size would make it a bit of a challenge to handle it with the VIA's SR, but there might be a way to do it anyway, possibly using the SR to get the first 8 bits and then finishing it up in bit-banging as we were talking about above. In addition to going to the CB1 input, the clock line could still go to a CA line to generate an interrupt when a frame starts, then you have plenty of time to get into the ISR and start polling the SR-full bit (bit 2 of the interrupt flag register, or IFR) for when the first 8 bits are completed, and take the rest of the bits in manually, then reset the SR and other things needed to start the process again for the next frame. I have not sharpened my pencil to figure out anything further than what I just wrote. It's just out-loud thinking. There's usually a way to do these things. Be sure to address the VIA SR bug in mode 011 though (the only bug in the VIA, and it's in all brands) which I tell about in tip #8 of the Tip of the Day column, at viewtopic.php?p=2310#p2310 .

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 25, 2018 7:45 am 
Offline

Joined: Sat Jul 20, 2013 8:23 am
Posts: 6
This topic got me doing some archeology among old Eagle files from many years ago when I was toying around with the thought of a dedicated PS/2 keyboard interface. The idea I had was to use two shift registers to capture an entire byte from the keyboard including start, stop and parity bits. When all bits are captured the PS/2 clock line is pulled low to prevent further transfer (the keyboard will buffer) and the CPU can pull one byte from the data register without any stress. The interface have one RO data register and one RW control register. Sending data to the keyboard is bit banged but data in that direction is relatively rare (mainly updating the keyboard LEDs).

This circuit was hastily put together, have not been tested and may not work at all but maybe it will spark some ideas :)


Attachments:
ps2-interface.png
ps2-interface.png [ 16.19 KiB | Viewed 9469 times ]
Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 07, 2023 4:43 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
As it came up recently in a similar thread, but without the use of VIAs, I thought about how I'd do this with a VIA. This is untested but I think it should work.

I searched around, and other VIA-based methods I've seen mostly revolve around bitbanging - but I think it should be possible and quite comfortable to use the shift register as Garth suggested higher in this thread, to minimise CPU overheads, maybe requiring only one interrupt per character received from the keyboard.

This circuit is quite appealing as it only requires a few small external components:
Attachment:
File comment: VIA-based PS/2 circuit - with SR bug
ps2keyboard_via_bad.png
ps2keyboard_via_bad.png [ 17.56 KiB | Viewed 3460 times ]

However, it suffers from the shift register bug, so we do actually need to add another IC, following Garth's advice to work around that:
Attachment:
File comment: VIA-based PS/2 circuit with workaround
ps2keyboard_via_fixed.png
ps2keyboard_via_fixed.png [ 17.12 KiB | Viewed 3460 times ]

This should allow bidirectional communication with the PS/2 device. The general principle is to use PB6 pulse counting via Timer 2 to get interrupts after certain bits are transmitted. You could also use CB1 interrupts or the SR interrupt, but using PB6 pulse counting alone means that for the common case of reading data we only need to spend one interrupt per frame, exactly when the data is available.

So initially we set PB6 as an input, enable shift register input with an external clock source (mode 011), and enable Timer 2's pulse counting mode. The PS/2 clock falling causes CB1 to rise on the next PHI2 leading edge, shifting data into the shift register. First we count 9 pulses, to cover the start bit and eight data bits:
Code:
       start D0  D1  D2  D3  D4  D5  D6  D7
CA2 """\___/"""V"""\___/"""\___/"""V"""V""
PB6 """"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_
 T2  9   8   7   6   5   4   3   2   1   0
                               T2 IRQ ---^

When the interrupt arrives, we read data out of the shift register and reset Timer 2 to count another 11 pulses - that covers the parity bit, stop bit, next start bit, and 8 data bits - so this will give another interrupt after the next character arrives:
Code:
       start D0  D1  D2  D3  D4  D5  D6  D7 par stop       start D0  D1  D2  D3  D4  D5  D6  D7 par stop
CA2 """\___/"""V"""\___/"""\___/"""V"""V"""V"""V"""""""""""\___/"""V"""\___/"""\___/"""V"""V"""V"""V""""
PB6 """"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"""""""""\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"
 T2  9   8   7   6   5   4   3   2   1   0 B A   9           8   7   6   5   4   3   2   1   0 B A   9
                               T2 IRQ ---^                                         T2 IRQ ---^

This is not doing any checking of start/parity/stop bits, so could be vulnerable to going out of sync. It may be desirable to accept two interrupts per frame, reading the first 8 bits from the shift register in the first one and the last three bits in the second one, so we can check the start/stop/parity bits are correct and resynchronise if not:
Code:
       start D0  D1  D2  D3  D4  D5  D6  D7 par stop       start D0  D1  D2  D3  D4  D5  D6  D7 par stop
CA2 """\___/"""V"""\___/"""\___/"""V"""V"""V"""V"""""""""""\___/"""V"""\___/"""\___/"""V"""V"""V"""V""""
PB6 """"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"""""""""\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"\_/"
 T2  8   7   6   5   4   3   2   1   0 3 2   1   0 8         7   6   5   4   3   2   1   0 3 2   1   0 8
                           T2 IRQ ---^-----------^                             T2 IRQ ---^-----------^

If we need to pause data transmission or interrupt a character, we can briefly set PB6 as a low output to pull the PS/2 clock line low. This interrupts the device and we can set T2 to its initial value again, get an interrupt where we want it during the next character. This could be an appropriate response to detecting a framing error.

To send a character to the device, we need to pull the PS/2 clock (PB6) low as above, and then pull the PS/2 data line low by setting CB2 as a low output, then let the clock float again (by setting PB6 as an input). There are some timing constraints here. Then we need to send data in sync with the clock coming from the device. That can be done either by bitbanging CB2 based on CB1 rising-edge interrupts, or using the shift register, but note that we have more than 8 bits to send, so if we are using the shift register then we need to catch the interrupt on shift register completion (or use PB6 pulse counting again) and send a second byte at that point, in order to fill out the full frame. The second byte won't complete (the device won't send enough clock pulses) so we also then need to count the pulses and, after the frame is over, turn off the shift register output so that we're ready to receive data again.

It's also possible to poll timer 2 to determine progress during a transmit or receive, or to determine whether we are between frames - I'm not sure if that's useful for anything though.

Overall this should allow receiving data with only one interrupt per character, or two if you want to be a bit safer and check for framing errors, and allows for interrupting the device, and sending data to the device - so I think it should cover all the bases. Sending may be less efficient (requiring maybe two interrupts to manage the sending operation) but as that's rare, I don't see that as a big problem. It seems quite flexible, and while it's a shame it requires an extra IC in addition to the VIA, that's not bad overall!

Edit: I've built this now (the one with the 74HCT74 to guard against the shift register bug), and it works pretty well. The shift register is an awkward little thing to get working properly though - it doesn't act exactly how any of the datasheets say (comparing the WDC ones to the Rockwell ones, and to the old typewritten MOS one). The upshot is, we do need to use two interrupts per input character - but it's not wasted, as it allows doing all the framing and parity checks. I've attached the code for reference in case it's useful to anyone - this uses interrupts for reads, but bit-banging for writes (as they are much more rare) - though it should be possible, with care, to use the shift register for writes as well.

Edit 2 - I looked into using the shift register for writes as well as reads, but it's not a good fit because it changes the data on the wrong clock edge. To make that work you'd need some external circuit to uninvert the clock during writes, which is not really practical. The shift register would also drive CB2 high as well as low, when it's meant to be an open-collector signal, so it's not a great fit really.


Attachments:
File comment: Sample code for reading and writing the PS/2 keyboard
ps2test.s [6.94 KiB]
Downloaded 44 times
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 27 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 42 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: