[SAMC] RTC setup no longer works, but does when single stepping - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: July 28, 2023, 10:37:50 am
content: I have this really weird situation with the RTC on the SAMC21. This code previously worked and now it does not. I have tried all sorts. It appears that the processor stops after my RTC setup function if I put break points in with the debugger. as soon as a break point is after the function it does not get reached, any further code does not run. The processor is still executing code though, the prescaler interrupts fire and the code in these runs. So if I toggle the pins in the interrupt routine I get a square wave out. If I put the pin toggle code in the main while loop, nothing.Now if I break at the setup function and step through it it enters the while loop and toggles the pin. So why not when the program runs at normal speed?full code attachedMainCode:#include "samc21.h"#include "clock.h"#include "rtc.h"#include "nvic_hal.h"#include "eic.h"#include "adc_hal.h"#include "tc_hal.h"int main(void){clock_setup();//********************************************* Application setup code, DO NOT put any code above ******************************************// ************************************************ digital output setup examplepin_mode(PB06, Digital_output) ;//************************************************** TC PWM setup example *********************************************************connect_peripheral_to_clock(TC0_TC1_GCLK , F_32kHz) ;tc_pwm_setup_enable(TC0, 10, tc_prescaler_1) ; // connect counter to clock firsttc_pwm_duty_update(TC0, tc_ch1, 20) ;pin_mode(PB09, TC_pin) ;/******************************************************** ADC setup example ************************************************************adc_setup_enable_rr(ADC0, ADC_SF_1MHz, ADC_CH0 , adc_resolution_16_filtered_4) ;add_adc_channel(ADC0 , ADC_CH2 ) ;*///******************************************************* DO NOT put any code below before the while loop call*************************systick_setup_enable() ; // this runs time intervals of 100ms.rtc_setup_enable() ; // this runs all time intervals to 32ms 2.34% faster than suggested by the names and all time intervals over 100ms with crystal accuracy/* application code */while (1){pin_toggle(PB06) ;// *************************************************************** 250 µs ********************************************************if (rtc_return_250us_tick()) // 250 µs{} // end 250µs// **************************************************************** 500 µs ***********************************************************if (rtc_return_500us_tick()) // 500 µs{} // end 500 µs// ***************************************************************** 1 ms ***********************************************************if (rtc_return_1ms_tick()) // 1 ms{} // end 1 ms// ********************************************************************* 1 ms **************************************************if (rtc_return_2ms_tick()) // 2 ms{} // end 2ms// ******************************************************************** 4 ms *********************************************************if (rtc_return_4ms_tick()) // 4ms{} // end 4 ms// ******************************************************************** 8 ms ******************************************************if (rtc_return_8ms_tick()) // 8 ms{} // end 8 ms// ************************************************************ ****** 16 ms ****************************************************************if (rtc_return_16ms_tick()) // 16 ms{} // end 16 ms// ******************************************************************* 32 ms *****************************************************************if (rtc_return_32ms_tick()) // 32 ms{} // end 32 ms// ****************************************************************** 100 ms ***************************************************************if (systick_return_100ms_tick()) // 100 ms{} // end 100ms// ******************************************************************* 250 ms *****************************************************************if (rtc_return_250ms_tick()) // 250 ms{} // end 250 ms// ******************************************************************* 500 ms *****************************************************************if (rtc_return_500ms_tick()) // 500 ms{} // end 500 ms// ******************************************************************* 1 s *****************************************************************if (rtc_return_1s_tick()) // 1 s{} // end 1 s} // end of main program while loop} // end of main()RTCCode:/** rtc.c** Created: 16/06/2023 10:51:01* Author: cbsadmin*/#include "samc21.h"#include "nvic_hal.h"#include "rtc.h"#include "port_control.h"static volatile uint8_t flag_250us_tick ;static volatile uint8_t flag_500us_tick ;static volatile uint8_t flag_1ms_tick ;static volatile uint8_t flag_2ms_tick ;static volatile uint8_t flag_4ms_tick ;static volatile uint8_t flag_8ms_tick ;static volatile uint8_t flag_16ms_tick ;static volatile uint8_t flag_32ms_tick ;static volatile uint8_t flag_250ms_tick ;static volatile uint8_t flag_500ms_tick ;static volatile uint8_t flag_1s_tick ;volatile uint32_t _32ms_overflows ;volatile uint32_t sys_time ;volatile uint32_t rtcIntTime = 32 ;void rtc_setup_enable( void ){//RTC->MODE0.CTRLA.bit.COUNTSYNC = 1 ;RTC->MODE0.CTRLA.reg = 0xB << 8 ; // prescaler setup//RTC->MODE0.CTRLA.bit.MATCHCLR = 1 ;//RTC->MODE0.CTRLA.reg = 0x0 << 15 | 0xB << 8 | 0x1 << 7 ;// REG_RTC_MODE0_INTENSET = 0x0F ; // replaced belowRTC->MODE0.INTENSET.reg = 0x0F ; // set up interrupts//while ( RTC->MODE0.SYNCBUSY.bit.COMP0 ) ;//RTC->MODE0.COMP.reg = rtcIntTime ; // counter interrupt every 1swhile (RTC->MODE0.SYNCBUSY.bit.ENABLE) ;RTC->MODE0.CTRLA.bit.ENABLE = 1 ;interrupt_enable(NVIC_INT_RTC_CH) ;}uint32_t sys_time_ret(void){return sys_time ;}// 250µs tick codeuint8_t rtc_return_250us_tick(void){if (flag_250us_tick){flag_250us_tick = 0 ;return 1 ;}else return 0 ;}// 500us tick codeuint8_t rtc_return_500us_tick(void){if (flag_500us_tick){flag_500us_tick = 0 ;return 1 ;}else return 0 ;}// 1ms tick codeuint8_t rtc_return_1ms_tick(void){if (flag_1ms_tick){flag_1ms_tick = 0 ;return 1 ;}else return 0 ;}// 2ms tick codeuint8_t rtc_return_2ms_tick(void){if (flag_2ms_tick){flag_2ms_tick = 0 ;return 1 ;}else return 0 ;}// 4ms tick codeuint8_t rtc_return_4ms_tick(void){if (flag_4ms_tick){flag_4ms_tick = 0 ;return 1 ;}else return 0 ;}// 8ms tick codeuint8_t rtc_return_8ms_tick(void){if (flag_8ms_tick){flag_8ms_tick = 0 ;return 1 ;}else return 0 ;}// 16ms tick codeuint8_t rtc_return_16ms_tick(void){if (flag_16ms_tick){flag_16ms_tick = 0 ;return 1 ;}else return 0 ;}// 32ms tick codeuint8_t rtc_return_32ms_tick(void){if (flag_32ms_tick){flag_32ms_tick = 0 ;return 1 ;}else return 0 ;}// 250ms tick codeuint8_t rtc_return_250ms_tick(){if (flag_250ms_tick){flag_250ms_tick = 0 ;return 1 ;}else return 0 ;}// 500ms tick codeuint8_t rtc_return_500ms_tick(){if (flag_500ms_tick){flag_500ms_tick = 0 ;return 1 ;}else return 0 ;}// 1s tick codeuint8_t rtc_return_1s_tick(){if (flag_1s_tick){flag_1s_tick = 0 ;return 1 ;}else return 0 ;}void RTC_Handler( void ){if (RTC->MODE0.INTFLAG.bit.PER0){flag_250us_tick ++ ;sys_time ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 0 ;}if (RTC->MODE0.INTFLAG.bit.PER1){flag_500us_tick ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 1 ;}if (RTC->MODE0.INTFLAG.bit.PER2){flag_1ms_tick ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 2 ;}if (RTC->MODE0.INTFLAG.bit.PER3){flag_2ms_tick ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 3 ;}if (RTC->MODE0.INTFLAG.bit.PER4){flag_4ms_tick ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 4 ;}if (RTC->MODE0.INTFLAG.bit.PER5){flag_8ms_tick ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 5 ;}if (RTC->MODE0.INTFLAG.bit.PER6){flag_16ms_tick ++ ;RTC->MODE0.INTFLAG.reg = 0x1 << 6 ;}if (RTC->MODE0.INTFLAG.bit.PER7){flag_32ms_tick ++ ;_32ms_overflows ++ ;if ( (_32ms_overflows & 0x0F) == (0x1 << 3) ) flag_250ms_tick = 1 ;if ( (_32ms_overflows & 0x1F) == (0x1 << 4) ) flag_500ms_tick = 1 ;if ( (_32ms_overflows & 0x3F) == (0x1 << 5) ) flag_1s_tick = 1 ;RTC->MODE0.INTFLAG.reg = 0x1 << 7 ;}}// https://developer.arm.com/documentation/dui0497/a/cortex-m0-peripherals/optional-system-timer--systick?lang=en#define SYST_CSR ( *(RwReg *) 0xE000E010 ) // SysTick Control and Status Register#define SYST_RVR ( *(RwReg *) 0xE000E014 ) // SysTick Reload Value Register#define SYST_CVR ( *(RwReg *) 0xE000E018 ) // SysTick Current Value Registervolatile uint8_t sysTick_flag ;static volatile uint32_t systick_overflows ;const static uint32_t SYSTICK_TIMEOUT = 4800000 ;void systick_setup_enable(){SYST_RVR = SYSTICK_TIMEOUT ; // will roll over every 100 msSYST_CVR = SYSTICK_TIMEOUT ;SYST_CSR = 0x1 << 2 | 0x1 << 1 | 0x1 << 0 ;}void SysTick_Handler(){sysTick_flag = 1 ;systick_overflows ++ ;}uint8_t systick_return_100ms_tick(){if (sysTick_flag){sysTick_flag = 0 ;return 1 ;}else return 0 ;}

author: Simon
author_rank: Unknown
timestamp: July 28, 2023, 01:32:00 pm
content: Well turns out it is something to do with the PLL, I am however buggered if I know how the PLL misbehaving would cause the main program function to stop working specifically at the RTC and yet still run the interrupt code.

author: ataradov
author_rank: Super Contributor
timestamp: July 28, 2023, 05:11:19 pm
content: It all depends on how your clocks are setup and how exactly PLL misbehaves. If PLL goes out of lock and the output lock gate is bypassed, then the system may be running out of spec.If you pause execution then you should see where it is stuck exactly.

author: ajb
author_rank: Super Contributor
timestamp: July 28, 2023, 08:08:37 pm
content: Interrupts running while the main loop doesn't sounds like the MCU may be looping through an unimplemented interrupt handler. Somewhere in the project there should be a vector table filled with a bunch of weak references to a dummy handler. That dummy handler is the default handler for all interrupts until you define an actual ISR that overrides the weak dummy reference. If another interrupt is requested for which you haven't defined your own handler, it may end up trapped that dummy handler instead. Many dummy implementations are just `while(1);`, but anything that exits will immediately get re-entered because it hasn't clearer the IRQ, so still traps the MCU in a loop. You can try setting a breakpoint (or toggle an IO, or...) in the dummy handler to see if that's what's happening.

author: ataradov
author_rank: Super Contributor
timestamp: July 28, 2023, 08:17:58 pm
content: By default all interrupts have the same priority and if a dummy handler is running, nothing else would.As i said, it is enough to pause execution at any time to see exactly where it is looping. It is likely stuck in some loop in the main code.

author: Rudolph Riedel
author_rank: Regular Contributor
timestamp: July 30, 2023, 09:10:35 am
content: First tip, delete the "Debug" folder and then zip the project.The difference in this case is 2922 kiB to 27kiB without loosing anything relevant.And then your way of writing to registers makes things completely not readable without the datasheetplus doing the "math" to find out which bits may be meant to be written to.Instead of this:OSC32KCTRL->XOSC32K.reg = 0x5 << 8 | 0x1 << 3 | 0x1 << 2 | 0x1 << 1 ;while ( ( REG_OSC32KCTRL_STATUS & 0x1 ) != 0x1 ) ;Try this:OSC32KCTRL->XOSC32K.reg =OSC32KCTRL_OSC32K_STARTUP(5) |OSC32KCTRL_OSC32K_EN1K |OSC32KCTRL_OSC32K_EN32K |OSC32KCTRL_OSC32K_ENABLE;while(0 == (OSC32KCTRL->STATUS.reg & OSC32KCTRL_STATUS_OSC32KRDY));What is missing from this is setting the calibration value CALIB.Which is probably not the issue at hand but I do not like to analyze more of your code.

author: Simon
author_rank: Unknown
timestamp: July 31, 2023, 10:40:16 am
content: Quote from: ajb on July 28, 2023, 08:08:37 pmNo it was my handler it was working through, it was as though it ran through the setup code fell over during the RTC setup and then just constantly responded to the interrupt handlers (8 of them) instead of running the main code as well. so put code in the handler and it was fine, put code in the function that first checked if the handler had run and nothing.

author: Simon
author_rank: Unknown
timestamp: July 31, 2023, 10:44:26 am
content: Quote from: Rudolph Riedel on July 30, 2023, 09:10:35 amAs you may have seen throughout the project I have been changing over from writing masks to a register to using the structure definitions. However I notice that when I fired up MPLABX and created a dummy project with what ever the hell they call it this week that the registers are no longer structured but different names are used from the original defs that I have in studio so copying code over does not work directly - thanks microchip..... the other thing to remember is that some registers cannot be written to bit at a time so unless you want to insert a while check on the status of that register after every bit write nothing will happen and 1 line of code will be about 30, as I do not intend to touch the code again, I don't really care.it seems to work now that i have bastardized this code into mine.What remains a mystery is why if I single stepped the code the pin would toggle but if I just let it run it would remain stuck not running the loop.

author: ataradov
author_rank: Super Contributor
timestamp: July 31, 2023, 03:07:23 pm
content: Quote from: Simon on July 31, 2023, 10:44:26 amThis happens very often if you have issues with unstable/incorrect clocks. Clock sources are running while you step though the code, so you may step past the moment of instability.This is why it is better to let it run, get locked, pause and see where exactly it is locked. Then you can investigate that specific place.

author: Simon
author_rank: Unknown
timestamp: July 31, 2023, 03:41:48 pm
content: Yes this is what I thought might be the issue, the problem was that it was very hard to track down as it would always fail on the RTC setup which should not affect the clock, I eventually reasoned that it may be as you suggested and looked at the seemingly unrelated clock setup code and used the microchip code generator to get me started.

author: ataradov
author_rank: Super Contributor
timestamp: July 31, 2023, 04:24:22 pm
content: Why is it hard to track down? I don't understand why you don't just pause execution in this locked mode and see exactly where it is stuck. Why guess when you can know exactly?

author: ejeffrey
author_rank: Super Contributor
timestamp: July 31, 2023, 04:38:30 pm
content: I'm not sure what Simon was seeing, but in the past I had a clock setup bug where the MCU would run for 1000s of instructions after the incorrect clock setup before failing, and in addition the failure corrupted the machine state so that if you tried to pause after the fault it would look like nonsense.In the end, I figured out that the machine state could only look like that if there was a hardware failure and that was enough to point me at the clock setup.

author: Simon
author_rank: Unknown
timestamp: July 31, 2023, 07:25:51 pm
content: Quote from: ataradov on July 31, 2023, 04:24:22 pmThe execution consistently failed on exit from my RTC setup function. I could not find a problem there, I made the assumption after a lot of testing that there may be a problem in a closely related system like the clock.So I program the chip and nothing happens, I hit pause on the debugger and the program is stuck at the exit point of the RTC setup function.Now if I start to single step through the code it works, it runs around the while loop and every time it gets to the pin toggle function, the pin toggles. I assumed that the clock may be unstable and that in small bursts - whatever - it was working the program in single steps but free running would not be stable for long enough.All guesses. So I fixed the clock, now it works. I may be wrong, that is why I am asking. My code previously worked fine but that could have been a fluke.

author: ataradov
author_rank: Super Contributor
timestamp: July 31, 2023, 07:45:51 pm
content: What do you mean by "failed"? What is the value of the program counter when you stop the execution and what function/code it corresponds to? This is the most trivial thing to find out.

author: Simon
author_rank: Unknown
timestamp: July 31, 2023, 09:34:52 pm
content: Quote from: ataradov on July 31, 2023, 07:45:51 pmby fail I mean it ends up in a position where the program is not executing unless the code is in an interrupt. but if I single step it will run the code in the while loop. I am afraid that I don't know enough about these things to know what the program counter means to me. I will assume that as the processor is still executing something, the program counter will always be at one of many possible counts.

author: ataradov
author_rank: Super Contributor
timestamp: July 31, 2023, 10:39:14 pm
content: What tools are you using for debugging? So, if you let it run at full speed and get "locked", then pause execution, it would step though some code? Will it be the code inside while (1) {} ? Will PB06 start toggling if you single step though the code after it was already locked?

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 05:57:48 am
content: Quote from: ataradov on July 31, 2023, 10:39:14 pmYes, that is what I have been saying, once I single step it starts off into the while loop, otherwise it is stuck and just runs the interrupts. As I have this working now I can't really do much to go back and look at it. As always in the middle of the latest project and trying to meet a silly deadline.I am using an Atmel ICE

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2023, 06:06:08 am
content: I meant the IDE. Don't single step in the source code, in cases like this always looks at the disassembly and the exact instruction you are stopped at.If you end up in a loop, but the pin did not toggle, you can step though the assembly and see what actually happens.Although the behavior you are describing makes no sense and in cases like this I usually drop everything and investigate until I fully understand the details. Strange and hard to explain behavior is often a sign of a real underlying issue.It might also be something like incorrect flash wait states setting and it just happens to fetch the pin toggle instruction incorrectly. Although getting consistent reproduction would not be very likely.

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 07:31:08 am
content: I'm using microchip studio.Well I figured that given the behaviour it was not about the RTC setup code and must be fundamental as you say so I set up the clocks again. Having seen the setup code generated by MPLABX I took a leaf out of it's book and introduced a wait on each GCLK setup just to be sure. So now as far as I am aware each clock thing is setup as it should be.I take it that my understanding is correct that any GCLK can be clocked from 96MHz although only GCLK0-2 can output at above 48MHz. I am running the entire chip on the RTC crystal, using this to clock the PLL that will provide a 96MHz for the few counters etc that will take it and is divided in two for the CPU and everything else.

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2023, 07:39:27 am
content: All GCLKs can take 96 MHz as an input, but only 0-2 can also provide it as an output. And given that GCLK0 clocks the CPU, it never makes sense to output 96 MHz on it.And the only peripheral that can use 96 MHz is FREQM, which is pretty useless. Even TCCs on this device can only take 92 MHz.

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 07:43:12 am
content: Wait states are set to 2 additional waits as per the requirements at 48MHz I have now put this before the GCLK's are configured with the change in Main clock pre-scaler to 1 after all of the GCLK's have been setup.

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 07:48:36 am
content: Quote from: ataradov on August 01, 2023, 07:39:27 amWhat 92MHz is not a typo? 92 / 96...Yes the CPU must run from GCLK0, so unless I make another GCLK 48MHz from the PLL to then clock GCLK0 with a divider of 1 I and up with 2 48MHz clock sources.I need a stable 48MHz clock to run things like asynchronous serial communication rather than rely on the RC oscillator. If the PLL is not such a good idea as a main source I could run the CPU from the RC48MHz and create a PLL derived 48MHz

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 08:12:56 am
content: So I take the 96MHz into GCLK0 and divide by two.I also generate 32MHz by dividing by 3 for the ADC to run at full speed. This is what is confusing about 92MHz for the TCC's, it would totally ruin what seems to be a very well made plan to have the PLL work at 96MHz to give more frequency options as you can get a division by 3 but you can't divide 48MHz by 1.5 on a GCLK to get 32MHz.

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2023, 03:55:11 pm
content: Quote from: Simon on August 01, 2023, 07:48:36 amNo idea, but I would not expect it to be a typo. It is likely that they were shooting for 96 MHz, but it did not work reliably at that clock.Quote from: Simon on August 01, 2023, 07:48:36 amThere is nothing wrong with running CPU from the DPLL, just make sure you divide by two in the GCLK, so the end result is 48 MHz.

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2023, 03:59:09 pm
content: Quote from: Simon on August 01, 2023, 08:12:56 amADC can take up to 48 MHz, you can divide by two here.Quote from: Simon on August 01, 2023, 08:12:56 amI don't know if 92 MHz number is correct. You can try to push tit and see what happens, of course. If this is a real project, you may want to create a ticket and get that clarified.

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 07:21:14 pm
content: well this chip has undergone some revision, there is now a 64MHz version I believe. I would assume that the CPU running at a lower voltage on the same silicon can only achieve a certain speed. But if a mere 6% more clock were to tip the TCC input over the edge I would doubt anything over 48MHz, as we already know the CPU is now rated for 64MHz, I don't know if it is due to a change in process that has allowed this but with the DPLL capable in theory of going higher, I'm sure I saw a spec somewhere in excess of 100MHz the mere 4 MHz between two peripherals designed to work at nearly 100MHz would have me doubting the entire thing.I have run the TCC from 96MHz with no issue but of course this is at room temperature and like my experiments about 3 years ago on this chip you can even get away with one less wait state than you should at room temperature but of course not advisable in real life. Given this I would doubt that the TCC input is that marginal to have been dropped from 96 to 92MHz.Now the ADC has a maximum frequency of 16MHz, at this frequency it will do the rated 1MSPS with the default 4 clock periods of sampling time. The minimum prescaler of the ADC is 2, so if I were to use 48MHz I would have to divide it by 4 as 24MHz is too fast, that would run it at 12MHz or 750kSPS.The prescaler is 2 or 4 or a higher power of 2, 32MHz is the minimum frequency required to get the 16MHz, but 32 MHz cannot be obtained from anywhere but the PLL.The SAMC seems to be a bit of an unappreciated gem, my apprentice eventually admitted once I got him to read the datasheet that it is a cool chip and he is an STM32 fan, I mean a micro that can run the CPU at 48MHz and have a 96MHz clock all from a RTC crystal, that STM32 garbage would require you to have a second crystal or you would have to contend with the RC clock. Whoever designed the SAMC thought of just about everything. It's just a pity that they did not make more effort with documentation.

author: ataradov
author_rank: Super Contributor
timestamp: August 01, 2023, 07:48:00 pm
content: I've ran TCC at well over 100 MHz on SAM D11. But this was just a few devices at room temperature. I don't know how it might behave over the temperature and voltage range.

author: Simon
author_rank: Unknown
timestamp: August 01, 2023, 07:58:27 pm
content: Well i will contact microchip and ask them about it just to be sure.

author: Simon
author_rank: Unknown
timestamp: August 02, 2023, 09:39:26 am
content: So looking through the errata, 1.25.1QuoteSo I have changed the code I got out of microchips harmony or whatever it was to take this out. I don't know if this was a cause for error before and why it was so illusive. I like the way it says that at temperatures below 25C..... well I know the world is getting hotter but 25C is fairly high for most days in say the UK. So if I understand correctly I just have to accept that the DPLL may not be accurate, not that I had anything in place to deal with it being inaccurate. I'm not sure what I would do other than having to change the period value of the TCC and set it up again and switch everything to the 48MHz RC clock and change all of the pre-scalers where it really matters like for comms.

author: ataradov
author_rank: Super Contributor
timestamp: August 02, 2023, 02:35:35 pm
content: No, it will be accurate, the unlock indicator is spurious. This is why it says to basically just ignore it.With LBYPASS=0 it would disable the output if it thinks that it is inaccurate, but it thinks wrong. Bypassing it you do run a chance that it if really unlocks, your clock may not be stable, but it is generally not easy to make it unlock.