cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 LPTIM : CNT EXCEEDS ARR & INFINITE IRQ HANDLER PROCESSING(FIXED)

dqustc
Associate II
Posted on November 28, 2015 at 04:51

First of all, forgive my poor English 🙂

As title indicated,I want to propose two issue I confront in my work.

Before that,I would like to introduce the function I was supposed to achieve briefly. In my project, I used the example project which includes the FreeRTOS as the prototype to code my own function.The example project uses the SYSTICK register to count ticks which will stop when the MCU enters deep sleep mode(more accuratly, stop 1 mode).So I re-code the function using LPTIMER 1 instead. In fact , I don't care too much about how precisely the ticks counted in deep sleep mode is. It may drift a little along time, so the conpensation of time drift induced by stoping and re-configuring the LPTIMER is not realized.Fortunately, the code works, and the system run well....uh...seemed well.

Before going into deep sleep mode, I configure the register ARR to the next wakeup time, the same as the example code did so. Step 1: get CNT value, Step 2: minuse CNT from ARR to seem how many counts remain in current tick. Step 3: calculate the ARR value for wakeup(BTW, the enable and disable of LPTIMER is under the instruction of the the Manual).

the question is, the CNT is bigger than the ARR sometimes, which makes  (ARR - CNT) to be a negative number,and that is a very large positive number in an uint32_t type varialble. And this makes me confused. HOW CAN CNT EXCEEDS ARR? Did I do any thing wrong with LPTIMER, or is there any thing I should pay more attention to when configure the LPTIMER registers?

Another Question is :

Sometimes, my code run to an infinite processing of LPTIM1's IRQ Handler, which blocks the whole FreeRTOS threads.I checked the LPTIMER's register, the configurations are all correct.It's weird, and I want to know had anyone confronted the same thing as I did? How can I make all the things right?

ANSWER:

The reason why CNT exceeds ARR is that ARROK bit int ISR is not set while another write to ARR occurs. Restrictly follow the instruction of configing ARR will avoid this problem. Don't forget to clear the ARROK bit.

4 REPLIES 4
Posted on November 28, 2015 at 18:30

If the timer is 16-bit, then you'd probably want to hold the advancing value in a uint16_t, or mask it suitably.

If it never leaves the IRQ Handler you need to look very carefully at the asserted status, and how you are clearing it. Sitting in a debugger peering at it is probably not the best way to debug it. Watch also for the NVIC tail-chaining hazard, and that you qualify the source of the interrupt and clear it early in the handler.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
dqustc
Associate II
Posted on November 30, 2015 at 03:29

Thank you very much!

Maybe my description misguided you. What I really concerned is how to always keep CNT less than or equal to ARR. The reload value is calculated in a uint32_t and if the result is greater than 0xFFFF, 0xFFFF is set to ARR.

I run the program in KEIL. If I click run -> stop -> run -> stop... button when the program is well, everytime the program stops, the statement to be executed is different. But if the program is not OK, the same opt leads the program stops in the LPTIM1's IRQ Handler, no matter how many times I repeat. If the program run to an assert statement, program will stop in the assert most of the time.So I think it may be not caused by the asserted status.

For the clearing and other details..., I paste part of my code here, can you help my to check this out? Thank again!

void LPTIM1_IRQHandler(void)

{

if(__HAL_LPTIM_GET_FLAG(&sys_tick_timer, LPTIM_FLAG_ARRM)){

/* LPTIM in time Base mode */

//HAL_LPTIM_IRQHandler(&sys_tick_timer); LPTIM1->CNT

__HAL_LPTIM_CLEAR_FLAG(&sys_tick_timer, LPTIM_FLAG_ARRM);

#if configUSE_TICKLESS_IDLE == 2

if(LPTIM1->ARR != ulTimerCountsForOneTick - 1UL){

LPTIM1->ARR = ulTimerCountsForOneTick - 1UL;

while(!(LPTIM1->ISR & (1<<4)));

}

#endif

osSystickHandler();

lptick_flag ++;

HAL_IncTick();

}

__HAL_LPTIM_CLEAR_FLAG(&sys_tick_timer, LPTIM_FLAG_ARRM);

if(__HAL_LPTIM_GET_FLAG(&sys_tick_timer, LPTIM_FLAG_CMPM)){

__HAL_LPTIM_CLEAR_FLAG(&sys_tick_timer, LPTIM_FLAG_CMPM);

}

if(__HAL_LPTIM_GET_FLAG(&sys_tick_timer, LPTIM_FLAG_ARROK)){

__HAL_LPTIM_CLEAR_FLAG(&sys_tick_timer, LPTIM_FLAG_ARROK);

}

if(__HAL_LPTIM_GET_FLAG(&sys_tick_timer, LPTIM_FLAG_CMPOK)){

__HAL_LPTIM_CLEAR_FLAG(&sys_tick_timer, LPTIM_FLAG_CMPOK);

}

}

The other code, including LPTIMER1 init, enter SLEEP mode is in the attachment.

________________

Attachments :

lptimer1.c : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I0cs&d=%2Fa%2F0X0000000bcG%2F.gkQiyCrBu18KaSHqBndrkJzeV9g5qJMPh79490QBTk&asPdf=false
dqustc
Associate II
Posted on November 30, 2015 at 07:00

Another detail for the IRQ issue is,  the IRQ problem always happens after the MCU wakeup and the function __enable_irq() is called.The LPTIMER 1 was disabled before the __enable_irq() function. That means the ISR of LPTIM will never be set again.

I set a breakpoint at the first statement of the IRQ Handler.The breakpoints shows that the LPTIM interrupt is trigger while the ISR equals zero. A breakpoint after the __enable_irq() is never reached, while a run command will cause the program enter IRQ Handler again.

Martin Guthrie
Associate
Posted on January 30, 2017 at 17:54

I have done similar work and here are a few things I found that helped me,

  • HAL_LPTIM_ReadCounter() is not implemented correctly for L4 series, and maybe other series, I only checked L4.  The reference manual says that LPTIM counter value must be read multiple times and is only valid if the read value is the same two times in a row.  I instrumented my design and verified that this is the case.  As an API, HAL_LPTIM_ReadCounter() should do this for you...
  • The Autoreload write complete interrupt flag was something I had to disable in the HAL api HAL_LPTIM_Counter_Start_IT().  In my implementation the LPTIM was always reloaded with a new value, so what would happen is I would get into a loop of reoccurring LPTIM ARR interrupts and other code was not able to run.  Not enabling LPTIM_IT_ARROK worked.  It meant that I had to modify HAL code.
  • I also noticed that sometimes the callback (in this case AutoReloadMatchCallback()) was not always called when the LPTIM expired, despite setting that callback every time I started LPTIM.  So I ended up using a flag (in LPTIM1_IRQHanlder()) to let me know if the callback was called, and if it was not called, I called it explicitly myself.  This fixed my problem.

My theory is that there is a problem reading/writing LPTIM registers that the HAL api doesn't completely deal with properly.  However with the above workarounds I was able to get my STOP2 mode working using LPTIM1 to replace systic in a FreeRTOS environment.