立创CW32F030C8T6移植FreeRTOS

立创CW32F030C8T6移植FreeRTOS


前言

最近嘉立创做活动低价买了一个CW32的最小系统,心血来潮打算尝试移植FreeRTOS,以此来提高我的单片机水平,另外感谢野火的开源精神,我从野火的《FreeRTOS 内核实现与应用开发实战指南》中了解到了一些具体技术细节才最终成功移植,代码链接会附在文末。


一、下载FreeRTOS源码

首先从代码托管网站上https://sourceforge.net/projects/freertos/files/FreeRTOS/下载最新的FreeRTOS,下载的是v10.4.1版本。
在这里插入图片描述
下载解压后的是这些东西。
在这里插入图片描述
其中FreeRTOS是需要移植的操作系统。而FreeRTOS-Plus内我感觉是些附加的其他库,而且大部分好像是收费的,所以我们仅需要用到FreeRTOS这个文件夹即可。

二、移植FreeRTOS

首先需要找一套可以用来移植的源码,我从立创开发板https://wiki.lckfb.com/zh-hans/dwx-cw32f030c8t6/。这个网页的百度云盘中找到一份空白工程模板下载后。
在这里插入图片描述
这就是代码的文件夹了。
在这里插入图片描述
在其中创建一个FreeRTOS的文件夹,用于存放移植的代码。
在这里插入图片描述
并且在其中创建三个文件夹。
在这里插入图片描述分别用来移植以下代码。
在这里插入图片描述
将Source目录下的代码复制到src中,include也直接复制即可,注意portable仅需要MemMang文件夹和RVDS的ARM_CM0(因为CW32F030C8T6是M0的内核)。在这里插入图片描述
另外复制一份Demo中的FreeRTOSConfig并存入APP文件夹内,我复制的是stm32f103的。
在这里插入图片描述
后续我们就可以打开keil,将代码路径等存储进去了。
在这里插入图片描述

另外需要配置xPortSysTickHandler这个函数,具体位置如下。

extern void xPortSysTickHandler(void);
void SysTick_Handler(void)
{
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
      {
    #endif  /* INCLUDE_xTaskGetSchedulerState */  
        xPortSysTickHandler();
    #if (INCLUDE_xTaskGetSchedulerState  == 1 )
      }
    #endif  /* INCLUDE_xTaskGetSchedulerState */
}

在这里插入图片描述

然后从野火那里抄点main函数代码即可。

#include "board.h"
#include "stdio.h"
#include "bsp_uart.h"
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"


/**************************** 任务句柄 ********************************/
/* 
 * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄
 * 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么
 * 这个句柄可以为NULL。
 */
 /* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED1任务句柄 */
static TaskHandle_t LED1_Task_Handle = NULL;
/* LED2任务句柄 */
static TaskHandle_t LED2_Task_Handle = NULL;

/*
*************************************************************************
*                             函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */

static void LED1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void LED2_Task(void* pvParameters);/* LED2_Task任务实现 */

static void BSP_Init(void);/* 用于初始化板载相关资源 */


int32_t main(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  BSP_Init();
	printf("你好!\r\n");
	   /* 创建AppTaskCreate任务 */
  xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */
                        (const char*    )"AppTaskCreate",/* 任务名字 */
                        (uint16_t       )64,  /* 任务栈大小 */
                        (void*          )NULL,/* 任务入口函数参数 */
                        (UBaseType_t    )1, /* 任务的优先级 */
                        (TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针 */ 
												
	
  /* 启动任务调度 */           
  if(pdPASS == xReturn)
    vTaskStartScheduler();   /* 启动任务,开启调度 */
  else
    return -1;  
  
  while(1);   /* 正常不会执行到这里 */   
	
}



/***********************************************************************
  * @ 函数名  : AppTaskCreate
  * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
  * @ 参数    : 无  
  * @ 返回值  : 无
  **********************************************************************/
static void AppTaskCreate(void)
{
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  
  taskENTER_CRITICAL();           //进入临界区
  
  /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */
                        (const char*    )"LED1_Task",/* 任务名字 */
                        (uint16_t       )64,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )2,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED1_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    printf("创建LED1_Task任务成功!\r\n");
  
	/* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */
                        (const char*    )"LED2_Task",/* 任务名字 */
                        (uint16_t       )64,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )3,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED2_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    printf("创建LED2_Task任务成功!\r\n");
  
  vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
  
  taskEXIT_CRITICAL();            //退出临界区
}



/**********************************************************************
  * @ 函数名  : LED_Task
  * @ 功能说明: LED_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LED1_Task(void* parameter)
{	
    while (1)
    {
		  	// 高电平
	    	GPIO_WritePin(CW_GPIOC, GPIO_PIN_13, GPIO_Pin_SET);
        vTaskDelay(500);   /* 延时500个tick */
        printf("LED1_Task Running,LED1_ON\r\n");   
	    	// 低电平
	    	GPIO_WritePin(CW_GPIOC, GPIO_PIN_13, GPIO_Pin_RESET);   
        vTaskDelay(500);   /* 延时500个tick */		 		
        printf("LED1_Task Running,LED1_OFF\r\n");
    }
}

/**********************************************************************
  * @ 函数名  : LED_Task
  * @ 功能说明: LED_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LED2_Task(void* parameter)
{	
    while (1)
    {
	    	GPIO_WritePin(CW_GPIOC, GPIO_PIN_14, GPIO_Pin_SET);
        vTaskDelay(500);   /* 延时500个tick */
        printf("LED2_Task Running,LED2_ON\r\n");
        
	    	GPIO_WritePin(CW_GPIOC, GPIO_PIN_14, GPIO_Pin_RESET); 
        vTaskDelay(500);   /* 延时500个tick */		 		
        printf("LED2_Task Running,LED2_OFF\r\n");
    }
}




static void BSP_Init(void)
{
	board_init();	// 开发板初始化
	
	uart1_init(115200);	// 串口1波特率115200
	
	GPIO_InitTypeDef	GPIO_InitStruct; // GPIO初始化结构体
	
	__RCC_GPIOC_CLK_ENABLE();	// 使能GPIO时钟
	
    GPIO_InitStruct.Pins = GPIO_PIN_13|GPIO_PIN_14;				// GPIO引脚
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;		// 推挽输出
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;		// 输出速度高
    GPIO_Init(CW_GPIOC, &GPIO_InitStruct);			// 初始化
	
  
}






三、解决问题

在移植的过程中遇到数个问题,解决方法如下。

问题1:直接移植报错

.\OBJ\LED.axf: Error: L6218E: Undefined symbol xTaskGetCurrentTaskHandle (referred from stream_buffer.o).
问题主要在于xTaskGetCurrentTaskHandle 这个函数有个宏,把他打开就行。

问题2:主频问题

直接复制过来之后stm32f103的主频其实是72M,所以我们需要改成CW32的64M。
在这里插入图片描述

问题3:RAM报错

Error: L6406E: No space in execution regions with .ANY selector matching queue.o(.bss). 这个报错是因为移植的stm32f103它的RAM比CW32大的多,从其手册可知RAM是8KB。
在这里插入图片描述
故需要将HEAP_SIZE改小,我改成了5*1024。
在这里插入图片描述

问题4:上电卡死在初始化任务上

首先结论是我没有在FreeRTOSConfig中配置下面这个东西。
在这里插入图片描述
最开始没配置会卡死在startup中的PendSV这个中断函数上,我加上上面的代码就好了,应该是会用到这两个中断。
在这里插入图片描述

四、现象展示及代码

最终结果如下,LED灯闪烁就不展示了,因为其实也就一个灯在闪而已。
在这里插入图片描述
大概就是这些了,后续打算继续利用cw32做一些东西,也会发在CSDN上,可以私聊我一起学习共同进步。
代码链接如下:
通过百度网盘分享的文件:cw32移植freertos.rar
链接:https://pan.baidu.com/s/1AUHh22onuiauFJv6K06S5g?pwd=87w7
提取码:87w7

  • 20
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您好,使用立创EDA画STM32F103C8T6,您可以按照以下步骤进行操作: 1. 打开立创EDA软件,选择新建工程,选择STM32F103C8T6芯片型号。 2. 在工程中添加所需的元件,例如晶振、电容、电阻等。 3. 连接元件,按照STM32F103C8T6的引脚图进行连接。 4. 进行电路图的布局和连线,确保电路图的正确性。 5. 进行PCB布局,将电路图转换为PCB布局图。 6. 进行PCB连线,确保PCB布局的正确性。 7. 导出Gerber文件,进行PCB制板。 以上是使用立创EDA画STM32F103C8T6的基本步骤,希望对您有所帮助。 ### 回答2: 首先,立创EDA是一款非常实用的电路设计软件,它为STM32F103C8T6这样的单片机设计提供了非常好的支持。使用立创EDA画STM32F103C8T6,需要进行以下步骤: 1. 在电路设计中,要根据STM32F103C8T6的规格书进行针脚的连接。首先,在立创EDA的元器件库中找到STM32F103C8T6,把它拖动到电路图中。这样,STM32F103C8T6就会以缩略图的形式呈现在电路图中。 2. 在STM32F103C8T6上添加必要的外围电路元件,如晶振、稳压器、电容和推挽电阻等。需要注意的是,在添加外围电路元件时,要了解ESTM32F103C8T6芯片的规格书和参考设计。 3. 连接所有元器件和导线。连接时一定要根据芯片规格书和参考设计,以确保电路工作的可靠性。在连接时可以使用EDA自带的自动走线功能,也可以手动连接导线。 4. 进行电路仿真。在完成电路设计后,使用立创EDA自带的仿真功能进行仿真。仿真可模拟器件在电路工作正常时的性能和特性,以便及时发现问题并解决。针对STM32F103C8T6的电路设计可以进行信号仿真和电源仿真。 5. 导出PCB图。当电路设计及其仿真都通过后,可以将电路图导出到PCB绘图软件中进行PCB设计。在完成PCB设计后,再次进行电路仿真以验证PCB设计的正确性。 总而言之,使用立创EDA对STM32F103C8T6进行电路设计,需要对芯片的规格书和参考设计有非常清晰的理解,并严格按照规格书和参考设计进行设计和仿真。同时,要熟练掌握立创EDA的使用方法,以便快速高效地完成电路设计任务。 ### 回答3: 立创EDA是一款非常实用的电路设计软件,可以帮助工程师快速完成各种电路设计和仿真工作,其中也包括了对STM32F103C8T6芯片的支持,下面我们就来讲一下如何使用立创EDA画STM32F103C8T6。 首先,我们需要先下载和安装立创EDA软件。安装完成后,我们需要导入STM32F103C8T6芯片的库文件,以便在设计中使用。在立创EDA的菜单栏中找到“元器件库管理”选项,然后选择STM32F1系列芯片库文件进行导入。 导入完成后,在立创EDA的主界面上方,可以看到“元器件库”按钮,点击后会弹出库文件列表,选择我们导入的STM32F1系列芯片库就可以看到其中包含了STM32F103C8T6芯片。 在设计中,需要用到的元器件可以通过拖动和放置的方式添加进电路图中。对于STM32F103C8T6芯片,我们需要先添加其封装为LQFP48或LQFP64的芯片元件,随后根据需要选择添加其他外围元器件,例如晶振、电容、电阻等等。 添加完元器件后,我们需要进行电路连接,将各个元器件之间的引脚进行连线,建立电路图的逻辑关系。可以通过直接拖动线条的方式或者使用连接工具进行连线。 完成电路连接后,我们需要进行仿真操作,检查电路图的正确性和性能。立创EDA内置了丰富的仿真工具,可以直接在软件中进行电路的测试和调试。使用仿真工具时,需要先进行仿真设置,定义仿真的参数、时钟频率等等。 最后,完成电路设计后,我们需要将其导出为PCB文件,并进行布线、元器件放置和生成制板文件等步骤,最终完成整个电路的设计和制造。 以上就是使用立创EDA画STM32F103C8T6的基本步骤,需要注意的是,需要参考官方文档和芯片资料手册,了解STM32F103C8T6芯片的规格和特性,才能保证电路设计的正确性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值