Playing with watchdog

Starting small, I’ve started playing around with the watchdog, and all is working as expected.

However, I’m yet to get the ‘feel’ for how people code around here. Would somebody like to critique this before I go to far? I’m very interested in the right way to define the addresses for the watchdog registers.

#include 
#include 
#include "platform.h"
#include 
#include "encoding.h"
#include 

#define RTC_FREQUENCY 32768

/******************************************
* The Watchdog registers and magic values
******************************************/
volatile uint32_t *wdogcfg   = (uint32_t *)0x10000000;
volatile uint32_t *wdogcount = (uint32_t *)0x10000008;
volatile uint32_t *wdogs     = (uint32_t *)0x10000010;
volatile uint32_t *wdogfeed  = (uint32_t *)0x10000018;
volatile uint32_t *wdogkey   = (uint32_t *)0x1000001C;
volatile uint32_t *wdogcmp   = (uint32_t *)0x10000020;
const uint32_t wdog_key  = 0x0051F15E;
const uint32_t wdog_food = 0x0D09F00D;

const char * msg = "Testing the watchdog - it should reset every 5000 milliseconds\n";

static void watchdog_feed() {
  *wdogkey  = wdog_key;     /* Unlock watchdog registers */
  *wdogfeed = wdog_food;    /* Feed (reset) the watchdog */
}

static void watchdog_enable(uint32_t milliseconds) {
  uint8_t  scale = 0;
  uint32_t cmp_val = (uint64_t)milliseconds*RTC_FREQUENCY/1000;

  /* Work out what scale factor to use to get cmp_val < 2^16 */
  while(cmp_val > 65535) {
    scale++;
    cmp_val /= 2;
  }

  *wdogkey  = wdog_key;     /* Unlock watchdog registers */
  *wdogfeed = wdog_food;    /* Feed (reset) the watchdog */
  *wdogkey  = wdog_key;     /* Unlock watchdog registers */
  *wdogcmp  = cmp_val;      /* Set the compare count value */
  *wdogkey  = wdog_key;     /* Unlock watchdog registers */
  *wdogcfg  = (1<<12)       /* wdogenalways - wdog runs always */
            | (1<< 8)       /* wdogrsten    - enable reset     */
            | (scale << 0); /* wdogscale    - depend on timeout  */
}


int main(int argc, char *argv[])
{
  /* Enable the watchdog reset every 5000ms */
  watchdog_enable(5000);

  /* Display a message */
  write (STDOUT_FILENO, msg, strlen(msg));

  /* Loop to do nothing forever */
  while (1)
    ;

  /* Never gets here */
  return 0;
}
1 Like

Nice!

The way you’ve defined the addresses is just fine. But for your convenience we’ve provided some helper macros, when you #include "platform.h" you have access to them. platform.h includes a header for each device that defines the registers and fields. For example, see https://github.com/sifive/freedom-e-sdk/blob/master/bsp/include/sifive/devices/aon.h
and https://github.com/sifive/freedom-e-sdk/blob/master/bsp/env/freedom-e300-hifive1/platform.h

For example, your watchdog_feed function could be written:

AON_REG(AON_WDOGKEY) = AON_WDOGKEY_VALUE;
AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE;

This does the exact same thing as your code, but uses the constants defined in the header files which you’ve already included.

1 Like

Thanks for the knowledge!

In case anybody else can make use of it, here is the updated code:

/****************************************************************************
* Testing the watchdog on the SiFive HiFive1 RISC-V devboard
*
* Author : Mike Field 
*
* Feel free to use this code however you like!
****************************************************************************/
#include 
#include "platform.h"
#include "encoding.h"

#define RTC_FREQUENCY 32768

const char reset_msg[]   = "Testing the watchdog\n"
                           "It should reset every 5000 milliseconds\n";

const char watchdog_msg[] = "Watchdog reset occured\n";

/***************************************************************************/
void watchdog_enable(uint32_t milliseconds) {
  uint8_t  scale = 0;
  uint32_t cmp_val = (uint64_t)milliseconds*RTC_FREQUENCY/1000;

  /* Work out what scale factor to use, required to get cmp_val < 2^16 */
  while(cmp_val > 65535) {
    scale++;
    cmp_val /= 2;
  }

  /* Feed the watchdog */
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE;

  /* Set the compare count value */
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGCMP)  = cmp_val;

  /* Set the config register */
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGCFG)  = (1<<12)       /* wdogenalways - wdog runs always */
                        | (1<< 8)       /* wdogrsten    - enable reset     */
                        | (scale <>8) & 0x3;
  if(cause == 2)
    return 1;
  return 0;
}


/***************************************************************************/
void watchdog_feed() {
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE;
}

/***************************************************************************/
void watchdog_disable(void) {

  /* Feed the watchdog */
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGFEED) = AON_WDOGFEED_VALUE;


  /* Set the compare count value */
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGCMP)  = 0;

  /* Set the config register */
  AON_REG(AON_WDOGKEY)  = AON_WDOGKEY_VALUE;
  AON_REG(AON_WDOGCFG)  = 0;
}

/***************************************************************************/
int main(int argc, char *argv[])
{
  /* Enable the watchdog reset every 5000ms */
  watchdog_enable(5000);

  /* Display a message */
  if(watchdog_caused_reset())
    write (STDOUT_FILENO, watchdog_msg, sizeof(watchdog_msg)-1);
  else
    write (STDOUT_FILENO, reset_msg, sizeof(reset_msg)-1);

  /* Loop to do nothing forever */
  while (1)
    ;

  /* Never gets here */
  watchdog_disable();
  return 0;
}
/******************************  End of file  *****************************/
2 Likes