【IoT】FreeRTOS 进阶:如何移植 freeRTOS 到 STM32 Cortex-M3

本文详细介绍了如何将FreeRTOS实时操作系统移植到STM32 Cortex-M3微控制器上,包括理解FreeRTOS文件结构、移植前的准备、添加RTOS核心代码、编写配置文件、挂接中断、设置节拍时钟以及创建和启动任务等关键步骤。
摘要由CSDN通过智能技术生成

1、FreeRTOS 文件结构

下载包根目录下包含两个子目录:

FreeRTOS 和 FreeRTOS-Plus。

其中,FreeRTOS-Plus 文件夹中包含一些 FreeRTOS+ 组件和演示例程,重点说一下 FreeRTOS 文件夹。

FreeRTOS 文件夹下包含两个子目录:

Demo 和 Source。

其中,Demo 包含演示例程的工程文件,Source 包含实时操作系统源代码文件。

FreeRTOS 实时操作系统内核仅包含三个必要文件,此外还有三个可选文件。

RTOS 核心代码位于三个源文件中,分别是 tasks.c、queue.c 和 list.c。

这三个文件位于 FreeRTOS/Source 目录下,在同一目录下还有3个可选的文件:timers.c、event_groups.c和croutine.c,分别用于软件定时器、事件组和协程。

对于支持的处理器架构,RTOS 需要一些与处理器架构相关的代码。

可以称之为 RTOS 硬件接口层,它们位于 FreeRTOS/Source/Portable/[相应编译器]/[相应处理器架构]文件夹下。

我们这次要移植到Cortex-M3微控制,使用Keil MDK编译器,所以需要的RTOS硬件接口代码位于:

FreeRTOS\Source\portable\RVDS\ARM_CM3 文件夹下。

堆栈分配也是属于硬件接口层(移植层),在FreeRTOS/Source/portable/MemMang文件夹下具有各种类型的堆栈分配方案。

这里我们使用heap_1.c提供的堆栈分配方案。

FreeRTOS文件夹下的Demo文件夹中还包括各种演示例程,涉及多种架构的处理器以及多种编译器。

FreeRTOS/Demo/Common/Minimal文件夹下的演示例程代码中,绝大部分对所有移植硬件接口都是适用的。

FreeRTOS/Demo/Common/Full文件夹下的代码属于历史遗留代码,仅用于PC移植层。

2、移植前准备

一块具有Cortex-M3微处理器的硬件板子,并且保证板子可以正常运转。

下载 FreeRTOS 程序包;

下载 CMSIS-M3,其实主要是需要里面的core_cm3.h文件(可以去ARM官方下载,如果你安装了keil 5或比较新的Keil 4 MDK编译器,在目录:Keil\ARM\CMSIS文件夹下也可以找到)。

3、移植过程

3.1、添加 RTOS 核心代码

将tasks.c、queue.c和list.c这三个内核代码加入工程,将port.c和heap_1.c这两个与处理器相关代码加入工程。

port.c位于FreeRTOS\Source\portable\RVDS\ARM_CM3文件夹下;

heap_1.c位于FreeRTOS/Source/portable/MemMang文件夹下。

3.2、添加头文件路径

...\FreeRTOS\Source\portable\RVDS\ARM_CM3

...\FreeRTOS\Source\include

3.3、编写FreeRTOSConfig.h文件

对于刚接触FreeRTOS的用户来说,最简单方法是找一个类似的Demo工程,复制该工程下的FreeRTOSConfig.h文件,在这个基础上进行修改。

3.4、编写一些钩子函数

如果你在FreeRTOSConfig.h中设置了configUSE_TICK_HOOK=1,则必须编写voidvApplicationTickHook( void )函数。

该函数利用时间片中断,可以很方便的实现一个定时器功能。

如果你在FreeRTOSConfig.h中设置了configCHECK_FOR_STACK_OVERFLOW=1或=2,则必须编写voidvApplicationStackOverflowHook( xTaskHandle pxTask, signed char *pcTaskName )函数。

3.5、检查硬件

为了验证你的硬件板子是否可靠的工作,首先编写一个小程序片,比如闪烁一个LED灯或者发送一个字符等等,我们这里使用UART发送一个字符。

代码如下所示(假设你已经配置好了启动代码,并正确配置了UART): 

 #include"task.h"
       #include"queue.h"
       #include"list.h"
       #include"portable.h"   
       #include"debug.h"
     
       int main(void)
       {
           init_rtos_debug();           //初始化调试串口
           MAP_UARTCharPut('A');        //发送一个字符
           while(1);
       }

如果硬件可以正常发送字符,说明硬件以及启动代码OK,可以进行下一步。

3.6、挂接中断

在Cortex-M3硬件下,FreeRTOS使用SysTick作为系统节拍时钟,使用SVC和PendSVC进行上下文切换。

异常中断服务代码位于port.c文件中,FreeRTOS的作者已经为各种架构的CPU写好了这些代码,可以直接拿来用,需要用户做的,仅仅是将这些异常中断入口地址挂接到启动代码中。

在startup.s中,使用IMPORT关键字声明要挂接的异常中断服务函数名,然后将:     

   DCD     SVC_Handler            换成:   DCD     vPortSVCHandler
         DCD     PendSV_Handler         换成:   DCD     xPortPendSVHandler
         DCD     SysTick_Handler        换成:   DCD     xPortSysTickHandler

3.7、建立第一个任务Task

在步骤3.5中,我们为了测试硬件是是否能够工作,编写了一个发送字符的小函数,这里我们将把这个小函数作为我们第一个任务要执行的主要代码:

每隔1秒钟,发送一个字符。

代码如下所示:

   voidvTask(void *pvParameters)
   {
        while(1)
        {
            MAP_UARTCharPut(0x31);
            vTaskDelay(1000/portTICK_RATE_MS);
        }
   }

3.8、设置节拍时钟

这里我们使用SysTick定时器作为系统的节拍时钟,设定每隔10ms产生一次节拍中断。

由于FreeRTOS对移植做了非常多的工作,以至于我们只需要在FreeRTOSConfig.h中配置好以下两个宏定义即可:

configCPU_CLOCK_HZ     (/*你的硬件平台CPU系统时钟,Fcclk*/)
configTICK_RATE_HZ       ((portTickType)100)     
    
第一个宏定义CPU系统时钟,也就是CPU执行时的频率。

第二个宏定义FreeRTOS的时间片频率,这里定义为100,表明RTOS一秒钟可以切换100次任务,也就是每个时间片为10ms。

在prot.c中,函数vPortSetupTimerInterrupt()设置节拍时钟。

该函数根据上面的两个宏定义的参数,计算SysTick定时器的重装载数值寄存器,然后设置SysTick定时器的控制及状态寄存器,设置如下:

使用内核时钟源、使能中断、使能SysTick定时器。另外,函数vPortSetupTimerInterrupt()由函数vTaskStartScheduler()调用,这个函数用于启动调度器。

3.9、设置中断优先级相关宏

这里特别重要,因为涉及到中断优先级和中断嵌套。

这里先给出基于Cortex-M3硬件(lpc177x_8x系列微控制器)的一个配置例子,在FreeRTOSConfig.h中:

#ifdef __NVIC_PRIO_BITS
         #defineconfigPRIO_BITS   __NVIC_PRIO_BITS
#else
         #defineconfigPRIO_BITS   5  /*lpc177x_8x微处理器使用优先级寄存器的5位*/
#endif
 
/*设置内核使用的中断优先级*/
#define configKERNEL_INTERRUPT_PRIORITY      ( 31 << (8 - configPRIO_BITS) )

/*定义RTOS可以屏蔽的最大中断优先级,大于这个优先级的中断,不受RTOS控制*/
#defineconfigMAX_SYSCALL_INTERRUPT_PRIORITY   ( 5<< (8 - configPRIO_BITS) )

3.10、设置其它宏

还需要在FreeRTOSConfig.h设置一些必要的宏,这些宏如下所示:

#define configUSE_PREEMPTION 1            //配置为1使用抢占式内核,配置为0使用时间片
#define configUSE_IDLE_HOOK  0            //设置为1使用空闲钩子;设置为0不使用空闲钩子
#define configMAX_PRIORITIES      ( 5 )   //应用程序任务中可用优先级数目
#define configUSE_TICK_HOOK       0       //就设置为1使用时间片钩子,设置为0不使用
#define configMINIMAL_STACK_SIZE      ( ( unsigned short ) 80 )     //最小空闲堆栈
#define configTOTAL_HEAP_SIZE         ( ( size_t ) ( 5 * 1024 ) )   //内核总共可用RAM

3.11、创建任务

调用FreeRTOS提供的API函数来创建任务,代码如下所示:

xTaskCreate(vTask,"Task1",50,NULL,1,NULL);

3.12、开启调度器

调用FreeRTOS提供的API函数来启动调度器,代码如下所示:   

  vTaskStartScheduler();
      关于详细的开启调度器API函数,会在后续文章《FreeRTOS内核控制》一文中介绍。

      此时的main函数代码如下所示:


     int main(void)
     {
         init_rtos_debug();                             //初始化调试串口
  
          xTaskCreate(vTask,"Task1",50,NULL,1,NULL);
          vTaskStartScheduler();
          while(1);   
       }

4、小结

最基本的FreeRTOS应用程序就已经运行起来,将硬件板子接到PC的RS232串口,可以观察到每隔一秒钟,板子都会向PC发送一个指定的字符。

 

 


refer:

https://blog.csdn.net/zhzht19861011/article/details/50072033

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值