#申请原创# @21小跑堂
1.概述
RTX5是KEIL MDK-Arm集成开发环境自带的一个实时操作系统(RTOS),使用Cortex-M内核的话,RTX实时操作系统可以实现零中断延时;同时RTX实时操作系统还带有完善的中间件,如RL-FlashFS、RL-USB、RL-TCPnet等等,这些中间件可以快速嵌入到项目开发中去,加速产品开发;最重要的一点是,RTX5实时操作系统不需要移植,使用MDK5开发环境可以一键添加,进行简单的配置就可以使用了,下面来具体讲解一下。
2.基础工程
基于MM32开发板,我们先准备一个基础工程,这个基础工程实现几个首先的配置:SysTick的1ms中断作为延时,SWD利用成RTT的打印输出,以及配置一个LED灯,每间隔200ms闪烁一次,实现代码及工程如下所示:
main.c
#include "main.h"
#include "platform.h"
void InitLED(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}
int main(void)
{
PLATFORM_Init();
InitLED();
while (1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == Bit_RESET) ? Bit_SET : Bit_RESET);
SysTick_DelayMS(200);
}
}
platform.c & platform.h
#include "platform.h"
#include "SEGGER_RTT.h"
volatile uint32_t SysTick_DelayTick = 0;
void PLATFORM_InitSysTick(void)
{
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
{
while (1)
{
}
}
NVIC_SetPriority(SysTick_IRQn, 0x0);
}
void SysTick_DelayMS(uint32_t Tick)
{
SysTick_DelayTick = Tick;
while (SysTick_DelayTick)
{
}
}
void PLATFORM_InitConsole(void)
{
SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
}
int fputc(int ch, FILE *f)
{
SEGGER_RTT_PutCharSkip(0, (char)ch);
return (ch);
}
void PLATFORM_PrintInfo(void)
{
RCC_ClocksTypeDef RCC_Clocks;
printf("\r\n");
printf("\r\nMCU : MM32F3273G6P");
printf("\r\n");
switch (RCC->CFGR & RCC_CFGR_SWS)
{
case 0x00:
printf("\r\nHSI used as system clock source");
break;
case 0x04:
printf("\r\nHSE used as system clock source");
break;
case 0x08:
if (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC)
{
printf("\r\nPLL (clocked by HSE) used as system clock source");
}
else
{
printf("\r\nPLL (clocked by HSI) used as system clock source");
}
break;
case 0x0C:
printf("\r\nLSI used as system clock source");
break;
default:
break;
}
RCC_GetClocksFreq(&RCC_Clocks);
printf("\r\n");
printf("\r\nSYSCLK Frequency : %7.3f MHz", (double)RCC_Clocks.SYSCLK_Frequency / (double)1000000.0);
printf("\r\nHCLK Frequency : %7.3f MHz", (double)RCC_Clocks.HCLK_Frequency / (double)1000000.0);
printf("\r\nPCLK1 Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK1_Frequency / (double)1000000.0);
printf("\r\nPCLK2 Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK2_Frequency / (double)1000000.0);
printf("\r\n");
}
void PLATFORM_Init(void)
{
PLATFORM_InitSysTick();
PLATFORM_InitConsole();
PLATFORM_PrintInfo();
}
#ifndef __PLATFORM_H
#define __PLATFORM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "hal_conf.h"
void PLATFORM_Init(void);
void SysTick_DelayMS(uint32_t Tick);
#ifdef __cplusplus
}
#endif
#endif
mm32f3270_it.c
#include "mm32f3270_it.h"
extern volatile uint32_t SysTick_DelayTick;
void NMI_Handler(void)
{
while (1)
{
}
}
void HardFault_Handler(void)
{
while (1)
{
}
}
void MemManage_Handler(void)
{
while (1)
{
}
}
void BusFault_Handler(void)
{
while (1)
{
}
}
void UsageFault_Handler(void)
{
while (1)
{
}
}
void SVCall_Handler(void)
{
}
void DebugMon_Handler(void)
{
}
void PendSV_Handler(void)
{
}
void SysTick_Handler(void)
{
if (SysTick_DelayTick)
{
SysTick_DelayTick--;
}
}
基础工程附件:
MM32F3270_BASE.zip
(6.82 MB)
3.移植RTX5实时操作系统
3.1.在基础工程的工具栏点击Manage Run-Time Environment图标
3.2.在弹出的Manage Run-Time Environment窗口中,勾选CMSIS->RTOS2(API)->Keil RTX5,Variant列选择Souce(源码形式)
3.3.点击Manage Run-Time Environment窗口中左下角的Resolve按钮,通过这个按钮解决所有的依赖关系警告,最后点击OK
3.4.我们看到当前工程中之前已经添加了STARTUP中的system_mm32f327x.c和startup_mm32f327x_keil.s这两个文件,在刚刚又自动添加了Device以及这两个文件,这时就重复了,所以我们右击Device,点击Options for Component Class 'Device',在弹出的窗口中,将Include in Target build这个选项勾选去掉
3.5.在CMSIS组中,打开RTX_Config.h文件,使用Configuration Wizard模式进行配置,如下所示
3.6.在mm32f3270_it.c和mm32f3270_it.h中注释掉与SVCall_Handler、PendSV_Handler、以及SysTick_Handler相关的部分,如下所示:
#include "mm32f3270_it.h"
//extern volatile uint32_t SysTick_DelayTick;
void NMI_Handler(void)
{
while (1)
{
}
}
void HardFault_Handler(void)
{
while (1)
{
}
}
void MemManage_Handler(void)
{
while (1)
{
}
}
void BusFault_Handler(void)
{
while (1)
{
}
}
void UsageFault_Handler(void)
{
while (1)
{
}
}
//void SVCall_Handler(void)
//{
//}
void DebugMon_Handler(void)
{
}
//void PendSV_Handler(void)
//{
//}
//void SysTick_Handler(void)
//{
// if (SysTick_DelayTick)
// {
// SysTick_DelayTick--;
// }
//}
#ifndef __MM32F3270_IT_H
#define __MM32F3270_IT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "hal_conf.h"
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
//void SVCall_Handler(void);
void DebugMon_Handler(void);
//void PendSV_Handler(void);
//void SysTick_Handler(void);
#ifdef __cplusplus
}
#endif
#endif
3.7.在platform.c和platform.h中注释掉与SysTick相关的部分,如下所示:
#include "platform.h"
#include "SEGGER_RTT.h"
//volatile uint32_t SysTick_DelayTick = 0;
//void PLATFORM_InitSysTick(void)
//{
// RCC_ClocksTypeDef RCC_Clocks;
// RCC_GetClocksFreq(&RCC_Clocks);
// if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
// {
// while (1)
// {
// }
// }
// NVIC_SetPriority(SysTick_IRQn, 0x0);
//}
//void SysTick_DelayMS(uint32_t Tick)
//{
// SysTick_DelayTick = Tick;
// while (SysTick_DelayTick)
// {
// }
//}
void PLATFORM_InitConsole(void)
{
SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
}
int fputc(int ch, FILE *f)
{
SEGGER_RTT_PutCharSkip(0, (char)ch);
return (ch);
}
void PLATFORM_PrintInfo(void)
{
RCC_ClocksTypeDef RCC_Clocks;
printf("\r\n");
printf("\r\nMCU : MM32F3273G6P");
printf("\r\n");
switch (RCC->CFGR & RCC_CFGR_SWS)
{
case 0x00:
printf("\r\nHSI used as system clock source");
break;
case 0x04:
printf("\r\nHSE used as system clock source");
break;
case 0x08:
if (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC)
{
printf("\r\nPLL (clocked by HSE) used as system clock source");
}
else
{
printf("\r\nPLL (clocked by HSI) used as system clock source");
}
break;
case 0x0C:
printf("\r\nLSI used as system clock source");
break;
default:
break;
}
RCC_GetClocksFreq(&RCC_Clocks);
printf("\r\n");
printf("\r\nSYSCLK Frequency : %7.3f MHz", (double)RCC_Clocks.SYSCLK_Frequency / (double)1000000.0);
printf("\r\nHCLK Frequency : %7.3f MHz", (double)RCC_Clocks.HCLK_Frequency / (double)1000000.0);
printf("\r\nPCLK1 Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK1_Frequency / (double)1000000.0);
printf("\r\nPCLK2 Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK2_Frequency / (double)1000000.0);
printf("\r\n");
}
void PLATFORM_Init(void)
{
// PLATFORM_InitSysTick();
PLATFORM_InitConsole();
PLATFORM_PrintInfo();
}
#ifndef __PLATFORM_H
#define __PLATFORM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "hal_conf.h"
void PLATFORM_Init(void);
//void SysTick_DelayMS(uint32_t Tick);
#ifdef __cplusplus
}
#endif
#endif
3.8.修改main.c文件,添加RTX5部分功能,实现LED每间隔200ms闪烁一下,如下所示:
#include "main.h"
#include "platform.h"
#include "cmsis_os2.h"
void InitLED(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
}
const osThreadAttr_t osThreadAttr_Start =
{
.name = "Start",
.attr_bits = osThreadDetached,
.priority = osPriorityHigh4,
.stack_size = 2048,
};
osThreadId_t osThreadId_Start = NULL;
const osThreadAttr_t osThreadAttr_LED =
{
.name = "LED",
.attr_bits = osThreadDetached,
.priority = osPriorityHigh2,
.stack_size = 512,
};
osThreadId_t osThreadId_LED = NULL;
void osThreadFunc_LED(void *argument)
{
InitLED();
while (1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == Bit_RESET) ? Bit_SET : Bit_RESET);
osDelay(200);
}
}
void osThreadFunc_Start(void *argument)
{
osThreadId_LED = osThreadNew(osThreadFunc_LED, NULL, &osThreadAttr_LED);
while (1)
{
osDelay(1);
}
}
int main(void)
{
PLATFORM_Init();
osKernelInitialize();
osThreadId_Start = osThreadNew(osThreadFunc_Start, NULL, &osThreadAttr_Start);
osKernelStart();
while (1)
{
}
}
3.9.到此基于MM32F3270系列MCU的RTX5实时操作系统移植就完成了,接下来,我们来编译、下载、运行,查看是否正常……
4.调试过程
4.1.编译时,我们发现了2个Error,提示如下:
解决办法:在RTE_Componets.h文件中添加SystemCoreClock外部变量的调用声明,如下所示,再进行编译就没有报错了。
4.2.下载 & 调试
将编译无误的程序下载到MM32F3270芯片中去运行,结果发现LED灯并没有如预期的在闪烁……我们进行在线Debug,在全速运行后,进行暂停,这时发现程序一直停在了SVCall_Handler中断处理中;但是这个中断应该是被RTX5实时系统自行实现并调用的中断,怎么会出现空跑的情况呢?
解决办法:我们退出调试状态,在CMSIS分组中,查看irq_armv7m.S这个文件,发现RTX5的SVC中断名为SVC_Handler,与startup_mm32f327x_keil.s文件中定义的SVCall_Handler并不一致,所以我先同步一个中断函数的命名,将startup_mm32f327x_keil.s文件中的SVCall_Handler出现的地方都修改为SVC_Handler
4.3.对修改后的工程进行重新编译,并下载到芯片中运行,这个时候板载的LED每间隔200ms就会切换一次显示状态了,到此基于MM32F3270移植的RTX5实时操作系统就完成了,工程附件如下
RTX5工程文件:
MM32F3270_RTX5.zip
(7.42 MB)
|
MDK5一键添加RTX5实时操作系统,并逐步演示如何在MM32F3270上实现运行,保姆级教学,一学就会。