First thought on an interface (to use Paleolithic DROM)
Re: First thought on an interface (to use Paleolithic DROM)
I'm not a great fan of delay-based debouncing. I like the idea, which may be a utopia, that the first transition causes an action, immediately, and then there should be a lockout which ignores subsequent transitions for a while (of the order of a hundred milliseconds perhaps.)
In a very simple key-based monitor, that could be done by structuring the main loop as
- wait for keypress
- perform action
- delay
- back to waiting
The delay could be a simple counting loop. No need for RC or VIAs.
Edit: (Or the delay could incorporate display refresh?)
Might this work? Might it be applicable here?
In a very simple key-based monitor, that could be done by structuring the main loop as
- wait for keypress
- perform action
- delay
- back to waiting
The delay could be a simple counting loop. No need for RC or VIAs.
Edit: (Or the delay could incorporate display refresh?)
Might this work? Might it be applicable here?
- GARTHWILSON
- Forum Moderator
- Posts: 8773
- Joined: 30 Aug 2002
- Location: Southern California
- Contact:
Re: First thought on an interface (to use Paleolithic DROM)
Gamers want absolutely instant response. For mere typing, I suppose there's some maximum amount of delay time before it becomes a bit irritating if you're watching the screen as you type. For my workbench computer, 40ms delay is no problem; but it's just a keypad, not suitable for typing on. What I've done is watch it and ignore it until it has been seen as pressed continually for that long. If it ever appears not to be pressed in that time, the count starts over, and it is not considered valid until the key is observed to be pressed continually for the 40ms.
If it is held continually, the delay-before-repeat starts, and after that, if if it continues to be pressed, the faster repeat rate kicks in. It can get pretty complex when you implement all of that, and then even more complex if you implement n-key rollover too; but I did not do the latter. Similar to what Ed is saying, what I might do next time is register the keypress immediately, but not register the next press of the same key until the key has been observed to be up continually for some amount of time, perhaps 50ms.
In my last related work project, I only needed four keys, and I brought them through RxC networks into microcontroller pins that had Schmitt-trigger inputs so I didn't have to do the debouncing in software. That saved me time.
If it is held continually, the delay-before-repeat starts, and after that, if if it continues to be pressed, the faster repeat rate kicks in. It can get pretty complex when you implement all of that, and then even more complex if you implement n-key rollover too; but I did not do the latter. Similar to what Ed is saying, what I might do next time is register the keypress immediately, but not register the next press of the same key until the key has been observed to be up continually for some amount of time, perhaps 50ms.
In my last related work project, I only needed four keys, and I brought them through RxC networks into microcontroller pins that had Schmitt-trigger inputs so I didn't have to do the debouncing in software. That saved me time.
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?
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Re: First thought on an interface (to use Paleolithic DROM)
BigEd wrote:
In a very simple key-based monitor, that could be done by structuring the main loop as
- wait for keypress
- perform action
- delay
- back to waiting
- wait for keypress
- perform action
- delay
- back to waiting
- tests for keypress
- does things if true, and
- waits for keyrelease
- small delay while display is updated
- rinse and repeat
However, it handles each column independently; a keypress is only returned if it's in the same colum that's currently being displayed. So there are some tens or hundreds of microseconds before the same key - in general, the only one being pressed, is read again.
It might be possible to introduce a further simple delay - an eight bit count could be around 256 * five cycles per delay, call it half a millisecond.
I think I need to fire the scope up.
Neil
Re: First thought on an interface (to use Paleolithic DROM)
"wait for keyrelease" is something to do after a delay, I think - it's a good idea, if you don't want an auto-repeat, but doing it too early could be merely sampling keybounce.
Bruce wrote a stupendously clever and tiny delay loop - see
viewtopic.php?p=62581#p62581
but for a more conventional approach see
viewtopic.php?p=62459#p62459
(For musings on input delays, see https://danluu.com/input-lag/)
Bruce wrote a stupendously clever and tiny delay loop - see
viewtopic.php?p=62581#p62581
but for a more conventional approach see
viewtopic.php?p=62459#p62459
(For musings on input delays, see https://danluu.com/input-lag/)
Re: First thought on an interface (to use Paleolithic DROM)
BigEd wrote:
"wait for keyrelease" is something to do after a delay, I think - it's a good idea, if you don't want an auto-repeat, but doing it too early could be merely sampling keybounce.
Bruce wrote a stupendously clever and tiny delay loop - see
viewtopic.php?p=62581#p62581
Bruce wrote a stupendously clever and tiny delay loop - see
viewtopic.php?p=62581#p62581
And going to the very smallest version of the DROM routine with just GO and CR functions to make the maximum possible space means a software-only debounce has to be really good, not just "mostly OK", because there is no way to go back other than to do over 65,000 CR's to loop around an address at a time.
barnacle wrote:
BigEd wrote:
In a very simple key-based monitor, that could be done by structuring the main loop as
- wait for keypress
- perform action
- delay
- back to waiting
- wait for keypress
- perform action
- delay
- back to waiting
- tests for keypress
- does things if true, and
- waits for keyrelease
- small delay while display is updated
- rinse and repeat
However, it handles each column independently; a keypress is only returned if it's in the same colum that's currently being displayed. So there are some tens or hundreds of microseconds before the same key - in general, the only one being pressed, is read again.
Looking at the switches actually planned to be used in an oscilloscope moves it from generic pictures of bouncing switch timelines to the actual one the code is looking at, but those generic pictures show a stochastic process that is roughly one or a few separated early spikes, then mostly contacted with one or a few narrow dropouts, then full contact, then one or a few narrow dropouts on release, and one or a few separated spikes at the tail end of release.
If you have any ST inverters or NAND's on hand, looking at the cap/resister alone, with hysteresis after only, and with hysteresis before and after would be instructive. With hysteresis after, to have Press=0, that would be charging the cap when the switch is closed. Hysteresis before doesn't affect whether the cap charges or drains when the switch is closed, because there is both a press=high and press=low signal available from the priority encoder.
That's why the Logi Switch parts work as they do, to ride through the early noise period (which copes with different switches, as bouncier switches will have a longer noise period), then 20ms rides through a few dropouts, then the transition is passed through, and the same on the release.
And the whole process would take multiple swings through the LED cycle, so as written, it seems likely that a lot of key strokes will be read as double or triple strikes, some key strokes catching the key while its still bouncing enough for the hold loop to think it sees the release, and some release bounces being captured as fresh keystrokes.
A 10ms cap/resister rising delay preceded by hysteresis would filter out much of the "early scattered spikes", follow it by hysteresis and it would likely clean up 0/1 transition unless there's really bad luck when a drop-out hits, and then the main and followed by hysteresis would eliminate most key strokes caught during the early "mostly not pressed" part of the timeline, ride out most "dropouts while not quite fully pressed".
So depending on whether the oscilloscope on those switches shows too long a period of "halfway pressed" whether the cap might oscillate enough to pass the hysteresis boundaries, putting hysteresis before to filter the earliest and latest noise and also after to avoid transition noise might be pretty good.
Of course, there is the question of how good is good enough. One bounce in 100 keystrokes might be use-able in the version of the user interface with CR going forward on and "-" going back one. However, testing for wrap-around takes too many bytes, so "+" decrements both the high and low address byte, which goes back one when when the low byte is 0 (and zooms down 257 bytes when it isn't).
This also requires using the absurd trick that the base routine address "addr0" is page aligned, so the "GO" function jumps to the BRK/IRQ vector location holding addr0, which is a BRK instruction, which when executed does a BRK call to the $0200 location. Obviously this leaves clutter on the stack, but since the stack is not yet set up, that's a harmless side effect.
That would be like this, completely filling the 128 byte quota:
Code: Select all
code
org $ff80
; System Reset starts here
start: ; +6
; Set base address, this is also "review"
lda #>addr0
sta memptr+1
stz memptr ; start at page aligned addr0
loop_main: ; +19
; current state to leds
; put memptr and (memptr) into leds
; [x][x][x][x][x][x][ ][ ]
;
ldx #0
lda memptr+1
jsr to_leds
lda memptr
jsr to_leds
lda (memptr)
jsr to_leds
; Initialize the display count
; Need to drive six leds for display
; The sixth is redundant for 4x5 "keyboard"
; Top two leds are never driven, so dark
ldy #5
loop_digit: ; +10
; for each LED digit (right to left)...
lda leds,y
sta led_addr,y ; display bit pattern
lda keys
; d7=NOR(row1,row2,row3,row4,row5)
bmi loop_99 ; no key pressed
; +12
; do stuff to sort out the key value
; a hex key if below smallest command code
; above, set up to be KEY_GO
cmp #KEY_GO
bmi loop_hex ; enter hex value
beq exec ; jump punched in code
cmp #KEY_GB
beq loop_ob ; decrement memptr
bpl loop_pb
; +8
; remaining special key is return
; accept current byte value, increment memptr
inc memptr
bne loop_90
inc memptr+1
bra loop_90
loop_pb: ; +6
dec memptr+1
loop_ob:
dec memptr
bra loop
loop_hex: ; +14
; else shuffle key value into (memptr)
; In this version, d7=Press
; d7 set if hex key
pha
lda (memptr)
asl a
asl a
asl a
asl a
sta (memptr)
pla
ora (memptr)
sta (memptr)
loop_90: ; +5
; wait for key to be released
; this will cause display glitch, but...
lda keys
bmi loop_90
loop_99: ; +5
dey
bpl loop_digit
bra loop_main
to_leds: ; +23
; unpack byte into two successive LED patterns
; x has character position
pha
lsr a
lsr a
lsr a
lsr a ; high nibble
tay
lda LED_PATTERNS,y
sta leds,x ; this byte comes first
inx ; advance char position
pla
and #$0f ; low nibble
tay
lda LED_PATTERNS,y ; index into the patterns
sta leds,x ; and this byte comes next
inx ; advance char position
rts
org $ffec ; +16
LED_PATTERNS:
db 0b00111111 ;0
db 0b00000110 ;1
db 0b01011011 ;2
db 0b01001111 ;3
db 0b01100110 ;4
db 0b01101101 ;5
db 0b01111101 ;6
db 0b00000111 ;7
db 0b01111111 ;8
db 0b01101111 ;9
db 0b01011111 ;a
db 0b00111100 ;b
db 0b00101000 ;c
db 0b01011110 ;d
db 0b01111101 ;e
db 0b01110001 ;f
org $fffc ; +4
dw start
exec: dw addr0 ; "GO" key Re: First thought on an interface (to use Paleolithic DROM)
Getting a workable (if a bit wonky) backspace added to the "GO"/"CR" system is pretty much my last gasp on the DROM routine, falling over the finish line with exactly 0 bytes to spare (the one byte I thought I had was a miscount of a "lda keys" as two rather than three bytes).
IOW, I think that last one is kind of it for me regarding the DROM routine unless there is a hardware change ... if there's any way to squeeze out any space for a "round the horn" delay loop, leveraging the amount of time it would take to get back to the Y index where a character was first detected, I surely won't be the one to see it.
(That doesn't mean I won't have a look at an around-the-horn software debounce, just that I'll look at it in the context of the 256-384 bytes micro-monitor, to make it "not as glitchy" for the LEDs.)
However, with what we've seen from the tac switches on the oscilloscope from the other thread, it seesm plausible that a single ~10ms debounce delay, feeding into one Schmitt Trigger NAND configured as an inverter and then into one of the free inverters -- to get the d7 Press=0 signal rightside up again -- could well do it well enough.
Or, if it helps the routing, feeding into two Schmitt Trigger NAND's in succession. Although it seems like it's the hysteresis of the first one that would provide the needed glitch protection in moving from 1 to 0 (and back again) ... I can't see how there'd be harm in using the final free NAND on the same U10 chip to invert it back to get a direct drop signal for a press.
At the time scale of the bouncing, it's clearer that there'd be no benefit from filtering out the highest frequency noise, so a Schmitt Trigger in front of the capacitor wouldn't do any good very often, if ever ... as the very highest frequency noise has proportionally smaller ability to disrupt the capacitor charge level. So if U10 is specified as a Schmitt Trigger NAND, both free gates can be used on the back end of the debounce to cobble together a de-facto direct Schmitt Trigger buffer.
IOW, I think that last one is kind of it for me regarding the DROM routine unless there is a hardware change ... if there's any way to squeeze out any space for a "round the horn" delay loop, leveraging the amount of time it would take to get back to the Y index where a character was first detected, I surely won't be the one to see it.
(That doesn't mean I won't have a look at an around-the-horn software debounce, just that I'll look at it in the context of the 256-384 bytes micro-monitor, to make it "not as glitchy" for the LEDs.)
However, with what we've seen from the tac switches on the oscilloscope from the other thread, it seesm plausible that a single ~10ms debounce delay, feeding into one Schmitt Trigger NAND configured as an inverter and then into one of the free inverters -- to get the d7 Press=0 signal rightside up again -- could well do it well enough.
Or, if it helps the routing, feeding into two Schmitt Trigger NAND's in succession. Although it seems like it's the hysteresis of the first one that would provide the needed glitch protection in moving from 1 to 0 (and back again) ... I can't see how there'd be harm in using the final free NAND on the same U10 chip to invert it back to get a direct drop signal for a press.
At the time scale of the bouncing, it's clearer that there'd be no benefit from filtering out the highest frequency noise, so a Schmitt Trigger in front of the capacitor wouldn't do any good very often, if ever ... as the very highest frequency noise has proportionally smaller ability to disrupt the capacitor charge level. So if U10 is specified as a Schmitt Trigger NAND, both free gates can be used on the back end of the debounce to cobble together a de-facto direct Schmitt Trigger buffer.
Re: First thought on an interface (to use Paleolithic DROM)
I went a bit all out on the debouncing: 2 resistors and a capacitor per switch row, feeding a '541 for the Schmitt trigger non-inverted output.
However, I want to play further and make that footprint so it will also accept a SOIC, if the TI DIP part doesn't work well.
Neil
Neil
Re: First thought on an interface (to use Paleolithic DROM)
Sounds great - I can get your minimal monitor code (and indeed your Basic) onto the Source Repository when you're ready - just drop me a message. (Likewise I could update it if and when you make a change.)
Re: First thought on an interface (to use Paleolithic DROM)
I'll do that, Ed, thanks. But I think I should actually build one of each, and put together a complete package: circuit diagrams, gerbers, recommended order of construction, and perhaps some example programs?
The minimal monitor isn't much use absent the particular hardware; it's size restriction makes it somewhat hardware dependent
though the board will run the tiny basic with only changes to the UART address constants.
Neil
The minimal monitor isn't much use absent the particular hardware; it's size restriction makes it somewhat hardware dependent
Neil
Re: First thought on an interface (to use Paleolithic DROM)
I would be inclined to share early and share often: the ideas are valuable and the example is worth something. (Edit: a personal view of course not universally held!)
Re: First thought on an interface (to use Paleolithic DROM)
barnacle wrote:
I went a bit all out on the debouncing: 2 resistors and a capacitor per switch row, feeding a '541 for the Schmitt trigger non-inverted output. ...
In line with why the LS19-P won't work, the switch column goes live three clock cycles before the key is read, and then if there is no key the column switches before the next time the key is read ... is that enough time for the capacitor to discharge?
It may be that getting the values right for the capacitor to discharge after two or three pulses, a pulse at a time, may be plenty of time to ride out the attack bounce, and then the slower recharge guarantees riding out the release bounce. It seems like it would be something in the ratio of 16:1-20:1 between discharge speed and recharge speed, so a 5ms steady-state discharge might actually be a touch slow with discharge over roughly 1/8th of the time domain and recharge over 7/8ths while a button is pressed.
If net discharging while fully pressed, reading the key so soon into the discharge cycle would seem to give excellent debounce performance.
Here's an alpha of the DROM code with the wetware assisted backspace. This isn't the pseudo-ops of the ACME assembler I use, so let me know if I don't have this assembler's mnemonics correct anywhere ... I'll be converting it to ACME for generating the binary target.
One last note: for symmetric key read periods, that code works better with keys on the 2nd through 5th LED column of new ... obviously at the IRQ jiffy clock level, symmetry can be assured for all column lines.
- Attachments
-
- MESOLITHIC_DROM_v7.asm
- (3.43 KiB) Downloaded 8 times
Re: First thought on an interface (to use Paleolithic DROM)
Thanks Bruce; I'll assemble it and try single stepping on the simulator. I guess we won't find out about the time constants until I have a working framework.
To work around the possibility of having to use a SOIC Nexperia part if the TI _isn't_ a Schmitt input, I've squeezed in some more PCB warnings... that way I can test both parts in situ. I'd rather keep everything except passives as through hole if possible; soldering an sm resistor is a lot simpler for a neophyte than a soic, but both are certainly doable. But through-hole sockets are a doddle. Ugly but workable. Normal 14 and 16 pin SOICs will fit inside a normal DIP footprint, but not the wide package 20 pin.
My first thought for a construction order:
Neil
To work around the possibility of having to use a SOIC Nexperia part if the TI _isn't_ a Schmitt input, I've squeezed in some more PCB warnings... that way I can test both parts in situ. I'd rather keep everything except passives as through hole if possible; soldering an sm resistor is a lot simpler for a neophyte than a soic, but both are certainly doable. But through-hole sockets are a doddle. Ugly but workable. Normal 14 and 16 pin SOICs will fit inside a normal DIP footprint, but not the wide package 20 pin.
My first thought for a construction order:
- All the SM resistors
- All the SM capacitors
- The SM diode
- If applicable, the SOIC 20 buffer
- The DIP sockets
- The switches
- The seven-segment LEDs (decimal point to bottom right)
- The pin headers
Neil
Re: First thought on an interface (to use Paleolithic DROM)
Yeah, browsing around showed part of the market for direct drive Schmitt Trigger parts is the automotive industry (unsurprising that they like cleaning up high frequency noise), which isn't a market segment that helps maintains the stock of DIP packages.
I'll likely do a cycle count sometime in the next few days, to get an idea of how long the on-periods and off-periods are for the DROM code I posted if running at 1.8MHz (and see whether the asymmetry on the 1st LED column is pronounced). I have a hunch that a 6 LED cycle with a longer dwell on the first LED column might leave the 2nd-5th columns with a similar share of the time as a VIA clock tick interrupt on a steady 8 LED cycle ... though with the rotation between the columns happening at much higher frequency in the DROM code than with a proper background IRQ on a CIA clock tick.
Edit: I've looked, and the savings of two bytes by moving the led save routine out of the digit kills any chance for the capacitor to be drained on any other LED column. So I've added phy/ply back to the to_leds routine and put it back into the individual digit loop. That kills even the halfway proper backspace I had just worked out.
The best I can do is a single byte backspace that wraps at a page boundary on "-", and the "restart the address from the beginning" routine on "+", on the theory that if bad luck makes CR bounce across a page boundary, where the backspace function doesn't help, the user can make a note and then fix it up in a second pass while double checking the code.
Back of the envelope, restoring your LED segment definitions to the digit loop makes each digit loop without a detected keypress come in around 220 clock cycles, or about 0.12ms at 1.8MHz. So a steady state total discharge in 5ms when the key is closed and total charge in 100ms (20:1) would drop 1.8% of charge with 1 cycle on the key column discharging fast, 5 cycles on the other columns charging slow. If the hysteresis is roughly 2v to to drop and 3v to rise (I've seen in the range of 0.9v hysteresis gap in some HC ST datasheets), it would take around 33 full main loops with the switch fully closed to detect the key stroke, or 23ms.
Then for the DROM, as soon as the key is detected, the code locks the column on the key until the release is detected, so with the bias to discharge, it seems unlikely there will very often be bouncing at that point that lasts long enough to recharge the capacitor over the hysteresis boundary before the capacitor is completely discharged. Then after release, it would be roughly 60ms before release is detected, at which point even fairly worn tac switches seem like they'd be done bouncing.
On that quick look, perhaps 1:16 might be aimed at ... discharge for a 5ms complete discharge at steady state and charge at 80ms complete charge at steady state, giving a slight longer delay on the key attack but faster recovery from the key release.
I'll likely do a cycle count sometime in the next few days, to get an idea of how long the on-periods and off-periods are for the DROM code I posted if running at 1.8MHz (and see whether the asymmetry on the 1st LED column is pronounced). I have a hunch that a 6 LED cycle with a longer dwell on the first LED column might leave the 2nd-5th columns with a similar share of the time as a VIA clock tick interrupt on a steady 8 LED cycle ... though with the rotation between the columns happening at much higher frequency in the DROM code than with a proper background IRQ on a CIA clock tick.
Edit: I've looked, and the savings of two bytes by moving the led save routine out of the digit kills any chance for the capacitor to be drained on any other LED column. So I've added phy/ply back to the to_leds routine and put it back into the individual digit loop. That kills even the halfway proper backspace I had just worked out.
The best I can do is a single byte backspace that wraps at a page boundary on "-", and the "restart the address from the beginning" routine on "+", on the theory that if bad luck makes CR bounce across a page boundary, where the backspace function doesn't help, the user can make a note and then fix it up in a second pass while double checking the code.
Back of the envelope, restoring your LED segment definitions to the digit loop makes each digit loop without a detected keypress come in around 220 clock cycles, or about 0.12ms at 1.8MHz. So a steady state total discharge in 5ms when the key is closed and total charge in 100ms (20:1) would drop 1.8% of charge with 1 cycle on the key column discharging fast, 5 cycles on the other columns charging slow. If the hysteresis is roughly 2v to to drop and 3v to rise (I've seen in the range of 0.9v hysteresis gap in some HC ST datasheets), it would take around 33 full main loops with the switch fully closed to detect the key stroke, or 23ms.
Then for the DROM, as soon as the key is detected, the code locks the column on the key until the release is detected, so with the bias to discharge, it seems unlikely there will very often be bouncing at that point that lasts long enough to recharge the capacitor over the hysteresis boundary before the capacitor is completely discharged. Then after release, it would be roughly 60ms before release is detected, at which point even fairly worn tac switches seem like they'd be done bouncing.
On that quick look, perhaps 1:16 might be aimed at ... discharge for a 5ms complete discharge at steady state and charge at 80ms complete charge at steady state, giving a slight longer delay on the key attack but faster recovery from the key release.
- Attachments
-
- MESOLITHIC_DROM_wrappingbackspace.asm
- (3.46 KiB) Downloaded 9 times
Re: First thought on an interface (to use Paleolithic DROM)
Back of the envelope again, by contrast, on a 64 ticks per second IRQ routine, checking the key at the beginning of the IRQ before moving onto the next LED row later in the routine, the same capacitor with the same charge/discharge rates would only not be fully discharged between one tick and the next if the initial attack was in the last third of that window, while 7 ticks would be long enough for it to fully charge. So on the above charge/discharge rates, and using the span between ticks as a period for a cap to discharge if pressed, the debounce circuit would only act as a delay for attacks and releases occurring very close to the attempt to read them, and then likely only by one complete LED cycle.
Re: First thought on an interface (to use Paleolithic DROM)
I'd suspect you'd want a faster refresh rate than that; you'd want to see each LED refreshed fifty or sixty times a second minimum, so around four hundred ticks a second from an IRQ.
Neil
Neil