Hi all,
I'm playing with the the RTC on an MSP432 (MSP-EXP432P401R Launchpad) in a TI-RTOS (2.14.3.28) project. I'm using CCS 6.1.1.
I started with the standard empty project (File->New-Project->C/C++->CCS Project->MSP432 Target->Project Template TI-RTOS Examples->MSP-EXP432P401R Launchpad->Driver Examples->TI Driver Examples->Empty Examples->Empty Project phew!)
I've
- created a HWI to deal with RTC interrupts (Interrupt number = 45, Priority = 14).
- configured RTC to interrupt on ready to read, events (minute) and an alarm.
- created clock function running every 5 seconds toggling red the multicolour led on and off
- added and configured the seconds module (initialized to start with the same time as the RTC)
- added and configured the timestamp module
- heatBeat task changed to run every 2sec and to system_printf (and system_flush) time from the RTC, seconds module, timestamp module
- (Code is attached at bottom)
If I disable RTC interrupts in my initialization using MAP_RTC_C_disableInterrupt() then all is well (though of course the functionality related to the RTC interrupts doesn't work).
If I enable RTC interrupts in my initialization MAP_RTC_C_enableInterrupt(), then everything seems to work, except I occassionally get the following message in the console (the xx numbers vary):
"Invalid CIO command (xx) in the CIO buffer at address (xx) was not recognized. Please check the device and program memory maps."
This still happens even if I make the Hwi empty or if I globally disable interrupts (Hwi_disable(), Hwi_restore()) during the Hwi
I'm guessing the RTC interrupt is happening while the micro is dealing with the CIO stuff causing the CIO buffer to be corrupted.
Any suggestions for how to fix this??
Cheers
Julian
/* * SNIP TI STD HEADER FOR BREVITY */ /* XDCtools Header files */ #include <xdc/std.h> #include <xdc/cfg/global.h> #include <xdc/runtime/System.h> /* BIOS Header files */ #include <ti/sysbios/BIOS.h> /* TI-RTOS Header files */ #include <ti/drivers/GPIO.h> /* Board Header file */ #include "Board.h" #include <xdc/runtime/Timestamp.h> #include <ti/drivers/Power.h> #include <ti/drivers/power/PowerMSP432.h> #include <time.h> #include <ti/sysbios/hal/Seconds.h> #include <driverlib.h> #include <ti/sysbios/knl/Semaphore.h> #include <xdc/runtime/Log.h> int8_t readRTC(RTC_C_Calendar *td); // DO NOT READ THESE DIRECTLY. USE readRTC() static volatile RTC_C_Calendar current_RTC_Time; static volatile Bool current_RTC_Time_update_toggle = false; /* * ======== heartBeatFxn ======== * Toggle the Board_LED0. The Task_sleep is determined by arg0 which * is configured for the heartBeat Task instance. */ //-------------------------------------------------------------------------------------------- // Function called by the heartBeat task //-------------------------------------------------------------------------------------------- void heartBeatFxn(UArg arg0, UArg arg1) { uint32_t ts32; xdc_runtime_Types_Timestamp64 ts64; xdc_runtime_Types_FreqHz freq; uint32_t sec; time_t t1; //struct tm *ltm, *gtm; //char *curTime, *curTime2; char *curTime3; RTC_C_Calendar RTCTime; int8_t errs; while (1) { Task_sleep((UInt)arg0); GPIO_toggle(Board_LED0); Timestamp_get64(&ts64); ts32 = Timestamp_get32(); Timestamp_getFreq(&freq); sec = Seconds_get(); t1 = time(NULL); // This overrides the standard time() function to return Seconds_get() adjusted for epoch from 1/1/1900 // Without having set time zone or DLS mode all three strings end up the same //ltm = localtime(&t1); curTime = asctime(ltm); //gtm = gmtime(&t1); curTime2 = asctime(gtm); curTime3 = ctime(&t1); // Really same as first approach above. Uses localTime internally errs += readRTC(&RTCTime); System_printf("TSh64-%lu TSl64-%lu, TS32-%lu, FRh-%lu FRl-%lu\n", ts64.hi, ts64.lo, ts32, freq.hi, freq.lo); System_printf("Seconds: %lu, %lu, %s", sec, (uint32_t)t1, curTime3); System_printf("RTC: %02u/%02u/%02u (%u) %02u:%02u:%02u\n\n", RTCTime.dayOfmonth,RTCTime.month,RTCTime.year,RTCTime.dayOfWeek,RTCTime.hours,RTCTime.minutes,RTCTime.seconds); System_flush(); Log_info5("TSh64-%u TSl64-%u, TS32-%u, FRh-%u FRl-%u\n", ts64.hi, ts64.lo, ts32, freq.hi, freq.lo); } } //-------------------------------------------------------------------------------------------- // Function called by clock0 //-------------------------------------------------------------------------------------------- void periodicFxn(void) { GPIO_toggle(Board_LED1); } //-------------------------------------------------------------------------------------------- // Never use current_RTC_Time directly, use this function to get a copy. // This function provides protection against time updates midread. // This function is thread safe?? //-------------------------------------------------------------------------------------------- int8_t readRTC(RTC_C_Calendar *td) { Bool toggleState; uint8_t tries = 0; do { toggleState = current_RTC_Time_update_toggle; td->seconds = current_RTC_Time.seconds; td->minutes = current_RTC_Time.minutes; td->hours = current_RTC_Time.hours; td->dayOfWeek = current_RTC_Time.dayOfWeek; td->dayOfmonth = current_RTC_Time.dayOfmonth; td->month = current_RTC_Time.month; td->year = current_RTC_Time.year; tries++; // Should never take more than two tries because period between RTC updates is huge relative to runtime of this function. } while ((toggleState != current_RTC_Time_update_toggle) && (tries <= 3)); if (tries <= 3) { return (0); } else { return (1); } } //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- void hwi_RTCHandler(void) { uint32_t status; //UInt pDIE; //pDIE = Hwi_disable(); status = MAP_RTC_C_getEnabledInterruptStatus(); MAP_RTC_C_clearInterruptFlag(status); if (status & RTC_C_CLOCK_READ_READY_INTERRUPT) { current_RTC_Time = MAP_RTC_C_getCalendarTime(); current_RTC_Time_update_toggle = ~current_RTC_Time_update_toggle; MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P8, GPIO_PIN5); } if (status & RTC_C_TIME_EVENT_INTERRUPT) { MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P9, GPIO_PIN0); } if (status & RTC_C_CLOCK_ALARM_INTERRUPT) { MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P8, GPIO_PIN4); } //Hwi_restore(pDIE); } //-------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------- void RTCInit(void) { // Haven't setup power management stuff yet! struct tm t; time_t t1; RTC_C_Calendar start_RTC_Time; // External battery backed RTC would usually be the time master from which we set the internal RTC. // Here I just set a dummy time /* Time is Tuesday January 19th 2016 10:03:00 PM */ start_RTC_Time.seconds = 0; start_RTC_Time.minutes = 3; start_RTC_Time.hours = 22; start_RTC_Time.dayOfWeek = 2; // Doesn't seem to be any smarts behind this (not worked out from date, // no expected definition for what day 0 is) so I use 0=Sunday to match time.h start_RTC_Time.dayOfmonth = 19; start_RTC_Time.month = 1; // 1..12 start_RTC_Time.year = 2016; // 0.. 4095 // Current RTC time = RTC start time current_RTC_Time.seconds = start_RTC_Time.seconds; current_RTC_Time.minutes = start_RTC_Time.minutes; current_RTC_Time.hours = start_RTC_Time.hours; current_RTC_Time.dayOfWeek = start_RTC_Time.dayOfWeek; current_RTC_Time.dayOfmonth = start_RTC_Time.dayOfmonth; current_RTC_Time.month = start_RTC_Time.month; current_RTC_Time.year = start_RTC_Time.year; // Current Seconds since epoch -> set based on RTC start time t.tm_sec = start_RTC_Time.seconds; t.tm_min = start_RTC_Time.minutes; t.tm_hour = start_RTC_Time.hours; t.tm_wday = start_RTC_Time.dayOfWeek; // time.h uses 0 = Sunday t.tm_mday = start_RTC_Time.dayOfmonth; t.tm_mon = start_RTC_Time.month - 1; // time.h uses 0..11 t.tm_year = start_RTC_Time.year - 1900; // time.h uses years since 1900 t1 = mktime(&t); RTC_C_initCalendar(&start_RTC_Time, RTC_C_FORMAT_BINARY); // Set RTC-C - its hasn't started yet! MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_MINUTECHANGE); // Event interrupt - have minute, hour, noon, midnight options MAP_RTC_C_setCalendarAlarm(0x05, 0x22, RTC_C_ALARMCONDITION_OFF, RTC_C_ALARMCONDITION_OFF); // Alarm interrupt - set for 10:05 // Generate interrupt on RTC ready to read, RTC event or RTC alarm MAP_RTC_C_clearInterruptFlag(RTC_C_CLOCK_READ_READY_INTERRUPT | RTC_C_TIME_EVENT_INTERRUPT | RTC_C_CLOCK_ALARM_INTERRUPT); MAP_RTC_C_enableInterrupt(RTC_C_CLOCK_READ_READY_INTERRUPT | RTC_C_TIME_EVENT_INTERRUPT | RTC_C_CLOCK_ALARM_INTERRUPT); //MAP_RTC_C_disableInterrupt(RTC_C_CLOCK_READ_READY_INTERRUPT | RTC_C_TIME_EVENT_INTERRUPT | RTC_C_CLOCK_ALARM_INTERRUPT); // Just before we start up the RTC, set the RTOS seconds module to a matching time. Seconds_set(t1 - 2208988800); // Seconds module uses Unix epoch (1/1/1970, 00:00:00) but TI time function use an epoch starting at 1/1/1900 00:00:00:00 MAP_RTC_C_startClock(); //MAP_Interrupt_enableInterrupt(INT_RTC_C); // Don't seem to need this. Does the RTOS do it for me? } /* * ======== main ======== */ int main(void) { WDT_A_holdTimer(); /* Call board init functions */ Board_initGeneral(); Board_initGPIO(); // Board_initI2C(); // Board_initSDSPI(); // Board_initSPI(); // Board_initUART(); // Board_initWatchdog(); // Board_initWiFi(); //Power_enablePolicy(); RTCInit(); /* Turn on user LED */ GPIO_write(Board_LED0, Board_LED_ON); System_printf("Starting the example\nSystem provider is set to SysMin. " "Halt the target to view any SysMin contents in ROV.\n"); /* SysMin will only print to the console when you call flush or exit */ System_flush(); /* Start BIOS */ BIOS_start(); return (0); }