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.

TM4C1294NCPDT: RTC Clock Counter Mode Application

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL

I am trying to use RTC in counter mode using hibernation module but not sending processor into hibernating mode.

I am trying to create a sub second interrupt using RTC Match registers - precisely 10 HZ interrupt about 10 times within one second. I use a different GPIO pin to enable interrupt every one second. And within this one second I need precise ten 10 HZ interrupts. I am using the RTC subseconds register and Match Register for the same.

The code snippets to enable RTC and HIB:

// Configure Hibernate module clock.
//
HibernateEnableExpClk(ui32SysClock);


// Enable RTC mode.
//
HibernateRTCEnable();

//
// Configure the hibernate module counter to 24-hour calendar mode.
//
// HibernateCounterMode(HIBERNATE_COUNTER_24HR);
// Configure the hibernate module counter to RTC counter mode.
HibernateCounterMode(HIBERNATE_COUNTER_RTC);

############To get inetrrupt every ones econd we use the GPIO######################################################################################

// LaunchPad BoosterPack 1 Header for taking 1 PPS pulse configure pins
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_3); // Init PF3 as input

GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);

// Interrupt setup
GPIOIntDisable(GPIO_PORTF_BASE, GPIO_PIN_3); // Disable interrupt for PF4 (in case it was enabled)
GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_3); // Clear pending interrupts for PF4
// Register our handler function for port F pin 3
GPIOIntRegisterPin(GPIO_PORTF_BASE, GPIO_INT_PIN_3,IntGPIOf_Pin3);
GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_RISING_EDGE);

//
// Register the interrupt handler function for GPIO F pin 3
//
IntRegister(INT_GPIOF_TM4C129 , IntGPIOf_Pin3);

####################################################################################################

ENABLE HIBERNATE MATCH INTERRUPT

// Enable Hibernate Match Interrupt
HibernateRTCSet(0); // set RTC counter second to zero
// Clear pending interrupt from Hibernate Module
HibernateIntClear(HIBERNATE_INT_RTC_MATCH_0);
// Disable interrupts for Hibernate module
HibernateIntDisable(HIBERNATE_INT_RTC_MATCH_0);

HibernateIntRegister(Count10Hz_ISR); // register handler for this interrupt
// Register the interrupt handler function for RTC Match 0
//
IntRegister(INT_HIBERNATE_TM4C129 , Count10Hz_ISR);
//
// Enable the interrupt for RTC Match 0 in the processor vector table
//
// IntEnable(INT_HIBERNATE_TM4C129); // moved to just before main loop
// Enable processor interrupts.


// Reset RTC counter seconds
HibernateRTCMatchSet(0,0);

##########################################################################################################################################################

iSECOND ISR through GPIO 

void
IntGPIOf_Pin3(void)
{

// set PPS flag = true for processing in main loop

HWREG(UART0_BASE + 0) = '$'; // 400nS delay, 550nS jitter @ 115200 baud // UART send
// // Turn on the bit


pps_flag = TRUE;
hibRegister_subseconds = HibernateRTCSSGet(); // HWREG(HIB_RTCSS);get subseconds alone here in ISR

// set both RTC counters to zero seconds and sub seconds

HibernateRTCSet(0);

GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

}

#############################################################################################################

SUB SECOND ISR ENABLED BY HIB MATCH ISR

//*****************************************************************************
//
// This is the handler for 10 HZ interrupt within each 1 pps interval.
// Use RTC Match value to generate interrupt 10 times within 1 sec
//
//*****************************************************************************
void Count10Hz_ISR(void) {
HWREG(UART0_BASE + 0) = '|'; // ###########
// Turn on the bit

//MAIN LOOP FLAG
RTC_Flag = TRUE;

HWREG(HIB_IC) |= HIBERNATE_INT_RTC_MATCH_0;

} // end ISR

##############################################################################################

MAIN LOOP

while(1)
{
// spit out $ in an infinite loop
if (pps_flag == TRUE){
// reset pps flag
pps_flag = FALSE;


MatchDollarCounter = 0; // ###############



HWREG(HIB_RTCSS) &= 0x0000FFFF; // retaining lower 16 bits as is

while(!(HWREG(HIB_CTL) & HIB_CTL_WRC)); // ###### needed before next write
// measured ~90uS
HWREG(HIB_RTCSS) |= 0x0CCD0000; // ##### disassembled code shows that this does a read-modify-write over 4 instructions, which introduces a timing error ######
while(!(HWREG(HIB_CTL) & HIB_CTL_WRC)); // ###### needed before next write

HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0); // interrupt source for RTC interrupt} // end if pps flag


else if (RTC_Flag == TRUE) { // #############
// UARTFlushTx(FALSE); // Flush UART Transmit Buffer #############
// Turn off the bit

// GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, GPIO_PIN_1);

GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 1);
MatchDollarCounter++; // ##########

// hibernateRTCMatchValue = (HibernateRTCMatchGet(0) + 0x1000) << 16; // add 100 msec more each time. So zero is start of time ###############
hibernateRTCMatchValue = (0xCCD + 0xCCD*MatchDollarCounter) << 16; // add 100 msec more each time. So zero is start of time ###############

HWREG(HIB_RTCSS) &= 0x0000FFFF; // retaining lower 16 bits as is #################
while(!(HWREG(HIB_CTL) & HIB_CTL_WRC)); // ###### needed before next write (~90uS)
HWREG(HIB_RTCSS) |= hibernateRTCMatchValue; // ##### disassembled code shows that this does a read-modify-write over several instructions, which introduces a timing error ######
while(!(HWREG(HIB_CTL) & HIB_CTL_WRC)); // ###### needed before next write (~90uS)
// HibernateRTCSSMatchSet(0,hibernateRTCMatchValue); // ######## This will alter the Subsample Seconds, which we don't want to do! ########
RTC_Flag = FALSE;

if (MatchDollarCounter == 3)
HibernateIntDisable(HIBERNATE_INT_RTC_MATCH_0);

GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);
}


} // end while 1

#####################################################################################################################

PROBLEM: We can generate only 3 pulses and they are not evenly spaced at 10 HZ. They keelp increasing in time: The first interrupt is at 1/10 sec, the second at 132 microsecond and third at about 250 usec and we do not get fourth one.

I would appreciate reply on this as as much as help from TI as possible.

I am attaching original code file which was adapted from Tivaware example :

Example code for Hybernation Module is found in Tivaware\examples\boards\ek-tm4c1294xl\hibernate\hibernate.c

Thank you

Pavitra

hibernate.c
//*****************************************************************************
//
// hibernate.c - Hibernation Example.
//
// Copyright (c) 2013-2016 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.1.3.156 of the EK-TM4C1294XL Firmware Package.
//
//*****************************************************************************

#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include "inc/hw_gpio.h"
#include "inc/hw_hibernate.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/hibernate.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/systick.h"
#include "utils/ustdlib.h"
#include "utils/uartstdio.h"
#include "utils/cmdline.h"
#include "drivers/buttons.h"
#include "drivers/pinout.h"

//#include "inc/tm4c1294ncpdt.h"





//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Hibernate Example (hibernate)</h1>
//!
//! An example to demonstrate the use of the Hibernation module.  The user
//! can put the microcontroller in hibernation by typing 'hib' in the terminal
//! and pressing ENTER or by pressing USR_SW1 on the board.  The
//! microcontroller will then wake on its own after 5 seconds, or immediately
//! if the user presses the RESET button.  The External WAKE button, external
//! WAKE pins, and GPIO (PK6) wake sources can also be used to wake
//! immediately from hibernation.  The following wiring enables the use of
//! these pins as wake sources.
//!     WAKE on breadboard connection header (X11-95) to GND
//!     PK6 on BoosterPack 2 (X7-17) to GND
//!     PK6 on breadboard connection header (X11-63) to GND
//!
//! The program keeps a count of the number of times it has entered
//! hibernation.  The value of the counter is stored in the battery-backed
//! memory of the Hibernation module so that it can be retrieved when the
//! microcontroller wakes.  The program displays the wall time and date by
//! making use of the calendar function of the Hibernate module.  User can
//! modify the date and time if so desired.
//
//*****************************************************************************
// defines
#define FALSE 0
#define TRUE 1
#define FREQ 9 //  we need 9- 10 HZ pulses in 1 second width

#define CLKARRAYLEN 5 // we store these many samples of RTC clock
#define RTCTRIM   64 // trim reloaded every 64 sec

//*****************************************************************************
//
// A collection of wake sources that will be displayed to indicate the source
// of the most recent wake.
//
//*****************************************************************************
static char *g_ppcWakeSource[] =
{
    "RTC TIMEOUT",
    "RESET",
    "WAKE PIN",
    "GPIO WAKE",
    "SYSTEM RESET"
};

//*****************************************************************************
//
// Lookup table to convert numerical value of a month into text.
//
//*****************************************************************************
static char *g_ppcMonth[12] =
{
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec"
};

//*****************************************************************************
//
// Flag that informs that the user has requested hibernation.
//
//*****************************************************************************
volatile bool g_bHibernate;

//*****************************************************************************
//
// Variables that keep terminal position and status.
//
//*****************************************************************************
bool g_bFirstUpdate;
uint8_t g_ui8FirstLine;

//*****************************************************************************
//
// Flag that informs that date and time have to be set.
//
//*****************************************************************************
volatile bool g_bSetDate;

//*****************************************************************************
//
// Buffers to store display information.
//
//*****************************************************************************
char g_pcWakeBuf[40], g_pcHibBuf[40], g_pcDateTimeBuf[40];

//*****************************************************************************
//
// Buffer to store user command line input.
//
//*****************************************************************************
char g_pcInputBuf[40];

//*****************************************************************************
//
// Variables that keep track of the date and time.
//
//*****************************************************************************
uint32_t g_ui32MonthIdx, g_ui32DayIdx, g_ui32YearIdx;
uint32_t g_ui32HourIdx, g_ui32MinIdx;
//*****************************************************************************
//
// Variables that keep track of RTC counter mode and calculate drift
//
//*****************************************************************************
uint32_t  hibRegister_seconds=0;// Array to hold time stamp values from RTC counter
uint32_t  hibRegister_subseconds=0,hibRegister_subsecondsLast=0;
bool pps_flag=FALSE;
bool RTC_Flag = FALSE;
uint32_t MatchDollarCounter =0; // Counts from 0 to 9 for 10 HZ pulse
uint32_t hibernateRTCMatchValue = 0;

//uint32_t RTCTrim_Last = 0, RTCTrim_Current=0; // for RTC Trim registers
int RTCCount = 0,CountToSixtyFour=0;
uint32_t drift = 0;
//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

//*****************************************************************************
//
// This function reads the current date and time from the calendar logic of the
// hibernate module.  Return status indicates the validity of the data read.
// If the received data is valid, the 24-hour time format is converted to
// 12-hour format.
//
//*****************************************************************************
bool
DateTimeGet(struct tm *sTime)
{
    //
    // Get the latest time.
    //
    HibernateCalendarGet(sTime);

    //
    // Is valid data read?
    //
    if(((sTime->tm_sec < 0) || (sTime->tm_sec > 59)) ||
       ((sTime->tm_min < 0) || (sTime->tm_min > 59)) ||
       ((sTime->tm_hour < 0) || (sTime->tm_hour > 23)) ||
       ((sTime->tm_mday < 1) || (sTime->tm_mday > 31)) ||
       ((sTime->tm_mon < 0) || (sTime->tm_mon > 11)) ||
       ((sTime->tm_year < 100) || (sTime->tm_year > 199)))
    {
        //
        // No - Let the application know the same by returning relevant
        // message.
        //
        return false;
    }

    //
    // Return that new data is available so that it can be displayed.
    //
    return true;
}

//*****************************************************************************
//
// This function formats valid new date and time to be displayed on the home
// screen in the format "MMM DD, YYYY  HH : MM : SS AM/PM".  Example of this
// format is Aug 01, 2013  08:15:30 AM.  It also indicates if valid new data
// is available or not.  If date and time is invalid, this function sets the
// date and time to default value.
//
//*****************************************************************************
bool
DateTimeDisplayGet(char *pcBuf, uint32_t ui32BufSize)
{
    static uint32_t ui32SecondsPrev = 0xFF;
    struct tm sTime;
    uint32_t ui32Len;

    //
    // Get the latest date and time and check the validity.
    //
    if(DateTimeGet(&sTime) == false)
    {
        //
        // Invalid - Force set the date and time to default values and return
        // false to indicate no information to display.
        //
        g_bSetDate = true;
        return false;
    }

    //
    // If date and time is valid, check if seconds have updated from previous
    // visit.
    //
    if(ui32SecondsPrev == sTime.tm_sec)
    {
        //
        // No - Return false to indicate no information to display.
        //
        return false;
    }

    //
    // If valid new date and time is available, update a local variable to keep
    // track of seconds to determine new data for next visit.
    //
    ui32SecondsPrev = sTime.tm_sec;

    //
    // Format the date and time into a user readable format.
    //
    ui32Len = usnprintf(pcBuf, ui32BufSize, "%s %02u, 20%02u  ",
                        g_ppcMonth[sTime.tm_mon], sTime.tm_mday,
                        sTime.tm_year - 100);
    usnprintf(&pcBuf[ui32Len], ui32BufSize - ui32Len, "%02u : %02u : %02u",
              sTime.tm_hour, sTime.tm_min, sTime.tm_sec);

    //
    // Return true to indicate new information to display.
    //
    return true;
}

//*****************************************************************************
//
// This function writes the requested date and time to the calendar logic of
// hibernation module.
//
//*****************************************************************************
void
DateTimeSet(void)
{
    struct tm sTime;

    //
    // Get the latest date and time.  This is done here so that unchanged
    // parts of date and time can be written back as is.
    //
    HibernateCalendarGet(&sTime);

    //
    // Set the date and time values that are to be updated.
    //
    sTime.tm_hour = g_ui32HourIdx;
    sTime.tm_min = g_ui32MinIdx;
    sTime.tm_mon = g_ui32MonthIdx;
    sTime.tm_mday = g_ui32DayIdx;
    sTime.tm_year = 100 + g_ui32YearIdx;

    //
    // Update the calendar logic of hibernation module with the requested data.
    //
    HibernateCalendarSet(&sTime);
}

//*****************************************************************************
//
// This function sets the time to the default system time.
//
//*****************************************************************************
void
DateTimeDefaultSet(void)
{
    g_ui32MonthIdx = 7;
    g_ui32DayIdx = 29;
    g_ui32YearIdx = 13;
    g_ui32HourIdx = 8;
    g_ui32MinIdx = 30;

}
//*****************************************************************************
//
// This function updates individual buffers with valid date and time to be
// displayed on the date screen so that the date and time can be updated.
//
//*****************************************************************************
bool
DateTimeUpdateGet(void)
{
    struct tm sTime;

    //
    // Get the latest date and time and check the validity.
    //
    if(DateTimeGet(&sTime) == false)
    {
        //
        // Invalid - Return here with false as no information to update.  So
        // use default values.
        //
        DateTimeDefaultSet();
        return false;
    }

    //
    // If date and time is valid, copy the date and time values into respective
    // indexes.
    //
    g_ui32MonthIdx = sTime.tm_mon;
    g_ui32DayIdx = sTime.tm_mday;
    g_ui32YearIdx = sTime.tm_year - 100;
    g_ui32HourIdx = sTime.tm_hour;
    g_ui32MinIdx = sTime.tm_min;

    //
    // Return true to indicate new information has been updated.
    //
    return true;
}

//*****************************************************************************
//
// This function returns the number of days in a month including for a leap
// year.
//
//*****************************************************************************
uint32_t
GetDaysInMonth(uint32_t ui32Year, uint32_t ui32Mon)
{
    //
    // Return the number of days based on the month.
    //
    if(ui32Mon == 1)
    {
        //
        // For February return the number of days based on the year being a
        // leap year or not.
        //
        if((ui32Year % 4) == 0)
        {
            //
            // If leap year return 29.
            //
            return 29;
        }
        else
        {
            //
            // If not leap year return 28.
            //
            return 28;
        }
    }
    else if((ui32Mon == 3) || (ui32Mon == 5) || (ui32Mon == 8) ||
            (ui32Mon == 10))
    {
        //
        // For April, June, September and November return 30.
        //
        return 30;
    }

    //
    // For all the other months return 31.
    //
    return 31;
}

//*****************************************************************************
//
// This function returns the date and time value that is written to the
// calendar match register.  5 seconds are added to the current time.  Any
// side-effects due to this addition are handled here.
//
//*****************************************************************************
void
GetCalendarMatchValue(struct tm* sTime)
{
    uint32_t ui32MonthDays;

    //
    // Get the current date and time and add 5 secs to it.
    //
    HibernateCalendarGet(sTime);
    sTime->tm_sec += 5;

    //
    // Check if seconds is out of bounds.  If so subtract seconds by 60 and
    // increment minutes.
    //
    if(sTime->tm_sec > 59)
    {
        sTime->tm_sec -= 60;
        sTime->tm_min++;
    }

    //
    // Check if minutes is out of bounds.  If so subtract minutes by 60 and
    // increment hours.
    //
    if(sTime->tm_min > 59)
    {
        sTime->tm_min -= 60;
        sTime->tm_hour++;
    }

    //
    // Check if hours is out of bounds.  If so subtract minutes by 24 and
    // increment days.
    //
    if(sTime->tm_hour > 23)
    {
        sTime->tm_hour -= 24;
        sTime->tm_mday++;
    }

    //
    // Since different months have varying number of days, get the number of
    // days for the current month and year.
    //
    ui32MonthDays = GetDaysInMonth(sTime->tm_year, sTime->tm_mon);

    //
    // Check if days is out of bounds for the current month and year.  If so
    // subtract days by the number of days in the current month and increment
    // months.
    //
    if(sTime->tm_mday > ui32MonthDays)
    {
        sTime->tm_mday -= ui32MonthDays;
        sTime->tm_mon++;
    }

    //
    // Check if months is out of bounds.  If so subtract months by 11 and
    // increment years.
    //
    if(sTime->tm_mon > 11)
    {
        sTime->tm_mon -= 11;
        sTime->tm_year++;
    }

    //
    // Check if years is out of bounds.  If so subtract years by 100.
    //
    if(sTime->tm_year > 99)
    {
        sTime->tm_year -= 100;
    }
}

//*****************************************************************************
//
// This function does some application level cleanup and alerts the user
// before sending the hibernate request to the hardware.
//
//*****************************************************************************
void
AppHibernateEnter(void)
{
    uint32_t ui32Status;
    struct tm sTime;

    //
    // Print the buffer to the terminal.
    //
    UARTprintf("To wake, wait for 5 seconds or press WAKE or"
               "RESET\n");
    UARTprintf("See README.txt for additional wake sources.\n");

    //
    // Wait for UART transmit to complete before proceeding to
    // hibernate.
    //
    UARTFlushTx(false);

    //
    // Get calendar match value to be 5 seconds from the current time.
    //
    GetCalendarMatchValue(&sTime);

    //
    // Set the calendar match register such that it wakes up from
    // hibernation in 5 seconds.
    //
    HibernateCalendarMatchSet(0, &sTime);

    //
    // Read and clear any status bits that might have been set since
    // last clearing them.
    //
    ui32Status = HibernateIntStatus(0);
    HibernateIntClear(ui32Status);

    //
    // Configure Hibernate wake sources.
    //
    HibernateWakeSet(HIBERNATE_WAKE_PIN | HIBERNATE_WAKE_GPIO |
                     HIBERNATE_WAKE_RESET | HIBERNATE_WAKE_RTC);

    //
    // Request Hibernation.
    //
    HibernateRequest();

    //
    // Wait for a while for hibernate to activate.  It should never get
    // past this point.
    //
    SysCtlDelay(100);

    //
    // If it ever gets here, store the text, that informs the user on
    // what to do, into the respective widget buffers.
    //
    UARTprintf("The controller did not enter hibernate.  Press RESET"
               "button to restart example.\n");

    //
    // Wait here.
    //
    while(1)
    {
    }
}

//*****************************************************************************
//
// This function is the interrupt handler for the SysTick timer.  It monitors
// both the USR_SW buttons on the board.  If a button is pressed then we
// request a hibernate cycle.
//
//*****************************************************************************
void
SysTickIntHandler(void)
{
    uint32_t ui32Buttons;

    ui32Buttons = ButtonsPoll(0,0);

    switch(ui32Buttons & ALL_BUTTONS)
    {
        //
        // The user pressed USR_SW1.
        //
        case USR_SW1:
        {
            //
            // Set the hibernate flag to request a system hibernate cycle.
            //
            g_bHibernate = true;
            break;
        }

        //
        // For all other cases do nothing.
        //
        default:
        {
            break;
        }
    }

}

//*****************************************************************************
//
// This is the handler for INT_GPIOF Pin 3.  It triggers INT_GPIOA and saves the
// interrupt sequence number.
//
//*****************************************************************************
void
IntGPIOf_Pin3(void)
{

// set PPS flag = true for processing in main loop
//    UARTprintf("$");    // 4.2uS delay, 550nS jitter @ 115200 baud
    HWREG(UART0_BASE + 0) = '$';    // 400nS delay, 550nS jitter @ 115200 baud // UART send
// // Turn on the bit

 //   GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, GPIO_PIN_0);
   pps_flag = TRUE;
   hibRegister_subseconds = HibernateRTCSSGet(); // HWREG(HIB_RTCSS);get subseconds alone here in ISR
  // RTCTrim_Current = HibernateRTCTrimGet();

//    UARTprintf("$");    // 250uS delay, 30uS jitter @ 115200 baud

   // set both RTC counters to zero seconds and sub seconds

   HibernateRTCSet(0);

   GPIOIntClear(GPIO_PORTF_BASE, GPIO_INT_PIN_3);

}
//*****************************************************************************
//
// This is the handler for 10 HZ interrupt within each 1 pps interval.
// Use RTC Match value to generate interrupt 10 times within 1 sec
//
//*****************************************************************************
void Count10Hz_ISR(void) {
    HWREG(UART0_BASE + 0) = '|';    // ###########
    // Turn on the bit

    //    GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, GPIO_PIN_0);
    RTC_Flag = TRUE;
//    hibRegister_seconds = HWREG(HIB_RTCC); //Get seconds count
//    MatchDollarCounter++;  // ######  moved to main loop
//    MatchDollarCounter %=  FREQ; // Automatically set this value to ZERO on reaching 10 HZ  #######
//    if (MatchDollarCounter == 0) {

    HWREG(HIB_IC) |= HIBERNATE_INT_RTC_MATCH_0;
//    HibernateIntClear(HIBERNATE_INT_RTC_MATCH_0);   // ########  added
//                  }

} // end ISR
//*****************************************************************************
//
// This is the function to caLCLULATE if RTC clock drift is there within 1 second
//
//*****************************************************************************
void CalculateRTClkDrift(void)
{


//drift = (hibRegister_subseconds - hibRegister_subsecondsLast) / 32768; //RTC clock Rate is 32.768 KHZ

} // end calc clock drift


//*****************************************************************************
//
// This example demonstrates the different hibernate wake sources.  The
// microcontroller is put into hibernation by the user and wakes up based on
// timeout or one of the user inputs.  This example also demonstrates the RTC
// calendar function that keeps track of date and time.
//
//*****************************************************************************
int
main(void)
{


    uint32_t ui32SysClock;
    //
    // Run from the PLL at 120 MHz.
    //
    ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                           SYSCTL_OSC_MAIN |
                                           SYSCTL_USE_PLL |
                                           SYSCTL_CFG_VCO_480), 120000000);

    //
    // Configure the device pins.
    // Configures the device pins for the standard usages on the EK-TM4C1294XL.
    // No Ethernet or USB
    PinoutSet(false, false);
    // Enable the GPIO port that is used for the on-board LED.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

        //
        // Check if the peripheral access is enabled.
        //
        while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPION))
        {
        }

        // Enable the GPIO pin for the LED (PN0).  Set the direction as output, and
        // enable the GPIO pin for digital function.
        //
        GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);

        // Turn on the LED.

        GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0);
        // Clear Arrays
    /*    for (index=0;index<CLKARRAYLEN;index++) {
            hibRegister_seconds[index] = 0;
        }
        // reinitialize index
        index = 0; */


    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, ui32SysClock);

    //discard any data in UART FIFO

    UARTFlushTx(TRUE); // Discard UART Transmit Buffer
    // Enable the hibernate module.
    //
 //   SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
    //
    // Initialize these variables before they are used.
    //

    RTCCount = 0;
    drift = 0;
    CountToSixtyFour=0;
    //
    // Configure Hibernate module clock.
    //
    HibernateEnableExpClk(ui32SysClock);


    // Enable RTC mode.
    //
    HibernateRTCEnable();

    //
    // Configure the hibernate module counter to 24-hour calendar mode.
    //
  //  HibernateCounterMode(HIBERNATE_COUNTER_24HR);
//  Configure the hibernate module counter to RTC counter mode.
    HibernateCounterMode(HIBERNATE_COUNTER_RTC);
    //
    // Configure GPIOs used as Hibernate wake source.  PK6 is configured as a
    // wake source.  It is available on EK-TM4C1294XL BoosterPack 2 (X7-17)
    // and on the breadboard breakout connector (X11-63).  Short to ground to
    // generate a wake request.
    //
   // GPIOPadConfigSet(GPIO_PORTK_BASE, GPIO_PIN_6, GPIO_STRENGTH_2MA,
    //                 (GPIO_PIN_TYPE_WAKE_LOW | GPIO_PIN_TYPE_STD_WPU));


    // LaunchPad BoosterPack 1 Header for taking 1 PPS pulse configure pins
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_3);  // Init PF3 as input
  //  GPIODirModeSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_DIR_MODE_IN) ;

    GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);

    // Interrupt setup
       GPIOIntDisable(GPIO_PORTF_BASE, GPIO_PIN_3);        // Disable interrupt for PF4 (in case it was enabled)
       GPIOIntClear(GPIO_PORTF_BASE, GPIO_PIN_3);      // Clear pending interrupts for PF4
       // Register our handler function for port F pin 3
         GPIOIntRegisterPin(GPIO_PORTF_BASE, GPIO_INT_PIN_3,IntGPIOf_Pin3);
         GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_RISING_EDGE);

         //
         // Register the interrupt handler function for GPIO F pin 3
         //
         IntRegister(INT_GPIOF_TM4C129 , IntGPIOf_Pin3);

         // Configure POrt P Pin 1 (PP1) on booster pack 2 header) for transmitting a bit --DEBUG purposes
         // LaunchPad BoosterPack 1 Header for taking 1 PPS pulse configure pins
           SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
           //
                   // Check if the peripheral access is enabled.
                   //
                   while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOP))
                   {
                   }

           GPIOPinTypeGPIOOutput(GPIO_PORTP_BASE, GPIO_PIN_1);  // Init PP1 as output

           GPIOPadConfigSet(GPIO_PORTP_BASE, GPIO_PIN_1, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU);

    // Initialize the buttons
    //
 //   ButtonsInit();

    //
    // Initialize the SysTick interrupt to process user buttons.
    //
  //  SysTickPeriodSet(SysCtlClockGet() / 30);
  //  SysTickEnable();
  //  SysTickIntEnable();

               // Enable Hibernate Match Interrupt
                       HibernateRTCSet(0); // set RTC counter second to zero
                       // Clear pending interrupt from Hibernate Module
                       HibernateIntClear(HIBERNATE_INT_RTC_MATCH_0);
                       // Diable interrupts for Hibernate module
                       HibernateIntDisable(HIBERNATE_INT_RTC_MATCH_0);
//  ######## moved     HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0); // interrupt source for RTC interrupt
                       HibernateIntRegister(Count10Hz_ISR); // register handler for this interrupt
                       // Register the interrupt handler function for RTC Match 0
                             //
                           IntRegister(INT_HIBERNATE_TM4C129 , Count10Hz_ISR);
                             //
                             // Enable the interrupt for RTC Match 0 in the processor vector table
                             //
//                            IntEnable(INT_HIBERNATE_TM4C129); // moved to just before main loop
                             // Enable processor interrupts.


                              // Reset RTC counter seconds
                              HibernateRTCMatchSet(0,0);
                           //   if (MatchDollarCounter == 0) {
                               //         HibernateRTCSSMatchSet(0,6554); // Subseconds match value

                           //   }
// should only be in PPS section   HibernateRTCSSMatchSet(0,6554) ; // set to 100 milliseconds 6554 = 100 msec
    UARTprintf("BEGIN PRINTING\n");
    //
    // Loop forever.
    //

    // Enable interrupts for the pin
             GPIOIntEnable(GPIO_PORTF_BASE, GPIO_INT_PIN_3);    // ######### moved here
    //
    // Enable the interrupt for GPIO Port F pin 3
    //
    IntEnable(INT_GPIOF_TM4C129);   // #########  relocated

    IntMasterEnable();   // ###### relocated here so as not to cause interrupts before getting to main loop ############

    while(1)
    {
        // spit out $ in an infinite loop
        if (pps_flag == TRUE){
                // reset pps flag
                pps_flag = FALSE;
//                UARTFlushTx(FALSE); // Flush UART Transmit Buffer ############
                // Turn off the bit

            //        GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, GPIO_PIN_1);
                RTCCount++; // increment seconds count for RTC Trim
                RTCCount %= FREQ;
                MatchDollarCounter = 0;     // ###############
                //  HibernateRTCSSMatchSet(0,(2*6554)) ; // reset to 100 milliseconds 6554 = 100 msec every second
             //   HWREG(0x400FC004) = 0x00000CCD;
                  HWREG(HIB_RTCSS) &= 0x0000FFFF; // retaining lower 16 bits as is
//      GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 1);
                  while(!(HWREG(HIB_CTL) & HIB_CTL_WRC));   // ###### needed before next write
//      GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);         // measured ~90uS
                  HWREG(HIB_RTCSS) |= 0x0CCD0000;        // ##### disassembled code shows that this does a read-modify-write over 4 instructions, which introduces a timing error ######
                  while(!(HWREG(HIB_CTL) & HIB_CTL_WRC));   // ###### needed before next write
//                HibernateRTCSSMatchSet(0,0x0CCD0000) ;      // ######## The four zeros will clear the Subsample Seconds, which we don't want to do! ########
                  HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0); // interrupt source for RTC interrupt
        // do a few other things
                  // reset counter
/*                     if (MatchDollarCounter == 0) {
                             if ( RTCCount == 0) {
                                 if (hibRegister_subsecondsLast)
                               //  drift = abs((hibRegister_subseconds - hibRegister_subsecondsLast)) ; // 32768; //RTC clock Rate is 32.768 KHZ
                                     hibRegister_subseconds < hibRegister_subsecondsLast ?  (drift += hibRegister_subsecondsLast - hibRegister_subseconds) : (drift += hibRegister_subseconds - hibRegister_subsecondsLast);
                                 hibRegister_subsecondsLast = hibRegister_subseconds; // save last accumulated value of subsecons for 1 second interval
                                 // one needs to adjust the drift ticks into RTC TRIM as 64*this value as that will be reloaded once in 64 seconds only

                                 if (CountToSixtyFour == (6)){
                                 HibernateRTCTrimSet(drift*64);
                                 drift = 0; // accumulate drift for 64 seconds
                                 CountToSixtyFour %= (6);
                                 }


                                 CountToSixtyFour++;
                             }
                         HibernateIntEnable(HIBERNATE_INT_RTC_MATCH_0); // interrupt source for RTC interrupt
                                                      }
*/        } // end if pps flag

        // Read RTC Match Value


        else if (RTC_Flag == TRUE) {    // #############
//            UARTFlushTx(FALSE); // Flush UART Transmit Buffer #############
            // Turn off the bit

  //         GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, GPIO_PIN_1);

            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 1);
            MatchDollarCounter++;   // ##########

//            hibernateRTCMatchValue =  (HibernateRTCMatchGet(0) + 0x1000) << 16; // add 100 msec more each time. So zero is start of time ###############
            hibernateRTCMatchValue =  (0xCCD + 0xCCD*MatchDollarCounter) << 16; // add 100 msec more each time. So zero is start of time ###############

            HWREG(HIB_RTCSS) &= 0x0000FFFF; // retaining lower 16 bits as is    #################
            while(!(HWREG(HIB_CTL) & HIB_CTL_WRC));   // ###### needed before next write (~90uS)
            HWREG(HIB_RTCSS) |= hibernateRTCMatchValue;        // ##### disassembled code shows that this does a read-modify-write over several instructions, which introduces a timing error ######
            while(!(HWREG(HIB_CTL) & HIB_CTL_WRC));   // ###### needed before next write (~90uS)
//            HibernateRTCSSMatchSet(0,hibernateRTCMatchValue);      // ######## This will alter the Subsample Seconds, which we don't want to do! ########
            RTC_Flag = FALSE;

            if (MatchDollarCounter == 3)
                HibernateIntDisable(HIBERNATE_INT_RTC_MATCH_0);

            GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0);
        }

   //     SysCtlDelay(20000000);
    } // end while 1
} // end main

  • Hi,
    Is your 1s interrupt periodic or based on a random GPIO input?
  • Interrupt is periodic but triggered by GPIO Port F pin 3 which is programmed to raise interrupts every 1 second.

    Regards
    Pavitra
  • Hi,
    Can you please check if you are using HIB LFIOSC as the clock source for the Hibernate module? Please note that the onchip HIB low frequency oscillator (HIB LFIOSC) has a wide frequency variation. It is not recommended to use the HIB LFIOSC as an RTC clock source.
  • Hi,

    A 32.768 KHz crystal is used for RTC.

    We are using EK-TM4C1294XL Launchpad which has an onboard 32.768 KHz crystal.

    Thanks
    Pavitra
  • Hi,
    Can you do an experiment? Can you try to to generate sub-section match interrupt at 5Hz instead of 10Hz? You are not really using hibernate module to save power but rather to generate the sub-section match interrupt by adding the next sub-section match value, right? The hibernate module runs off of the 32kz OSC and to access the hibernate module registers it takes some cycles at 32kz frequency. From the time the sub-section match value is first cleared to the time a new (next) sub-section match register is written, the sub-section counter has already elapsed. If the sub-section counter value has already counted over next match value before the next value is fully written then the match may be missed. This is just one direction I'm looking into. Not necessary the root cause yet. Another thing you can try is to reset the RTC counter for each 0.1s and always set the sub-section match to 0.1s.
  • Hello

    I am aware that a small amount of sub-second time is lost because the SS match value is in the same register as the SS clock value. Therefore, I have to do a read-modify-write with masking to preserve the SS time (almost). But that error can be corrected for.

    “For the current experiment, the Tiva is doing little else, so 100ms should be plenty of time to set up for the next interval. And the oscilloscope confirms that by use of test point flags. The times I am seeing are: 100mS from the GPS 1PPS edge to the first SS interrupt, another 132mS to the next, and another 268mS to third (total of 500mS at that point); no more until the next second when the pattern repeats. Each time, the GPS edge clears the counters, and the SS match is incremented by 0xCCD at each interrupt.

    “Yes, the RTC counter instead at each 100mS time, or empirically generated match could be derived to make it work. But I’d like to understand what’s going on first. I’m using the RTC to potentially take advantage of the timing trim capability after the basics are worked out, and because it seemed at first like the RTC would be a natural for this sort of problem

    Thank you