天天看點

STM32F7xx —— 看門狗                               STM32F7xx —— 看門狗

                               STM32F7xx —— 看門狗

看門狗:指定時間内不喂狗,就重新開機系統。

最簡單的看門狗設計(喂狗就是指定時間内給寄存器寫一個固定值)

// 初始化獨立看門狗
// prer:分頻數:0~7(隻有低 3 位有效!)
// rlr:自動重裝載值,0~0XFFF.
// 分頻因子=4*2^prer.但最大值隻能是 256!
// rlr:重裝載寄存器值:低 11 位有效.
// 時間計算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
static IWDG_HandleTypeDef iwdg_handle;
void WatchdogInit(void)
{
  iwdg_handle.Instance = IWDG;
  iwdg_handle.Init.Prescaler = 5;
  iwdg_handle.Init.Reload = 250;
  iwdg_handle.Init.Window = IWDG_WINDOW_DISABLE; // 關閉視窗功能

  HAL_IWDG_Init(&iwdg_handle);

  os_watchdog_lock = xSemaphoreCreateMutex();
}

void WatchdogFeed(void)
{
  HAL_IWDG_Refresh(&iwdg_handle);
}
           

FreeRTOS看門狗設計(系統看門狗+任務看門狗)(其他作業系統也可以用這種思路)

任務看門狗:監控每個任務的活動狀态,如果任務卡死,會導緻系統重新開機。核心思想是使用計數,計數減為0後說明任務卡死。

TaskHandle_t os_watchdog_handle;

// 互斥信号量
static SemaphoreHandle_t os_watchdog_lock;
#define WATCHDOG_LOCK()    xSemaphoreTake(os_watchdog_lock, 100);
#define WATCHDOG_UNLOCK()  xSemaphoreGive(os_watchdog_lock)

#define WATCHDOG_CHECK_INTERVAL  100  // 100ms喂一次狗
#define WATCHDOG_POOL_SIZE       (OS_PRIO_MAX + OS_PRIO_MAX - 1) // 任務池 2倍的任務-1

typedef struct
{
  TaskHandle_t handle; // 任務句柄
  const char *name;    // 任務看門狗名稱
  uint16_t timeout;    // 任務看門狗逾時
  uint16_t time;       // 任務看門狗計數
  uint8_t suspended;   // 任務看門狗暫停
} watchdog_t;

static watchdog_t watchdogs[WATCHDOG_POOL_SIZE];

static void task_watchdog(void *params)
{
  int i;

  while(1)
  {
    WatchdogFeed();

    for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
    {
      if(0 == watchdogs[i].handle)
      {
        continue;
      }

      if(!watchdogs[i].suspended && watchdogs[i].time)
      {
        --(watchdogs[i].time);
      }
      if(!watchdogs[i].suspended && (0 == watchdogs[i].time))
      {
        printf("!!!!!!!!!!!!!!!! Watchdog %s timeout !!!!!!!!!!!!!!!!\n", watchdogs[i].name);
        while(1);  // reset
      }
    }

    vTaskDelay(WATCHDOG_CHECK_INTERVAL);
  }
}

// 初始化獨立看門狗
// prer:分頻數:0~7(隻有低 3 位有效!)
// rlr:自動重裝載值,0~0XFFF.
// 分頻因子=4*2^prer.但最大值隻能是 256!
// rlr:重裝載寄存器值:低 11 位有效.
// 時間計算(大概):Tout=((4*2^prer)*rlr)/32 (ms).
static IWDG_HandleTypeDef iwdg_handle;
void WatchdogInit(void)
{
  iwdg_handle.Instance = IWDG;
  iwdg_handle.Init.Prescaler = 5;
  iwdg_handle.Init.Reload = 250;
  iwdg_handle.Init.Window = IWDG_WINDOW_DISABLE; // 關閉視窗功能

  HAL_IWDG_Init(&iwdg_handle);

  os_watchdog_lock = xSemaphoreCreateMutex();

  xTaskCreate((TaskFunction_t)task_watchdog,
              (const char*   )"task_watchdog",
              (uint16_t      )OS_WATCHDOG_STK_SIZE,
              (void*         )NULL,
              (UBaseType_t   )OS_PRIO_WATCHDOG,
              (TaskHandle_t* )&os_watchdog_handle);
}

void WatchdogFeed(void)
{
  HAL_IWDG_Refresh(&iwdg_handle);
}

//===============================================================================================================
// 任務看門狗注冊
void WatchdogRegister(const char *name, uint16_t timeout)
{
  int i;
  TaskHandle_t handle = xTaskGetCurrentTaskHandle();

  WATCHDOG_LOCK();
  for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
  {
    if (handle == watchdogs[i].handle)
    {
      WATCHDOG_UNLOCK();
      return;
    }
  }
  for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
  {
    if (0 == watchdogs[i].handle)
    {
      watchdogs[i].handle = handle;
      watchdogs[i].name = name;
      watchdogs[i].timeout = (timeout + WATCHDOG_CHECK_INTERVAL - 1) / WATCHDOG_CHECK_INTERVAL;
      watchdogs[i].time = watchdogs[i].timeout;
      watchdogs[i].suspended = 0;
      break;
    }
  }
  WATCHDOG_UNLOCK();
}

// 任務看門狗喂狗
void WatchdogKick(void)
{
  int i;
  TaskHandle_t handle = xTaskGetCurrentTaskHandle();

  for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
  {
    if (handle == watchdogs[i].handle)
    {
      WATCHDOG_LOCK();
      watchdogs[i].time = watchdogs[i].timeout;
      WATCHDOG_UNLOCK();
      break;
    }
  }
}

// 任務看門狗暫停
void WatchdogSuspend(void)
{
  int i;
  TaskHandle_t handle = xTaskGetCurrentTaskHandle();

  for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
  {
    if (handle == watchdogs[i].handle)
    {
      WATCHDOG_LOCK();
      watchdogs[i].suspended = 1;
      WATCHDOG_UNLOCK();
      break;
    }
  }
}

// 任務看門狗恢複
void WatchdogResume(void)
{
  int i;
  TaskHandle_t handle = xTaskGetCurrentTaskHandle();

  for(i = 0; i < WATCHDOG_POOL_SIZE; ++i)
  {
    if (handle == watchdogs[i].handle)
    {
      WATCHDOG_LOCK();
      watchdogs[i].time = watchdogs[i].timeout;
      watchdogs[i].suspended = 0;
      WATCHDOG_UNLOCK();
      break;
    }
  }
}
           

繼續閱讀