stm32 单片机使用 rt-thread 的syswatch 系统守护软件包
一、系统看守(syswatch)组件 介绍
系统看守(syswatch)组件 主要功能是保障实时操作系统正常运行,防止系统死机以及各种异常引起的线程阻塞,保障整个系统长期正常运行。
系统看守具备以下几种行为模式:
1、系统崩溃或硬件异常导致系统失去调度时,执行 系统复位 恢复系统正常运行。
2、当有异常导致某些线程长时间阻塞时,可根据用户的配置实施 系统复位 / 杀掉阻塞线程 / 重启阻塞线程 的方式恢复系统正常运行。
原理介绍
系统看守(syswatch)组件 使用实时操作系统中允许的最高优先级作为看守线程的优先级,保障看守线程不会被阻塞,同时看守线程由看门狗提供看护,保障看守线程正常运行。系统看守通过 线程调度回调接口 监测线程的调度情况,当检测到有线程发生异常阻塞时,开始检测和确认具体哪个线程发生了异常阻塞,最后根据异常解决模式执行 系统复位 / 杀掉阻塞线程 / 重启阻塞线程 清除异常,使系统恢复正常运行。
配置参数说明
注意事项
1、syswatch 依赖于看门狗设备而工作,使用本组件时请确认已注册了看门狗设备。
2、syswatch 全权管理看门狗,请不要在其它线程中使用和操作看门狗。
3、syswatch 提供了3种异常解决模式,请根据实际需要配置适合的工作模式。
4、syswatch_set_event_hook 提供用户安装事件回调函数,以便针对重要事件发生时进行一些必要处理,如系统复位前须对重要数据进行保存时,可设置回调函数完成相应处理,如不需要可不设置。
二、开发配置
2.1 开发环境
基于 env 进行配置开发。RT-Thread Env 工具包括配置器和包管理器,用来对内核和组件的功能进行配置,对组件进行自由裁剪,对线上软件包进行管理,使得系统以搭积木的方式进行构建,简单方便。
硬件:基于野火 stm32f407 开发板
软件:rt-thread 4.1.1 版本,基于 stm32f407-atk-explorer bsp包
2.2 时钟配置
stm32f407-atk-explorer bsp包的外部晶振是8MHZ,野火 stm32f407 开发板外部晶振是25MHZ,需要先修改配置系统时钟。
参考野火教程:
系统时钟的计算:SYSCLK=PLLCLK=HSE/m*n/p
HSE 使用 25M,参数 m 设置为 25,所以需要修改系统时钟的时候只需要修改参数 n 和 p 即可,SYSCLK=PLLCLK=HSE/m*n/p。
系统时钟配置完整代码如下:
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/**Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE
|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.LSIState = RCC_LSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
}
2.3 开启看门狗
Kconfig 文件 相关
config BSP_USING_WDT
bool "Enable Watchdog Timer"
select RT_USING_WDT
default n
开始之后,下面的选项会自动勾选。
Kconfig 文件 相关
config RT_USING_WDT
bool "Using Watch Dog device drivers"
default n
重新编译,下载到开发板,查看设备
使用的是独立看门狗(IWDG)
区分独立看门狗(IWDG)和窗口看门狗(WWDG)
2.4 syswatch 组件
开启 syswatch 组件
下载软件包
编译
三、测试
下载到开发板,运行如下
查看线程
配置的异常解决模式是2,可知可重启异常线程。
测试代码,编写异常线程:
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-11-06 SummerGift first version
* 2018-11-19 flybreak add stm32f407-atk-explorer bsp
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
static rt_thread_t tid1 = RT_NULL;
/* defined the LED0 pin: PF6 */
#define LED0_PIN GET_PIN(F, 6)
#define LED1_PIN GET_PIN(C, 6)
/* 线程 1 的入口函数 */
static void thread1_entry(void *parameter)
{
rt_kprintf("hello world\r\n");
while(1)
{
}
}
int main(void)
{
/* set LED0 pin mode to output */
rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);
/* 创建线程 1,名称是 thread1,入口是 thread1_entry*/
tid1 = rt_thread_create("thread1",
thread1_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
while (1)
{
rt_pin_write(LED0_PIN, PIN_HIGH);
rt_pin_write(LED1_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED0_PIN, PIN_LOW);
rt_pin_write(LED1_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
测试结果,异常线程可重新重启
参考:
https://gitee.com/RT-Thread-Mirror/rt-thread-syswatch
STM32库开发实战指南——基于野火霸天虎开发板