diff --git a/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c index 6b61819ee9..5a09e84a3d 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/lp_ticker.c @@ -54,8 +54,21 @@ 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) { @@ -214,25 +227,7 @@ const ticker_info_t* lp_ticker_get_info() static void tmr1_vec(void) { - /* NOTE: Avoid blocking in ISR due to wait for "clear interrupt flag" - * - * "clear interrupt flag" needs wait to take effect which isn't added here to avoid - * blocking in ISR. - * - * Continuing above, we will get stuck in ISR due to dummy interrupt until - * "clear interrupt flag" takes effect. To avoid it, we disable interrupt here and enable - * interrupt in lp_ticker_fire_interrupt/lp_ticker_set_interrupt. There is another risk - * that we may get stuck in a loop of ISR and lp_ticker_fire_interrupt/ - * lp_ticker_set_interrupt (called by lp_ticker_irq_handler), but actually we don't: - * 1. When lp_ticker_fire_interrupt gets called, it means there is a past event and so this - * interrupt isn't dummy. - * 2. With LPTICKER_DELAY_TICKS enabled, it is lp_ticker_set_interrupt_wrapper rather than - * lp_ticker_set_interrupt that gets straight called. lp_ticker_set_interrupt_wrapper - * guarantees that lp_ticker_set_interrupt won't get re-called in LPTICKER_DELAY_TICKS ticks - * which is just enough for "clear interrupt flag" to take effect. - */ lp_ticker_clear_interrupt(); - lp_ticker_disable_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/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c index 6cf30d1f2b..1811c72dfc 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/lp_ticker.c @@ -54,8 +54,21 @@ 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) { @@ -214,25 +227,7 @@ const ticker_info_t* lp_ticker_get_info() static void tmr1_vec(void) { - /* NOTE: Avoid blocking in ISR due to wait for "clear interrupt flag" - * - * "clear interrupt flag" needs wait to take effect which isn't added here to avoid - * blocking in ISR. - * - * Continuing above, we will get stuck in ISR due to dummy interrupt until - * "clear interrupt flag" takes effect. To avoid it, we disable interrupt here and enable - * interrupt in lp_ticker_fire_interrupt/lp_ticker_set_interrupt. There is another risk - * that we may get stuck in a loop of ISR and lp_ticker_fire_interrupt/ - * lp_ticker_set_interrupt (called by lp_ticker_irq_handler), but actually we don't: - * 1. When lp_ticker_fire_interrupt gets called, it means there is a past event and so this - * interrupt isn't dummy. - * 2. With LPTICKER_DELAY_TICKS enabled, it is lp_ticker_set_interrupt_wrapper rather than - * lp_ticker_set_interrupt that gets straight called. lp_ticker_set_interrupt_wrapper - * guarantees that lp_ticker_set_interrupt won't get re-called in LPTICKER_DELAY_TICKS ticks - * which is just enough for "clear interrupt flag" to take effect. - */ lp_ticker_clear_interrupt(); - lp_ticker_disable_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/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c index dda02fef4c..c2faafc856 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/lp_ticker.c @@ -56,8 +56,21 @@ 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) { @@ -218,25 +231,7 @@ const ticker_info_t* lp_ticker_get_info() void TMR1_IRQHandler(void) { - /* NOTE: Avoid blocking in ISR due to wait for "clear interrupt flag" - * - * "clear interrupt flag" needs wait to take effect which isn't added here to avoid - * blocking in ISR. - * - * Continuing above, we will get stuck in ISR due to dummy interrupt until - * "clear interrupt flag" takes effect. To avoid it, we disable interrupt here and enable - * interrupt in lp_ticker_fire_interrupt/lp_ticker_set_interrupt. There is another risk - * that we may get stuck in a loop of ISR and lp_ticker_fire_interrupt/ - * lp_ticker_set_interrupt (called by lp_ticker_irq_handler), but actually we don't: - * 1. When lp_ticker_fire_interrupt gets called, it means there is a past event and so this - * interrupt isn't dummy. - * 2. With LPTICKER_DELAY_TICKS enabled, it is lp_ticker_set_interrupt_wrapper rather than - * lp_ticker_set_interrupt that gets straight called. lp_ticker_set_interrupt_wrapper - * guarantees that lp_ticker_set_interrupt won't get re-called in LPTICKER_DELAY_TICKS ticks - * which is just enough for "clear interrupt flag" to take effect. - */ lp_ticker_clear_interrupt(); - lp_ticker_disable_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/lp_ticker.c b/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c index 956bc8892f..1f55c08ca2 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/lp_ticker.c @@ -54,8 +54,21 @@ 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) { @@ -213,25 +226,7 @@ const ticker_info_t* lp_ticker_get_info() static void tmr1_vec(void) { - /* NOTE: Avoid blocking in ISR due to wait for "clear interrupt flag" - * - * "clear interrupt flag" needs wait to take effect which isn't added here to avoid - * blocking in ISR. - * - * Continuing above, we will get stuck in ISR due to dummy interrupt until - * "clear interrupt flag" takes effect. To avoid it, we disable interrupt here and enable - * interrupt in lp_ticker_fire_interrupt/lp_ticker_set_interrupt. There is another risk - * that we may get stuck in a loop of ISR and lp_ticker_fire_interrupt/ - * lp_ticker_set_interrupt (called by lp_ticker_irq_handler), but actually we don't: - * 1. When lp_ticker_fire_interrupt gets called, it means there is a past event and so this - * interrupt isn't dummy. - * 2. With LPTICKER_DELAY_TICKS enabled, it is lp_ticker_set_interrupt_wrapper rather than - * lp_ticker_set_interrupt that gets straight called. lp_ticker_set_interrupt_wrapper - * guarantees that lp_ticker_set_interrupt won't get re-called in LPTICKER_DELAY_TICKS ticks - * which is just enough for "clear interrupt flag" to take effect. - */ lp_ticker_clear_interrupt(); - lp_ticker_disable_interrupt(); // NOTE: lp_ticker_set_interrupt() may get called in lp_ticker_irq_handler(); lp_ticker_irq_handler();