6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun May 12, 2024 5:28 am

All times are UTC




Post new topic Reply to topic  [ 27 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Wed Nov 08, 2023 11:03 pm 
Offline

Joined: Sun Feb 22, 2004 9:01 pm
Posts: 78
There's a similar interrupt-driven implementation here and a polled implementation here. I believe the interupt-driven implementation relies on the bug-free 6522, which is the case in the BBC computer.

_________________
--
JGH - http://mdfs.net


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 08, 2023 11:23 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
Thanks Jonathan. I think these are actually both bitbanged, not using the shift register, so they would indeed not suffer the bug even on the modern 65C22, but then they would presumably need one interrupt per bit. I couldn't see the source code there for the Sprow one.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 08, 2023 11:32 pm 
Offline

Joined: Sun Feb 22, 2004 9:01 pm
Posts: 78
Something I've been toying with is using a 6522 for both a PS2 keyboard and a quadrature mouse.
There is a standard interface for a 3-button mouse for Acorn computers, and a common PS2 keyboard interface.
A mouse needs two interupts, two direction states and a number of button states.
A PS2 keyboard needs one interupt and three data lines.
With an Acorn-standard 3-button mouse you can fit the available data lines, but at least one of the mouse interupts would need to share with the PS2 interupt. I've sketched code that would be able to tell what the interupt source would be, but I'm not certain how to arrange things electrically.

Attachment:
PS2Mse2.gif
PS2Mse2.gif [ 6.58 KiB | Viewed 2308 times ]

_________________
--
JGH - http://mdfs.net


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 08, 2023 11:39 pm 
Offline

Joined: Sun Feb 22, 2004 9:01 pm
Posts: 78
gfoot wrote:
Thanks Jonathan. I think these are actually both bitbanged, not using the shift register, so they would indeed not suffer the bug even on the modern 65C22, but then they would presumably need one interrupt per bit. I couldn't see the source code there for the Sprow one.

There's no source, but I disassembled it as I wanted to rewrite it to live in ROM instead of RAM. ;) I think it uses a CB1 interupt to start a transaction, then bitbangs to read the data word.

_________________
--
JGH - http://mdfs.net


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 09, 2023 12:11 am 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
I'm not sure how the mouse interrupt signals work there, are they just halves of the quadrature signal, so could idle in either the high or low state? It's difficult if that's the case, especially if they can idle low.

A couple of things might make that circuit more compact - firstly you don't really need PB4 and the transistor, you can use DDRB to swap PB3 between being an input and an output, to get the same effect. If its an input then it will get pulled high, and if you make it a low output then it will drive the line low. This is how I controlled the clock in my circuit.

Second, CB2 can be used as an output, so similarly you can simulate an open drain I/O line by toggling it between output-low and interrupt input, in the PCR. It may be better to use this for the keyboard clock rather than CB1, then you don't need PB1.

I guess you don't want to use the printer port where I think one of the CA1/CA2 lines is unused?

Another option for a falling-edge triggered interrupt is PB6, with T2 in pulse counting mode, and setting T2 to zero so you get an interrupt on the next pulse.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 09, 2023 12:44 pm 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 704
Location: Texas
When using a VIA I always connect KEY-CLK to CA1 and KEY-DATA to PA7. That said...

whartung wrote:
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.


I had a 1.5 MHz system a while ago and the timing was *really* tight to have interrupts each clock pulse. I wouldn't parity check or anything.

gfoot wrote:
I'm not sure how the mouse interrupt signals work there


When using a VIA I always connect MOUSE-CLK to CA2 and MOUSE-DATA to PA6. The reason for this is the mouse needs you to send data back to it in a VERY specific way to initialize it. CA2 can be an output! Thankfully the keyboard doesn't need that to initialize, because CA1 cannot be an output.

One "gotcha" I found when doing all of this stuff was that PA has both the 'regular read' and the 'handshake read'. I had other (joystick) inputs on the lower PA pins, so I would go and 'regular read' those guys at times, and it was breaking the keyboard/mouse interrupts bigtime. Instead I 'regular read' the keyboard/mouse and then 'handshake read' for the other PA pins. It has to do with clearing the interrupt bits and stuff.

If you want the most detailed PS/2 protocols for both keyboard and mouse, I would search for "ps/2 protocol toronto". The University of Toronto has three EXCELLENT articles on literally everything you would need, and then some!

I have code for this stuff on my projects github pages in case you want to check that out, normally my keyboard/mouse interrupts are near the bottom of the code.

github.com/stevenchadburrow

Thanks!

Chad


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 09, 2023 1:17 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
sburrow wrote:
I had a 1.5 MHz system a while ago and the timing was *really* tight to have interrupts each clock pulse. I wouldn't parity check or anything.
Yes that sounds like a concern. Even in my example using the shift register, it's still important that we read that byte within 100us of the clock pulse that caused the interrupt, and long interrupt handlers elsewhere in the system could cause it to miss the window. There is also the option of using NMI for interrupts on every clock pulse, without anything else being able to delay the processing, but this is certainly an area where an external shift register can give a lot more leeway. And we always have the option of asking the keyboard to repeat the last character if we missed it (framing or parity errors).

Edit: I looked at your code in github, and it looks like you are indeed using NMI for the keyboard clock :)

Quote:
When using a VIA I always connect MOUSE-CLK to CA2 and MOUSE-DATA to PA6. The reason for this is the mouse needs you to send data back to it in a VERY specific way to initialize it. CA2 can be an output! Thankfully the keyboard doesn't need that to initialize, because CA1 cannot be an output.
Beware that some PS/2 keyboards do need to initialise - so my code above sends a "reset" command to the keyboard on startup ($ff). In the past I've also made a simple circuit to send this reset command, with a D flipflop and some diodes. I think this is partly because they support both PS/2 and USB, and default to a kind of neutral mode where they are experimenting with both, waiting for the host to do something positive with one interface or the other.

But note that jgharston was referring to a specific kind of mouse used with early Acorn Archimedes computers - not a PS/2 mouse.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 09, 2023 5:48 pm 
Offline

Joined: Sun Feb 22, 2004 9:01 pm
Posts: 78
gfoot wrote:
I'm not sure how the mouse interrupt signals work there, are they just halves of the quadrature signal, so could idle in either the high or low state? It's difficult if that's the case, especially if they can idle low.
The two interupt lines interupt when a motion happens on that axis. The two data lines indicate which direction on that access the motion is, fed from the two quadrature disks. So, eg:
CB1 interupt, moving left/right, read PB0=0 moving leftwards, PB1=1 moving rightwards.
CB2 interupt, movng up/down, read PB2=0 moving downwards, PB1=1 moving upwards.
see eg Mouse.src
gfoot wrote:
I guess you don't want to use the printer port where I think one of the CA1/CA2 lines is unused?
CA1 is PrinterACK, and CA2 is PrinterStrobe. And that would need two plugs on the lead. ;)
gfoot wrote:
But note that jgharston was referring to a specific kind of mouse used with early Acorn Archimedes computers - not a PS/2 mouse.
And BBC computers prior to the Archimedes. (And the Spectrum, the Amstrad CPC, Atari ST, Commdore Amiga, and some PCs.)

_________________
--
JGH - http://mdfs.net


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 09, 2023 10:52 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
jgharston wrote:
gfoot wrote:
I guess you don't want to use the printer port where I think one of the CA1/CA2 lines is unused?
CA1 is PrinterACK, and CA2 is PrinterStrobe. And that would need two plugs on the lead. ;)

Ah OK - I misunderstood a comment in the MMFS code about CA1 being unused.

In that case I think PB6 may indeed be your best option for an additional interrupt trigger, leaving CB1 and CB2 free for the mouse. I had a play with it just now on a BBC Micro, with the PS/2 clock line connected to PB6 and PS/2 data connected to PB7 - it works fairly well but the OS interrupt latency causes a lot of problems. As Chad cautioned, the window for reading the bit after the clock goes low is rather small - maybe 50us - and if the OS is servicing some other interrupt (e.g. keypresses) then my handler doesn't get called quickly enough to reliably capture the bit from the keyboard. The only way I could really get it to read data reliably from the keyboard was using an interrupt to start the operation, but then blocking in the interrupt handler to read the later bits. So then we block for about a millisecond on every keypress... and twice on every key released... not very good! And I still get some errors, probably due to the OS being mid-interrupt when the key is pressed, meaning we miss the start bit.


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 10, 2023 12:20 am 
Offline

Joined: Sat Oct 09, 2021 11:21 am
Posts: 704
Location: Texas
gfoot wrote:
Edit: I looked at your code in github, and it looks like you are indeed using NMI for the keyboard clock :)


Not :) instead :(

Here's my story there. On my older Acolyte boards, I connected KEY-CLOCK to /NMI and KEY-DATA to /IRQ. I would keep /IRQ interrupts OFF, but inside of the /NMI interrupt I would turn them back ON. If it triggered, it was low, if it didn't trigger, it was high. To get back to the /NMI, I would simply manipulate the stack a bit.

Here's the problem though: It would miss an initial clock pulse occasionally. I have no idea why! I tried delays and other things, but nothing fixed it. It was rare, but often enough that it screwed things up royally on a semi-regular basis. I then implemented parity check to help, and it did, uh, help, a bit. But ultimately the problem was still there, and a key would occasionally misfire and that is bad news for a lot of reasons.

The alternative that worked almost perfectly was using KEY-CLOCK on /IRQ and KEY-DATA nor KEY-CLOCK on /NMI. This was weird but because that initial clock pulse was hitting a *level* sensitive interrupt, it wouldn't be missed. The nor-gate would simple toggle the /NMI if the signal was a specific logic level half-way through the KEY-CLOCK period. Timing was extremely close cut at 3 MHz.

When I use the VIA, I *never* have a problem.

It might have been a hardware problem, something about long cables and ground bounce or something. Who knows, I won't do that again, however tempting it is.

Thanks! Good discussion!

Chad


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 10, 2023 6:20 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
Ah right. Well, as you said, the timing is quite tight at 1-3MHz. My BBC Micro code suffers problems with a 2MHz CPU.

I fleshed out my PB6-interrupt-based keyboard code a bit more though, and it's very reliable now - you can see it here and even run it but of course the emulator doesn't have a PS/2 keyboard attached: https://bbcmic.ro/#%7B%22v%22%3A1%2C%22 ... %5Cn%22%7D

This implementation is specifically for the BBC Micro, especially dealing with late interrupts due to the OS being part-way through handling an interrupt when the keyboard interrupt occurs. I'm not sure how important that would be for other systems, especially if you have the option of running the CPU at a faster clock speed to reduce the impact of handling other interrupts like this.

The program installs an interrupt handler that manages the keyboard and stores incoming bytes in a circular buffer; it then runs some BASIC code to monitor that buffer and print the byte values to the screen, along with an animation to help ensure that it's not permanently blocked in the interrupt handler. I didn't implement anything like keycode translation or inserting characters into OS buffers, because I was only really interested in the usage of the 6522 VIA. Comparing the code to the Sprow disassembly, there's some similarity in the way the read interrupt handler works - I am surprised though that the Sprow code doesn't suffer from the same problems that I did with other OS interrupts delaying the processing of the keyboard interrupts.

Hardware-wise, the PS/2 clock is connected to PB6, and PS/2 data to PB7. I didn't add pull-up resistors - the NMOS 6522 pulls up fairly well anyway - but it's probably better to use them. Timer 2 is used to create the PB6 interrupt, and Timer 1 is used to apply timeouts to each byte operation, so that if there's a problem with the signal from the keyboard we don't end up stuck waiting for a clock pulse that will never come. CB1, CB2, PB0-PB5 are all free for use by a mouse or other devices.

The data signal could be moved from PB7, though the code takes some advantage of it being on PB7 - it'd require a few extra instructions to use a different pin.

Parity and stop bits are checked, and if these checks fail we send a break signal to the keyboard, which may result in retransmission. It would probably be better to explicitly send the $FE command for those cases.

The start bit is not checked because I found that I couldn't reliably sample it. Instead I used the pulse counting on PB6 to wait specifically for the first data bit, by which point Timer 2 is set to -2, and then the rest of the read operation proceeds from there. Being able to use Timer 2 to reliably tell how far we are through the byte, regardless of interrupt response time, was very useful here. If Timer 2 is less than -2 already then we have missed the first data bit, and we abandon the read and again send a break signal to the keyboard, which this time will cause retransmission of the byte. I tested this and it seemed very reliable - mashing keys on the BBC's keyboard is enough to cause a lot of latency in the OS IRQ handler, and cause missed bytes from the PS/2 keyboard, but with this behaviour of interrupting the PS/2 keyboard mid-byte, the eventual byte stream from the keyboard looks perfect to me, with no missed bytes.

The interrupt handler blocks until the byte is fully received, which usually takes about a millisecond. The timeout for receiving the byte is set to 2ms because that's what I saw specified in a document somewhere; there's also a write timeout set to 17ms, also based on some numbers I saw documented somewhere, so if the keyboard doesn't send the right clock pulses during a write operation, we don't block forever waiting for them. I also tested to make sure that TIME was incrementing at the right rate, and it seems unaffected, so we are not blocking for too long in the interrupt handler.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 15, 2023 9:41 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
gfoot wrote:
... 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.


Note that the low part count ways to read the PS/2 are sometimes only useful for reading, so you may need to have a PS2 output for writing on its own.

If it's being done to initialize the keyboard, during the start up routine, you may be able to start the write going, go do some more setup on other things, and then come back and finish the write, so that you can poll the VIA for when it is going to be ready for the final slice of data. That is important because some dual mode PS2/USB keyboards won't talk PS/2 on the appropriate lines unless they see PS/2 signals on the line.

Then the VIA-SSR looks more promising. If you allocate one GPIO to turning the PS2 functions on or off, then you can even multiplex use of the serial shift register with other uses: using three gates of a NAND, use GPIO output high NAND with the clock for the PS2 clock. Use the GPIO output high NAND with the data, and feed it through a third NAND gate with VCC to put it right side up again. Feed both through Schottkey diodes ... I am guessing that is with the cathode tied to the NAND output and the anode to the PS2 Clock and Data lines, so that when the NAND gates go low, they can pull the PS/2 lines low, but when they go high, the line is pulled high following their pull up resisters unless something else is pulling it low.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 27 posts ]  Go to page Previous  1, 2

All times are UTC


Who is online

Users browsing this forum: No registered users and 8 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: