Reply
Posts: 60
Registered: ‎09-15-2015
Accepted Solution

RTC alarm firing multiple times on EFM8SB1

I'm trying to use the RTC on an EFM8SB1, with an alarm period of 1 second. I enabled the 

"Alarm Auto-Reset" feature so that my software doesn't have to clear the ALRM flag in the RTC0CN0 indirect register. I'm using an external 32.768 kHz crystal.

 

Here is my ISR:

SI_INTERRUPT (RTC0ALARM_ISR, RTC0ALARM_IRQn)
{
	P1_B1 = !P1_B1;
	counter++;
}

However, my RTC counter variable was incrementing more quickly than expected, so I attached a logic sniffer to a pin that should toggle each time the ISR executes, and I get a trace like this:

Logic_2017-06-24_01-24-23.png

 

The auto-generated docs above the ISR says:

Remember to clear flag bits: 
RTC0CN0::ALRM (RTC Alarm Event Flag and Auto Reset Enable)

But this seems contrary to the datasheet:

Acrobat_2017-06-24_01-26-12.png

 

What's the proper way of doing this?

 

Also, what changes will I need to make when I put the MCU to sleep, and use the alarm as a wake-up source? The datasheet says I need to check wake-up flags to be sure I don't miss the alarm event, but when I put it to sleep, my ISRs still seem to be firing upon wakeup, so I'm not sure why I have to worry about that.

Posts: 326
Registered: ‎09-22-2009

Re: RTC alarm firing multiple times on EFM8SB1

What code has this note to clear the Auto Reset Enable above the interrupt?

 

The SB1 has a code example for SleepMode smaRTClockWake. I think this shows what you are trying to do. Before going to sleep, interrupts are disabled. You can see the sequence in RTC_SleepTicks().

Posts: 60
Registered: ‎09-15-2015

Re: RTC alarm firing multiple times on EFM8SB1


Alan_S wrote:

What code has this note to clear the Auto Reset Enable above the interrupt?

 


The RTC Alarm auto-generated interrupt function:

The RTC Alarm auto-generated interrupt function:
//-----------------------------------------------------------------------------
// RTC0ALARM_ISR
//-----------------------------------------------------------------------------
//
// RTC0ALARM ISR Content goes here. Remember to clear flag bits:
// RTC0CN0::ALRM (RTC Alarm Event Flag and Auto Reset Enable)
//
//-----------------------------------------------------------------------------
SI_INTERRUPT (RTC0ALARM_ISR, RTC0ALARM_IRQn) {
...

So you're saying I should disable interrupts when going to sleep, and instead look at the wake-up sources? That'll be kind of goofy, since sometimes I'm awake when I'm handling RTC interrupts, and sometimes I'm asleep, but I suppose I can make that work.

 

Next question: I'd like to keep my alarm at 1 second, but be able to read the RTC directly to be able to get down to 10s-of-milliseconds. Right now, I'm doing something like this:

void writeIndirect(uint8_t address, uint8_t val)
{
	while(RTC0ADR & RTC0ADR_BUSY__SET);
	RTC0ADR = address;
	RTC0DAT = val;
}

uint8_t readIndirect(uint8_t address)
{
	while(RTC0ADR & RTC0ADR_BUSY__SET);
	RTC0ADR = RTC0ADR_BUSY__SET | address;
	while(RTC0ADR & RTC0ADR_BUSY__SET);
	return RTC0DAT;
}

uint32_t Rtc_GetTicks()
{
	uint32_t ticks;
	SFRPAGE = 0;

	// write 1 to RTC0CAP to transfer contents to CAPTUREn registers
	writeIndirect(RTC0CN0,
			RTC0CN0_RTC0EN__ENABLED |
			RTC0CN0_RTC0TR__RUN|
			RTC0CN0_MCLKEN__DISABLED |
			RTC0CN0_RTC0AEN__ENABLED |
			RTC0CN0_ALRM__SET |
			RTC0CN0_RTC0CAP__SET |
			RTC0CN0_RTC0SET__NOT_SET );

	while(readIndirect(RTC0CN0) & RTC0CN0_RTC0CAP__SET); // Poll RTC0CAP until it is cleared to 0 by hardware.
	ticks = readIndirect(CAPTURE0) << 24;
	ticks |= RTC0DAT << 16;
	ticks |= RTC0DAT << 8;
	ticks |= RTC0DAT << 0;
	return ticks;
}

However, I'm getting wacky values from RTC0DAT. Since my alarm is 1 second, I feel like CAPTURE should *never* have a value greater than 32768 (my RTC crystal frequency), but I get values that are very small (<100) and very large (>100,000). The datasheet does not indicate the endianness of the CAPTURE register (huge, glaring omission!), but I matched the endianness the smaRTClock_Date_Tracker, and also tried flipping it, to no avail. This makes me think I'm doing something wrong.

 

The datasheet says I should be able to just do successive reads of RTC0DAT (since auto-increment is always enabled on CAPTURE), but the smaRTClock_Date_Tracker demo calls RTC_Read() each time, which is similar to my readIndirect() function — this is a much "heavier" way of reading the register, as it writes the address, and waits for BUSY. We're talking about a potential increase of 4-10 times the number of instructions for the same operation, by my calculations, so I'd like to avoid that if possible. 

 

In general, these indirect accesses are really challenging to debug, especially due to the weird timing requirements. This is, by far, the worst peripheral I've used on the EFM8 since picking up the architecture two years ago — if you're ever collecting feedback from users to figure out what changes should be made for future EFM8s, please take this under consideration. I know that we're always low on SFRs, but I feel like even if you have to have a dedicated SFRPAGE for the RTC, it'd be way easier than this nonsense. It really feels like the RTC was haphazardly bolted onto the SFR bus. Just my two cents!

<a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero</font></font> </a> jmg
Posts: 1,155
Registered: ‎04-27-2004

Re: RTC alarm firing multiple times on EFM8SB1


However, my RTC counter variable was incrementing more quickly than expected, so I attached a logic sniffer to a pin that should toggle each time the ISR executes, ....


This may or may not be related, but I recall some notes (errata?) around RTC's etc, that suggest there are two state machines running, and that some signaling required the next 32kHz edge for the changes to 'stick'.

ie because one side is always on, and the other side is a wake-up and different much faster clock, it is not easy to have instant response on each side.

To the 32kHz side, next 32kHz clock is sync instant, but at 24.5MHz that's ~ 750 sysCLK

Posts: 60
Registered: ‎09-15-2015

Re: RTC alarm firing multiple times on EFM8SB1

Alright, I've got it working, by reading CAPTURE registers by address each time, instead of relying on the auto-address-increment feature.

 

And if I use the wake-up flags instead of the RTC interrupt, the interrupt only occurs once. It's still not clear to me why an RTC interrupt generates multiple interrupts (the data looks exactly like a pin debounce problem, honestly), but I can work around it. Thanks for the info everyone!