And create iwdg_set_period_ms in header file as a wrapper for iwdg_set_period_ticks.
This allows to define one's own LSI_FREQUENCY before including iwdg.h to adjust iwdg period calculations to LSI clock of real device. Also iwdg_set_period_ticks now rounds period up to nearest possible value rather than truncating it down. Signed-off-by: Filip Moc <d...@moc6.cz> --- Notes: I changed semantics of count & prescale calculations to always round up instead of truncating down. This simplifies the code a bit but also introduces a bit more magic. To understand why the code ended up being simpler: First to round up you need to change this line "count >>= 1;" to this "count = (count + 1) >> 1;". Now let's move the "count--;" line before while cycle. To compensate you remove the "-1" in while condition and adjust the shift line like this: "count = ((count + 2) >> 1) - 1;". But now if you look at it it just does exactly the same thing as simple "count >>= 1;". Then just merge decrement and underflow prevention. It seems to be the right thing to do. When user requests some period we can't setup it's better to set longer period rather than shorter so that watchdog wouldn't timeout before it was supposed to do so. Well I guess most people won't care whether watchdog timeouts 10% sooner or later, let alone some rounding. After this it should be relatively easy to solve this issue: https://github.com/libopencm3/libopencm3/issues/533 Just by adding lines such as #ifndef LSI_FREQUENCY #define LSI_FREQUENCY 40000 #endif where needed. include/libopencm3/stm32/common/iwdg_common_all.h | 40 ++++++++++++++++++++++- lib/stm32/common/iwdg_common_all.c | 38 ++++++++++----------- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/include/libopencm3/stm32/common/iwdg_common_all.h b/include/libopencm3/stm32/common/iwdg_common_all.h index d7430b53..996876d0 100644 --- a/include/libopencm3/stm32/common/iwdg_common_all.h +++ b/include/libopencm3/stm32/common/iwdg_common_all.h @@ -34,6 +34,18 @@ specific memorymap.h header before including this header file.*/ /**@{*/ +/** @addtogroup iwdg_file IWDG peripheral API +@ingroup peripheral_apis +@{ +*/ +#ifndef LSI_FREQUENCY +/** LSI freqency is 32 kHz on most chips. Define your own LSI_FREQUENCY before +including iwdg header file if your device's LSI is running on different clock. +*/ +#define LSI_FREQUENCY 32000 +#endif +/**@}*/ + /* --- IWDG registers ------------------------------------------------------ */ /** Key Register (IWDG_KR) */ @@ -104,13 +116,39 @@ specific memorymap.h header before including this header file.*/ BEGIN_DECLS void iwdg_start(void); -void iwdg_set_period_ms(uint32_t period); +void iwdg_set_period_ticks(uint32_t period); bool iwdg_reload_busy(void); bool iwdg_prescaler_busy(void); void iwdg_reset(void); END_DECLS +/** @addtogroup iwdg_file IWDG peripheral API +@ingroup peripheral_apis +@{ +*/ + +/*---------------------------------------------------------------------------*/ +/** @brief IWDG Set Period in Milliseconds + +The countdown period is converted to ticks of LSI clock. The maximum period is +1048576000 / LSI_FREQUENCY (32.768 seconds for 32 kHz LSI clock). For periods +less than 1ms you may want to use iwdg_set_period_ticks directly. + +Note that this library assumes 32 kHz LSI clock by default. If your device's +LSI runs on different clock define your own LSI_FREQUENCY before including iwdg +header file. + +@param[in] period uint32_t Period in milliseconds (<= 1048576000 / +LSI_FREQUENCY) from a watchdog reset until a system reset is issued. +*/ +static inline void iwdg_set_period_ms(uint32_t period) +{ + iwdg_set_period_ticks(period * LSI_FREQUENCY / 1000); +} + +/**@}*/ + #endif /** @cond */ #else diff --git a/lib/stm32/common/iwdg_common_all.c b/lib/stm32/common/iwdg_common_all.c index 44b3b9b3..6e597722 100644 --- a/lib/stm32/common/iwdg_common_all.c +++ b/lib/stm32/common/iwdg_common_all.c @@ -39,7 +39,6 @@ relevant bit is not set, the IWDG timer must be enabled by software. #include <libopencm3/stm32/iwdg.h> -#define LSI_FREQUENCY 32000 #define COUNT_LENGTH 12 #define COUNT_MASK ((1 << COUNT_LENGTH)-1) @@ -57,45 +56,44 @@ void iwdg_start(void) } /*---------------------------------------------------------------------------*/ -/** @brief IWDG Set Period in Milliseconds +/** @brief IWDG Set Period in Ticks of LSI clock The countdown period is converted into count and prescale values. The maximum -period is 32.76 seconds; values above this are truncated. Periods less than 1ms -are not supported by this library. +period is 1048576 (0x100000) ticks; values above this are truncated. -A delay of up to 5 clock cycles of the LSI clock (about 156 microseconds) -can occasionally occur if the prescale or preload registers are currently busy -loading a previous value. +A delay of up to 5 clock cycles of the LSI clock can occasionally occur if the +prescale or preload registers are currently busy loading a previous value. -@param[in] period uint32_t Period in milliseconds (< 32760) from a watchdog -reset until a system reset is issued. +Note that even with lowest prescaler setting LSI clock is divided by 4 so you +can't set period shorter than 4 ticks. + +@param[in] period uint32_t Period in ticks of LSI clock (<= 1048576) from a +watchdog reset until a system reset is issued. This is rounded up to nearest +possible period. */ -void iwdg_set_period_ms(uint32_t period) +void iwdg_set_period_ticks(uint32_t period) { const int PRESCALER_MAX = 6; uint8_t prescale = 0; - /* Set the count to represent ticks of 8kHz clock (the 32kHz LSI clock - * divided by 4 = lowest prescaler setting) + /* Set the count to represent ticks divided by 4 (lowest prescaler + * setting) rounding up (ceil) the original period */ - uint32_t count = period << 3; + uint32_t count = (period + 3) >> 2; - /* Prevent underflow */ - if (count == 0) { - count = 1; + /* IWDG_RLR actually holds count - 1 (but prevent underflow) */ + if (count > 0) { + count--; } /* Shift count while increasing prescaler as many times as needed to * fit into IWDG_RLR */ - while ((count - 1) >> COUNT_LENGTH) { + while (count >> COUNT_LENGTH) { count >>= 1; prescale++; } - /* IWDG_RLR actually holds count - 1 */ - count--; - /* Clamp to max possible period */ if (prescale > PRESCALER_MAX) { count = COUNT_MASK; -- 2.11.0 _______________________________________________ libopencm3-devel mailing list libopencm3-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libopencm3-devel