uC-OS2 V2.93 STM32L476 移植:系统启动篇

前言

  • 前两篇已经 通过 STM32CubeMX 搭建了 NUCLEO-L476RG 的 STM32L476RG 的 裸机工程,下载了 uC-OS2 V2.93 的源码,并把 uC-OS2 的源文件加入 Keil MDK5 工程

  • 本篇适配 uC-OS2 的 系统定时器(Systick)与 PendSV_Handler,创建 用户任务,让 uC-OS2 启动并运行起来

开发环境

  • win10 64位

  • Keil uVision5,MDK V5.36

  • uC-OS2 V2.93

  • 开发板:NUCLEO-L476RG ,MCU 为 STM32L476RG

  • STM32CubeMX 6.9.1,用于生成 STM32的裸机工程

创建用户任务

  • 这里创建一个 led 闪烁的任务,在 main.c 中实现
c 复制代码
#include "main.h"
#include "led.h"
#include "app_cfg.h"
#include "os.h"

UART_HandleTypeDef huart2;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);

#define TASK_LED_PRIO               5
#define TASK_LED_STACK_SIZE         128
static OS_STK task_led_stack[TASK_LED_STACK_SIZE];

static void task_led_entry(void *p_arg)
{
    while (1)
    {
        led_grn_ctrl(1);
        OSTimeDly(1000);
        led_grn_ctrl(0);
        OSTimeDly(1000);
    }
}

void led_task_init(void)
{
    OSTaskCreate(task_led_entry,(void *)0, &task_led_stack[TASK_LED_STACK_SIZE-1], TASK_LED_PRIO);
}

HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
    return HAL_OK;
}

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_USART2_UART_Init();
    OSInit();
    led_task_init();
    OS_CPU_SysTickInitFreq(80000000);
    OSStart();

    return 0;
}

适配 Systick

  • 工程编译下载后,发现 任务没有正常调度起来,原因是没有适配 uC-OS2

  • 首先需要开启 uC-OS2 的系统定时器,也就是系统的心跳

  • uC-OS2 V2.93 有 Systick 的初始化函数,uC-OS2\Ports\ARM-Cortex-M\ARMv7-M\os_cpu_c.c,OS_CPU_SysTickInitFreq

  • 备注: STM32的 HAL库,默认在 HAL_Init 中通过 HAL_InitTick 初始化了 1ms 一次的 Systick

  • 这里首先重新 STM32 HAL 库的 HAL_InitTick,默认是个 weak 函数,可以重新,这里重写为空,也就是不通过 STM32 HAL 库初始化 Systick

c 复制代码
HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
    return HAL_OK;
}
  • 通过 OS_CPU_SysTickInitFreq(80000000); 初始化 Systick

  • 初始化了 Systick,就要处理一下 Systick 的中断函数: SysTick_Handler,需要调用 uC-OS2 的 OS_CPU_SysTickHandler,修改文件 stm32l476_ucosii_led\Core\Src\stm32l4xx_it.c

c 复制代码
#include "app_cfg.h"
#include "os_cpu.h"

void SysTick_Handler(void)
{
    OS_CPU_SysTickHandler();
    HAL_IncTick();
}
  • 以上的修改, Systick 初始化,Systick 的中断可以周期性的触发

  • 如果发现 Systick 没有按1毫秒触发一次中断,如延时1秒发现时间是 10秒,需要修改 uC-OS2\Cfg\Template\os_cfg.h,修改 OS_TICKS_PER_SEC, 改为 #define OS_TICKS_PER_SEC 1000u,也就是 1毫秒触发一次Systick 中断

适配 PendSV_Handler

  • 像 STM32 系列的芯片,默认通过 PendSV_Handler 中断进行任务的切换,修改文件 stm32l476_ucosii_led\Core\Src\stm32l4xx_it.c 中的 PendSV_Handler
c 复制代码
void PendSV_Handler(void)
{
    OS_CPU_PendSVHandler();
}
  • 注意 stm32l476_ucosii_led\Core\Src\stm32l4xx_it.c 中 包含头文件
c 复制代码
#include "app_cfg.h"
#include "os_cpu.h"

编译烧写

  • 编译烧写后,发现开发板的 LED 正常的闪烁, uC-OS2 系统移植初步完成,任务切换、系统延时等正常工作了

  • 可以点击 Keil MDK5 的【Debug】调试按钮,进入 Debug 调试模式,加入【断点】,单步或者连续运行,观察 uC-OS2 的任务调度、切换,用户例程的执行等

调试说明

  • 如果调试发现【断点】不起作用,需要调整 Keil MDK5 的编译优化等级,改为 O0 试试
  • 通过软件调试,可以熟悉整个系统的初始化、启动、运行流程

小结

  • 本篇通过适配 uC-OS2 的两个关键的适配: 系统滴答定时器与 PendSV 系统异常,实现 uC-OS2 的正常启动与运行

  • uC-OS2 移植起来相对简单,后面继续研究 uC-OS2,如增加串口输出、移植 Shell 等

相关推荐
XiHongShi20165 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
优信电子5 天前
AIT1001 非接触式红外测温模块 STM32 驱动开发实战:从引脚到代码全解析
stm32·嵌入式·温度传感器·红外测温·非接触式测温·ait1001
深圳老胡5 天前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
wuyk5555 天前
《WiFi 嵌入式物联网开发全套实战》| 第 16 章 ESP32 AP+STA 双模共存原理与工程坑点
网络·stm32·物联网
Brilliantwxx5 天前
【STM32】 SPI Flash 驱动开发实战:阻塞模式驱动 W25Q64(含工程代码)
开发语言·stm32·单片机·嵌入式硬件
youcans_5 天前
【嵌入式软件AI编程】16. Claude Code 与 VS Code 的协同开发
stm32·mcu·嵌入式·ai编程·claude code
Zw-awa5 天前
按键接到 STM32 后:GPIO 输入到底读到了什么
stm32
MarkZhou6245 天前
智能蒸烤双核通信架构拆解:从冗余耦合到分层解耦
stm32·单片机·嵌入式硬件·架构·安卓·安全架构
chem41115 天前
STM32CubeMX Linux 开发环境搭建
stm32·单片机·linux系统
无敌贵点大王6 天前
RTThread学习记录11——RT-Thread 设备模型吃透:UART/ADC/PWM/PIN 到底有什么区别?
c语言·stm32·学习·链表