diff --git a/TESTS/mbed_hal/common_tickers/main.cpp b/TESTS/mbed_hal/common_tickers/main.cpp index b63df92c0c3..873f06b78ba 100644 --- a/TESTS/mbed_hal/common_tickers/main.cpp +++ b/TESTS/mbed_hal/common_tickers/main.cpp @@ -52,6 +52,7 @@ unsigned int ticker_overflow_delta; /* Auxiliary function to count ticker ticks elapsed during execution of N cycles of empty while loop. * Parameter is used to disable compiler optimisation. */ +MBED_NOINLINE uint32_t count_ticks(uint32_t cycles, uint32_t step) { register uint32_t reg_cycles = cycles; diff --git a/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c index 282005904fe..5a09e84a3df 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c @@ -42,17 +42,42 @@ static const struct nu_modinit_s timer1_modinit = {TIMER_1, TMR1_MODULE, CLK_CLK #define TIMER_MODINIT timer1_modinit -static int ticker_inited = 0; +/* Timer interrupt enable/disable + * + * Because Timer interrupt enable/disable (TIMER_EnableInt/TIMER_DisableInt) needs wait for lp_ticker, + * we call NVIC_DisableIRQ/NVIC_EnableIRQ instead. + */ + +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu -/* NOTE: When system clock is higher than timer clock, we need to add 3 engine clock - * (recommended by designer) delay to wait for above timer control to take effect. */ +/* Synchronization issue with LXT/LIRC-clocked Timer + * + * PCLK : typical HCLK/2 + * ECLK (engine clock) : LXT/LIRC for Timer used to implement lp_ticker + * + * When system clock is higher than Timer clock (LXT/LIRC), we need to add delay for ECLK + * domain to take effect: + * 1. Write : typical 1PCLK + 2ECLK + * Read-check doesn't work because it just checks PCLK domain and doesn't check into + * ECLK domain. + * 2. Clear interrupt flag : typical 2PCLK + * It is very rare that we would meet dummy interrupt and get stuck in ISR until + * 'clear interrupt flag' takes effect. The issue is ignorable because the pending + * time is very short (at most 1 dummy interrupt). We won't take special handling for it. + */ void lp_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + lp_ticker_disable_interrupt(); + lp_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -86,7 +111,7 @@ void lp_ticker_init(void) // Set vector NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); @@ -101,6 +126,33 @@ void lp_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); } +void lp_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); + + /* Disable wakeup */ + TIMER_DisableWakeup(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + timestamp_t lp_ticker_read() { if (! ticker_inited) { @@ -129,20 +181,29 @@ void lp_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); + /* NOTE: Rely on LPTICKER_DELAY_TICKS to be non-blocking. */ timer_base->CMP = cmp_timer; - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_clear_interrupt(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* To avoid sync issue, we clear TIF/TWKF simultaneously rather than call separate + * driver API: + * + * TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + * TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + */ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + timer_base->INTSTS = TIMER_INTSTS_TIF_Msk | TIMER_INTSTS_TWKF_Msk; } void lp_ticker_fire_interrupt(void) @@ -150,6 +211,9 @@ void lp_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* lp_ticker_get_info() @@ -163,11 +227,7 @@ const ticker_info_t* lp_ticker_get_info() static void tmr1_vec(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); - - TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + lp_ticker_clear_interrupt(); // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler(); lp_ticker_irq_handler(); diff --git a/targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c b/targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c index 51072c13b0a..0fadea09deb 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/us_ticker.c @@ -15,6 +15,9 @@ */ #include "us_ticker_api.h" + +#if DEVICE_USTICKER + #include "sleep_api.h" #include "mbed_assert.h" #include "nu_modutil.h" @@ -37,7 +40,8 @@ static const struct nu_modinit_s timer0_modinit = {TIMER_0, TMR0_MODULE, CLK_CLK #define TIMER_MODINIT timer0_modinit -static int ticker_inited = 0; +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu @@ -45,6 +49,11 @@ static int ticker_inited = 0; void us_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + us_ticker_disable_interrupt(); + us_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -73,7 +82,7 @@ void us_ticker_init(void) NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); @@ -82,6 +91,26 @@ void us_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); } +void us_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + uint32_t us_ticker_read() { if (! ticker_inited) { @@ -110,11 +139,15 @@ void us_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); timer_base->CMP = cmp_timer; + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_clear_interrupt(void) @@ -127,6 +160,9 @@ void us_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* us_ticker_get_info() @@ -140,8 +176,10 @@ const ticker_info_t* us_ticker_get_info() static void tmr0_vec(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - + us_ticker_clear_interrupt(); + // NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler(); us_ticker_irq_handler(); } + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c index a09360608ea..1811c72dfcf 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c @@ -42,17 +42,42 @@ static const struct nu_modinit_s timer1_modinit = {TIMER_1, TMR1_MODULE, CLK_CLK #define TIMER_MODINIT timer1_modinit -static int ticker_inited = 0; +/* Timer interrupt enable/disable + * + * Because Timer interrupt enable/disable (TIMER_EnableInt/TIMER_DisableInt) needs wait for lp_ticker, + * we call NVIC_DisableIRQ/NVIC_EnableIRQ instead. + */ + +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu -/* NOTE: When system clock is higher than timer clock, we need to add 3 engine clock - * (recommended by designer) delay to wait for above timer control to take effect. */ +/* Synchronization issue with LXT/LIRC-clocked Timer + * + * PCLK : typical HCLK/2 + * ECLK (engine clock) : LXT/LIRC for Timer used to implement lp_ticker + * + * When system clock is higher than Timer clock (LXT/LIRC), we need to add delay for ECLK + * domain to take effect: + * 1. Write : typical 1PCLK + 2ECLK + * Read-check doesn't work because it just checks PCLK domain and doesn't check into + * ECLK domain. + * 2. Clear interrupt flag : typical 2PCLK + * It is very rare that we would meet dummy interrupt and get stuck in ISR until + * 'clear interrupt flag' takes effect. The issue is ignorable because the pending + * time is very short (at most 1 dummy interrupt). We won't take special handling for it. + */ void lp_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + lp_ticker_disable_interrupt(); + lp_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -86,7 +111,7 @@ void lp_ticker_init(void) // Set vector NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); @@ -101,6 +126,33 @@ void lp_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); } +void lp_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); + + /* Disable wakeup */ + TIMER_DisableWakeup(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + timestamp_t lp_ticker_read() { if (! ticker_inited) { @@ -129,20 +181,29 @@ void lp_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); + /* NOTE: Rely on LPTICKER_DELAY_TICKS to be non-blocking. */ timer_base->CMP = cmp_timer; - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_clear_interrupt(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* To avoid sync issue, we clear TIF/TWKF simultaneously rather than call separate + * driver API: + * + * TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + * TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + */ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + timer_base->INTSTS = TIMER_INTSTS_TIF_Msk | TIMER_INTSTS_TWKF_Msk; } void lp_ticker_fire_interrupt(void) @@ -150,6 +211,9 @@ void lp_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* lp_ticker_get_info() @@ -163,11 +227,7 @@ const ticker_info_t* lp_ticker_get_info() static void tmr1_vec(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); - - TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + lp_ticker_clear_interrupt(); // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler(); lp_ticker_irq_handler(); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/us_ticker.c b/targets/TARGET_NUVOTON/TARGET_M480/us_ticker.c index 9cce7987318..1441cf26b3e 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/us_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/us_ticker.c @@ -15,6 +15,9 @@ */ #include "us_ticker_api.h" + +#if DEVICE_USTICKER + #include "sleep_api.h" #include "mbed_assert.h" #include "nu_modutil.h" @@ -37,7 +40,8 @@ static const struct nu_modinit_s timer0_modinit = {TIMER_0, TMR0_MODULE, CLK_CLK #define TIMER_MODINIT timer0_modinit -static int ticker_inited = 0; +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu @@ -45,6 +49,11 @@ static int ticker_inited = 0; void us_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + us_ticker_disable_interrupt(); + us_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -73,7 +82,7 @@ void us_ticker_init(void) NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); @@ -82,6 +91,26 @@ void us_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); } +void us_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + uint32_t us_ticker_read() { if (! ticker_inited) { @@ -110,11 +139,15 @@ void us_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); timer_base->CMP = cmp_timer; + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_clear_interrupt(void) @@ -127,6 +160,9 @@ void us_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* us_ticker_get_info() @@ -140,8 +176,10 @@ const ticker_info_t* us_ticker_get_info() static void tmr0_vec(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - + us_ticker_clear_interrupt(); + // NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler(); us_ticker_irq_handler(); } + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_clk.c b/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_clk.c index 32f791872c4..16bcab302dc 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_clk.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/device/StdDriver/nano100_clk.c @@ -70,7 +70,9 @@ void CLK_EnableCKO(uint32_t u32ClkSrc, uint32_t u32ClkDiv) */ void CLK_PowerDown(void) { - SCB->SCR = SCB_SCR_SLEEPDEEP_Msk; + /* Set the processor uses deep sleep as its low power mode */ + SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; + CLK->PWRCTL |= (CLK_PWRCTL_PD_EN_Msk | CLK_PWRCTL_WK_DLY_Msk ); __WFI(); } @@ -81,6 +83,9 @@ void CLK_PowerDown(void) */ void CLK_Idle(void) { + /* Set the processor uses sleep as its low power mode */ + SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk; + CLK->PWRCTL &= ~(CLK_PWRCTL_PD_EN_Msk ); __WFI(); } diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/device/TOOLCHAIN_IAR/NANO130.icf b/targets/TARGET_NUVOTON/TARGET_NANO100/device/TOOLCHAIN_IAR/NANO130.icf index 1663174b16b..af97fd718e0 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/device/TOOLCHAIN_IAR/NANO130.icf +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/device/TOOLCHAIN_IAR/NANO130.icf @@ -10,7 +10,7 @@ define symbol __ICFEDIT_region_IRAM_start__ = 0x20000000; define symbol __ICFEDIT_region_IRAM_end__ = 0x20004000 - 1; /*-Sizes-*/ define symbol __ICFEDIT_size_cstack__ = 0x600; -define symbol __ICFEDIT_size_heap__ = 0x1000; +define symbol __ICFEDIT_size_heap__ = 0xE00; /**** End of ICF editor section. ###ICF###*/ diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c index 6355531d330..c2faafc8564 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c @@ -44,17 +44,42 @@ static const struct nu_modinit_s timer1_modinit = {TIMER_1, TMR1_MODULE, CLK_CLK #define TIMER_MODINIT timer1_modinit -static int ticker_inited = 0; +/* Timer interrupt enable/disable + * + * Because Timer interrupt enable/disable (TIMER_EnableInt/TIMER_DisableInt) needs wait for lp_ticker, + * we call NVIC_DisableIRQ/NVIC_EnableIRQ instead. + */ + +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu -/* NOTE: When system clock is higher than timer clock, we need to add 3 engine clock - * (recommended by designer) delay to wait for above timer control to take effect. */ +/* Synchronization issue with LXT/LIRC-clocked Timer + * + * PCLK : typical HCLK/2 + * ECLK (engine clock) : LXT/LIRC for Timer used to implement lp_ticker + * + * When system clock is higher than Timer clock (LXT/LIRC), we need to add delay for ECLK + * domain to take effect: + * 1. Write : typical 1PCLK + 2ECLK + * Read-check doesn't work because it just checks PCLK domain and doesn't check into + * ECLK domain. + * 2. Clear interrupt flag : typical 2PCLK + * It is very rare that we would meet dummy interrupt and get stuck in ISR until + * 'clear interrupt flag' takes effect. The issue is ignorable because the pending + * time is very short (at most 1 dummy interrupt). We won't take special handling for it. + */ void lp_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + lp_ticker_disable_interrupt(); + lp_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -90,7 +115,7 @@ void lp_ticker_init(void) // Set vector NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); @@ -105,6 +130,33 @@ void lp_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_TMR_ACT_Msk)); } +void lp_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_TMR_ACT_Msk)); + + /* Disable wakeup */ + TIMER_DisableWakeup(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + timestamp_t lp_ticker_read() { if (! ticker_inited) { @@ -133,20 +185,29 @@ void lp_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); + /* NOTE: Rely on LPTICKER_DELAY_TICKS to be non-blocking. */ timer_base->CMPR = cmp_timer; - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_clear_interrupt(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* To avoid sync issue, we clear TIF/TWKF simultaneously rather than call separate + * driver API: + * + * TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + * TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + */ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + timer_base->ISR = TIMER_ISR_TMR_IS_Msk | TIMER_ISR_TMR_WAKE_STS_Msk; } void lp_ticker_fire_interrupt(void) @@ -154,6 +215,9 @@ void lp_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* lp_ticker_get_info() @@ -167,11 +231,7 @@ const ticker_info_t* lp_ticker_get_info() void TMR1_IRQHandler(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); - - TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + lp_ticker_clear_interrupt(); // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler(); lp_ticker_irq_handler(); diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/us_ticker.c b/targets/TARGET_NUVOTON/TARGET_NANO100/us_ticker.c index 07f7ff9adb6..0c5160d839d 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/us_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/us_ticker.c @@ -15,6 +15,9 @@ */ #include "us_ticker_api.h" + +#if DEVICE_USTICKER + #include "sleep_api.h" #include "mbed_assert.h" #include "nu_modutil.h" @@ -39,7 +42,8 @@ static const struct nu_modinit_s timer0_modinit = {TIMER_0, TMR0_MODULE, CLK_CLK #define TIMER_MODINIT timer0_modinit -static int ticker_inited = 0; +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu @@ -47,6 +51,11 @@ static int ticker_inited = 0; void us_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + us_ticker_disable_interrupt(); + us_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -75,7 +84,7 @@ void us_ticker_init(void) NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); @@ -84,6 +93,26 @@ void us_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_TMR_ACT_Msk)); } +void us_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_TMR_ACT_Msk)); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + uint32_t us_ticker_read() { if (! ticker_inited) { @@ -112,11 +141,15 @@ void us_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); timer_base->CMPR = cmp_timer; + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_clear_interrupt(void) @@ -129,6 +162,9 @@ void us_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* us_ticker_get_info() @@ -142,8 +178,10 @@ const ticker_info_t* us_ticker_get_info() void TMR0_IRQHandler(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - + us_ticker_clear_interrupt(); + // NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler(); us_ticker_irq_handler(); } + +#endif diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c index 08ce7f8989b..1f55c08ca21 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c @@ -42,17 +42,42 @@ static const struct nu_modinit_s timer1_modinit = {TIMER_1, TMR1_MODULE, CLK_CLK #define TIMER_MODINIT timer1_modinit -static int ticker_inited = 0; +/* Timer interrupt enable/disable + * + * Because Timer interrupt enable/disable (TIMER_EnableInt/TIMER_DisableInt) needs wait for lp_ticker, + * we call NVIC_DisableIRQ/NVIC_EnableIRQ instead. + */ + +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu -/* NOTE: When system clock is higher than timer clock, we need to add 3 engine clock - * (recommended by designer) delay to wait for above timer control to take effect. */ +/* Synchronization issue with LXT/LIRC-clocked Timer + * + * PCLK : typical HCLK/2 + * ECLK (engine clock) : LXT/LIRC for Timer used to implement lp_ticker + * + * When system clock is higher than Timer clock (LXT/LIRC), we need to add delay for ECLK + * domain to take effect: + * 1. Write : typical 1PCLK + 2ECLK + * Read-check doesn't work because it just checks PCLK domain and doesn't check into + * ECLK domain. + * 2. Clear interrupt flag : typical 2PCLK + * It is very rare that we would meet dummy interrupt and get stuck in ISR until + * 'clear interrupt flag' takes effect. The issue is ignorable because the pending + * time is very short (at most 1 dummy interrupt). We won't take special handling for it. + */ void lp_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + lp_ticker_disable_interrupt(); + lp_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -85,7 +110,7 @@ void lp_ticker_init(void) // Set vector NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); @@ -100,6 +125,33 @@ void lp_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); } +void lp_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); + + /* Disable wakeup */ + TIMER_DisableWakeup(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + timestamp_t lp_ticker_read() { if (! ticker_inited) { @@ -128,20 +180,29 @@ void lp_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); + /* NOTE: Rely on LPTICKER_DELAY_TICKS to be non-blocking. */ timer_base->CMP = cmp_timer; - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void lp_ticker_clear_interrupt(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + /* To avoid sync issue, we clear TIF/TWKF simultaneously rather than call separate + * driver API: + * + * TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + * TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + */ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + timer_base->INTSTS = TIMER_INTSTS_TIF_Msk | TIMER_INTSTS_TWKF_Msk; } void lp_ticker_fire_interrupt(void) @@ -149,6 +210,9 @@ void lp_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* lp_ticker_get_info() @@ -162,11 +226,7 @@ const ticker_info_t* lp_ticker_get_info() static void tmr1_vec(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); - - TIMER_ClearWakeupFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - wait_us((NU_US_PER_SEC / NU_TMRCLK_PER_SEC) * 3); + lp_ticker_clear_interrupt(); // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler(); lp_ticker_irq_handler(); diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/us_ticker.c b/targets/TARGET_NUVOTON/TARGET_NUC472/us_ticker.c index 30836509add..03e58bac608 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/us_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/us_ticker.c @@ -15,6 +15,9 @@ */ #include "us_ticker_api.h" + +#if DEVICE_USTICKER + #include "sleep_api.h" #include "mbed_assert.h" #include "nu_modutil.h" @@ -37,7 +40,8 @@ static const struct nu_modinit_s timer0_modinit = {TIMER_0, TMR0_MODULE, CLK_CLK #define TIMER_MODINIT timer0_modinit -static int ticker_inited = 0; +/* Track ticker status */ +static volatile uint16_t ticker_inited = 0; #define TMR_CMP_MIN 2 #define TMR_CMP_MAX 0xFFFFFFu @@ -45,6 +49,11 @@ static int ticker_inited = 0; void us_ticker_init(void) { if (ticker_inited) { + /* By HAL spec, ticker_init allows the ticker to keep counting and disables the + * ticker interrupt. */ + us_ticker_disable_interrupt(); + us_ticker_clear_interrupt(); + NVIC_ClearPendingIRQ(TIMER_MODINIT.irq_n); return; } ticker_inited = 1; @@ -72,7 +81,7 @@ void us_ticker_init(void) NVIC_SetVector(TIMER_MODINIT.irq_n, (uint32_t) TIMER_MODINIT.var); - NVIC_EnableIRQ(TIMER_MODINIT.irq_n); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); TIMER_EnableInt(timer_base); @@ -81,6 +90,26 @@ void us_ticker_init(void) while(! (timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); } +void us_ticker_free(void) +{ + TIMER_T *timer_base = (TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname); + + /* Stop counting */ + TIMER_Stop(timer_base); + + /* Wait for timer to stop counting and unset active flag */ + while((timer_base->CTL & TIMER_CTL_ACTSTS_Msk)); + + /* Disable interrupt */ + TIMER_DisableInt(timer_base); + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); + + /* Disable IP clock */ + CLK_DisableModuleClock(TIMER_MODINIT.clkidx); + + ticker_inited = 0; +} + uint32_t us_ticker_read() { if (! ticker_inited) { @@ -109,11 +138,15 @@ void us_ticker_set_interrupt(timestamp_t timestamp) uint32_t cmp_timer = timestamp * NU_TMRCLK_PER_TICK; cmp_timer = NU_CLAMP(cmp_timer, TMR_CMP_MIN, TMR_CMP_MAX); timer_base->CMP = cmp_timer; + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_disable_interrupt(void) { - TIMER_DisableInt((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); + /* We cannot call ticker_irq_handler now. */ + NVIC_DisableIRQ(TIMER_MODINIT.irq_n); } void us_ticker_clear_interrupt(void) @@ -126,6 +159,9 @@ void us_ticker_fire_interrupt(void) // NOTE: This event was in the past. Set the interrupt as pending, but don't process it here. // This prevents a recursive loop under heavy load which can lead to a stack overflow. NVIC_SetPendingIRQ(TIMER_MODINIT.irq_n); + + /* We can call ticker_irq_handler now. */ + NVIC_EnableIRQ(TIMER_MODINIT.irq_n); } const ticker_info_t* us_ticker_get_info() @@ -139,8 +175,10 @@ const ticker_info_t* us_ticker_get_info() static void tmr0_vec(void) { - TIMER_ClearIntFlag((TIMER_T *) NU_MODBASE(TIMER_MODINIT.modname)); - + us_ticker_clear_interrupt(); + // NOTE: us_ticker_set_interrupt() may get called in us_ticker_irq_handler(); us_ticker_irq_handler(); } + +#endif diff --git a/targets/targets.json b/targets/targets.json index bcf7250ba2f..2e5536b8bf9 100755 --- a/targets/targets.json +++ b/targets/targets.json @@ -3843,8 +3843,8 @@ } }, "inherits": ["Target"], - "macros_add": ["MBEDTLS_CONFIG_HW_SUPPORT"], - "device_has": ["RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "CAN", "FLASH", "EMAC"], + "macros_add": ["MBEDTLS_CONFIG_HW_SUPPORT", "LPTICKER_DELAY_TICKS=3"], + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "CAN", "FLASH", "EMAC"], "release_versions": ["5"], "device_name": "NUC472HI8AE", "bootloader_supported": true, @@ -3914,8 +3914,9 @@ } }, "inherits": ["Target"], + "macros_add": ["LPTICKER_DELAY_TICKS=3"], "progen": {"target": "numaker-pfm-m453"}, - "device_has": ["RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "CAN", "FLASH"], + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "CAN", "FLASH"], "release_versions": ["2", "5"], "device_name": "M453VG6AE", "bootloader_supported": true @@ -3945,8 +3946,8 @@ } }, "inherits": ["Target"], - "macros": ["CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"","MBED_FAULT_HANDLER_DISABLED"], - "device_has": ["RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"], + "macros": ["CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"","MBED_FAULT_HANDLER_DISABLED", "LPTICKER_DELAY_TICKS=3"], + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH"], "release_versions": ["5"], "device_name": "NANO130KE3BN" }, @@ -4112,8 +4113,8 @@ } }, "inherits": ["Target"], - "macros_add": ["MBEDTLS_CONFIG_HW_SUPPORT"], - "device_has": ["RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "FLASH", "CAN", "EMAC"], + "macros_add": ["MBEDTLS_CONFIG_HW_SUPPORT", "LPTICKER_DELAY_TICKS=3"], + "device_has": ["USTICKER", "LPTICKER", "RTC", "ANALOGIN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "STDIO_MESSAGES", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "TRNG", "FLASH", "CAN", "EMAC"], "release_versions": ["5"], "device_name": "M487JIDAE", "bootloader_supported": true,