MSP430 Tutorial

MPS430 Real-Time Clock


MPS430 Real-Time Clock (RTC_A)

A real-time clock (RTC) is a computer clock that keeps track of the current date and time. Just as the clock shown below plus date and year.





Real time clocks (RTC) are used in a variety of applications - from watches and clocks to time-stamping events, to generating events. All MSP430 devices contain both a digitally-controlled RC-type oscillator and a crystal oscillator. The RC-type oscillator is typically used for the CPU clock and the crystal oscillator is typically used for the peripherals. In the real-time clock application, the crystal oscillator is used as the clock source for the timer/counter that serves as the time base (either Timer_A or the Watchdog Timer in this application report).
The general implementation of the RTC is simple. It consists of a timer/counter giving 1-second interrupts and a small CPU routine to count the interrupts. The CPU can sleep or perform other functions between interrupts.
The real time clock uses the LFXT1 oscillator in LF mode with a 32768-Hz crystal.

The Real Time Clock module A (RTC_A) provides a real-time clock and calendar function that can also be configured as a general-purpose counter. The RTC_A module can be configured as a real-time clock with calendar function (calendar mode) or as a 32-bit general purpose counter (counter mode) with the RTCMODE bit set to zero.



Calendar Mode (MSP430F5529)

Calendar mode is selected when RTCMODE is set. In calendar mode, the RTC_A module provides seconds, minutes, hours, day of week, day of month, month, and year in selectable BCD or hexadecimal format. The calendar includes a leap-year algorithm that considers all years evenly divisible by four as leap years. This algorithm is accurate from the year 1901 through 2099.

			
/*
* Initialize Calendar Mode of RTC:
* Base Address of the RTC_A_A
* Pass in current time, intialized above
* Use BCD as Calendar Register Format
*/
RTC_A_initCalendar(RTC_A_BASE, &currentTime, RTC_A_FORMAT_BCD);
		
void RTC_A_initCalendar(uint16_t baseAddress,
	Calendar *CalendarTime,
	uint16_t formatSelect)
{
	HWREG8(baseAddress + OFS_RTCCTL01_H) |= RTCMODE_H + RTCHOLD_H;

	HWREG16(baseAddress + OFS_RTCCTL01) &= ~(RTCBCD);
	HWREG16(baseAddress + OFS_RTCCTL01) |= formatSelect;

	HWREG8(baseAddress + OFS_RTCTIM0_L) = CalendarTime->Seconds;
	HWREG8(baseAddress + OFS_RTCTIM0_H) = CalendarTime->Minutes;
	HWREG8(baseAddress + OFS_RTCTIM1_L) = CalendarTime->Hours;
	HWREG8(baseAddress + OFS_RTCTIM1_H) = CalendarTime->DayOfWeek;
	HWREG8(baseAddress + OFS_RTCDATE_L) = CalendarTime->DayOfMonth;
	HWREG8(baseAddress + OFS_RTCDATE_H) = CalendarTime->Month;
	HWREG16(baseAddress + OFS_RTCYEAR) = CalendarTime->Year;
}
		


Initializing RTC (MSP430F5529)

#include <string.h>
#include "driverlib.h"

#include "USB_config/descriptors.h"
#include "USB_API/USB_Common/device.h"
#include "USB_API/USB_Common/usb.h"                     //USB-specific functions
#include "USB_API/USB_CDC_API/UsbCdc.h"
#include "USB_app/usbConstructs.h"


/*
 * NOTE: Modify hal.h to select a specific evaluation board and customize for
 * your own board.
 */
#include "hal.h"
volatile Calendar newTime;

// Application globals
volatile uint8_t hour = 4, min = 30, sec = 00;  // Real-time clock (RTC) values.  4:30:00
volatile uint8_t bSendTimeToHost = FALSE;       // RTC-->main():  "send the time over USB"

/*
 * ======== main ========
 */
volatile unsigned int count = 0;
volatile unsigned int i;
void main(void)
{
	Calendar currentTime;

	WDT_A_hold(WDT_A_BASE); //Stop watchdog timer
    
   	// Select XT1
	/* 
	* Enable XT1: port5 pin4 and pin5 are connected to 32768 Hz external oscillator on the schematics.
	* The GPIO_setAsPeripheralModuleFunctionInputPin() function sets them to their periferal designated 
	* functions - XIN, XOUT.
	*/
   	GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4 + GPIO_PIN5);

  	//Initialize LFXT1 - low frequency 32768 Hz oscillator
  	/*
	* The DRIVE settings of XT1 in LF mode can be increased with the XT1DRIVE bits. At power up, the XT1
	* starts with the highest drive settings for fast, reliable startup. If needed, user software can reduce the drive
	* strength to further reduce power. 
	*/
  	UCS_turnOnLFXT1(UCS_XT1_DRIVE_3, UCS_XCAP_3);

	//Setup Current Date and Time for Calendar
	currentTime.Seconds = 0x00;
	currentTime.Minutes = 0x30;
	currentTime.Hours = 0x16;
	currentTime.DayOfWeek = 0x03;
	currentTime.DayOfMonth = 0x20;
	currentTime.Month = 0x07;
	currentTime.Year = 0x2011;

	//Initialize Calendar Mode of RTC
	/*
 	* Base Address of the RTC_A_A
 	* Pass in current time, intialized above
 	* Use BCD as Calendar Register Format
 	* ----------------------------------------------------------------------------------------------------------
 	* Calendar mode is selected when RTCMODE is set. In calendar mode, the RTC_A module provides 
 	* seconds, minutes, hours, day of week, day of month, month, and year in selectable BCD or hexadecimal 
 	* format. The calendar includes a leap-year algorithm that considers all years evenly divisible by four as 
 	* leap years. This algorithm is accurate from the year 1901 through 2099.
 	* -----------------------------------------------------------------------------------------------------------
 	*/
	RTC_A_initCalendar(RTC_A_BASE, &currentTime, RTC_A_FORMAT_BINARY);	// Enable RTC in the calendar mode.

	//Setup Calendar Alarm for 5:00pm on the 5th day of the week.
	//Note: Does not specify day of the week.
	RTC_A_configureCalendarAlarmParam param = {0};
	param.minutesAlarm = 0x00;
	param.hoursAlarm = 0x17;				//Setup Calendar Alarm for 5:00pm
	param.dayOfWeekAlarm = RTC_A_ALARMCONDITION_OFF;
	param.dayOfMonthAlarm = 0x05;			//5th day of the week
	RTC_A_configureCalendarAlarm(RTC_A_BASE, &param);

	//Specify an interrupt to assert every minute
	RTC_A_setCalendarEvent(RTC_A_BASE, RTC_A_CALENDAREVENT_MINUTECHANGE);

	//Enable interrupt for RTC Ready Status, which asserts when the RTC
	//Calendar registers are ready to read.
	//Also, enable interrupts for the Calendar alarm and Calendar event.
	RTC_A_clearInterrupt(RTC_A_BASE, RTCRDYIFG + RTCTEVIFG + RTCAIFG);
	RTC_A_enableInterrupt(RTC_A_BASE, RTCRDYIE + RTCTEVIE + RTCAIE);

	//Start RTC Clock
	RTC_A_startClock(RTC_A_BASE);

		
		

Real-Time Clock and Prescale Dividers

The prescale dividers, RT0PS and RT1PS, are automatically configured to provide a 1-s clock interval for the RTC_A.

RT0PS is sourced from ACLK. ACLK must be set to 32768 Hz (nominal) for proper RTC_A calendar operation.

RT1PS is cascaded with the output ACLK/256 of RT0PS, which is ACLK/256 = 128 Hz.
The RTC_A is sourced with the /128 output of RT1PS, thereby providing the required 1-s interval.
Switching from counter to calendar mode clears the seconds, minutes, hours, day-of-week, and year counts and sets day-of-month and month counts to 1. In addition, RT0PS and RT1PS are cleared.


When RTCBCD = 1, BCD format is selected for the calendar registers. The format must be selected before the time is set. Changing the state of RTCBCD clears the seconds, minutes, hours, day-of-week, and year counts and sets day-of-month and month counts to 1. In addition, RT0PS and RT1PS are cleared.


The following example code flips LED connected to P2.0, shown above on the circuit diagram, every second.

		
#include "driverlib.h"

volatile Calendar newTime;

void main(void)
{
    Calendar currentTime;

    WDT_A_hold(WDT_A_BASE);

    //Set P2.0 to output direction
    GPIO_setAsOutputPin(
        GPIO_PORT_P2,
        GPIO_PIN0
        );

    // Select XT1
    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_P5,
        GPIO_PIN4 + GPIO_PIN5
        );

    //Initialize LFXT1
    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,
                    UCS_XCAP_3
                    );

    //Setup Current Time for Calendar
    currentTime.Seconds = 0x00;
    currentTime.Minutes = 0x26;
    currentTime.Hours = 0x13;
    currentTime.DayOfWeek = 0x03;
    currentTime.DayOfMonth = 0x20;
    currentTime.Month = 0x07;
    currentTime.Year = 0x2011;

    //Initialize Calendar Mode of RTC
    /*
     * Base Address of the RTC_A_A
     * Pass in current time, intialized above
     * Use BCD as Calendar Register Format
     */
    RTC_A_initCalendar(RTC_A_BASE, &currentTime, RTC_A_FORMAT_BCD);
    
    //Setup Calendar Alarm for 5:00pm on the 5th day of the week.
    //Note: Does not specify day of the week.
    RTC_A_configureCalendarAlarmParam param = {0};
    param.minutesAlarm = 0x00;
    param.hoursAlarm = 0x17;
    param.dayOfWeekAlarm = RTC_A_ALARMCONDITION_OFF;
    param.dayOfMonthAlarm = 0x05;
    RTC_A_configureCalendarAlarm(RTC_A_BASE, &param);

    //Specify an interrupt to assert every minute
    RTC_A_setCalendarEvent(RTC_A_BASE,
                           RTC_A_CALENDAREVENT_MINUTECHANGE);

    //Enable interrupt for RTC Ready Status, which asserts when the RTC
    //Calendar registers are ready to read.
    //Also, enable interrupts for the Calendar alarm and Calendar event.
    RTC_A_clearInterrupt(RTC_A_BASE,
                         RTCRDYIFG + RTCTEVIFG + RTCAIFG);
    RTC_A_enableInterrupt(RTC_A_BASE,
                          RTCRDYIE + RTCTEVIE + RTCAIE);

    //Start RTC Clock
    RTC_A_startClock(RTC_A_BASE);

    //Enter LPM3 mode with interrupts enabled
    __bis_SR_register(LPM3_bits + GIE);
    __no_operation();
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=RTC_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(RTC_VECTOR)))
#endif
void RTC_A_ISR(void)
{
    switch(__even_in_range(RTCIV,16))
    {
    case 0: break;      //No interrupts
    case 2:             //RTCRDYIFG
        //Toggle P2.0 every second
        GPIO_toggleOutputOnPin(
            GPIO_PORT_P2,
            GPIO_PIN0);
        break;
    case 4:             //RTCEVIFG
        //Interrupts every minute
        __no_operation();

        //Read out New Time a Minute Later BREAKPOINT HERE
        newTime = RTC_A_getCalendarTime(RTC_A_BASE);
        break;
    case 6:             //RTCAIFG
        //Interrupts 5:00pm on 5th day of week
        __no_operation();
        break;
    case 8: break;      //RT0PSIFG
    case 10: break;     //RT1PSIFG
    case 12: break;     //Reserved
    case 14: break;     //Reserved
    case 16: break;     //Reserved
    default: break;
    }
}
		
		

Real-Time Clock Interrupts in Calendar Mode

The RTC_A module has five interrupt sources available, each with independent enables and flags. namely RT0PSIFG, RT1PSIFG, RTCRDYIFG, RTCTEVIFG, and RTCAIFG. These flags are prioritized and combined to source a single interrupt vector. The interrupt vector register (RTCIV - real time clock interrupt vector) is used to determine which flag requested an interrupt.
The highest-priority enabled interrupt generates a number in the RTCIV register (see register description). This number can be evaluated or added to the program counter (PC) to automatically enter the appropriate software routine. Disabled RTC interrupts do not affect the RTCIV value.

Any access, read or write, of the RTCIV register automatically resets the highest-pending interrupt flag. If another interrupt flag is set, another interrupt is immediately generated after servicing the initial interrupt. In addition, all flags can be cleared via software.
The user-programmable alarm event sources the real-time clock interrupt, RTCAIFG. Setting RTCAIE enables the interrupt. In addition to the user-programmable alarm, the RTC_A module provides for an interval alarm that sources real-time clock interrupt, RTCTEVIFG. The interval alarm can be selected to cause an alarm event when RTCMIN changed or RTCHOUR changed, every day at midnight (00:00:00) or every day at noon (12:00:00). The event is selectable with the RTCTEV bits. Setting the RTCTEVIE bit enables the interrupt.

The RTCRDY bit sources the real-time clock interrupt, RTCRDYIFG, and is useful in synchronizing the read of time registers with the system clock. Setting the RTCRDYIE bit enables the interrupt.

RT0PSIFG can be used to generate interrupt intervals selectable by the RT0IP bits. In calendar mode, RT0PS is sourced with ACLK at 32768 Hz, so intervals of 16384 Hz, 8192 Hz, 4096 Hz, 2048 Hz, 1024 Hz, 512 Hz, 256 Hz, or 128 Hz are possible. Setting the RT0PSIE bit enables the interrupt.

RT1PSIFG can generate interrupt intervals selectable by the RT1IP bits. In calendar mode, RT1PS is sourced with the output of RT0PS, which is 128 Hz (32768/256 Hz). Therefore, intervals of 64 Hz, 32 Hz, 16 Hz, 8 Hz, 4 Hz, 2 Hz, 1 Hz, or 0.5 Hz are possible. Setting the RT1PSIE bit enables the interrupt.