发新帖本帖赏金 70.00元(功能说明)我要提问
返回列表
打印
[MM32软件]

基于MM32F3270移植RTX5实时操作系统

[复制链接]
874|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创#   @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)

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 70.00 元 2024-11-08
理由:恭喜通过原创审核!期待您更多的原创作品~

评论
21小跑堂 2024-11-8 16:04 回复TA
MDK5一键添加RTX5实时操作系统,并逐步演示如何在MM32F3270上实现运行,保姆级教学,一学就会。 
沙发
suncat0504| | 2024-11-7 18:00 | 只看该作者
RTX实时操作系统可以实现零中断延时,移植方便。

使用特权

评论回复
板凳
xionghaoyun| | 2024-11-11 10:09 | 只看该作者
不明觉厉

使用特权

评论回复
发新帖 本帖赏金 70.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司资深现场应用工程师
简介:诚信·承诺·创新·合作

70

主题

3001

帖子

31

粉丝