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.
Hi,
I am using MSP430FR2433 MCU, it is configured to go to LPM3.5 and wakes every 1s using RTC interrupt. Now I am trying to update persistent variable stored in FRAM at every RTC wakeup in RTC_ISR but these variables are not updating in RTC_ISR function. So I tried updating the variable in the main function after every RTC wakeup, it updated properly this time.
I think this might be due to MCU going to sleep early before able to complete FRAM update process, So I was looking for FRAM register to check the status if the operation is ongoing but I am not able to find it anywhere in the family user guide or any of the examples.
Thanks
Jeevant Sah
A write to FRAM is (effectively) instantaneous, so (to my knowledge) there's no "write-in-progress" flag.
During an LPM3.5 wakeup, the RTC ISR is actually called some time after main() is entered, since initially interrupts are disabled. So it seems odd that they would be different. How are you turning off Write Protection in each case? You presumably need PFWP=0, since section "TI.persistent" is normally put in Program FRAM.
Hi Bruce,
Thanks for quick reply.
I am using following RTC_ISR code to update the variable:
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = RTC_VECTOR __interrupt void RTC_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(RTC_VECTOR))) RTC_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(RTCIV, RTCIV_RTCIF)) { case RTCIV_NONE : break; // No interrupt pending case RTCIV_RTCIF: // RTC Overflow SYSCFG0 = FRWPPW | DFWP; // Program FRAM write enable incrementSeconds(); // This function increment seconds persistent variable in assembly language SYSCFG0 = FRWPPW | PFWP | DFWP; // Program FRAM write protected (not writable) break; default: break; } }
I am using this code to update it in main:
int main(void) { WDTCTL = WDTPW | WDTHOLD; // Stop WDT initGpio(); // Configure GPIO // Initialize XT1 32kHz crystal P2SEL0 |= BIT0 | BIT1; // set XT1 pin as second function do { CSCTL7 &= ~(XT1OFFG | DCOFFG); // Clear XT1 and DCO fault flag SFRIFG1 &= ~OFIFG; } while (SFRIFG1 & OFIFG); // Test oscillator fault flag // First determine whether we are coming out of an LPMx.5 or a regular RESET. if (SYSRSTIV == SYSRSTIV_LPM5WU) // When woken up from LPM3.5, reinit { // If MCU wakes up from LPM3.5, re-init and then return to LPM3.5 again. SYSCFG0 = FRWPPW | DFWP; // Program FRAM write enable incrementSeconds(); // This function increment seconds persistent variable in assembly language SYSCFG0 = FRWPPW | PFWP | DFWP; // Program FRAM write protected (not writable) __enable_interrupt(); // The RTC interrupt should trigger now... } else { // Device powered up from a cold start. // It configures the device and puts the device into LPM3.5 // Initialize RTC // Interrupt and reset happen every 1024/32768 * 32 = 1 sec. RTCMOD = 32-1; RTCCTL = RTCSS__XT1CLK | RTCSR | RTCPS__1024 | RTCIE; } // Enter LPM3.5 mode with interrupts enabled. Note that this operation does // not return. The LPM3.5 will exit through a RESET event, resulting in a // re-start of the code. PMMCTL0_H = PMMPW_H; // Open PMM Registers for write PMMCTL0_L |= PMMREGOFF; // and set PMMREGOFF __bis_SR_register(LPM3_bits | GIE); __no_operation(); return 0; }
This seemed odd enough that I ran this on a Launchpad, and I see FRAM updating from the ISR update.
I filled in some blanks: I ran the RTC from VLOCLK (no crystal) and my incrementSeconds() just does "++seconds;"
I suspect something is going on outside the code you posted.
Hello,
Since you are entering an LPM lower than LPM0, the FRAM Controller turns off FRAM power, so you may to need to enable it and wait for it to come back up to write to it.
That being said, check out our Compute Through Power Loss (CTPL) FRAM library. It has an example for this exact scenario you are trying to accomplish.
https://dev.ti.com/tirex/explore/node?node=AASKcgTluVTGDhQHM5IVkw__IOGqZri__LATEST
Hi Jace,
This should not be the issue as same code when called from main function works fine but with ISR it doesn't and as stated above by Bruce that ISR is called sometimes after main function is called, so I assume by the time ISR is called FRAM should be ready to be used.
Still I will try to enable it and add some delay before updating the variable and check if it works or not.
Regarding CTPL it uses a lot more memory than regular code and I don't need to store the whole state of MCU, so I would rather like to use persistent for some variables and save the memory for other code.
I think you might be right Bruce as my incrementSeconds() is more complex that just ++seconds, I will once try the Jace's idea tomorrow and if that doesn't works I will post the whole code here tomorrow with full explanation.
Hi,
I am attaching the whole project.
In this project I am trying to use this RTC Calendar(Link) with MSP430FR2433 and update time by calling incrementSeconds function (in RTC_Calender.asm) at every second using RTC interrupt. MCU stays in LPM3.5 to decrease current consumption and only wakes up when RTC interrupt is triggered. In order to make the variable of RTC Calendar library stay in the memory while in LPM3.5 I have made the library variable as persistent in RTC_Calendar.asm file using ' .usect ".TI.persistent" ' and I only update them when FRAM write protection is disabled and re-enable it as soon as variables are updated.
Here is the code that I updated in RTC_Calendar.asm:
;Updated persistent Variables ;Old variables TI_year .usect ".TI.persistent", 2,2 ;.bss TI_year, 2,2 TI_second .usect ".TI.persistent", 1 ;.bss TI_second, 1 TI_minute .usect ".TI.persistent", 1 ;.bss TI_minute, 1 TI_hour .usect ".TI.persistent", 1 ;.bss TI_hour, 1 TI_day .usect ".TI.persistent", 1 ;.bss TI_day, 1 TI_month .usect ".TI.persistent", 1 ;.bss TI_month, 1 TI_PM .usect ".TI.persistent", 1 ;.bss TI_PM, 1 TI_FebDays .usect ".TI.persistent", 1 ;.bss TI_FebDays, 1 TI_dayOfWeek .usect ".TI.persistent", 1 ;.bss TI_dayOfWeek, 1 TI_dayLightZone .usect ".TI.persistent", 1 ;.bss TI_dayLightZone, 1 TI_dayLightSavings .usect ".TI.persistent", 1 ;.bss TI_dayLightSavings, 1
Project file: RTC_Calendar_AutoUpdate.zip
Hello Jeevant,
I highly encourage you to utilize the CTPL library for this type of application. It will help to simplify you implementation code and basically turns LPM3.5 into a LPM3 mode due to its ability to save states of the peripherals. Remember, when waking up form LPMx.5 modes, you are going through a full reset, so all of our peripherals and variables get re-initiated, and you start your code from the beginning again. with the CTPL library, you start executing code where you left off, just like a higher LPM.
Hi Jace,
Thanks for suggestions, but using CTPL will not work for me as it uses a lot of FRAM space to save various variable for saving the state. CTPL library alone takes around 4KB of flash memory out of 16KB to run which is way too much for the application I am building and hence I don't have enough memory left for other activities. And that is why I can't use CTPL.
All I need is a way to solve this specific problem as this will solve a lot of problems for me. If you know how to solve this kindly let me know.
And if this way of doing this task is wrong please suggest me to how to use CTPL with less memory usage.
Thanks
Jeevant Sah
The assembly code was written for the msp430 (non-X) but the FR2433 is msp430x. The compiler only recognizes only one or the other (globally) so you can't really mix them.
In this case, the RTC functions are being called with CALLA but they return with RET (not RETA) so the stack gets thrown off and the returns go off into limbo. Eventually the CPU resets (not indicating LPM3.5) and you re-initialize the FRAM variables, so it appears no update was done.
The reason the update from main works is that it doesn't return, so the stack skew isn't noticed.
I changed all the RET-s to RETA-s, and the (internal) CALL-s to CALLA-s (maybe 20 places all together), and the program operates as expected. As far as know there's no way to do this with e.g. an assembler option.
Hi Bruce,
Thanks for the solution. It worked like a charm. Can you please tell me if any other changes are needed in assembly code so that this type of error can be avoided?(I am not good in assembly language)
Also can you tell me more about how we can port assembly/c language code from flash series MCU to fram series MCU? Is there any guide regarding this that can help me understand this?
There are some MSP430 Assembly Wizards on the Forum, but I'm not one of them. (I've written enough assembly code for other systems that I can find my way around.)
Searching for a few minutes turned up SLAA380B, which touches on some of these topics:
https://www.ti.com/lit/an/slaa380b/slaa380b.pdf
The msp430x distinction isn't Flash vs FRAM really, you just have to know. CCS knows -- it makes the -mspx choice when you specify the MCU -- which goes a long way. Avoiding assembly is the simplest way to avoid such conflicts.
**Attention** This is a public forum