-
-
Save jefftenney/02b313fe649a14b4c75237f925872d72 to your computer and use it in GitHub Desktop.
| // The original github gist for lptimTick.c is no longer maintained. It grew into a | |
| // full-fledged repository, https://github.com/jefftenney/LPTIM-Tick/, which integrates | |
| // lptimTick.c into a project for the STM32L476. | |
| // | |
| // Another repo, https://github.com/jefftenney/LPTIM-Tick-U5/, integrates a newer | |
| // version of lptimTick.c into a project for STM32U585. The newer version of | |
| // lptimTick.c supports the newest revision of the LPTIM timer silicon. | |
| // | |
| // Thus there are two actively maintained versions of lptimTick.c, and you must choose | |
| // the correct one for your LPTIM silicon: | |
| // | |
| // Type 1 or 2: https://github.com/jefftenney/LPTIM-Tick/blob/main/Core/Src/lptimTick.c | |
| // Type 3: https://github.com/jefftenney/LPTIM-Tick-U5/blob/main/Core/Src/lptimTick.c | |
| // | |
| // To determine which LPTIM variant is in your STM32, see AN4865 from ST. | |
| // | |
| // This gist is not actively maintained, but it still contains all original revisions | |
| // of lptimTick.c and github comments for historical value. |
Thank you for your program, but it seems not well if I use LPTIM instead of the SYSTICK.
Here is some of program. I copy the lptimTick with out any change.
FreeRTOSConfig_Defautl.h
#if (configUSE_TICKLESS_IDLE == 2) // Integrate lptimTick.c -- Start of Block
/**
* @brief Preprocessor code in lptimTick.c requires that configTICK_RATE_HZ be
* a preprocessor-friendly numeric literal.
* As a result, the application *ignores* the CubeMX configuration of the FreeRTOS tick rate.
*/
#undef configTICK_RATE_HZ
#define configTICK_RATE_HZ (1000UL) // 之所以不能用之前定义的主要因为#if语法中不支持((TickType_t)1000)
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 6
extern void freeRTOSPreStopProcessing (uint32_t ulExpectedIdleTime);
extern void freeRTOSPostStopProcessing(uint32_t ulExpectedIdleTime);
#define configPRE_SLEEP_PROCESSING(x) freeRTOSPreStopProcessing(x)
#define configPOST_SLEEP_PROCESSING(x) freeRTOSPostStopProcessing(x)
#endif // configUSE_TICKLESS_IDLE == 2
Pre and Post code:
#if (configUSE_TICKLESS_IDLE == 2)
static uint32_t rccCFGRSave;
static uint32_t rccCRSave;
void freeRTOSPreStopProcessing(uint32_t ulExpectedIdleTime)
{
UNUSED(ulExpectedIdleTime);
digitalWrite(LED, LOW);
HAL_SuspendTick();
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
rccCRSave = RCC->CR;
rccCFGRSave = RCC->CFGR;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}
void freeRTOSPostStopProcessing(uint32_t ulExpectedIdleTime)
{
UNUSED(ulExpectedIdleTime);
digitalWrite(LED, HIGH);
if (SCB->SCR & SCB_SCR_SLEEPDEEP_Msk)
{
RCC->CR = rccCRSave;
RCC->CFGR = rccCFGRSave;
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}
HAL_ResumeTick();
}
#endif
For the low power, I will suspend some threads after power-on about 2 minutes.
void displaySleepTimerCB(const void *parameter)
{
UNUSED(parameter);
xDisplay.sleep();
if (xGlobalWorkMode == WM_LOWPOWER)
{
xDisplay.enterLowPowerMode();
osThreadSuspend(displayThreadID);
attachInterrupt(digitalPinToInterrupt(sButton.getPinNumber()), buttonClickTriggerIRQ, FALLING);
attachInterrupt(digitalPinToInterrupt(cButton.getPinNumber()), buttonClickTriggerIRQ, FALLING);
osThreadSuspend(periphRunThreadID);
}
}
Then I use EXTI interrupt, if it catched the button pressed, it will resume key detect thread.
void buttonClickTriggerIRQ(void)
{
osThreadResume(periphRunThreadID);
xDisplay.run();
osTimerStart(displaySleepTimerID, DISPLAY_HOLD_TIME);
detachInterrupt(digitalPinToInterrupt(sButton.getPinNumber()));
detachInterrupt(digitalPinToInterrupt(cButton.getPinNumber()));
logDebug("Button-Click");
}
Then the periphThread will check the button and response to the user Shell during the next 3 minutes depend on the
osTimerStart(displaySleepTimerID, DISPLAY_HOLD_TIME); -> DISPLAY_HOLD_TIME
Here is the periphThread
void periphRunThread(void const *argument)
{
logDebug("periphRunTask...[%d]", uxTaskGetStackHighWaterMark(NULL));
for (;;)
{
xShellRunTask(); // xShell Loop
sButton.tick();
cButton.tick();
osDelay(10);
}
}
Then if button pressed, it will resume the display thread, and after the timer is over time, it will suspend again/
But usually, it can not work well after I press the button, sometimes it will be normal, I can certain that if I use the SYSTICK it will be OK.
Could you give me some tips, thank you!
Hi Jeff,
I am trying to start a software timer within an ISR handler, the workflow is as described below:
- Suppress the tick
- Enter sleep mode, waiting for an interrupt, and then use WFI.
Then I wake up the MCU by an external interrupt, for example, a push button
The MCU wakes up and enables the interrupts, then the ISR starts to run and tries to start the software timer from the ISR.
What happens is that the software timer fires immediately, which I suspect that the timer fires because the tick is not yet restored and the OS tick is not stable.
How can I solve this Issue?
Note: I am using STM32H562 MCU with tickless idle, and LPtimer following your code.
STM32U5 Support
Please see LPTIM-Tick-U5 for STM32U5 support. The version of lptimTick.c in that repo is adapted to the upgraded LPTIM found in the U5 family.
The STM32U5 seems not to have the silicon bug that occasionally causes the CPU to be stuck in the LPTIM interrupt handler for a full count of the LPTIM. As a result, the STM32U5 version of lptimTick.c supports the prescaler again.