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.

MSP430FR5989: MSP430FR5989

Part Number: MSP430FR5989
Other Parts Discussed in Thread: MSP430FR6989

Hi,

I hope this post will be a bit clearer than the previous one.

The context is the same. Our application runs on custom board developed around msp430fr5989 and we use PCF8523 to supply an external clock on PJ.4 LXFIN. 

We have a test in the application than uses the internal RTC_C block to give us an interrupt on various time events. The one we use in this particular test is a time event every minute. 

During the minute waiting for the interrupt we want to go in LPM3.5 low power mode. We use for this the FRAM utility ctpl. 

The test can be invoked with or without entering the LPM3.5 mode.  

In this case the interrupt occurs as expected  and we can  resume the execution of code. 

in the case the LPM3.5 is invoked the low power mode is entered  via the ctpl api.

upon return from the deep sleep we get in the ISR of the RTC_C. the RTCIV gives us a vector 0 RTCIV_NONE instead of the RTCIV_RTCTEVIFG that we are exepting. 

Here below some snippets of code showing what we try to do:

Your kind assistance in solving this problem would be greatly appreciated. 

I fear another stupid mistake of mine but can not figure it  out at this time.

We initially developed this code on the eval board MSP430FR6989 and this test was passing then. 

in any case thank you so much for having a look.

Jean-Pierre Sainfeld

==================================== TEST code =================================

void testTimeEventMinute(void)
{
uint16_t count = 0;
uint8_t answer;
log_print(LOG_ALWAYS,"%s\n\r", __FUNCTION__);

static Calendar cm =
{
0, //! Seconds of minute between 0-59
0, //! Minutes of hour between 0-59
14, //! Hour of day between 0-23
3, //! Day of week between 0-6
16, //! Day of month between 1-31
6, //! Month between 1-12
2020 //! Year between 0-4095
};

test_event_minute_continue = true;


/*
* Clear all interrupts from Calendar Module
* before making decision about notifications
*/
CM_clearInterrupt(RTC_C_TIME_EVENT_INTERRUPT |
RTC_C_CLOCK_READ_READY_INTERRUPT |
RTC_C_CLOCK_ALARM_INTERRUPT);
/*
* Disable all interrupts from Calendar Module
* before making decision about notifications
*/
CM_disableInterrupt(RTC_C_TIME_EVENT_INTERRUPT |
RTC_C_CLOCK_READ_READY_INTERRUPT |
RTC_C_CLOCK_ALARM_INTERRUPT);

/*
* Initialize the Calendar Manager
*/
CM_init(&cm);

/*
* Notified every time a minute has elapsed
*/
CM_registerEvent(RTC_C_CALENDAREVENT_MINUTECHANGE);


/*
* Generate interrupt on time events
*/
CM_enableInterrupt(RTC_C_TIME_EVENT_INTERRUPT );
/*
* Start the Calendar
*/
CM_start();


// Ask user if he wants to go to deep sleep
// waiting for this event
mp_print(BACK_CHANNEL,"%s\n\r","Do you want to go to Low Power Mode waiting for this event (y/n)? ");
answer = mp_getchar(BACK_CHANNEL);
mp_print(BACK_CHANNEL,"%s %c\n\r","Your ANSWER ->", answer);


while (test_event_minute_continue == true)
{
if (answer == 'y')
{
/*
* Enter Low Power Mode with interrupts enabled
*/
__enable_interrupt();

// this code for deep sleep - does work but cannot debug through it yet
log_print(LOG_ALWAYS,"%s going to deep sleep\n\r", __FUNCTION__);
ctpl_enterLpm35(CTPL_DISABLE_RESTORE_ON_RESET);<----------------------------------------- This is where we enter the LPM3.5 using the CTPL Library API. 
log_print(LOG_ALWAYS,"%s returned from deep sleep\n\r", __FUNCTION__);
}

count++;
if (count == 0)
{
mp_print(BACK_CHANNEL,".");
LED_toggle(1);
}
/*
* Check if event Second was triggered
*/
unsigned long val = 0;
val = BIT_CHK(eventBitmap, rtcReadyInterruptTriggered);

if (val == 1)
{
/*
* Log the per Second Interrupt event
*/
mp_print(BACK_CHANNEL,"Interrupt for SECOND was triggered\n\r");

/*
* Ask calendar manager to handle the event
*/
CM_handleSecondEvent();

}

/*
* Check if the event Minute was triggered
*/
val = BIT_CHK(eventBitmap, rtcTimeEventMinuteInterruptTriggered);
if ( val == 1)
{
mp_print(BACK_CHANNEL,"Interrupt for MINUTE was triggered\n\r");
/*
* let the test event handler process the event
*/
test_handleMinuteEvent();
}


/*
* Check if the event Hour was triggered
*/
val = BIT_CHK(eventBitmap, rtcTimeEventHourInterruptTriggered);
if ( val == 1)
{
mp_print(BACK_CHANNEL,"Interrupt for Hour was triggered\n\r");
/*
* let the test event handler process the event
*/
test_handleHourEvent();
}

/*
* Check if the event Noon was triggered
*/
val = BIT_CHK(eventBitmap, rtcTimeEventNoonInterruptTriggered);
if ( val == 1)
{
mp_print(BACK_CHANNEL,"Interrupt for Noon was triggered\n\r");
/*
* let the test event handler process the event
*/
test_handleNoonEvent();
}

/*
* Check if the event Midnight was triggered
*/
val = BIT_CHK(eventBitmap, rtcTimeEventMidnightInterruptTriggered);
if ( val == 1)
{
mp_print(BACK_CHANNEL,"Interrupt for Midnight was triggered\n\r");
/*
* let the test event handler process the event
*/
test_handleMidnightEvent();
}
}

log_print(LOG_ALWAYS,"%s Complete\n\r", __FUNCTION__);

return;
}

======================== ISR =======================================

/*
 *==================================
 * Interrupts Service Routine (ISR)
 *==================================
 */
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=RTC_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(RTC_VECTOR)))
#endif


void RTC_ISR (void)
{
    switch (__even_in_range(RTCIV, RTCIV_RT1PSIFG))
    {
    /*
     * Vector 0
     * No Interrupt
     */
    case RTCIV_NONE:
    {

        _no_operation(); <-------------------------------- Upon return from Deep Sleep we get the interrupt but we have RTCIV_NONE instead of the time event one 
    }
    break;

    /*
     * Vector 2
     * RTCOFIFG
     * 32-kHz crystal oscillator fault interrupt flag.
     * This interrupt can be used as LPM3.5 wake-up event.
     * It also indicates a clock failure during backup operation.
     * 0b = No interrupt pending
     * 1b = Interrupt pending.
     * A 32-kHz crystal oscillator fault occurred after last reset.
     */
    case RTCIV_RTCOFIFG:
    {
        RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_OSCILLATOR_FAULT_INTERRUPT);
        _no_operation();
    }
    break;

    /*
     * Vector 4
     * RTCRDYIFG
     * This vector correspond to
     * RTC_C_CLOCK_READ_READY_INTERRUPT
     * Real-time clock ready interrupt flag
     * 0b = RTC cannot be read safely
     * 1b = RTC can be read safely
     *
     */
    case RTCIV_RTCRDYIFG:
    {
        /*
         * Interrupt every second
         */
        eventBitmap = BIT_SET(eventBitmap, rtcReadyInterruptTriggered);
        RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_CLOCK_READ_READY_INTERRUPT);
    }
    break;

    /*
     * Vector 6
     * RTCEVIFG
     */
    case RTCIV_RTCTEVIFG:
    {
        /*
         * Real-time clock time event interrupt flag.
         * In modules supporting LPM3.5 this interrupt
         * can be used as LPM3.5 wake-up event.
         * 0b = No time event occurred
         * 1b = Time event occurred
         */

        /*
         * We use Calendar Mode (RTCMODE =1)
         *
         * Read Register control 1 bit 0 an 1
         * 1-0 RTCTEVx RW 0h Real-time clock time event
         * 00b = Minute changed
         * 01b = Hour changed
         * 10b = Every day at midnight (00:00)
         * 11b = Every day at noon (12:00)
         */
        switch(HWREG8(RTC_C_BASE + OFS_RTCCTL13_L ) & RTCTEV_3 )
        {
        case RTCTEV__MIN:
        {
            /*
             * Interrupts every minute
             */
            eventBitmap = BIT_SET(eventBitmap, rtcTimeEventMinuteInterruptTriggered);
            RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_TIME_EVENT_INTERRUPT);
        }
        break;

        case RTCTEV__HOUR:
        {
            /*
             * Interrupts every hour
             */
            eventBitmap = BIT_SET(eventBitmap, rtcTimeEventHourInterruptTriggered);
            RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_TIME_EVENT_INTERRUPT);
        }
        break;

        /*
         * Interrupt every day at midnight
         */
        case RTCTEV__0000:
        {
            eventBitmap = BIT_SET(eventBitmap, rtcTimeEventMidnightInterruptTriggered);
            RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_TIME_EVENT_INTERRUPT);
        }
        break;

        /*
         * Interrupt every day at noon
         */
        case RTCTEV__1200:
        {
            eventBitmap = BIT_SET(eventBitmap, rtcTimeEventNoonInterruptTriggered);
            RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_TIME_EVENT_INTERRUPT);
        }
        break;

        default:
        {
            RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_TIME_EVENT_INTERRUPT);
            RTC_C_disableInterrupt(RTC_C_BASE, RTC_C_TIME_EVENT_INTERRUPT);
        }
        break;
        }
    }
    break;

    /*
     * Vector 8
     * RTCAIFG
     */
    case RTCIV_RTCAIFG:
    {
        eventBitmap = BIT_SET(eventBitmap, rtcAlarmInterruptTriggered);
        RTC_C_clearInterrupt(RTC_C_BASE, RTC_C_CLOCK_ALARM_INTERRUPT);
    }
    break;

    /*
     * Vector A
     * RT0PSIFG
     */
    case RTCIV_RT0PSIFG:
    {
        _no_operation();
    }
    break;

    /*
     * Vector C
     * RT1PSIFG
     */
    case RTCIV_RT1PSIFG:
    {
        _no_operation();
    }
    break;

    /*
     * Default Case
     */
    default:
    {
        _no_operation();
    }
    break;
    }
}

  • Is it possible to put in a hook to capture RTCCTL0 just before the switch() in the ISR?

    I'm not quite clear what the result is if you don't re-enable the interrupt that woke you up. [Ref UG (SLAU367P) Sec 29.2.9]  And it seems odd that ctpl_RTC_restore doesn't use the RTCKEY.

  • Bruce,

    Thank you for your reply.

    I did a screen shot of the execution at the time of the ISR. 

    It shows RTCCTL0 to be 0x9604

    High Byte for the KEY. 

    Low Byte indicates RTCTEVIFG RTC Time Event Interrupt Flag

    Single Assembly Step after the switch I get the following:

    The core registers seems to have been corrupted 0x0F3FFF does not look like a heathy  value. Further assembly step uses R15 which contains this bogus value and then we at the no_operation step. 

    I will step through the CTPL code next to see if I can get more information. I surmise at this point that something goes wrong in the 

    saving and restoring of the peripheral RTC.  Is this what you meant in your reply?

    Talk to you soon 

    Thank you again for your help

    Jean-Pierre Sainfeld

    P.S: I found an errata for this in  MSP430FR5989 Device Erratasheet

    The description and the workaround is a bit cryptic and I am not sure what to make of it. 

    I am also looking into the use of CTPL_LPM_DEBUG. 

    So far no break through :-)

    == 

    RTC Module

    Functional
    RTC interrupt flag can be lost during LPMx.5 entry

    An RTC interrupt flag can get lost if it triggers within a small critical time window of the device's entry into LPM3.5. This results in the RTC interrupt flag not triggering a wake-up from LPM3.5. The subsequent RTC interrupt flag is captured to wake device up from LPM3.5.

    Use LPM3 for timing-critical applications where the device is entering LPM3.5 close to the RTC interrupt flag triggering.

    ====== 

  • As you say, 0x9604 shows RTCEVIFG (0x04), but not RTCEVIE (0x40). And yet, you're in the ISR anyway. RTCIV is a synthesized register, and will read as the (highest priority) enabled interrupt, and there isn't one.

    That section in the UG says that the IFG+IE, at the moment it's triggered, is latched somewhere, independent of what RTCCTL0 says (since it's gone in LPM3.5).The IFG+IE has to be somewhere in order for the wakeup to happen.So as soon as ctpl_init re-enables interrupts, the latched IRQ (not necessarily based on RTCCTL0) takes place.

    It then just says "restore the IEs" without saying what happens if you don't. I suspect this is what happens.

    Last night I was looking at the wrong function. ctpl_RTC_C_restore does appear to use the RTCKEY, so I'm not sure why RTCEVIE hasn't been restored.

    I expect that the RTC interrupt should trigger down at the end of ctpl_init (just past ctpl_return), by which time a number of registers would seem to have "normal" values. The suggestion is that it's happening at an unexpected place. The debugger's CPUX traceback doesn't do very well over interrupt boundaries, but the return point can be reconstructed from the stack (Memory view).

    [Edit: I just noticed the tail end of your reply. I think that's Erratum RTC10. It didn't seem to match your symptom (though it is in the general vicinity), so I didn't pay much attention.]

  • Bruce, 

    Good morning!

    Few days have passed since our last exchange. 

    I have not yet found the solution to our problems related to the CTPL issue.

    My understanding of the steps have however greatly improved  ( even beyond my initial desire :-))

    I have walked the code in the debugger from reset to wake up a number of times and monitoring the stack. 

    I have defined a large stack 2000 and fill it with the pattern 0xA5. I followed the use of stack from main to ctpl_enterLpm35.

    When I come back from a deep sleep, I see that all my stack has been used up. 

    I am wondering if there some initial precautions I need to take regarding stack usage before entering and exit  low power mode. 

    The other thing I  would like to fixe in this example is the use of vsnprintf I use to log my messages over the serial port. 

    CCS recommends moving those to RAM. I am not yet sure how to achieve this for functions I have not written. 

    I will keep digging in the stack issues. 

    If you have some pointers for me I would be thankful. 

    Talk to you soon

    Jean-Pierre Sainfeld

  • I'm guessing your stack is in SRAM (it usually is). SRAM is powered off in LPMx.5, so your 0xA5 initialization will disappear. This is one of the reasons for CTPL's existence.

    I was thinking of something more modest. You've succeeded in reaching a breakpoint in your RTC ISR, so I was suggesting you figure out where it interrupted from. My suspicion is that it's (for whatever reason) triggering prematurely, so where it was when the interrupt occurred is interesting.

    I suggest:

    1) Get back to your breakpoint in the RTC ISR (as seen in your screenshot)

    2) Use the Register View (top right) to find the value in the SP (Stack Pointer) register.

    3) Subtract a small number (32, maybe)  from that address and use that value in a Memory Browser View.

    The debugger has difficulty decoding the ISR's return address from the stack, but a human can.

    -----

    ULP Advice is just advice. You can ignore it without guilt. I don't suggest moving snprintf to RAM, since it's rather large and it probably isn't called very often. It does take a lot of stack (figure 100-150 bytes for "nofloat") but it sounds as though you have plenty of that.

    -----

    I don't have your device, and you said this symptom doesn't occur on an FR6989 (I have one of those), so all I can do is guess.

  • Bruce, 

    Thank you so much for your suggestion. 

    I have indeed followed the code step by step watching the stack. Through this painful process, I realized that the culprit of this situation, was the UART driver when used in Interrupt mode. This driver uses in this case a ring buffer and a stucture to keep track of the pointers to the ring buffer. 

    My stupid oversight for this driver was that those data elements need also to be protected from the power loss. 

    Once I moved this data to the persistent storage by the proper use of the #prgama PERSISTENT, things start to improve tremendously. 

    Once more proven true, the problem is almost always the pilot who either has not read the manual correctly or misunderstood the fine points in a subsystem. 

    I probably could write a big volume of all these type of mistakes I have made over the years :-)

    This issue, thanks to your very kind assistance is now behind me. 

    Thank you again 

    Jean-Pierre Sainfeld

**Attention** This is a public forum