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.

MSP432P4111: Seconds_set() for tirtos/packages/ti/sysbios/family/arm/msp432 appears to overwrite RTCTEVx field in RTCCTL1, so I can't get HOURCHANGE event to work after clock_settime

Part Number: MSP432P4111
Other Parts Discussed in Thread: SYSBIOS

I am trying to configure the RTC to generate an interrupt based on the "hour changed" event.  I can get "minute changed" to work fine.  However, when I try "hour changed" I see that the RTCTEVx field gets overwritten in the tirtos/packages/ti/sysbios/family/arm/msp432/Seconds.c Seconds_set() function.  This seems like a bug.  If not, how can I configure for RTCTEVx = 01b and still use clock_settime() (which ultimately calls Seconds_set())?

 

//MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_HOURCHANGE);    /* does not work after call to Seconds_set() */

MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_MINUTECHANGE);

MAP_RTC_C_clearInterruptFlag(RTC_C_TIME_EVENT_INTERRUPT);

MAP_RTC_C_enableInterrupt(RTC_C_TIME_EVENT_INTERRUPT);

  • I guess I wasn't clear in my description of the problem.  I understand how to set a calendarEvent for each hour using RTC_C_CALENDAREVENT_HOURCHANGE; the problem is that it doesn't work.  Setting a calendarEvent for each minute (RTC_C_CALENDAREVENT_MINUTECHANGE) works just fine.  I think the reason the HOURCHANGE doesn't work is because of the code in TI's Seconds_set() function.  See the highlight below.  As a result, I see the following happen...

     

    MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_HOURCHANGE);

    MAP_RTC_C_clearInterruptFlag(RTC_C_TIME_EVENT_INTERRUPT);

    MAP_RTC_C_enableInterrupt(RTC_C_TIME_EVENT_INTERRUPT);

    ... interrupt occurs on the hour

    Seconds_set();    /* called to update clock */

    ...now interrupt occurs on the minute

     

    Void Seconds_set(UInt32 seconds)

    {

    UInt hwiKey;

    struct tm *currTime;

    struct tm result;

    volatile UInt8 rtcKey;

    currTime = LOCALTIME((const time_t *)&seconds, &result);

    /* currTime should never be NULL, but this keeps klocwork happy */

    if (currTime == NULL) {

    return;

    }

    /* localtime returns years from 1970 */

    currTime->tm_year += 1900;

    /* Adjust months to be 1 based for RTC */

    currTime->tm_mon++;

    hwiKey = Hwi_disable();

    /* Save previous register state */

    rtcKey = RTCCTL0_H;

    /* Enable and unlock the RTC module */

    RTCCTL0_H = RTCKEY_H;

    RTCCTL1 = RTCHOLD;    <<< I believe this line overwrites previous code that set RTCCTL1.RTCEVx = 01 = hour changed

    /* Set RTC Registers */

    RTCSEC = (UInt8)currTime->tm_sec;

    RTCMIN = (UInt8)currTime->tm_min;

    RTCHOUR = (UInt8)currTime->tm_hour;

    RTCDAY = (UInt8)currTime->tm_mday;

    RTCMON = (UInt8)currTime->tm_mon;

    RTCYEAR = (UInt16)currTime->tm_year;

    RTCCTL1 &= ~(RTCHOLD); /* Start RTC calendar mode */

    RTCCTL0_H = rtcKey; /* Lock the RTC registers */

    Hwi_restore(hwiKey);

    }

     

  • Hi John

    It is better to set some bit in registers by |= not use = directly because that will change other bits to 0 except you want to do this on purpose.

  • Gary,

    I understand that, thanks.  My point was that the code I referenced to have this possible bug is TI SYSBIOS code.  I was kind of hoping I'd either get confirmation that it is a bug and that it will be fixed, or that it is not a bug and maybe an explanation why.  Is there a formal way I can/should submit a bug on TI code?

    John

  • Hi John

    I have not find any demo about calendar with TI-RTOS. Could you show me where you find it? Or if it created by yourself, could you share the project to me? I want to reproduce the issue first.

  • I did not use a demo, but I think if you tried the rtc_c_calendar_alarm_interrupt example (norotos) you could reproduce the issue. 

    https://dev.ti.com/tirex/explore/node?a=krol.2c__1.35.00.33&node=ALd0vnSKNEZTTvep7M3OBA__z-lQYNj__LATEST

    You would need to specify HOURCHANGE for the interrupt instead of MINUTECHANGE, and then call seconds_Set() sometime after the MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_HOURCHANGE): call and before the main while(1) loop.  I believe this will reproduce the issue - and interrupts would occur every minute instead of every hour.

    Thanks for investigating this.

  • No very clear about the modification. Could you send me the modified c file to me? Thanks

  • Sorry, just seeing your response.  I don't have a modified c file to send you.  I had implemented the basic functionality I described above into code that was customized and targeted for our hardware.  Here is the code.  What I found is that initially, RTC_C_IRQHandler() was called every hour as I would expect.  However, if secondsSet() was called, from that point on RTC_C_IRQHandler() was called every minute.  (So you'll see in the code below that HOURCHANGE is commented out and MINUTECHANGE is being used until the issue is resolved.)

    John

    #if 1

    /*

    * RTC time event IRQ and IRQ handler init

    * - basic RTC init already done via clock_settime()

    * - this taken mainly from TI example code (vibrationCapture.c)

    */

    HwiP_Handle hwiPRTC = NULL;

    HwiP_Params hwiPRTCParams;

     

    HwiP_Params_init(&hwiPRTCParams);

    hwiPRTCParams.arg = 0;

    hwiPRTCParams.priority = 0x20;

    hwiPRTC = HwiP_create(INT_RTC_C, (HwiP_Fxn)RTC_C_IRQHandler, &hwiPRTCParams);

     

    if (hwiPRTC == NULL)

    {

    ret_val = -1;

    }

     

    if (sem_init(&rtcTimerMutex, 1, 0) != 0)

    {

    ret_val = -1;

    }

     

    // todo - fix so hourchange works

    //MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_HOURCHANGE);

    MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_MINUTECHANGE);

    MAP_RTC_C_clearInterruptFlag(RTC_C_TIME_EVENT_INTERRUPT);

    MAP_RTC_C_enableInterrupt(RTC_C_TIME_EVENT_INTERRUPT);

    #endif

    return ret_val;

    }

     

    void RTC_C_IRQHandler(void)

    {

    uint32_t status;

     

    /* clear active interrupt(s) */

    status = MAP_RTC_C_getEnabledInterruptStatus();

    MAP_RTC_C_clearInterruptFlag(status);

     

    rtcTimerTick++;

     

    /* using semaphore so timer handling does not take place in HWi context */

    sem_post(&rtcTimerMutex);

    }

  • Hi John

    Sorry for the late reply due to the labor day holiday. I will setup the hardware to reproduce this issue first.

  • Hi John

    I have test the code example attached 

    /* --COPYRIGHT--,BSD
     * Copyright (c) 2017, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     * --/COPYRIGHT--*/
    /*******************************************************************************
     * MSP432 RTC_C - Calendar Mode
     *
     * Description: This program demonstrates the RTC mode by triggering an
     * interrupt every minute. The date is set at the start of execution and an
     * additional alarm for a specific time is also set to demonstrate the various
     * modes of alarms/events for the RTC_C module.
     *
     *                MSP432P4111
     *             ------------------
     *         /|\|                  |
     *          | |                  |
     *          --|RST         P1.0  |---> P1.0 LED
     *            |     PJ.0 LFXIN   |---------
     *            |                  |         |
     *            |                  |     < 32khz xTal >
     *            |                  |         |
     *            |     PJ.1 LFXOUT  |---------
     *
     ******************************************************************************/
    /* DriverLib Includes */
    #include <ti/devices/msp432p4xx/driverlib/driverlib.h>
    
    /* Statics */
     static volatile RTC_C_Calendar newTime;
    
     //![Simple RTC Config]
     /* Time is November 12th 1955 10:03:00 PM */
     const RTC_C_Calendar currentTime =
     {
             0x00,
             0x03,
             0x22,
             0x12,
             0x11,
             0x1955
     };
     //![Simple RTC Config]
    
    
    int main(void)
    {
        /* Halting WDT  */
        MAP_WDT_A_holdTimer();
    
        /* Configuring pins for peripheral/crystal usage and LED for output */
        MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
                GPIO_PIN0 | GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
        MAP_GPIO_setAsOutputPin(GPIO_PORT_P2, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN0);
        MAP_GPIO_setOutputLowOnPin(GPIO_PORT_P2, GPIO_PIN0 | GPIO_PIN1 | GPIO_PIN2);
        /* Setting the external clock frequency. This API is optional, but will
         * come in handy if the user ever wants to use the getMCLK/getACLK/etc
         * functions
         */
        CS_setExternalClockSourceFrequency(32000,48000000);
    
        /* Starting LFXT in non-bypass mode without a timeout. */
        CS_startLFXT(CS_LFXT_DRIVE3);
    
        //![Simple RTC Example]
        /* Initializing RTC with current time as described in time in
         * definitions section */
        MAP_RTC_C_initCalendar(&currentTime, RTC_C_FORMAT_BCD);
    
        /* Setup Calendar Alarm for 10:04pm (for the flux capacitor) */
        MAP_RTC_C_setCalendarAlarm(0x04, 0x22, RTC_C_ALARMCONDITION_OFF,
                RTC_C_ALARMCONDITION_OFF);
    
        /* Specify an interrupt to assert every minute */
        MAP_RTC_C_setCalendarEvent(RTC_C_CALENDAREVENT_HOURCHANGE);
    
        /* 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. */
        MAP_RTC_C_clearInterruptFlag(
                  RTC_C_TIME_EVENT_INTERRUPT
                        | RTC_C_CLOCK_ALARM_INTERRUPT);
        MAP_RTC_C_enableInterrupt(
                 RTC_C_TIME_EVENT_INTERRUPT
                        | RTC_C_CLOCK_ALARM_INTERRUPT);
    
        /* Start RTC Clock */
        MAP_RTC_C_startClock();
        //![Simple RTC Example]
    
    
        /* Enable interrupts and go to sleep. */
        MAP_Interrupt_enableInterrupt(INT_RTC_C);
        MAP_Interrupt_enableSleepOnIsrExit();
        MAP_Interrupt_enableMaster();
    
        while(1)
        {
            MAP_PCM_gotoLPM0();
        }
    
    }
    
    /* RTC ISR */
    void RTC_C_IRQHandler(void)
    {
        uint32_t status;
    
        status = MAP_RTC_C_getEnabledInterruptStatus();
        MAP_RTC_C_clearInterruptFlag(status);
        MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P2, GPIO_PIN0);
        if (status & RTC_C_CLOCK_READ_READY_INTERRUPT)
        {
          //  MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
        }
    
        if (status & RTC_C_TIME_EVENT_INTERRUPT)
        {
            /* Interrupts every minute - Set breakpoint here */
            __no_operation();
            newTime = MAP_RTC_C_getCalendarTime();
            MAP_GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);
    
        }
    
        if (status & RTC_C_CLOCK_ALARM_INTERRUPT)
        {
            /* Interrupts at 10:04pm */
            __no_operation();
        }
    
    }
    
    
    

    You can see I just modify the RTC_C_CALENDAREVENT_MINUTECHANGE to RTC_C_CALENDAREVENT_HOURCHANGE and some LED toggle code to show the event. The device can toggle P1.0 every hour successfully.

  • Gary,

    Yes that all works fine.  But I believe the bug is in the Seconds_set() call, such that if Seconds_set() is called at any time after your example code executes, the RTC_C_IRQHandler() will execute every minute instead of every hour.

    Here is output from my program.  The RTC is initialized to 12/31/2020 23:58:20 at the start of the program.  The program prints out the date/time whenever the RTC_C_IRQHandler() executes.  At the start, prior to Seconds_set() call, you can see it executes on the hour at midnight and does not execute on the minute (as expected).

    However, once the HW acquires time from GPS and sets the clock (using clock_settime(), which uses Seconds_set()), the RTC_C_IRQHandler begins to execute every 1 minute.  This happens because I think there is a bug in Seconds_set() that overwrites the RTCCTL1 register (and forces the event back to the default of "on the minute" interrupts).  My earlier post shows the specific line in Seconds_set().

    John

    AGM> date
    Thu Dec 31 23:58:23 2020

    AGM> handle RTC timer interrupt (1): Fri Jan  1 00:00:00 2021

    AGM> date
    Fri Jan  1 00:00:46 2021

    AGM> date
    Fri Jan  1 00:01:09 2021

    AGM> date
    Fri Jan  1 00:02:08 2021

    AGM> date
    Fri Jan  1 00:04:10 2021

    AGM>
    GPS data available.

    AGM> clock set: the time is... Mon May 10 16:22:18 2021

    AGM> date
    Mon May 10 16:22:40 2021

    AGM> handle RTC timer interrupt (2): Mon May 10 16:23:00 2021

    AGM> handle RTC timer interrupt (3): Mon May 10 16:24:00 2021

    AGM> handle RTC timer interrupt (4): Mon May 10 16:25:00 2021

    AGM> handle RTC timer interrupt (5): Mon May 10 16:26:00 2021

  • Hi John

    I am not sure why you must call function Seconds_set()  and where this function come from.

    But keep in mind the bit to control the event is located at register RTCCTL13, the RTCTEV bits control this. You can use CCS go into debug mode to see if it is changed after you call Seconds_set() .

  • The Seconds_set() function is part of the Seconds Module of the TI RTOS (SYS/BIOS).  Seconds_set() is used by clock_settime(), which we use at the application layer to set the time.  We use clock_settime() because it provides a POSIX compliant function to set time and provides some abstraction from the hardware specific RTC registers.

    I have used the debugger to confirm that the register bit is changed after calling clock_settime().  What I'm trying to do is get TI to acknowledge the problem and determine whether they will fix it or not, or explain why they don't think it is a problem.  Do you think this SYS/BIOS problem will be addressed by TI?  Or do you think we have to work around it?  I'm open to suggestions as to how to proceed, but I'm convinced it's a bug.

  • Hi John

    I have not found the the seconds module in the TI RTOS, could you show me where you found it?

    Here are the modules listed in the TI Drives syscfg that is not include the RTC module 

  • Gary, The Seconds module is part of ti.sysbios.hal and is described in the User's Guide...

    .....

  • Hi John

    I have reproduce this issue. 

    RTCCTL1 = RTCHOLD;    <<< I believe this line overwrites previous code that set RTCCTL1.RTCEVx = 01 = hour changed

    You are correct that is due to this code clear RTCEV to all 0x00 and make enable minute event.

    I think you can re-config the RTC after calling Seconds_set() function, just change the sequence will be ok. I don't think that is a bug, because RTCCTL1 = RTCHOLD; can be used to clear the register that to make sure the register is in a state we know. If customer want to do other configuration they can do that after calling it.

  • Gary,

    Thanks for continuing to investigate this.  I'm glad you were able to reproduce the issue.  However, I do think it's a bug, for 2 reasons.

    1.  In the Seconds_set() function, the RTCHOLD bit is cleared individually (in the second line), which leads me to believe it should be set individually (in the first line).  Otherwise, why wouldn't the second line be "RTCCTL1 = 0;" ?

    (from Seconds_set())...

    RTCCTL1 = RTCHOLD; 

    ...

    RTCCTL1 &= ~(RTCHOLD); /* Start RTC calendar mode */

    2.  Re-configuring RTCCTL1 seems like a crude workaround.  Other bits in RTCCTL1 are affected by the first line of code, including RTCBCD and RTCMODE.  So the re-config process would have to read RTCCTL1, call Seconds_set(), then write back the original RTCCTL1 value.  That could be easily avoided by making the first line of code above  "RTCCTL1 |= RTCHOLD;"

    Until I hear otherwise, I'll implement the workaround since I need the hourly alarm functionality.

    John

     

  • Hi John

    Thanks for your comments. You can keep the workaround. That is little hard to modify the SYSBIOS's lib code now. Sorry about that.

  • Gary,

    I'll implement the workaround, however I'm marking this as "not resolved" since I do believe sysbios code should be changed to correct this behavior.

    John