-
Notifications
You must be signed in to change notification settings - Fork 1k
Add Low Power driver #183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Low Power driver #183
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One major things to review: PinMap_WKUP
cores/arduino/stm32/PeripheralPins.h
Outdated
@@ -71,5 +71,7 @@ extern const PinMap PinMap_Ethernet[]; | |||
//*** QUADSPI *** | |||
extern const PinMap PinMap_QUADSPI[]; | |||
|
|||
//*** WKUP *** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not be here. Only one linked to Peripheral <--> pins should be here.
cores/arduino/stm32/uart.c
Outdated
@@ -112,6 +112,7 @@ void uart_init(serial_t *obj) | |||
USART_TypeDef *uart_tx = pinmap_peripheral(obj->pin_tx, PinMap_UART_TX); | |||
USART_TypeDef *uart_rx = pinmap_peripheral(obj->pin_rx, PinMap_UART_RX); | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove NL please
cores/arduino/stm32/uart.c
Outdated
@@ -126,6 +127,19 @@ void uart_init(serial_t *obj) | |||
return; | |||
} | |||
|
|||
#ifdef STM32L4xx | |||
// Select HSI as source clock |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, Could you explain why only L4 and why only USART 1-3 ? Waht about UART4-5?
@@ -188,3 +188,11 @@ const PinMap PinMap_SPI_SSEL[] = { | |||
|
|||
//*** CAN *** | |||
// NO CAN | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PeripheralPins should only contains array For Pin <--> Peripheral.
How this array is defined? Is it linked to boards? MCU ? Is it exhaustive?
|
||
//*** WAKE UP *** | ||
|
||
const PinMap PinMap_WKUP[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PeripheralPins should only contains array For Pin <--> Peripheral.
How this array is defined? Is it linked to boards? MCU ? Is it exhaustive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @fpistm. Please add comment ...
From what I've read in MCU datasheet that is related to a given range of MCUs (e.g. L4x6), so this can be defined for all boards using the same MCU. Whether each pin is connected or not should not change the table.
variants/NUCLEO_L476RG/variant.cpp
Outdated
@@ -123,11 +123,11 @@ WEAK void SystemClock_Config(void) | |||
{ | |||
RCC_OscInitTypeDef RCC_OscInitStruct = {}; | |||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; | |||
RCC_OscInitTypeDef RCC_OscInitStructHSI = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be mixed with RCC_OscInitStruct
variants/NUCLEO_L476RG/variant.cpp
Outdated
@@ -123,11 +123,11 @@ WEAK void SystemClock_Config(void) | |||
{ | |||
RCC_OscInitTypeDef RCC_OscInitStruct = {}; | |||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; | |||
RCC_OscInitTypeDef RCC_OscInitStructHSI = {}; | |||
|
|||
/* MSI is enabled after System reset, activate PLL with MSI as source */ | |||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ex: RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI | RCC_OSCILLATORTYPE_HSI
....
variants/NUCLEO_L476RG/variant.cpp
Outdated
@@ -156,6 +155,18 @@ WEAK void SystemClock_Config(void) | |||
/* Initialization Error */ | |||
while(1); | |||
} | |||
|
|||
/*## Enable the HSI clock #*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See previous comment, to avoid call twice HAL_RCC_OscConfig()
* @param mode: pin mode (edge or state). The configuration have to be compatible. | ||
* @retval None | ||
*/ | ||
void LowPower_EnableWakeUpPin(uint32_t pin, uint32_t mode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the STM32L1xx supported ? (default ?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
L1 not supported.
UNUSED(mode); | ||
#endif | ||
PinName p = digitalPinToPinName(pin); | ||
uint32_t wupPin = pinmap_find_function(p, PinMap_WKUP); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PinMap_WKUP is the config? Maybe it should be at sketch level ? And/Or adding a method to set wakeup pins?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PinMap_WKUP is the list of wake up pins available on the board.
I don't think it should be at sketch level.
I suggest to move PinMap_WKUP in variant.cpp. What do you think about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to clarify a few points I think concerning this table:
which low power modes are we talking about ?
where are the pins defined for a given MCU ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wake up pins touch the standby mode.
If you confirm us that pins are the same across a MCU family, we will able to look for another logic and remove the array from variant.cpp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add it in the comments or above table declaration that PinMap_WKUP only applies to standby/shutdown. I am not sure whether pins are always the same accross MCUs from the same family ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for the PR. Few comments and questions shared
UNUSED(mode); | ||
#endif | ||
PinName p = digitalPinToPinName(pin); | ||
uint32_t wupPin = pinmap_find_function(p, PinMap_WKUP); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to clarify a few points I think concerning this table:
which low power modes are we talking about ?
where are the pins defined for a given MCU ?
cores/arduino/stm32/LowPower.c
Outdated
void LowPower_sleep(){ | ||
/*Suspend Tick increment to prevent wakeup by Systick interrupt. | ||
Otherwise the Systick interrupt will wake up the device within 1ms (HAL time base)*/ | ||
HAL_SuspendTick(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we disable IRQs and re-enable them after
using __disable_irq(); and __enable_irq(); ?
Otherwise the IRQ handler can be called after HAL_SuspendTick(); and this could have side effects in case the tick is being used by the interrupt handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same applies to all modes ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understood, you suggest something like this:
__disable_irq();
HAL_SuspendTick();
__enable_irq();
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was advising __disable_irq before suspending tick and __enable_irq after HAL_ResumeTick
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately you can't because interrupts allow to wake up the MCU. HAL_SuspendTick() disables only Tick IRQ as explained in the comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you tried it?
I think it should block the SW handling of interrupts (disabled at NVIC level), but it should not block the peripherals interrupts to wake-up the MCU. and yes we still need to stop the TICK interrupt otherwise it would wake-up the MCU.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hope I'm clear enough ... the point is to enter a critical section, not to disable interrupts at peripheral level.
cores/arduino/stm32/LowPower.c
Outdated
extern "C" { | ||
#endif | ||
|
||
static UART_HandleTypeDef* WakeUpUart = NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what are WakeUpUart and WakeUpUartCb ? please comment what this is intended for
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is use to save the wake up callback provides by user from enableWakeupFrom()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please comment in the code ...
enableWakeupFrom does not seem to be related to UART, but callback seems to cover UART only .. this could be misleading ...
/** | ||
* @brief Configure the UART as a wakeup source. A callback can be called when | ||
* the chip leaves the low power mode. See board datasheet to check | ||
* with which low power mode the UART is compatible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from the above implementation we can state that this is not supported in standby nor shutdown modes
cores/arduino/stm32/LowPower.c
Outdated
HAL_ResumeTick(); | ||
|
||
if (WakeUpUartCb != NULL) { | ||
WakeUpUartCb(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not clear why UART callback is always called, even if wake-up source is not UART ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At first sight, we aren't able to know which source wake up the MCU. Maybe we have missed something.
variants/NUCLEO_L476RG/variant.cpp
Outdated
@@ -125,9 +125,10 @@ WEAK void SystemClock_Config(void) | |||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; | |||
|
|||
/* MSI is enabled after System reset, activate PLL with MSI as source */ | |||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; | |||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI|RCC_OSCILLATORTYPE_HSI; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so that means we will always have HSI and MSI running ... can't we keep HSI only as the purpose of this PR is to save power ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll look the impact of keep only HSI. But I think we could.
const PinMap PinMap_WKUP[] = { | ||
{PA_0, NP, 1}, //WKUP1 | ||
{PC_13, NP, 2}, //WKUP2 | ||
// {PE_6, NP, 3}, //WKUP3 - Not connected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would keep it anyway and leave it up to the user to select a pin that is configured.
|
||
//*** WAKE UP *** | ||
|
||
const PinMap PinMap_WKUP[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @fpistm. Please add comment ...
From what I've read in MCU datasheet that is related to a given range of MCUs (e.g. L4x6), so this can be defined for all boards using the same MCU. Whether each pin is connected or not should not change the table.
… into quakesense Add LowPower driver and fix some conflicts in cores/arduino/stm32/uart.c
Hi @fprwi6labs |
…ource in stop mode Signed-off-by: fpr <[email protected]>
Hi @fpistm PinMap_WKUP has been moved from PeripheralPins.c to LowPower.c. For the moment we keep it until you can confirm those pins are common to all MCU familly. Critical section added. Wake up from I2C is not possible with the current I2C implementation. It is not possible to use the listen interrupt as wake up source (see datasheet). We have no solution to both keep the I2C functionality and add the wake up from I2C. |
Hi @fpistm,
You can find all the changes in the quakesense branch of my fork of Arduino_Core_STM32 repo (the branch is called quakesense because it includes the improvements I made to the LowPower library in order to use it in my QuakeSense project which I also used for testing the LowPower driver and STM32LowPower library). I have added some updates to my fork of STM32LowPower library - branch generic-config and then I made some tests on my STM32 Nucleo F401RE: LowPower driver seemed to work quite well using the examples provided by the STM32LowPower library and I was able to put the STM32F401RE in idle, sleep, deepSleep and shutdown mode. @fpistm and @fprwi6labs, what do you think ? |
Hi @biagiom , |
extern "C" { | ||
#endif | ||
|
||
// NOTE: is these pins are common to a MCU family? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hereafter the list of the 21 possibles wake up pins across all STM32 MCU (Fx/H7/Lx)
#define SYS_WKUP0 PA_0
#define SYS_WKUP1 PA_0
#define SYS_WKUP1 PA_2
#define SYS_WKUP1 PC_13
#define SYS_WKUP2 PA_2
#define SYS_WKUP2 PC_0
#define SYS_WKUP2 PC_13
#define SYS_WKUP3 PA_2
#define SYS_WKUP3 PC_1
#define SYS_WKUP3 PE_6
#define SYS_WKUP3 PI_8
#define SYS_WKUP4 PA_2
#define SYS_WKUP4 PC_13
#define SYS_WKUP4 PI_11
#define SYS_WKUP5 PC_1
#define SYS_WKUP5 PC_5
#define SYS_WKUP5 PI_8
#define SYS_WKUP6 PB_5
#define SYS_WKUP6 PI_11
#define SYS_WKUP7 PB_15
#define SYS_WKUP8 PF_2
I will add defines linked to the targeted MCU in the variant to avoid defining a pinmap array and use those define here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's OK for me
Driver build against all series has not been tested. Several series failed due to unknown macros or parameters. |
Signed-off-by: fpr <[email protected]>
Signed-off-by: fpr <[email protected]>
Hi @fpistm Fixed! Test build passed for all series. |
Fully replaced by #255 |
Allow to use some low power mode:
Wake up sources (depends on LP mode):
The driver works with NUCLEO-L476RG & NUCLEO-L053R8.
This driver is used by the STM32LowPower library.