国民技术N32G45X系列freertos移植
GaoSheng Lv4

国民技术G45X系列移植FreeRtos一共分为四步:
1.下载FreeRtos源码
2.添加FreeRtos源码到原有的工程文件
3.添加修改FreeRTOSConfig.h文件、n32g45x_it.h文件
4.修改Delay.c文件

一、下载FreeRtos源码

官网: http://www.freertos.org/ 
代码托管网站: https://sourceforge.net/projects/freertos/files/FreeRTOS/
Github https://github.com/FreeRTOS
这里使用的版本是V202012.00
使用的平台是N32G455RE
以国民技术SDK中的LedBlink工程为模板

二、添加FreeRtos源码到原有工程文件

在KEIL工程中新建分组FreeRTOS_CODE添加如下文件:
image
在KEIL工程中新建分组FreeRTOS_PORTABLE添加如下文件:
image
在KEIL工程中添加对应头文件路径:
image

三、添加并修改FreeRtosConfig.h、n32g45x_it.h文件

1.此时编译应该会报错:“error: #5: cannot open source input file “FreeRTOSConfig.h”: No such file or directory”
image
FreeRTOSConfig.h 是FreeRTOS 的配置文件,一般的操作系统都有裁剪、配置功能,而这些裁剪及配置都是通过一个文件来完成的,基本都是通过宏定义来完成对系统的配置和裁剪。
从freertos源码的DEMO中M4F工程中直接拷贝过来。

2.编译报错:“Error: L6200E: Symbol SVC_Handler multiply defined (by port.o and n32g45x_it.o).”
image
SVC_Handler重复定义。删除n32g45x_it.c中的SVC_Handler。

3.编译报错:“Error: L6406E: No space in execution regions with .ANY selector matching heap_4.o(.bss).”
image
RAM溢出的报错,所以需要根据自身实际情况修改。修改FreeRTOSConfig.h文件中的configTOTAL_HEAP_SIZE参数
image

4.编译报错:
image
FreeRTOSConfig.h 中开启了这些钩子函数,但是却没有定义导致的。在 FreeRTOSConfig.h 中关闭这些钩子函数即可,即将相应的宏定义改为 0。
image

四、修改Delay.c文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "NZ_Delay.h"
#include "FreeRTOS.h"
#include "task.h" 

/**
 * SysTick->LOAD为24位寄存器,所以,最大延时为:
 * nms<=(0xffffff/SYSCLK)*1000
 * SYSCLK单位为Hz,nms单位为ms
 * 对108M条件下,nms<=155
 */
//static u8   max_ms = 155;
//static u32  fac_us = 0;  //us延时倍乘数      
//static u32  fac_ms = 0;  //ms延时倍乘数

extern void xPortSysTickHandler(void);
void SysTick_Handler(void)

    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
        xPortSysTickHandler(); 
    }
}

/**
 * @brief 初始化延迟函数
 * @note  SYSTICK的时钟固定为HCLK时钟
 */
static u32  fac_us = 0;  //us延时倍乘数      
static u32  fac_ms = 0;  //ms延时倍乘数
void NZ_Delay_init(void)
{
 u32 reload;

 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟HCLK
 fac_us = (SystemCoreClock / (1000000));     //为系统时钟

 reload = (SystemCoreClock / 1000000);      //每秒钟的计数次数 单位为M 
 reload *= (1000000 / configTICK_RATE_HZ);       //根据configTICK_RATE_HZ设定溢出时间
 fac_ms = (1000 / configTICK_RATE_HZ);        //代表OS可以延时的最少单位    

 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;     //开启SYSTICK中断
 SysTick->LOAD=reload;                  //每1/configTICK_RATE_HZ断一次 
 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;     //开启SYSTICK   
}


/**
 * @brief us级别延时函数
 * @param nus:需要延时的微秒数
 * @note  如果延时的时间到了毫秒级别,则用NZ_Delay_xms实现
 */
void NZ_Delay_us(u32 nus)
{
  u32 ticks;
  u32 told,tnow,tcnt = 0;
  u32 reload = SysTick->LOAD;    //LOAD的值       
  ticks = nus*fac_us;       //需要的节拍数 
  told  = SysTick->VAL;          //刚进入时的计数器值
  while(1)
  {
    tnow = SysTick->VAL; 
    if(tnow != told)
    {     
      if(tnow<told)   //这里注意一下SYSTICK是一个递减的计数器就可以了
       tcnt += told-tnow; 
      else 
       tcnt += reload-tnow+told;    
      
      told = tnow;
      if(tcnt >= ticks) //时间超过/等于要延迟的时间,则退出
       break;   
    }  
  };
}

void NZ_Delay_ms(u32 nms)
{
  if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) //系统已经运行
  {  
    if(nms >= fac_ms)       //延时的时间大于OS的最少时间周期 
    { 
      vTaskDelay(nms / fac_ms);    //FreeRTOS延时
    }
    
    nms %= fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时    
  }
  NZ_Delay_us((u32)(nms*1000));    //普通方式延时    
}

/**
 * @brief ms级别延时函数
 * @param nms:需要延时的微秒数
 */
void NZ_Delay_xms(u32 nms)
{
  u32 i;
  for(i=0;i<nms;i++) NZ_Delay_us(1000);  
}

编译报错:“Error: L6200E: Symbol SysTick_Handler multiply defined (by nz_delay.o and n32g45x_it.o).”
image
SysTick_Handler重复定义。删除n32g45X_it.c中的SysTick_Handler。

到这里算是已经移稙完成。
下面做简单的验证。
在main.c函数添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "main.h"
#include "NZ_Delay.h"
#include "FreeRTOS.h"
#include "task.h"

//任务优先级
#define START_TASK_PRIO  1
//任务堆栈大小 
#define START_STK_SIZE   128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define LED0_TASK_PRIO  2
//任务堆栈大小 
#define LED0_STK_SIZE   50  
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);


//任务优先级
#define FLOAT_TASK_PRIO  4
//任务堆栈大小 
#define FLOAT_STK_SIZE   128
//任务句柄
TaskHandle_t FLOATTask_Handler;
//任务函数
void float_task(void *pvParameters);

int main(void)
{
 GPIO_InitType  GPIO_InitStructure;
 RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
  /** 配置GPIO */
 GPIO_InitStructure.Pin        = GPIO_PIN_8;
 GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

 //创建开始任务
    xTaskCreate((TaskFunction_t )start_task,      //任务函数
                (const char*    )"start_task",    //任务名称
                (uint16_t       )START_STK_SIZE,  //任务堆栈大小
                (void*          )NULL,             //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,   //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}


//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建LED0任务
    xTaskCreate((TaskFunction_t )led0_task,      
                (const char*    )"led0_task",    
                (uint16_t       )LED0_STK_SIZE, 
                (void*          )NULL,    
                (UBaseType_t    )LED0_TASK_PRIO, 
                (TaskHandle_t*  )&LED0Task_Handler);   
      
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//LED0任务函数 
void led0_task(void *pvParameters)
{
    while(1)
    {
        GPIOA->POD ^= GPIO_PIN_8;
        vTaskDelay(1000);
    }
}   

现象为PA8的LED灯闪烁。

本站由 提供部署服务