Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

millis() timing off when USE_RTC is defined #28

Open
hobzcalvin opened this issue Oct 22, 2013 · 13 comments
Open

millis() timing off when USE_RTC is defined #28

hobzcalvin opened this issue Oct 22, 2013 · 13 comments
Milestone

Comments

@hobzcalvin
Copy link

Hi, first I'm curious if anyone is still working on this project. Lack of recent commits suggests no.

I'm using Xmegaduino to program an atxmega16a4u. The timing of millis() appears to be off: delay(1000) takes about .7 seconds, not 1.

In wiring.c, RTC.PER is being set to 0. If I change it to 1, delay() and millis() work almost as expected—they still run slightly fast, but fine for my purposes. I may issue a pull request for this change, but I don't understand the code well enough to be sure. For example, I have no idea why the rtc_millis variable is increased by 4 in an interrupt vector that, AFAICT, should run every millisecond. Yet, the timing seems (almost) right this way.

@karlbackstrom
Copy link

Hi, glad to hear you have a interest in Xmegaduino.

It is a sleeping project, but all pull requests are appreciated.

I checked your fix, and I agree that RTC.PER should probably be changed to one.

About that after your fix the clock is almost correct, I think that is because of this row:
CLK.RTCCTRL = CLK_RTCSRC_RCOSC_gc | CLK_RTCEN_bm;
This set the clock to 1.024 kHz instead of 1kHz.

@hobzcalvin
Copy link
Author

Thanks for the quick response.

You're right about the 1.024 kHz. There isn't really an alternative. The ultra-low-power clock is supposedly at a straight 32kHz, scalable down to 1kHz, but its accuracy varies by +/- 30%. On my unit it actually runs faster than the calibrated RC.

Ah, here's everything I wanted to know about interrupts and PER choices, from the data sheet:

Due to the asynchronous clock domains, events will be generated only for every third overflow or compare match if the period register is zero. If the period register is one, events will be generated only for every second overflow or compare match. When the period register is equal to or above two, events will trigger at every overflow or compare match, just as the interrupt request.

I'm unclear on the timing between overflow and reset-to-zero, but experimentation suggests that PER=1 is in fact equivalent to PER=3, and thus rtc_millis += 4 makes sense. I would prefer to use PER=3 since it isn't a special case that requires a data sheet hunt to understand!

@karlbackstrom
Copy link

Yes, now when you mention it, the alternative was too inaccurate to use for timing. Thank you for testing it.

PER=3 (PER=4?) makes sense. Please go ahead and make a pull request and I will have a look at it.

You might be interested in checking out the task-arduino-1.5.x branch too. Please be cautious if you run linux though, you are advised to run your distro's version of avr-gcc as the one in the package gives faulty binaries.
I have great hope that some Arduino developers will upgrade the avr-gcc on all platforms in Arduino so that Xmegaduino doesn't have to bundle our own. (There was recently a thread started about that)

@hobzcalvin
Copy link
Author

Sure thing, I'll send a pull request when I get some other stuff together, such as boards.txt / variant entries for the board I'm working on.

I thought PER=4 would be right, but that counts too slowly. I guess when PER=3, CNT goes 0, 1, 2, 3/int, 0, 1, 2, 3/int... even though I would think 0, 1, 2, 3/int/0, 1, 2 3/int/0... makes more sense. The data sheet doesn't seem to specify either way, which is troubling.

I'll take a look at that branch...incidentally I got Xmegaduino working with the ino tool, but it was annoying. It expects lots of things named "arduino".

@karlbackstrom
Copy link

Looking forward to it!
If possible, please separate pull requests as one pull request per feature/bug fix.

@karlbackstrom
Copy link

Any updates? :)

@hobzcalvin
Copy link
Author

I couldn't reproduce this! We switched to using the atxmega16c4, whereas I was using an atxmega15a4u previously. No matter what I set PER to, the overflow interrupt always seems to happen with the same frequency. Very strange. I'm following the instructions for setting PER to the letter as far as I can tell. I can break the interrupt entirely, but not change its period. It's a simple fix that I'm happy to submit anyway, I guess. You can see my fork of Xmegaduino; not much on there yet: https://github.com/hobzcalvin/Xmegaduino/commits/xmegaduino

@karlbackstrom
Copy link

Have you checked the errata in the documentation if your version of the chip had any known hardware bugs?

Strange indeed!

@karlbackstrom karlbackstrom modified the milestones: 1.5-beta6, 1.5-beta5 Apr 9, 2014
@KHeintz
Copy link

KHeintz commented Jul 24, 2014

I think this solve the RTC timer problem.
I use this changes in wiring.c

#define CLK_RTCSRC_RCOSC32_gc (0x06<<1)// Set the internal 32.768kHZ oscillator as clock source for RTC.

#ifdef USE_RTC
/* Turn on internal 32kHz. */
OSC.CTRL |= OSC_RC32KEN_bm; //cal RC Oscillator

do {
    /* Wait for the 32kHz oscillator to stabilize. */
} while ( ( OSC.STATUS & OSC_RC32KRDY_bm ) == 0);

/* Set internal 32.768kHZ oscillator as clock source for RTC. */
CLK.RTCCTRL = CLK_RTCSRC_RCOSC32_gc | CLK_RTCEN_bm;//32.768kHZ RC RTC clock


#if defined(USE_RTC)
do {
    /* Wait until RTC is not busy. */
} while (  RTC.STATUS & RTC_SYNCBUSY_bm );

/* Configure RTC period to 1 millisecond. */
RTC.PER = 129;//1ms 
RTC.CNT = 0;
RTC.COMP = 129; 
RTC.CTRL = ( RTC.CTRL & ~RTC_PRESCALER_gm ) | RTC_PRESCALER_DIV1_gc;

@karlbackstrom
Copy link

Great! Please send a pull request and I will take a look.

@KHeintz
Copy link

KHeintz commented Jul 25, 2014

This enhanced the 16 bit RTC counter resolution to around 30.5μs (Xmega X32A4U data sheet 20. RTC – 16-bit Real-Time Counter). Should work for all AxU and U types XMegas. I change the 32 MHz clock init a little bit that the DFLL auto cal feature is used (AVR1606 and AVR1003).
Millis() works now as expected. Only ~2sec per hour off. I think that is for a RC clock very good.

@KHeintz
Copy link

KHeintz commented Jul 25, 2014

arduino#2208

@karlbackstrom
Copy link

Sorry for getting back so late, could you make a pull request to Xmegaduino project and not the original Arduino project. Think the chance is slim to get this one into the official Arduino project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants