This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Setting the Hibernation RTC clock

Other Parts Discussed in Thread: EK-TM4C123GXL

Greetings Ti Forum

I want to generate a 1Hz interrupt as accurately as possible using the Tiva C Series LaunchPad, for this reason I'm attempting to use the RTC in the Hibernation Module. My objective is then to use the 32.768 kHz crystal signal as the clock source for the RTC module and use the Hibernation Module RTC match interrupt generate the required 1 Hz interrupt. 

But I have some questions on how to set it up since I cannot get the necessary clarity to do so from neither the device data sheet nor the peripheral driver library user manual (I'm programming in C). 

  1. The bit field OSCDRV in the HIBCTL register controls the oscillator drive capability of the module. Since the Launchpad schematic specifies that 24 pF capacitors are installed with the 32.768kHz crystal, this bit should be set to one.

    The Data sheet says this bit is not meant to be changed once the Hibernation oscillator has started because stability is not guaranteed if changed after the oscillator is running.

    But to access the Hibernation Module Registers and set the OSCDRV bit I need to first set CLK32EN doesn’t this already start the oscillator. How can I change this setting without worrying about clock stability problems?
     
  2. In the Hibernation Control Register Description (in the data sheet) there is a mention of an internal 32.768-kHz oscillator on the description of the OSCBYP (Oscillator Bypass) bit (I didn’t find any reference to it before). When I enable the clocking on the Hibernation Module (set CLK32EN) which is the clock source used for the Hibernation Module the internal oscillator or the 32.768 crystal?

    because the reset at reset OSCBYP = 1 (Internal Oscillator enabled) and OSCDRV = 0 (low crystal drive)

    And how can I change to the crystal source? Disabling the oscillator (OSCBYP = 0) and setting OSCRV to 1?
     
  3. In the RTC match ISR I would like to clear the interrupt and set the RTC match value to one second in the future, hopefully without losing any of the accumulated crystal cycles in the sub-second counters. But I ran into the following problem:

    According to the Datasheet the RTC match interrupt takes priority over an interrupt clear. Therefore, writes to the HIBIC.RTCALT0 ( RTCALT0 bit in the hibernation interrupt clear register) do not clear the RTCALT0 bit in HIBRIS register if the values of HIBRTCM0 and HIBRTCC are equal.

    Is this true for value of  these two registers exclusively or does it also include the sub-second counters (since the match functionality does extend to these additional bits) ? I could insert a 1/32.768 delay on the ISR to wait for the sub-second counter not to match and then clear the interrupt and write the new match value one secon in the future but I'm not sure it will work.

    The data sheet offers two suggestions on how to deal with the problem: 1) write a new value to the load register HIBRTCLD 2) disable the RTC and re-enable the RTC. The first suggestion I didn’t like because it means I lose any accumulated sub-second counts (if any). And the second option doesn’t really explain what does enabling and disabling the RTC register do, does it clear the RTC's second count value, does it stop counting but still allow me to clear the interrupt even if the second counts match?

 

Hope I was clear on explaining my problem and sorry for the long post but I cant get the answers I need from the data sheet, example programs or googling it. Any help is appreciated and many thanks to those who suggest answers.

  • Hello Jesus

    1. The Oscillator drive bit is set along with the CLK32EN
    2. The Internal oscillator is available only on the TM4C129x device and is not an accurate 32.768KHz. The OSCBYP bit is used when there is an external single ended clock source e.g. from a Clock Distribution device.
    3. It means that if the set condition and clear happen at the same time, then the set condition takes precedence. If the set condition has already happened then the clear will take precedence.

    Normally when using the hibernate the expectation is that the device will be used for hibernate low power mode. Wakeup from this mode would take multiple ms and hence the condition for the interrupt would have already gone by then.
  • Thanks for the reply Amit, especially point 3, it was a bit confusing for me when i read it on the data sheet. With your clarification and a bit of trail and error I was able to produce the following code that is meant to simply generate the sought after, 1Hz interrupt:

    #include "inc/hw_hibernate.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/hibernate.h"
    
    //
    // Handler for hibernate interrupts.
    //
    void HibernateISRHandler(void)
    {
    	uint32_t ui32Status;
    
    	// Get the interrupt status and clear any pending interrupts.
    	ui32Status = HibernateIntStatus(true);
    	HibernateIntClear(ui32Status);
    
    	// Process the RTC match 0 interrupt.
    	if(ui32Status & HIBERNATE_INT_RTC_MATCH_0)
    	{
    		// update match value
    		uint32_t ui32RTCMatch;
    		ui32RTCMatch = HibernateRTCMatchGet(0);
    		HibernateRTCMatchSet(0,ui32RTCMatch + 1);	// a second in the future
    
    //		HibernateRTCSet(0);							// reset RTC count
    
    		// toggle gpio value
    		if(GPIOPinRead(GPIO_PORTF_BASE, GPIO_PIN_3))
    		{
    			GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,0x00);
    		}
    		else
    		{
    			GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,0x08);
    		}
    
    	}
    
    }
    
    //
    // main function
    //
    int main(void)
                                  {
    	// run system clock at 40-MHz
    	SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
    			       SYSCTL_OSC_MAIN);
    
    	// GPIO Config RGB: 2=red=pin1, 4=blue=pin2 and 8=green=pin3
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
    	GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0x08);
    
    	// Hibernation Module config
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
    	HibernateEnableExpClk(0);		// set HIBCTL.CLK32EN, input irelevant
    	while(!(HWREG(HIB_RIS) & HIB_RIS_WC)) {}	// wait for clk stability
    	HibernateClockConfig(HIBERNATE_OSC_LOWDRIVE);
    	SysCtlDelay(64000000);
    
    	// Hib RTC Config
    	HibernateRTCEnable();							// start RTC count
    	HibernateRTCSet(0);								// load RTC value
    	HibernateRTCMatchSet(0,5);						// set match value
    	HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0);	// En RTC match interrupt
    
    	// MCU intrrupt set up
    	IntEnable(INT_HIBERNATE_TM4C123);
    	IntMasterEnable();
    
    	// signal for me
    	GPIOPinWrite(GPIO_PORTF_BASE,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, 0x00);
    
    	// catch loop
    	while(1)
    	{
    		if(HibernateRTCGet() > HibernateRTCMatchGet(0))
    		{
    			_nop();
    		}
    	}
    
    }

    The above code does generate a 1Hz interrupt as expected but after about 65 seconds the interrupt is no longer generated. As if the RTC count somehow surpassed the match value (hibernation register inspection revealed this to be the case) but how is this so? The processor is running at 40-MHz, it has a whole second before the RTC count value is increased and the Hibernation ISR is pretty short.I inspected the

    I inspected the driverlib/hibernation.c source code and it uses a static function called _HibernateWriteComplete() which polls the WRC bit in the HIBCTL to make sure hibernation register writes are completed before proceeding but in theory, the hibernation module registers running at 32.769-kHz meaning that only a single cycle (1/32768 of a second) is necessary to complete the write. In my ISR I only make 2 writes to Hibernation module registers which does not add up to the whole second I have before the RTC count in increased. I know there are additional timing overhead sources I'm not considering like: the ISR service time, and the function calls made inside the ISR itself but even if considered these overheads would not explain why does the RTC count value Increase beyond the RTC match value. maybe its something I'm missing.

    I also tried simply resetting the RTC count to zero in the ISR to see if it improved the problem. The ISR kept firing well after five minutes but not at a 1Hz, it was well over.

  • Hello Jesus,

    You are right. The behavior is not explainable. I would need to run your code on my EK-TM4C123GXL to see what is happening. Since I have a little extra workload as the holiday season is around the corner, please ping me if you do not hear from me over the next few days.
  • Any help is greatly aprechiated, thankyou :)
  • Hello Jesus

    I think i understand the issue and it arises from an errata. However to get you going, the following changes are required

    1. In the Interrupt Handler

    Replace
    ui32RTCMatch = HibernateRTCMatchGet(0);
    with
    ui32RTCMatch = HibernateRTCGet();

    2. In the main function

    Replace
    HibernateRTCEnable(); // start RTC count
    HibernateRTCSet(0); // load RTC value
    HibernateRTCMatchSet(0,5); // set match value
    HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0); // En RTC match interrupt

    with
    HibernateRTCSet(0); // load RTC value
    HibernateRTCMatchSet(0,5); // set match value
    HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0); // En RTC match interrupt
    HibernateRTCTrimSet(0x7FFF);
    HibernateRTCEnable(); // start RTC count

    The key here is HibernateRTCTrimSet function call which re-intializes the Trim which gets modified due to a know issue of Hibernate register initialization.
  • Thank you Amit, I just tried the modification to the code you suggested and it's been generating the interrupt consistently. Thank you, for your time, your patients and for being so kind.

  • Hello Jesus

    Glad it is working for you as well. I would need to check the documentation and errata to see why this issue has not been captured.