Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
256 changes: 255 additions & 1 deletion targets/TARGET_STM/lp_ticker.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,264 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************
*/
#include "device.h"

#if DEVICE_LOWPOWERTIMER

#include "rtc_api_hal.h"

#if MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM

LPTIM_HandleTypeDef LptimHandle;

volatile uint32_t lp_SlaveCounter = 0;
volatile uint32_t lp_oc_int_part = 0;
volatile uint16_t lp_TickPeriod_us;
volatile uint8_t lp_Fired = 0;

static void LPTIM1_IRQHandler(void);
static void (*irq_handler)(void);


void lp_ticker_init(void)
{
/* Check if LPTIM is already configured */
#if (TARGET_STM32L0)
if (READ_BIT(RCC->APB1ENR, RCC_APB1ENR_LPTIM1EN) != RESET) {
return;
}
#else
if (__HAL_RCC_LPTIM1_IS_CLK_ENABLED()) {
return;
}
#endif

RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};

#if MBED_CONF_TARGET_LSE_AVAILABLE

/* Enable LSE clock */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;

/* Select the LSE clock as LPTIM peripheral clock */
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
#if (TARGET_STM32L0)
RCC_PeriphCLKInitStruct.LptimClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
#else
RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSE;
#endif

#else /* MBED_CONF_TARGET_LSE_AVAILABLE */

/* Enable LSI clock */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;

/* Select the LSI clock as LPTIM peripheral clock */
RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
#if (TARGET_STM32L0)
RCC_PeriphCLKInitStruct.LptimClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
#else
RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
#endif

#endif /* MBED_CONF_TARGET_LSE_AVAILABLE */

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
error("HAL_RCC_OscConfig ERROR\n");
return;
}

if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig ERROR\n");
return;
}

__HAL_RCC_LPTIM1_CLK_ENABLE();
__HAL_RCC_LPTIM1_FORCE_RESET();
__HAL_RCC_LPTIM1_RELEASE_RESET();

/* Initialize the LPTIM peripheral */
LptimHandle.Instance = LPTIM1;
LptimHandle.State = HAL_LPTIM_STATE_RESET;
LptimHandle.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;

/* Prescaler impact:
tick period = Prescaler division factor / LPTIM clock
Example with LPTIM clock = 32768 Hz LSE
Prescaler = LPTIM_PRESCALER_DIV1 => lp_TickPeriod_us = 31us => 2s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV2 => lp_TickPeriod_us = 61us => 4s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV4 => lp_TickPeriod_us = 122us => 8s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV8 => lp_TickPeriod_us = 244us => 16s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV16 => lp_TickPeriod_us = 488us => 32s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV32 => lp_TickPeriod_us = 976us => 64s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV64 => lp_TickPeriod_us = 1.9ms => 128s with 16b timer
Prescaler = LPTIM_PRESCALER_DIV128 => lp_TickPeriod_us = 3.9ms => 256s with 16b timer
*/
LptimHandle.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV2;
lp_TickPeriod_us = 2 * 1000000 / RTC_CLOCK;

LptimHandle.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
LptimHandle.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
LptimHandle.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
LptimHandle.Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;
#if (TARGET_STM32L4)
LptimHandle.Init.Input1Source = LPTIM_INPUT1SOURCE_GPIO;
LptimHandle.Init.Input2Source = LPTIM_INPUT2SOURCE_GPIO;
#endif /* TARGET_STM32L4 */

if (HAL_LPTIM_Init(&LptimHandle) != HAL_OK) {
error("HAL_LPTIM_Init ERROR\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this \n needed ? an app can deal with it or via config (there is an option fr the new line for stdio?)

return;
}

NVIC_SetVector(LPTIM1_IRQn, (uint32_t)LPTIM1_IRQHandler);
NVIC_EnableIRQ(LPTIM1_IRQn);

#if !(TARGET_STM32L4)
/* EXTI lines are not configured by default */
__HAL_LPTIM_WAKEUPTIMER_EXTI_ENABLE_IT();
__HAL_LPTIM_WAKEUPTIMER_EXTI_ENABLE_RISING_EDGE();
#endif

__HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_ARRM);
__HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_CMPM);
__HAL_LPTIM_ENABLE_IT(&LptimHandle, LPTIM_IT_CMPOK);
HAL_LPTIM_Counter_Start(&LptimHandle, 0xFFFF);
}

static void LPTIM1_IRQHandler(void)
{
LptimHandle.Instance = LPTIM1;

if (lp_Fired) {
lp_Fired = 0;
if (irq_handler) {
irq_handler();
}
}

/* Compare match interrupt */
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPM) != RESET) {
if (__HAL_LPTIM_GET_IT_SOURCE(&LptimHandle, LPTIM_IT_CMPM) != RESET) {
/* Clear Compare match flag */
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);

if (lp_oc_int_part > 0) {
lp_oc_int_part--;
} else {
if (irq_handler) {
irq_handler();
}
}
}
}

/* Compare write interrupt */
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK) != RESET) {
if (__HAL_LPTIM_GET_IT_SOURCE(&LptimHandle, LPTIM_IT_CMPOK) != RESET) {
/* Clear Compare write flag */
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK);
}
}

/* Autoreload match interrupt */
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_ARRM) != RESET) {
if (__HAL_LPTIM_GET_IT_SOURCE(&LptimHandle, LPTIM_IT_ARRM) != RESET) {
/* Clear Autoreload match flag */
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_ARRM);
lp_SlaveCounter++;
}
}

#if !(TARGET_STM32L4)
__HAL_LPTIM_WAKEUPTIMER_EXTI_CLEAR_FLAG();
#endif
}


uint32_t lp_ticker_read_TickCounter(void)
{
uint16_t cntH_old, cntH, cntL;

LptimHandle.Instance = LPTIM1;

/* same algo as us_ticker_read in us_ticker_16b.c */
do {
cntH_old = lp_SlaveCounter;
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_ARRM) == SET) {
cntH_old += 1;
}
cntL = LPTIM1->CNT;
cntH = lp_SlaveCounter;
if (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_ARRM) == SET) {
cntH += 1;
}
} while (cntH_old != cntH);
uint32_t lp_time = (uint32_t)(cntH << 16 | cntL);
return lp_time;
}

uint32_t lp_ticker_read(void)
{
lp_ticker_init();
return lp_ticker_read_TickCounter() * (uint32_t)lp_TickPeriod_us;
}

void lp_ticker_set_interrupt(timestamp_t timestamp)
{
// Disable IRQs
core_util_critical_section_enter();

uint32_t timestamp_TickCounter = timestamp / (uint32_t)lp_TickPeriod_us;

LptimHandle.Instance = LPTIM1;
irq_handler = (void (*)(void))lp_ticker_irq_handler;

__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK);
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
__HAL_LPTIM_COMPARE_SET(&LptimHandle, timestamp_TickCounter & 0xFFFF);

/* CMPOK is set by hardware to inform application that the APB bus write operation to the LPTIM_CMP register has been successfully completed */
while (__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPOK) == RESET) {
}

/* same algo as us_ticker_set_interrupt in us_ticker_16b.c */
uint32_t current_time_TickCounter = lp_ticker_read_TickCounter();
uint32_t delta = timestamp_TickCounter - current_time_TickCounter;
lp_oc_int_part = (delta - 1) >> 16;
if ( ((delta - 1) & 0xFFFF) >= 0x8000 &&
__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPM) == SET ) {
++lp_oc_int_part;
}

// Enable IRQs
core_util_critical_section_exit();
}

void lp_ticker_fire_interrupt(void)
{
lp_Fired = 1;
NVIC_SetPendingIRQ(LPTIM1_IRQn);
}

void lp_ticker_disable_interrupt(void)
{
LptimHandle.Instance = LPTIM1;
__HAL_LPTIM_DISABLE_IT(&LptimHandle, LPTIM_IT_CMPM);
}

void lp_ticker_clear_interrupt(void)
{
LptimHandle.Instance = LPTIM1;
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
}

#else /* MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */

void lp_ticker_init(void)
{
rtc_init();
Expand Down Expand Up @@ -74,4 +326,6 @@ void lp_ticker_clear_interrupt(void)
NVIC_ClearPendingIRQ(RTC_WKUP_IRQn);
}

#endif /* MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */

#endif /* DEVICE_LOWPOWERTIMER */
17 changes: 8 additions & 9 deletions targets/TARGET_STM/rtc_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,14 @@
#if DEVICE_RTC

#include "rtc_api_hal.h"
#include "mbed_error.h"
#include "mbed_mktime.h"

static RTC_HandleTypeDef RtcHandle;

#if DEVICE_LOWPOWERTIMER
#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM
static void (*irq_handler)(void);
static void RTC_IRQHandler(void);
#endif
#endif /* DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */

void rtc_init(void)
{
Expand All @@ -55,7 +54,7 @@ void rtc_init(void)
}

#if MBED_CONF_TARGET_LSE_AVAILABLE
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
Expand All @@ -78,7 +77,7 @@ void rtc_init(void)
__HAL_RCC_BACKUPRESET_RELEASE();

// Enable LSI clock
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
Expand Down Expand Up @@ -108,7 +107,7 @@ void rtc_init(void)
RtcHandle.Init.HourFormat = RTC_HOURFORMAT_24;

/* PREDIV_A : 7-bit asynchronous prescaler */
#if DEVICE_LOWPOWERTIMER
#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM
/* PREDIV_A is set to a small value to improve the SubSeconds resolution */
/* with a 32768Hz clock, PREDIV_A=7 gives a precision of 244us */
RtcHandle.Init.AsynchPrediv = 7;
Expand Down Expand Up @@ -297,7 +296,7 @@ void rtc_synchronize(void)
}
}

#if DEVICE_LOWPOWERTIMER
#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM

static void RTC_IRQHandler(void)
{
Expand Down Expand Up @@ -345,7 +344,7 @@ void rtc_set_wake_up_timer(uint32_t delta)
NVIC_EnableIRQ(RTC_WKUP_IRQn);

RtcHandle.Instance = RTC;
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 0xFFFF & WakeUpCounter, WakeUpClock[DivIndex-1]) != HAL_OK) {
if (HAL_RTCEx_SetWakeUpTimer_IT(&RtcHandle, 0xFFFF & WakeUpCounter, WakeUpClock[DivIndex - 1]) != HAL_OK) {
error("rtc_set_wake_up_timer init error (%d)\n", DivIndex);
}
}
Expand All @@ -356,6 +355,6 @@ void rtc_deactivate_wake_up_timer(void)
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
}

#endif /* DEVICE_LOWPOWERTIMER */
#endif /* DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */

#endif /* DEVICE_RTC */
5 changes: 5 additions & 0 deletions targets/TARGET_STM/rtc_api_hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@
#include "rtc_api.h"
#include "ticker_api.h"
#include "lp_ticker_api.h"
#include "us_ticker_api.h"
#include "hal_tick.h"
#include "mbed_critical.h"
#include "mbed_error.h"
#include "mbed_debug.h"

#ifdef __cplusplus
extern "C" {
Expand Down
4 changes: 0 additions & 4 deletions targets/TARGET_STM/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,8 @@
*/
#if DEVICE_SLEEP

#include "cmsis.h"
#include "us_ticker_api.h"
#include "sleep_api.h"
#include "rtc_api_hal.h"
#include "hal_tick.h"
#include "mbed_critical.h"

extern void HAL_SuspendTick(void);
extern void HAL_ResumeTick(void);
Expand Down
Loading