diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-16 22:15:33 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-16 22:15:33 +0000 |
commit | 1837532bd7d611d44bb487ee1cbc07940dba14a5 (patch) | |
tree | d06b5b451b2353f7812b1a6759250237a35f472e /nuttx/arch | |
parent | d6bb7827132efdc10f128019ae742591896efbf4 (diff) | |
download | px4-firmware-1837532bd7d611d44bb487ee1cbc07940dba14a5.tar.gz px4-firmware-1837532bd7d611d44bb487ee1cbc07940dba14a5.tar.bz2 px4-firmware-1837532bd7d611d44bb487ee1cbc07940dba14a5.zip |
Fix a couple of bugs in the STM32 IWDG driver
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4620 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/arch')
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_iwdg.c | 78 |
1 files changed, 60 insertions, 18 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_iwdg.c b/nuttx/arch/arm/src/stm32/stm32_iwdg.c index 908851302..e7db53f91 100644 --- a/nuttx/arch/arm/src/stm32/stm32_iwdg.c +++ b/nuttx/arch/arm/src/stm32/stm32_iwdg.c @@ -44,6 +44,7 @@ #include <errno.h> #include <debug.h> +#include <nuttx/clock.h> #include <nuttx/watchdog.h> #include <arch/board/board.h> @@ -90,6 +91,19 @@ #define CONFIG_STM32_IWDG_ONETIMESETUP 1 +/* REVISIT: Another possibility is that we CAN change the prescaler and + * reload values after starting the timer. This option is untested but the + * implementation place conditioned on the following: + */ + +#undef CONFIG_STM32_IWDG_DEFERREDSETUP + +/* But you can only try one at a time */ + +#if defined(CONFIG_STM32_IWDG_ONETIMESETUP) && defined(CONFIG_STM32_IWDG_DEFERREDSETUP) +# error "Both CONFIG_STM32_IWDG_ONETIMESETUP and CONFIG_STM32_IWDG_DEFERREDSETUP are defined" +#endif + /* Debug ********************************************************************/ /* Non-standard debug that may be enabled just for testing the watchdog * driver. NOTE: that only lldbg types are used so that the output is @@ -117,6 +131,7 @@ struct stm32_lowerhalf_s FAR const struct watchdog_ops_s *ops; /* Lower half operations */ uint32_t lsifreq; /* The calibrated frequency of the LSI oscillator */ uint32_t timeout; /* The (actual) selected timeout */ + uint32_t lastreset; /* The last reset time */ bool started; /* true: The watchdog timer has been started */ uint8_t prescaler; /* Clock prescaler value */ uint16_t reload; /* Timer reload value */ @@ -282,7 +297,7 @@ static inline void stm32_setprescaler(FAR struct stm32_lowerhalf_s *priv) * yet be cleared. */ -#ifndef CONFIG_STM32_IWDG_ONETIMESETUP +#ifdef CONFIG_STM32_IWDG_DEFERREDSETUP while ((stm32_getreg(STM32_IWDG_SR) & (IWDG_SR_PVU|IWDG_SR_RVU)) != 0); #endif @@ -317,6 +332,7 @@ static inline void stm32_setprescaler(FAR struct stm32_lowerhalf_s *priv) static int stm32_start(FAR struct watchdog_lowerhalf_s *lower) { FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; + irqstate_t flags; wdvdbg("Entry: started=%d\n"); DEBUGASSERT(priv); @@ -331,9 +347,11 @@ static int stm32_start(FAR struct watchdog_lowerhalf_s *lower) * is started, then refuse any further attempts to change timeout. */ - /* Set up prescaler and reload value for the selected timeout */ + /* Set up prescaler and reload value for the selected timeout before + * starting the watchdog timer. + */ -#ifdef CONFIG_STM32_IWDG_ONETIMESETUP +#if defined(CONFIG_STM32_IWDG_ONETIMESETUP) || defined(CONFIG_STM32_IWDG_DEFERREDSETUP) stm32_setprescaler(priv); #endif @@ -342,8 +360,11 @@ static int stm32_start(FAR struct watchdog_lowerhalf_s *lower) * bits, the watchdog is automatically enabled at power-on. */ + flags = irqsave(); stm32_putreg(IWDG_KR_KEY_START, STM32_IWDG_KR); - priv->started = true; + priv->lastreset = clock_systimer(); + priv->started = true; + irqrestore(flags); } return OK; } @@ -390,10 +411,18 @@ static int stm32_stop(FAR struct watchdog_lowerhalf_s *lower) static int stm32_keepalive(FAR struct watchdog_lowerhalf_s *lower) { - /* Reload the IWDG timer */ + FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; + irqstate_t flags; wdvdbg("Entry\n"); + + /* Reload the IWDG timer */ + + flags = irqsave(); stm32_putreg(IWDG_KR_KEY_RELOAD, STM32_IWDG_KR); + priv->lastreset = clock_systimer(); + irqrestore(flags); + return OK; } @@ -417,8 +446,8 @@ static int stm32_getstatus(FAR struct watchdog_lowerhalf_s *lower, FAR struct watchdog_status_s *status) { FAR struct stm32_lowerhalf_s *priv = (FAR struct stm32_lowerhalf_s *)lower; + uint32_t ticks; uint32_t elapsed; - uint16_t reload; wdvdbg("Entry\n"); DEBUGASSERT(priv); @@ -431,23 +460,28 @@ static int stm32_getstatus(FAR struct watchdog_lowerhalf_s *lower, status->flags |= WDFLAGS_ACTIVE; } - /* Return the actual timeout is milliseconds */ + /* Return the actual timeout in milliseconds */ status->timeout = priv->timeout; - /* I am not sure what will be returned when reading from the reload register. - * Documentation says that the value from the VDD section should be read - * so presume it the decremented value. - */ + /* Get the elapsed time since the last ping */ + + ticks = clock_systimer() - priv->lastreset; + elapsed = (int32_t)TICK2MSEC(ticks); + + if (elapsed > priv->timeout) + { + elapsed = priv->timeout; + } + + /* Return the approximate time until the watchdog timer expiration */ - reload = stm32_getreg(STM32_IWDG_RLR); - elapsed = priv->reload - reload; - status->timeleft = (priv->timeout * elapsed) / priv->reload; + status->timeleft = priv->timeout - elapsed; wdvdbg("Status :\n"); wdvdbg(" flags : %08x\n", status->flags); wdvdbg(" timeout : %d\n", status->timeout); - wdvdbg(" timeleft : %d\n", status->flags); + wdvdbg(" timeleft : %d\n", status->timeleft); return OK; } @@ -579,11 +613,19 @@ static int stm32_settimeout(FAR struct watchdog_lowerhalf_s *lower, */ #ifndef CONFIG_STM32_IWDG_ONETIMESETUP - stm32_setprescaler(priv); + /* If CONFIG_STM32_IWDG_DEFERREDSETUP is selected, then perform the register + * configuration only if the timer has been started. + */ + +#ifdef CONFIG_STM32_IWDG_DEFERREDSETUP + if (priv->started) +#endif + { + stm32_setprescaler(priv); + } #endif - wdvdbg("prescaler=%d fiwdg=%d reload=%d timeout=%d\n", - prescaler, fiwdg, reload, priv->timeout); + wdvdbg("prescaler=%d fiwdg=%d reload=%d\n", prescaler, fiwdg, reload); return OK; } |