[A Project to interface a PS/2 keyboard to a 68hc11 microcontroller]
Captures but No Interrupt
After the tribulations of the last few days, I decided to change the program to display the value in the IC3 captured-value register (TIC3) – the last value of the free-running 16-bit hardware cycle-counter when the most recent IC3 pin-event occurred. Adding debug code like this has to be done very carefully, as there is only 256 bytes RAM available for the program, and it is already close to that limit.
Anywho, guess what? TIC3 register always read as $FFFF, no captured timer values, ever.
RTFM, and then Do So Again
Re-reading chapter 10 of the 600-page Motorola M68HC11 Reference Manual, then re-re-reading it, highlighted a bug in the program.
It turns out I had missed a little piece of the input-capture configuration logic. To be more precise, I had initially included it, but had, for some obscure reason, removed it from the program a little while back.
The missing piece was to configure IC3 to capture falling edges (or indeed rising edges would have done just as well) :
ldaa #$02 ; capture IC3 falling edges staa TCTL2,X
And now we have captured timer values – the IC3 event, driven by the loopback wire from PORTB pin 2, is indeed generating logic transitions on IC3. So I can cross that one off.
You’re The One That I Want
Next step was to reinsert a “CLI” instruction to clear the global interrupt-mask flag, and this now gave conclusive evidence that the ISR is now being called – the ISR is coded to switch LED2 on as well as incrementing the IC3-interrupt-counter variable – and LED2 does indeed illuminate at runtime (and the ISR is the only place in the code where LED2 is tickled – I checked, just to be sure).
; PS/2 kbd interrupt-service routine p2k_intr ldd counter ; increment counter addd #1 std counter ldaa #$01 ; acknowledge interrupt: clear IC3F flag staa TFLG2,X ; yes, clear it by storing a 1, as per docs! ldab #LED2 ; toggle LED2 bsr bptog rti
Unfortunately, the program hangs hard at exactly that point (or very very shortly afterwards). Puzzling, but at least we have a conventional interrupt problem now – the program seems to either be running off into the middle of nowhere (corrupted stack-pointer or corrupted stacked register values) or is accidentally twiddling a hardware register that hangs the MCU. I like conventional problems much better than mysterious ones!
As well as LED2 turning on, using the BUFFALO memory-dump command (and some judicious pressing of the SBC reset button), it is apparent that the interrupt-counter (at address $0102) is indeed being incremented. But in spite of only toggling the driving pin one time, the counter is being incremented several thousands or millions of times…
At first glance, the above apparently odd way of clearing the IC3F “acknowledge” flag, in the ISR code, appears to be not working. This mechanism of clearing a timer-flag bit is a wierd feature of the 68hc11: those flag registers are unusual in that you can change a one-valued flag bit to zero by storing a one in that bit-position; any zero bits “stored” have no effect; this is inherited from the 6801, which needed this oddness because it has no BCLR bit-clear instruction. Of course on the 68hc11 you could use BCLR, but in this case it doesn’t save any cycles or code-size over the (odd) load/store method.
However, given that we are getting multiple interrupts when only one is expected, suggests that the IC3F is not getting cleared, thus retriggering the same interrupt as soon as the ISR tries to return. Either I am targeting the wrong bit of TFLG2, or the clearing-code is borked?
Back to the Tech Ref Manual
Ack! The right bit is being targeted, but of the wrong register: should be clearing bit 1 of TFLG1, not TFLG2! I guess that is one disadvantage of an MCU with lots of on-chip devices: there’s just so darned many control-registers that it can be hard keeping track of ’em all… Just FYI, for input-capture 3, the control-registers are TMSK2, TCTL2 and TFLG1.
One quick edit later, and we have fully working simulated PS/2 keyboard-clock interrupts working, and being counted. In the run below, typing ‘t’ triggers a falling-edge on IC3 via a loopback cable to PORTB pin 2, which the program twiddles in response to the command; typing ‘r’ just displays the value of the counter-variable that the ISR increments.
Bingo! It took a while, but I’m calling that a minor win. At last, we are ready to think about hooking up an actual PS/2 keyboard and capturing real bitstream-clock interrupts.