返回列表 发新帖我要提问本帖赏金: 70.00元(功能说明)

[MM32软件] 基于MM32F3270移植RTX5实时操作系统

[复制链接]
3624|3
 楼主| xld0932 发表于 2024-11-5 15:49 | 显示全部楼层 |阅读模式
#申请原创#   @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
  1. #include "main.h"
  2. #include "platform.h"

  3. void InitLED(void)
  4. {
  5.     GPIO_InitTypeDef GPIO_InitStruct;

  6.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);

  7.     GPIO_StructInit(&GPIO_InitStruct);
  8.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_13;
  9.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  10.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
  11.     GPIO_Init(GPIOC, &GPIO_InitStruct);

  12.     GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
  13. }

  14. int main(void)
  15. {
  16.     PLATFORM_Init();

  17.     InitLED();

  18.     while (1)
  19.     {
  20.         GPIO_WriteBit(GPIOC, GPIO_Pin_13, (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == Bit_RESET) ? Bit_SET : Bit_RESET);

  21.         SysTick_DelayMS(200);
  22.     }
  23. }


platform.c & platform.h
  1. #include "platform.h"
  2. #include "SEGGER_RTT.h"

  3. volatile uint32_t SysTick_DelayTick = 0;

  4. void PLATFORM_InitSysTick(void)
  5. {
  6.     RCC_ClocksTypeDef  RCC_Clocks;
  7.     RCC_GetClocksFreq(&RCC_Clocks);

  8.     if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
  9.     {
  10.         while (1)
  11.         {
  12.         }
  13.     }

  14.     NVIC_SetPriority(SysTick_IRQn, 0x0);
  15. }

  16. void SysTick_DelayMS(uint32_t Tick)
  17. {
  18.     SysTick_DelayTick = Tick;

  19.     while (SysTick_DelayTick)
  20.     {
  21.     }
  22. }

  23. void PLATFORM_InitConsole(void)
  24. {
  25.     SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
  26. }

  27. int fputc(int ch, FILE *f)
  28. {
  29.     SEGGER_RTT_PutCharSkip(0, (char)ch);

  30.     return (ch);
  31. }

  32. void PLATFORM_PrintInfo(void)
  33. {
  34.     RCC_ClocksTypeDef RCC_Clocks;

  35.     printf("\r\n");
  36.     printf("\r\nMCU : MM32F3273G6P");
  37.     printf("\r\n");

  38.     switch (RCC->CFGR & RCC_CFGR_SWS)
  39.     {
  40.         case 0x00:
  41.             printf("\r\nHSI used as system clock source");
  42.             break;

  43.         case 0x04:
  44.             printf("\r\nHSE used as system clock source");
  45.             break;

  46.         case 0x08:
  47.             if (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC)
  48.             {
  49.                 printf("\r\nPLL (clocked by HSE) used as system clock source");
  50.             }
  51.             else
  52.             {
  53.                 printf("\r\nPLL (clocked by HSI) used as system clock source");
  54.             }

  55.             break;

  56.         case 0x0C:
  57.             printf("\r\nLSI used as system clock source");
  58.             break;

  59.         default:
  60.             break;
  61.     }

  62.     RCC_GetClocksFreq(&RCC_Clocks);

  63.     printf("\r\n");
  64.     printf("\r\nSYSCLK Frequency : %7.3f MHz", (double)RCC_Clocks.SYSCLK_Frequency / (double)1000000.0);
  65.     printf("\r\nHCLK   Frequency : %7.3f MHz", (double)RCC_Clocks.HCLK_Frequency   / (double)1000000.0);
  66.     printf("\r\nPCLK1  Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK1_Frequency  / (double)1000000.0);
  67.     printf("\r\nPCLK2  Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK2_Frequency  / (double)1000000.0);
  68.     printf("\r\n");
  69. }

  70. void PLATFORM_Init(void)
  71. {
  72.     PLATFORM_InitSysTick();

  73.     PLATFORM_InitConsole();

  74.     PLATFORM_PrintInfo();
  75. }

  76. #ifndef __PLATFORM_H
  77. #define __PLATFORM_H

  78. #ifdef __cplusplus
  79. extern "C" {
  80. #endif

  81. #include <stdio.h>
  82. #include "hal_conf.h"

  83. void PLATFORM_Init(void);
  84. void SysTick_DelayMS(uint32_t Tick);

  85. #ifdef __cplusplus
  86. }
  87. #endif

  88. #endif
mm32f3270_it.c
  1. #include "mm32f3270_it.h"

  2. extern volatile uint32_t SysTick_DelayTick;

  3. void NMI_Handler(void)
  4. {
  5.     while (1)
  6.     {
  7.     }
  8. }

  9. void HardFault_Handler(void)
  10. {
  11.     while (1)
  12.     {
  13.     }
  14. }

  15. void MemManage_Handler(void)
  16. {
  17.     while (1)
  18.     {
  19.     }
  20. }

  21. void BusFault_Handler(void)
  22. {
  23.     while (1)
  24.     {
  25.     }
  26. }

  27. void UsageFault_Handler(void)
  28. {
  29.     while (1)
  30.     {
  31.     }
  32. }

  33. void SVCall_Handler(void)
  34. {
  35. }

  36. void DebugMon_Handler(void)
  37. {
  38. }

  39. void PendSV_Handler(void)
  40. {
  41. }

  42. void SysTick_Handler(void)
  43. {
  44.     if (SysTick_DelayTick)
  45.     {
  46.         SysTick_DelayTick--;
  47.     }
  48. }



基础工程附件: MM32F3270_BASE.zip (6.82 MB, 下载次数: 7)

3.移植RTX5实时操作系统
3.1.在基础工程的工具栏点击Manage Run-Time Environment图标
1.png

3.2.在弹出的Manage Run-Time Environment窗口中,勾选CMSIS->RTOS2(API)->Keil RTX5,Variant列选择Souce(源码形式)
2.png

3.3.点击Manage Run-Time Environment窗口中左下角的Resolve按钮,通过这个按钮解决所有的依赖关系警告,最后点击OK
3.png

3.4.我们看到当前工程中之前已经添加了STARTUP中的system_mm32f327x.c和startup_mm32f327x_keil.s这两个文件,在刚刚又自动添加了Device以及这两个文件,这时就重复了,所以我们右击Device,点击Options for Component Class 'Device',在弹出的窗口中,将Include in Target build这个选项勾选去掉
4.png
5.png
6.png

3.5.在CMSIS组中,打开RTX_Config.h文件,使用Configuration Wizard模式进行配置,如下所示
7.png

3.6.在mm32f3270_it.c和mm32f3270_it.h中注释掉与SVCall_Handler、PendSV_Handler、以及SysTick_Handler相关的部分,如下所示:
  1. #include "mm32f3270_it.h"

  2. //extern volatile uint32_t SysTick_DelayTick;

  3. void NMI_Handler(void)
  4. {
  5.     while (1)
  6.     {
  7.     }
  8. }

  9. void HardFault_Handler(void)
  10. {
  11.     while (1)
  12.     {
  13.     }
  14. }

  15. void MemManage_Handler(void)
  16. {
  17.     while (1)
  18.     {
  19.     }
  20. }

  21. void BusFault_Handler(void)
  22. {
  23.     while (1)
  24.     {
  25.     }
  26. }

  27. void UsageFault_Handler(void)
  28. {
  29.     while (1)
  30.     {
  31.     }
  32. }

  33. //void SVCall_Handler(void)
  34. //{
  35. //}

  36. void DebugMon_Handler(void)
  37. {
  38. }

  39. //void PendSV_Handler(void)
  40. //{
  41. //}

  42. //void SysTick_Handler(void)
  43. //{
  44. //    if (SysTick_DelayTick)
  45. //    {
  46. //        SysTick_DelayTick--;
  47. //    }
  48. //}

  49. #ifndef __MM32F3270_IT_H
  50. #define __MM32F3270_IT_H

  51. #ifdef __cplusplus
  52. extern "C" {
  53. #endif

  54. #include "hal_conf.h"

  55. void NMI_Handler(void);
  56. void HardFault_Handler(void);
  57. void MemManage_Handler(void);
  58. void BusFault_Handler(void);
  59. void UsageFault_Handler(void);
  60. //void SVCall_Handler(void);
  61. void DebugMon_Handler(void);
  62. //void PendSV_Handler(void);
  63. //void SysTick_Handler(void);

  64. #ifdef __cplusplus
  65. }
  66. #endif

  67. #endif


3.7.在platform.c和platform.h中注释掉与SysTick相关的部分,如下所示:
  1. #include "platform.h"
  2. #include "SEGGER_RTT.h"

  3. //volatile uint32_t SysTick_DelayTick = 0;

  4. //void PLATFORM_InitSysTick(void)
  5. //{
  6. //    RCC_ClocksTypeDef  RCC_Clocks;
  7. //    RCC_GetClocksFreq(&RCC_Clocks);

  8. //    if (SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000))
  9. //    {
  10. //        while (1)
  11. //        {
  12. //        }
  13. //    }

  14. //    NVIC_SetPriority(SysTick_IRQn, 0x0);
  15. //}

  16. //void SysTick_DelayMS(uint32_t Tick)
  17. //{
  18. //    SysTick_DelayTick = Tick;

  19. //    while (SysTick_DelayTick)
  20. //    {
  21. //    }
  22. //}

  23. void PLATFORM_InitConsole(void)
  24. {
  25.     SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
  26. }

  27. int fputc(int ch, FILE *f)
  28. {
  29.     SEGGER_RTT_PutCharSkip(0, (char)ch);

  30.     return (ch);
  31. }

  32. void PLATFORM_PrintInfo(void)
  33. {
  34.     RCC_ClocksTypeDef RCC_Clocks;

  35.     printf("\r\n");
  36.     printf("\r\nMCU : MM32F3273G6P");
  37.     printf("\r\n");

  38.     switch (RCC->CFGR & RCC_CFGR_SWS)
  39.     {
  40.         case 0x00:
  41.             printf("\r\nHSI used as system clock source");
  42.             break;

  43.         case 0x04:
  44.             printf("\r\nHSE used as system clock source");
  45.             break;

  46.         case 0x08:
  47.             if (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC)
  48.             {
  49.                 printf("\r\nPLL (clocked by HSE) used as system clock source");
  50.             }
  51.             else
  52.             {
  53.                 printf("\r\nPLL (clocked by HSI) used as system clock source");
  54.             }

  55.             break;

  56.         case 0x0C:
  57.             printf("\r\nLSI used as system clock source");
  58.             break;

  59.         default:
  60.             break;
  61.     }

  62.     RCC_GetClocksFreq(&RCC_Clocks);

  63.     printf("\r\n");
  64.     printf("\r\nSYSCLK Frequency : %7.3f MHz", (double)RCC_Clocks.SYSCLK_Frequency / (double)1000000.0);
  65.     printf("\r\nHCLK   Frequency : %7.3f MHz", (double)RCC_Clocks.HCLK_Frequency   / (double)1000000.0);
  66.     printf("\r\nPCLK1  Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK1_Frequency  / (double)1000000.0);
  67.     printf("\r\nPCLK2  Frequency : %7.3f MHz", (double)RCC_Clocks.PCLK2_Frequency  / (double)1000000.0);
  68.     printf("\r\n");
  69. }

  70. void PLATFORM_Init(void)
  71. {
  72. //    PLATFORM_InitSysTick();

  73.     PLATFORM_InitConsole();

  74.     PLATFORM_PrintInfo();
  75. }

  76. #ifndef __PLATFORM_H
  77. #define __PLATFORM_H

  78. #ifdef __cplusplus
  79. extern "C" {
  80. #endif

  81. #include <stdio.h>
  82. #include "hal_conf.h"

  83. void PLATFORM_Init(void);
  84. //void SysTick_DelayMS(uint32_t Tick);

  85. #ifdef __cplusplus
  86. }
  87. #endif

  88. #endif


3.8.修改main.c文件,添加RTX5部分功能,实现LED每间隔200ms闪烁一下,如下所示:
  1. #include "main.h"
  2. #include "platform.h"
  3. #include "cmsis_os2.h"

  4. void InitLED(void)
  5. {
  6.     GPIO_InitTypeDef GPIO_InitStruct;

  7.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);

  8.     GPIO_StructInit(&GPIO_InitStruct);
  9.     GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_13;
  10.     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  11.     GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_Out_PP;
  12.     GPIO_Init(GPIOC, &GPIO_InitStruct);

  13.     GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
  14. }

  15. const osThreadAttr_t osThreadAttr_Start =
  16. {
  17.     .name       = "Start",
  18.     .attr_bits  = osThreadDetached,
  19.     .priority   = osPriorityHigh4,
  20.     .stack_size = 2048,
  21. };

  22. osThreadId_t osThreadId_Start = NULL;

  23. const osThreadAttr_t osThreadAttr_LED =
  24. {
  25.     .name       = "LED",
  26.     .attr_bits  = osThreadDetached,
  27.     .priority   = osPriorityHigh2,
  28.     .stack_size = 512,
  29. };

  30. osThreadId_t osThreadId_LED = NULL;

  31. void osThreadFunc_LED(void *argument)
  32. {
  33.     InitLED();

  34.     while (1)
  35.     {
  36.         GPIO_WriteBit(GPIOC, GPIO_Pin_13, (GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13) == Bit_RESET) ? Bit_SET : Bit_RESET);

  37.         osDelay(200);
  38.     }
  39. }

  40. void osThreadFunc_Start(void *argument)
  41. {
  42.     osThreadId_LED = osThreadNew(osThreadFunc_LED, NULL, &osThreadAttr_LED);

  43.     while (1)
  44.     {
  45.         osDelay(1);
  46.     }
  47. }

  48. int main(void)
  49. {
  50.     PLATFORM_Init();

  51.     osKernelInitialize();

  52.     osThreadId_Start = osThreadNew(osThreadFunc_Start, NULL, &osThreadAttr_Start);

  53.     osKernelStart();

  54.     while (1)
  55.     {
  56.     }
  57. }


3.9.到此基于MM32F3270系列MCU的RTX5实时操作系统移植就完成了,接下来,我们来编译、下载、运行,查看是否正常……

4.调试过程

4.1.编译时,我们发现了2个Error,提示如下:
8.png

解决办法:在RTE_Componets.h文件中添加SystemCoreClock外部变量的调用声明,如下所示,再进行编译就没有报错了。
9.png

4.2.下载 & 调试
将编译无误的程序下载到MM32F3270芯片中去运行,结果发现LED灯并没有如预期的在闪烁……我们进行在线Debug,在全速运行后,进行暂停,这时发现程序一直停在了SVCall_Handler中断处理中;但是这个中断应该是被RTX5实时系统自行实现并调用的中断,怎么会出现空跑的情况呢?
10.png

解决办法:我们退出调试状态,在CMSIS分组中,查看irq_armv7m.S这个文件,发现RTX5的SVC中断名为SVC_Handler,与startup_mm32f327x_keil.s文件中定义的SVCall_Handler并不一致,所以我先同步一个中断函数的命名,将startup_mm32f327x_keil.s文件中的SVCall_Handler出现的地方都修改为SVC_Handler
11.png

4.3.对修改后的工程进行重新编译,并下载到芯片中运行,这个时候板载的LED每间隔200ms就会切换一次显示状态了,到此基于MM32F3270移植的RTX5实时操作系统就完成了,工程附件如下

RTX5工程文件: MM32F3270_RTX5.zip (7.42 MB, 下载次数: 10)

打赏榜单

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

评论

MDK5一键添加RTX5实时操作系统,并逐步演示如何在MM32F3270上实现运行,保姆级教学,一学就会。  发表于 2024-11-8 16:04
suncat0504 发表于 2024-11-7 18:00 | 显示全部楼层
RTX实时操作系统可以实现零中断延时,移植方便。
xionghaoyun 发表于 2024-11-11 10:09 | 显示全部楼层
不明觉厉
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部