Jump to content
xv4y

Real-Time Clock (RTC) Library for the MSP430/LaunchPad

Recommended Posts

Interesting, why would one library lag and the other wouldn't? I mean, they both use the same clocksource, don't they?

In theory yes. However the original library had the code to configure ACLK to run off the crystal in the constructor. This code ran before the initialisation in the Energia library, which then changed the configuration of ACLK to run off the VLO instead. Also, Energia reconfigured P2.6 & P2.7 which interfered with crystal operation. By moving the clock setup to the begin() function, it ensures the clock is configured AFTER the Energia library does its playing.

Share this post


Link to post
Share on other sites

Hi folks,

 

Well the first sRTC lib was quickly written for Energia 006 which did not have the P2_6 and P2_7 forced to GPIO and the ACLK set to VLO. Energia is still in early development stage, and my library was waiting for someone like Grahamf72 to improve it.

Someone (sorry I forgot who) suggested some modifications to my library for "code cleanliness". I've done the mods and added a ++ operator. It is neat indeed, but uses slightly more Flash worst slightly more RAM. We have not that much RAM on the MSP430 so personally I prefer to use the Inc_chunk routine directly.

 

Perhaps I need to upgrade my blog page code, but first I will have a look to Graham's work and see if it is better to directly link to his package if available somewhere for download.

 

Yan.

Share this post


Link to post
Share on other sites

I'd just like to point out that Yan (xv4r) did all the hard work with the code, I just tracked down the cause of the timing bug in Energia 9, and tweaked it a little to make it more suited for a couple of uses that I have for it. I still consider it his library, not mine.

 

Other than the attachment to the posts in this thread, I haven't set up webpage where it is available for download. Yan you are more than welcome to place it on your website, since it is 90% your work anyway. From experiments I've done with it, if dates are turned off, the resulting library compiles to be exactly the same size as your original library - which is proof that it is your work, not mine.

 

Although I won't take much credit for the library, if people do find it useful I would love a PM with a brief rundown of your project.  At the moment I am using it in a clock connected to a 16x2 LCD, where it has run for a couple of weeks and is still within a second of my desktop computer.  I have two plans for projects that will implement this code. One is a logging weather station and the other is a "word clock" - the type that highlights different words to indicate the time.

Share this post


Link to post
Share on other sites

If you say delay, you mean a delay_cycles or delay_ms type of wait routine?

 

In that case, yes, it does affect your clock accuracy, as you could at best time the period between two executions of your loop. This means that, for example, you'd wait one second and then execute some clock display refresh routine that takes 1 millisecond. This means that every loop iteration will take 1.001 second. So after 3600 seconds (one hour) you'll be off by 3.6 seconds.

This will be even worse if you use interrupts, as the delay routine will just continue where it was interrupted. So if you have an interrupt that takes 50 microseconds executed four times per second, it will enlongate your loop iteration by 4 * 0.05 = 0.2 milliceonds. The whole iteration will now be 1.0012 seconds, and you'll be off by 4.32 seconds.

And the nack with interrupts is, you never exacly know when they'll happen, so you cannot compensate for them.

Share this post


Link to post
Share on other sites

If you say delay, you mean a delay_cycles or delay_ms type of wait routine?

 

In that case, yes, it does affect your clock accuracy, as you could at best time the period between two executions of your loop. This means that, for example, you'd wait one second and then execute some clock display refresh routine that takes 1 millisecond. This means that every loop iteration will take 1.001 second. So after 3600 seconds (one hour) you'll be off by 3.6 seconds.

This will be even worse if you use interrupts, as the delay routine will just continue where it was interrupted. So if you have an interrupt that takes 50 microseconds executed four times per second, it will enlongate your loop iteration by 4 * 0.05 = 0.2 milliceonds. The whole iteration will now be 1.0012 seconds, and you'll be off by 4.32 seconds.

And the nack with interrupts is, you never exacly know when they'll happen, so you cannot compensate for them.

 

 

is greatly affected. can check yourself. 

if you do Clock on the method of delay(): 1% or more of the difference depends on the specific code.

 

d'oh ! now i must find a smarter way to deal with my problem. which i don't know what is wrong :/ is there a way to do "debugging" to check the variable' states etc. cause my code has been so messy for me.. : / 

Share this post


Link to post
Share on other sites

In CCS/IAR you can attach "watches" to your variables, I don't know about Energia.

 

If your code is too messy, start cleaning it up.

 

You could share your code, so we can have a look at your problem... given you describe the problem.

Share this post


Link to post
Share on other sites

In CCS/IAR you can attach "watches" to your variables, I don't know about Energia.

 

If your code is too messy, start cleaning it up.

 

You could share your code, so we can have a look at your problem... given you describe the problem.

 

I am using Energia.. I will try to tidy up the code and then share with you guys. I am having a strange problem on my Light Alarm Clock Project ^_^''. Thank you.

Share this post


Link to post
Share on other sites

Can you please tell me what happens if i use "delay" method in my code. Does it affect the accuracy of the Clock?

If you are using this RTC library, in most cases it will not be affected by delay().

 

It is best practice to not have any code that calls delay() inside the Timer Interrupt Function. Short delays will work ok, but if the delay is long enough that the timer will trigger again before you have finished handling the previous interrupt, you will very quickly run out of RAM. If using my version of the RTC library and with #define RTCSUBSECONDS turned on, your interrupt routine must run in less than 3 milliseconds. This doesn't give scope for using delay() - your interrupt needs to just increment the clock counter & get out.

 

If however you are using delay() in other sections of code outside the Timer Interrupt function it won't have any effect on the accuracy of the timer. The RTC library requires you to create an interrupt function, which is configured to trigger based on ACLK - either once per second or 256 times per second (depending on if you use #define RTCSUBSECONDS). Energia also sets up an interrupt based on the SMCLK that is called 31250 times per second. This interrupt is used to increment an internal counter that is used for the millis() function. When you call delay(), it simply starts a loop in LPM0 that waits until the specified number of millis() have elapsed. This loop doesn't stop the ACLK interrupt from running, so if the RTC's ACLK interrupt triggers whilst inside the delay() function, it will run and update the RTC as per normal.

 

So for example the following code will work as per normal...

#include <RTCplus.h>

RealTimeClock rtc;

setup(){
  rtc.begin();
};

loop(){
  delay(5000);  // put code here to do something useful - eg print the value of the RTC.
                // this code will only run approximately once every 5 seconds
                // but when it does run, the RTC will be accurate.
};
interrupt(TIMER1_A0_VECTOR) Timer(void) {
    rtc.Inc();     // While we can do some other things inside the interrupt other than just increment the
                   // timer, care needs to be taken with how long the routines used here take to run. It is
                    // best to just increment the timer and not do much else.
};

But the following code will crash - it will run out RAM because the Timer keeps getting called before it has finished running.

#include <RTCplus.h>

RealTimeClock rtc;

void setup(){
  rtc.begin();
};

void loop(){
};
interrupt(TIMER1_A0_VECTOR) Timer(void) {
    rtc.Inc();
    delay(5000);  // bad practice to call delay, or run any other code that will
                  // take a long time to execute, inside the interrupt routine.
                  // If the delay is still running when the interrupt next triggers
                  // we will ultimately end up running out of RAM, because of all
                  // the interrupt calls getting put on the stack.
      // other time consuming code here - bad.
};

Share this post


Link to post
Share on other sites

Oh I see, I had read the question as "how accurate will a clock be if I use delay to count my seconds". If the question was meant as "can I use delay on other places in my code while using this RTC lib" then delay shouldn't pose much of a problem. However I still recommend not using delay inside interrupts, only use it in setup() and/or loop().

On the other hand, I've barely ever required the need for any delay like this. Most of my code is written in either only interrupts or a tick driven statemachine.

In the latter case I have a state machine function that is either called by the timer interrupt or in the loop() (or main while in IAR/CCS) and the timer wakes the MSP from low power, then the loop will execute and go back to low power. If I need any set delay I use a counter that counts these ticks.

Share this post


Link to post
Share on other sites

 

If you are using this RTC library, in most cases it will not be affected by delay().

 

It is best practice to not have any code that calls delay() inside the Timer Interrupt Function. Short delays will work ok, but if the delay is long enough that the timer will trigger again before you have finished handling the previous interrupt, you will very quickly run out of RAM. If using my version of the RTC library and with #define RTCSUBSECONDS turned on, your interrupt routine must run in less than 3 milliseconds. This doesn't give scope for using delay() - your interrupt needs to just increment the clock counter & get out.

 

If however you are using delay() in other sections of code outside the Timer Interrupt function it won't have any effect on the accuracy of the timer. The RTC library requires you to create an interrupt function, which is configured to trigger based on ACLK - either once per second or 256 times per second (depending on if you use #define RTCSUBSECONDS). Energia also sets up an interrupt based on the SMCLK that is called 31250 times per second. This interrupt is used to increment an internal counter that is used for the millis() function. When you call delay(), it simply starts a loop in LPM0 that waits until the specified number of millis() have elapsed. This loop doesn't stop the ACLK interrupt from running, so if the RTC's ACLK interrupt triggers whilst inside the delay() function, it will run and update the RTC as per normal.

 

So for example the following code will work as per normal...

#include <RTCplus.h>

RealTimeClock rtc;

setup(){
  rtc.begin();
};

loop(){
  delay(5000);  // put code here to do something useful - eg print the value of the RTC.
                // this code will only run approximately once every 5 seconds
                // but when it does run, the RTC will be accurate.
};
interrupt(TIMER1_A0_VECTOR) Timer(void) {
    rtc.Inc();     // While we can do some other things inside the interrupt other than just increment the
                   // timer, care needs to be taken with how long the routines used here take to run. It is
                    // best to just increment the timer and not do much else.
};

But the following code will crash - it will run out RAM because the Timer keeps getting called before it has finished running.

#include <RTCplus.h>

RealTimeClock rtc;

void setup(){
  rtc.begin();
};

void loop(){
};
interrupt(TIMER1_A0_VECTOR) Timer(void) {
    rtc.Inc();
    delay(5000);  // bad practice to call delay, or run any other code that will
                  // take a long time to execute, inside the interrupt routine.
                  // If the delay is still running when the interrupt next triggers
                  // we will ultimately end up running out of RAM, because of all
                  // the interrupt calls getting put on the stack.
      // other time consuming code here - bad.
};

thank you , my code is like the first example code that you have written. so there should not be any accuracy problem. i will try this this evening and write you the results.

p.s. i am using RTCplus

Share this post


Link to post
Share on other sites

i have tested it. it is still accurate using "delay"s.. however i have also noticed that my problem was solved using that "delay" i was calling a function, inside another function which are using timings.. when i have carried the second call into the main loop it began working.. my work has been based too much trial and error : /  it is still far to my expectations : //

Share this post


Link to post
Share on other sites

I'f you're having a lot of local variables (those declared inside functions) you might run out of stack space, on IAR the stack is by default defined at 50 bytes, of which most function calls eat at 2 to 10, excluding local variables. so if you have a loop() calling function1() calling function2() calling delay() you have a call depth of 4, which means your functions cannot exceed 10 bytes of stack space on average or you'll run out of stack when an interrupt occurs. Your compiler or run time will not complain, but you might overwrite global variables without intention!

Share this post


Link to post
Share on other sites

I'f you're having a lot of local variables (those declared inside functions) you might run out of stack space, on IAR the stack is by default defined at 50 bytes, of which most function calls eat at 2 to 10, excluding local variables. so if you have a loop() calling function1() calling function2() calling delay() you have a call depth of 4, which means your functions cannot exceed 10 bytes of stack space on average or you'll run out of stack when an interrupt occurs. Your compiler or run time will not complain, but you might overwrite global variables without intention!

http://forum.43oh.com/topic/3306-light-alarm-clock-project-using-msp430/?p=29113

 

the code is on the link. it is messy and not perfect. the lighting part works good now but buzzer sound is not continous. thanks.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×