6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 01, 2024 1:25 am

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: Mon May 02, 2022 8:01 pm 
Offline
User avatar

Joined: Sun Dec 26, 2021 8:27 pm
Posts: 182
I'm essentially debouncing. Set LASTKB = MILLIS at a point in time, compare 16 bit timer value MILLIS to it continuously and check if 100 ticks have passed.
First I subtract the two 16 bit numbers. Then subtract the 100 and check carry.

Surely there must be a much better way to do this?

Code:
sec        ;
lda MILLIS ; Timer increments via IRQ
sbc LASTKB ; Fixed point in time
sta TMPL
lda MILLISH
sbc LASTKBH
sta TMPH

sec
lda TMPL
sbc #100 ; I want to check if 100 ticks have passed
lda TMPH
sbc #0
bcc notyet ; Result was negative, time has not elapsed

_________________
---
New new new new new video out! Serial Bootloader for my 65uino
Also, check out: I2C on a 6502 Single Board Computer
and Complete hardware overview of my 6502 SBC R1 :)


Top
 Profile  
Reply with quote  
PostPosted: Mon May 02, 2022 8:11 pm 
Offline

Joined: Sat Jan 02, 2016 10:22 am
Posts: 197
You could add the 100 to MILLIS before you save the LASTKB value.

The all you need in the checking code is a compare.


Top
 Profile  
Reply with quote  
PostPosted: Mon May 02, 2022 8:15 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 333
The obvious improvement is to set LASTKB = MILLIS + 100 instead. Then
Code:
lda MILLIS
cmp LASTKB
lda MILLIS+1
sbc LASTKB+1
bcc notyet


... as Martin said while I was typing. I will leave replacing "sec / sbc" with "cmp" as my contribution.


Top
 Profile  
Reply with quote  
PostPosted: Mon May 02, 2022 8:33 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8534
Location: Southern California
Martin A wrote:
You could add the 100 to MILLIS before you save the LASTKB value.

The all you need in the checking code is a compare.

Yes; you could have lots of tasks watching the same clock on the wall, each one having its own target time which it compares to.

Like Martin A says, add the desired delay to the current time (just once), and store the resulting target time in that task's variable. Then just watch for when the current time matches (or exceeds) the target time. Take the current time minus the target time. If the answer is negative, you haven't arrived yet. It works nicely for multiple-precision too.

This is part of what's discussed in my article "Simple methods for multitasking without a multitasking OS, for systems that lack the resources to implement a multitasking OS, or where hard realtime requirements would rule one out anyway."

_________________
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: Mon May 02, 2022 8:45 pm 
Offline
User avatar

Joined: Sun Dec 26, 2021 8:27 pm
Posts: 182
Of course! Much better!

Thank you all!

_________________
---
New new new new new video out! Serial Bootloader for my 65uino
Also, check out: I2C on a 6502 Single Board Computer
and Complete hardware overview of my 6502 SBC R1 :)


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2022 4:39 am 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
Personally, I would set the timer as a countdown timer you want to elapse, then use the IRQ to call the timer routine that decrements instead.

This way should be faster:

LDA MILLIS
BNE :1

DEC MILLIS+1 ; to use the full 16-bit value, then increment this by 1 when initializing values
BMI ALARM ; and use BEQ instead

:1 DEC MILLIS


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2022 4:48 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8534
Location: Southern California
Rob, that's ok if you're only timing one thing; but you wouldn't want the ISR to have to do that for lots of things that are being timed. AndersNielsen said the particular application was debouncing; but since he apparently wants to be running other things at once (otherwise he might just use a timing loop), I imagine there is cooperative multitasking, or there will be later. I think it's better to run just the one clock, and have the various tasks compare it to their target times. I've done this in quite a few products.

_________________
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: Tue May 03, 2022 5:11 am 
Offline
User avatar

Joined: Sun Dec 26, 2021 8:27 pm
Posts: 182
Technically I could time my main loop roughly and do

Code:
DEC lastkb
BNE notyet
[…]
;reset lastkb
notyet:


That would probably be the least overhead, running only every x loops - but not very consistent, timing wise.

If I used the ISR to decrement, like Rob suggested, it would be more consistent but the more things that need timing would quickly bloat the ISR.

_________________
---
New new new new new video out! Serial Bootloader for my 65uino
Also, check out: I2C on a 6502 Single Board Computer
and Complete hardware overview of my 6502 SBC R1 :)


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2022 12:59 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
GARTHWILSON wrote:
Rob, that's ok if you're only timing one thing; but you wouldn't want the ISR to have to do that for lots of things that are being timed. AndersNielsen said the particular application was debouncing; but since he apparently wants to be running other things at once (otherwise he might just use a timing loop), I imagine there is cooperative multitasking, or there will be later. I think it's better to run just the one clock, and have the various tasks compare it to their target times. I've done this in quite a few products.

The debouncing would still affect the count-up timer the same way as the extra ticks will still be added to the timer . The number of variables used would still be the same for a count-up timer vs countdown timer. The same number of variables would be needed for multi-tasking for each method. The countdown way eliminates the clock altogether except at the beginning when one has to calculate the difference between the starting MILLIS time and the target time.

Doing a 16-bit comparison takes 5 cycles longer on each pass using the count-up timer for a multitask environment. I see way more benefits to using a countdown timer vs count-up timer. The only real difference is one can more readily see the time elapsed with a count-up timer vs time-remaining for a countdown timer.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2022 1:08 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
AndersNielsen wrote:
Technically I could time my main loop roughly and do

Code:
DEC lastkb
BNE notyet
[…]
;reset lastkb
notyet:


That would probably be the least overhead, running only every x loops - but not very consistent, timing wise.

If I used the ISR to decrement, like Rob suggested, it would be more consistent but the more things that need timing would quickly bloat the ISR.

There shouldn't be any extra bloat as the calculations to set the timer are pretty much the same with each method and depending on the use-method, may be faster for a countdown timer.

For a count-up timer you have to subtract the desired elapsed time from the current clock's time. For a countdown timer, you just set the desired elapsed time with values.


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2022 3:49 pm 
Offline

Joined: Mon Sep 17, 2018 2:39 am
Posts: 138
Hi!
John West wrote:
The obvious improvement is to set LASTKB = MILLIS + 100 instead. Then
Code:
lda MILLIS
cmp LASTKB
lda MILLIS+1
sbc LASTKB+1
bcc notyet


... as Martin said while I was typing. I will leave replacing "sec / sbc" with "cmp" as my contribution.


The above (and all the other code samples given) suffer from a data race: the ISR could fire just between the first LDA MILLIS and the second LDA MILLIS+1, and the roll-up will invalidate the count:

- Suppose MILLS = $0100
- LDA MILLS ; A = 0
- Now, the ISR fires and MILLS = $00FF
- LDA MILLS+1 : A = 0

So, instead of reading $0100 or $00FF, you are reading $0000, an invalid value.

To avoid this, you must read the value properly, the only way to do it in the presence of NMI is:
Code:
readTime:
  LDX MILLS+1
  LDA MILLS
  CPX MILLS+1
  BNE readTime
  RTS


Now, if you have multiple tasks waiting for a given time to perform some action, it is better to have a priority queue with all the tasks, so you only check the earliest task available each loop.

Have Fun!


Top
 Profile  
Reply with quote  
PostPosted: Tue May 03, 2022 7:28 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8534
Location: Southern California
The routine to see if it's time yet will run so many times that its total number of cycles will dwarf the set-up time. The compare-to-zero thing is of course always preferable when it's a practical option, which it won't be if you're timing multiple things with the same timer, unless you implement dmsc's interesting idea of a priority queue. Even there, I think the accuracy, for the things that need it, would be lost, as there would be some indeterminate number of cycles required to set up for the next time-out, and error would accumulate. When one task is written, it may still be unknown how accurate the clock will need to be for another task that has not been written yet. Many things will also need more than just the 16 bits of a VIA timer. Even in the case of key debouncing, if your φ2 rate is rather high, the 16 bits of a VIA's timer won't be enough. As keys age and get bouncier, they require more debounce time. I one situation I saw it need over 100ms before I finally decided it's time to give in and go to the effort to replace that key. I usually go for 30ms though; and even at just 5MHz, you can only reach about 13ms with a VIA's timer. The thing to do then is to set it up to generate an interrupt at some round number like 1ms or 10ms, and have the ISR increment a variable which will probably have multiple bytes. And yes, I always do what dmsc says, about comparing to make sure the time didn't get incremented and carry between bytes read.

_________________
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  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

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