Timer
hylee101001
Posts: 48
I have been trying to make a timer that can pause about 30 sec. Half of the trial, my code works, but not the other half of the chance. So far, I figured that cnt is 16 bit number, and in decimal it varies -2^31 ~ 2^32 -1
So, if the cnt starts from negative region, it works, but if the cnt happens to return the positive region, due to the overflow, it messes up. So, to fight to that, I wrote the following code but still doesn't work well. Please help me.
Also, the weird thing is that this absolute function below, alwyas seems returning y value no matter what the calculation is. I do not know what I am missing. I thought this is the only way I could bypass the overflow..
What this code does is to measure the difference between current clock and the target cnt value and compare that with clkfreq so it stops when the clock is about 30 second elapsed.
PUB main | finish , check, base
usb.quickStart
base := cnt finish := cnt + clkfreq*30 check := absolute(cnt, finish) repeat while (check-clkfreq > 0) usb.str(String("elasp:")) usb.decLn((cnt-base)/clkfreq) usb.str(String("remaining: ")) usb.decLn((check-clkfreq)/clkfreq) usb.decLn(cnt) usb.decLn(finish) check := absolute(cnt, finish) usb.newline
usb.newline PRI absolute(x, y)
if (x>=y) result := x-y else result := y-x
So, if the cnt starts from negative region, it works, but if the cnt happens to return the positive region, due to the overflow, it messes up. So, to fight to that, I wrote the following code but still doesn't work well. Please help me.
Also, the weird thing is that this absolute function below, alwyas seems returning y value no matter what the calculation is. I do not know what I am missing. I thought this is the only way I could bypass the overflow..
What this code does is to measure the difference between current clock and the target cnt value and compare that with clkfreq so it stops when the clock is about 30 second elapsed.
PUB main | finish , check, base
usb.quickStart
base := cnt finish := cnt + clkfreq*30 check := absolute(cnt, finish) repeat while (check-clkfreq > 0) usb.str(String("elasp:")) usb.decLn((cnt-base)/clkfreq) usb.str(String("remaining: ")) usb.decLn((check-clkfreq)/clkfreq) usb.decLn(cnt) usb.decLn(finish) check := absolute(cnt, finish) usb.newline
usb.newline PRI absolute(x, y)
if (x>=y) result := x-y else result := y-x
Comments
Sandy
targetCnt := clkfreq * 30 + cnt repeat until cnt - targetCnt > 0 usb.decLn(||(cnt - targetCnt)) ' || is the absolute value operator ...
The problem in your absolute method is that x>=y is an assignment operator, equivalent to x := x > y. => is the operator for greater than or equal to.
I should have mentiond that I wanted to not use waitcnt because I need to write data in sd card for 30 seconds. Is there a better way?
If possible more than 30 seconds...
Perhaps, I just realized that I need to use a cog with waitcnt that changes flag of a loop in the default cog.
In your case 30 is longer than you can measure time with a single interval. You can only measure intervals up to about 26 seconds (with a 80MHz clock).
You'll want to count seconds. Use one of the RTC objects to track seconds. If you have trouble, let us know and we can help.
Chris,I'm pretty sure (since I've been bit by it several times) you can only compare intervals up to half the rollover time. Intervals longer than half the rollover time end up being evaluated as negative.
For example 30 times a 1 second wait:
For sure: the code in the loop must not take longer than 1 second to run here. Otherwise you can do for example 3 times a 10 second wait.
Andy
pub main | check
usb.quickStart timer.start check := 0
repeat while (check < 30_000) check := timer.millis usb.str(string("elapsed: ")) usb.decLn(check) usb.str(string("remaining: ")) usb.decLn(30_000 - check) usb.newline usb.newline timer.pause(5) ' prevent PST overflow
I second this suggestion. JonnyMac's timing routines are very simple to use and provide delays in milliseconds, so longer time delays are not a problem.
I second this suggestion. JonnyMac's timing routines are very simple to use and provide delays in milliseconds, so longer time delays are not a problem.
Part of the reason that I developed my timer object is to avoid long BLOCKING delays; this is just a waste of bandwidth. This style is nothing new; I simply created an object that helps me implement scheduling type programs very easily. A lot of my programs are looking like this now:
pub main | t1, t2, t3
timer.start
longfill(@t1, 0, 3)
repeat if ((timer.millis - t1) => T1_MILLIS) run_process_1 t1 += T1_MILLIS
if ((timer.millis - t2) => T2_MILLIS) run_process_2 t2 += T2_MILLIS
if ((timer.millis - t3) => T3_MILLIS) run_process_3 t3 += T3_MILLIS
I have been somewhat following this thread, but your last post peeked my interest just a wee bit more. Any chance I could convince you to provide a more full example of this source being used.
Bruce
Let's say that a process wants to run every 5 milliseconds but something caused the actual delay to be 6 milliseconds. It will run, and the adjustment made to its timer will cause it to run again 4 milliseconds later (back on schedule).
Mind you, this style is not for processes that require hyper-critical timing, and you want ensure that the combined time in your called processes is less than the shortest timer in your schedule.
Another strategy that I uses is to create separate timer objects for different processes. When I do this I use the .adjust methods to back-up a timer for a new cycle.
Last week I wrote some code for an escape house. In that case the client wanted a count-down time. No problem, I set the timer to a negative value and then use the absolute operator to fix it before sending it to a set of giant clock digits. That app takes advantage of my timer object's hold and release methods.
If possible more than 30 seconds...
Perhaps, I just realized that I need to use a cog with waitcnt that changes flag of a loop in the default cog.
You can always lower the SysCLK ?
2^32/80M = 53.687 sec
2^32/5M = 858.993 sec
Thank you for providing such a nice example. Your timer object looks pretty darn impressive. If you ever have a project that you are willing to share, in which you utilize all the methods of the timer object, I would be very interested in seeing all the various methods being utilized or perhaps an updated timer article.
Very nice... Thank you.
Bruce
The key to understanding the timer is that the internal storage unit is milliseconds -- this would let me time an event of about 24 days. This is an event timer, not an RTC, so I don't see any reason to go beyond that. Any of the methods that deal with seconds are in fact updating the internal milliseconds value.
I've recently worked on two commercial projects that required countdown timing. The attached demo gives you an idea how I do that. Note that I made a decision this morning to change my timer object to simplify putting it on hold with a specific value. Please overwrite the version you have now.
George Lucas once said that movies are never finished, they're simply abandoned. That's how I feel about my objects.
Thanks for the insight and update. Truly appreciated.
I like the fact that you kept updating as needed. Reusable code... Got to love it.
Bruce