STemWin裸机移植FreeRTOS操作系统

        本文在正点原子STemWin裸机例程上对FreeRTOS进行移植。由于正点原子的教程是基于UCOSIII操作系统的,此文补充一下FreeRTOS移植到STemWin的方法,便于学习FreeRTOS的同学使用。本教程的硬件平台是正点原子的STM32战舰开发板,作者ustc修竹。

一、移植要准备的工作 

        由于本移植过程是在 STemWin不带操作系统的基础上进行的,所以我们先介绍一下子已有的文件,并且补充哪些需要修改及添加进来。

图1.1

 图1.2

        如上图所示,左边图1.1是已经移植好的裸机模板,我们在此基础上移植,右边图1.2是移植后的模板。

        首先是SYSTEM文件夹,这个是为UCOSIII编写的,这个原文件替换需要替换。具体文件位置打开正点原子的资料:4.程序源码->3.扩展例程->5.FreeRTOS例程,从例程中随便找一个SYSTEM文件夹复制然后替换掉裸机模板例程中的SYSTEM例程。不需要改动。

        其次是模板例程中的EMWIN_Config里面的GUI_X.c得替换成GUI_X_FreeRTOS.c,这个文件的位置在STemWin文件夹的OS文件夹中,做过裸机移植的应该知道。将EMWIN_LIB中的STemWin526_CM3_keil.lib文件删除,添加STemWin526_CM3_OS_keil.lib到EMWIN_LIB中,这个文件的位置在STemWin文件夹的Lib文件夹中,做过裸机移植的应该也知道。

        在例程模板的USER里面需要添加一个FreeRTOSConfig.h,这个文件的具体位置:4.程序源码->3.扩展例程->5.FreeRTOS例程,从例程中随便找一个,复制到模板文件里面然后添加进USER。这个可以直接用,但是要检查FreeRTOSConfig.h中有没有打开互斥信号量,计数信号量功能,如果没有打开需要打开一下,不然会报错。

        在项目里新建两个文件夹:FreeRTOS/src,FreeRTOS/port。这两个文件用来放FreeRTOS的源代码,是移植RTOS的文件。

二、STemWin文件的修改

        主要需要修改两个文件:GUIConfig.h与GUI_X_FreeRTOS.c。

1、GUIConfig.h的修改

         加了操作系统以后,主要是操作系统的功能得开启。

        修改前:#define GUI_OS                    (0)  // 不使用操作系统

        修改后:#define GUI_OS                    (1)  // 使用操作系统

        参考正点原子的UCOSIII移植教程,貌似还需要定义可以调用STemWin的任务最大数目,这个本人没有定义也可以正常使用,如果觉得需要的自己设置,感兴趣的可以看一下正点原子这方面的内容。

2、GUI_X_FreeRTOS.c的修改

        该文件主要是配置操作系统的接口,STemWin使用这些接口管理系统资源。其中与裸机不同的是,裸机主要采用的是简单的延时,使用RTOS以后要使用阻塞延时。该文件代码如下(相关的信息已在代码中标注):

#include "GUI.h"
/* FreeRTOS头文件*/
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/*********************************************************************
*
* Global data
*/
static xSemaphoreHandle xQueueMutex = NULL;    //互斥信号量
static xSemaphoreHandle xSemaTxDone = NULL;    //二值信号量
 
/*********************************************************************
*
* Timing:
* GUI_X_GetTime()
* GUI_X_Delay(int)

Some timing dependent routines require a GetTime
and delay function. Default time unit (tick), normally is
1 ms.
*/
int GUI_X_GetTime(void)
{
	return ((int) xTaskGetTickCount());
}

void GUI_X_Delay(int ms)        //延时ms
{
  vTaskDelay( ms );
}

/*********************************************************************
*
* GUI_X_Init()
*
* Note:
* GUI_X_Init() is called from GUI_Init is a possibility to init
* some hardware which needs to be up and running before the GUI.
* If not required, leave this routine blank.
*/

void GUI_X_Init(void) {
}

/*********************************************************************
*
* GUI_X_ExecIdle
*
* Note:
* Called if WM is in idle state
*/

void GUI_X_ExecIdle(void) {
	GUI_X_Delay(1);                //延时1ms
}

/*********************************************************************
*
* Multitasking:
*
* GUI_X_InitOS()
* GUI_X_GetTaskId()
* GUI_X_Lock()
* GUI_X_Unlock()
*
* Note:
* The following routines are required only if emWin is used in a
* true multi task environment, which means you have more than one
* thread using the emWin API.
* In this case the
* #define GUI_OS 1
* needs to be in GUIConf.h
*/

/* Init OS */
void GUI_X_InitOS(void)
{ 
  /* 创建互斥信号量 */
  xQueueMutex = xSemaphoreCreateMutex();
  configASSERT (xQueueMutex != NULL);
  /* 创建二值信号量 */
  vSemaphoreCreateBinary( xSemaTxDone );
  configASSERT ( xSemaTxDone != NULL );
}

void GUI_X_Unlock(void)        //释放互斥量
{
  xSemaphoreGive(xQueueMutex);
}

void GUI_X_Lock(void)        //锁互斥量
{
  if(xQueueMutex == NULL)
  {
    GUI_X_InitOS();
  }
	/* 获取互斥量 */
  xSemaphoreTake(xQueueMutex,   /* 信号量句柄 */
								 portMAX_DELAY);/* 阻塞等待 */
}

/* 获取任务句柄 */
U32 GUI_X_GetTaskId(void) 
{ 
  return ((U32) xTaskGetCurrentTaskHandle());
}

void GUI_X_WaitEvent (void) 
{
  /* 获取信号量 */
  while(xSemaphoreTake(xSemaTxDone,              /* 信号量句柄 */
								       portMAX_DELAY) != pdTRUE);/* 阻塞等待 */
}

void GUI_X_SignalEvent (void) 
{
  /* 给出信号量 */
  xSemaphoreGive(xSemaTxDone);
}

/*********************************************************************
*
* Logging: OS dependent

Note:
Logging is used in higher debug levels only. The typical target
build does not use logging and does therefor not require any of
the logging routines below. For a release build without logging
the routines below may be eliminated to save some space.
(If the linker is not function aware and eliminates unreferenced
functions automatically)

*/
//下面三个函数主要是用来调试、输出错误信息的,用的不多
void GUI_X_Log (const char *s) { }
void GUI_X_Warn (const char *s) { }
void GUI_X_ErrorOut(const char *s) { }

/*************************** End of file ****************************/

        至此,关于STemWin的相关文件修改完成,后面是关于FreeRTOS的修改。

三、FreeRTOS的移植

        关于这一部分,可以参考野火关于FreeRTOS移植的教程,本人对于FreeRTOS的学习是参考野火的教程完成的。开头已经在例程模板中建了两个文件夹:FreeRTOS/src,FreeRTOS/port。我们要在这两个文件夹中添加需要移植的文件如下:

图3.1

        熟悉FreeRTOS移植的用户对此应该很熟悉,首先就直接将野火的FreeRTOS教程书籍配套程序的第13个例程移植工程模板中的FreeRTOS文件夹复制到我们的裸机工程模板中。作者:ustc修竹。然后我们在例程中开始添加文件,其中上图3.1中FreeRTOS/src里面的六个文件,对应的我们添加FreeRTOS里面的六个文件,六个文件的路径:FreeRTOS->src,把这六个文件添加好以后如图3.1所示。图3.1中FreeRTOS/port的两个文件分别从不同的文件夹中选择添加的,heap_4.c文件位置:FreeRTOS->port->MenMang,这个文件夹中有五个内存管理文件,我们选择第四个;port.c文件位置:FreeRTOS->port->RVDS->ARM_CM3,从这个路径选择文件然后添加进去。至此我们所需要的文件添加完毕。在本文的开头部分添加的FreeRTOSConfig.h可以选择正点原子的也可以选择野火的,如果采用野火的头文件,则需要把bsp_usart.h修改为usart.h。

        这一块的内容不管是通过野火还是正点原子又或者是其他途径学习FreeRTOS的,大致得方法都差不多。

        关于系统时钟的开启,由于我们用得是正点原子得delay.c文件,所以我们要stm32f10x_it.c文件得部分代码修改一下。把三个中断在这个文件注释掉:SVC_Handler,PendSV_Handler,SysTick_Handler。其中前两个函数FreeRTOS已经为用户实现了,而正点原子的在delay.c中实现了第三个函数,所以全部注释即可,如图3.2所示:

 图3.2

        delay.c文件中实现系统中断的代码如下:

//systick中断服务函数
void SysTick_Handler(void)
{	
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//ϵͳÒѾ­ÔËÐÐ
    {
        xPortSysTickHandler();	
    }
}

         其余的像FreeRTOSConfig.h中的配置前文也说过,要将互斥信号量,计数信号量功能等功能打开。

四、关于main.c函数的修改

        因为换了操作系统,所以main.c函数需要修改的地方较多,就不单独解释了,相关的信息已经在代码中详细标注了,这对于已经完成FreeRTOS学习的用户来说不难理解。

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "ILI93xx.h"
#include "usart.h"	 
#include "24cxx.h"
#include "flash.h"
#include "touch.h"
#include "sram.h"
#include "malloc.h"
#include "GUI.h"
#include "GUIDemo.h"
#include "WM.h"
#include "DIALOG.h"
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"

static void AppTaskCreate(void);/* 用于创建任务 */
static void LED0_Task(void* pvParameters);/* LED1_Task任务实现 */
static void touch_task(void* pvParameters);/* touch_task任务实现*/
static void emwindemo_task(void* pvParameters);/* emwindemo_task任务实现 */

/* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED0任务句柄 */
static TaskHandle_t LED0_Task_Handle = NULL;
/* touch_task任务句柄 */
static TaskHandle_t touch_task_Handle = NULL;
/*emwindemo_task任务句柄 */
static TaskHandle_t emwindemo_task_Handle = NULL;

int main(void)
{	 
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */	
	delay_init();	    	//延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); 	//设置中断分组
	uart_init(115200);	 	//串口初始化115200
 	LED_Init();			    //LED端口初始化
	TFTLCD_Init();			//LCD初始化	
	KEY_Init();	 			//按键初始化
 	TP_Init();				//触摸屏初始化
	FSMC_SRAM_Init();		//SRAM初始化
//	TIM3_Int_Init(999,71);	//1KHZ定时器,这是裸机用的 
//	TIM6_Int_Init(999,719);	//10ms中断,这是裸机用的 

	my_mem_init(SRAMIN); 		//初始化内部内存池
	my_mem_init(SRAMEX);  		//初始化外部内存池
	
	  /* 创建AppTaskCreate任务 */
  xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,  /* 任务入口函数 */
                        (const char*    )"AppTaskCreate",/* 任务名字 */
                        (uint16_t       )256,  /* 任务栈大小 */
                        (void*          )NULL,/* 任务入口函数参数 */
                        (UBaseType_t    )6, /* 任务的优先级 */
                        (TaskHandle_t*  )&AppTaskCreate_Handle);/* 任务控制块指针 */ 
  /* 启动任务调度 */           
  if(pdPASS == xReturn)
    vTaskStartScheduler();   /* 启动任务,开启调度 */
  else
    return -1; 
//ustc修竹
	while(1);
}

static void AppTaskCreate(void)
{
  BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
  
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC,ENABLE);//开启CRC时钟
  WM_SetCreateFlags(WM_CF_MEMDEV);//使用自动存储设备
  GUI_Init();  			//STemWin初始化
	
  taskENTER_CRITICAL();           //进入临界区
  
  /* 创建LED0_Task */
  xReturn = xTaskCreate((TaskFunction_t )LED0_Task, /* 任务入口函数 */
                        (const char*    )"LED0_Task",/* 任务名字 */
                        (uint16_t       )128,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )4,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED0_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
  
	/* 创建touch_task */
  xReturn = xTaskCreate((TaskFunction_t )touch_task, /* 任务入口函数 */
                        (const char*    )"touch_task",/* 任务名字 */
                        (uint16_t       )256,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )5,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&touch_task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
	
	/* 创建emwindemo_task */
  xReturn = xTaskCreate((TaskFunction_t )emwindemo_task, /* 任务入口函数 */
                        (const char*    )"emwindemo_task",/* 任务名字 */
                        (uint16_t       )2048,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )3,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&emwindemo_task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
  
  vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
  
  taskEXIT_CRITICAL();            //退出临界区
//ustc修竹
}

//EMWINDEMO任务
void emwindemo_task(void *p_arg)
{
	while(1)
	{
		GUIDEMO_Main(); 
	}
}

//TOUCH任务
void touch_task(void *p_arg)
{
	while(1)
	{
		GUI_TOUCH_Exec();	
		vTaskDelay(5);        //延时5ms
	}
}

static void LED0_Task(void* parameter)
{	
    while (1)
    {
        LED0 = !LED0;
        vTaskDelay(500);   /* 延时500个tick */
    }
}


       至此,可以对该工程进行编译了。但是值得注意的是,在编译后系统可能会提示堆栈不够用的情况然后报错,这个时候我们需要修改一个头文件的内容,该头文件是malloc.h,找到该头文件后对其修改内容如下:

 图4.1

         malloc.h中第31行,一般默认是40*1024,我们需要修改一下,一般根据经验修改成20*1024即可正常编译。最后的编译结果如图4.2:

图4.2 

        我们希望跑例程,我们在main.c中的emwindemo_task任务里面跑我们想跑的例程,同时在例程的EMWIN_Demo添加我们要跑的文件,如图4.3所示:

图4.3 

        因为我们是在正点原子的裸机模板上移植的RTOS,所以例程在模板中已经添加了,直接复制上面的main.c的代码即可运行例程。

        最后,如果还有报错,请考虑头文件有没有添加完整,关于FreeRTOS的头文件路径不能少了,相关的路径如图4.4所示:

图4.4 

        将程序烧录进开发板以后,应该与正点原子的UCOSIII系统所展示的结果是一样的。至此移植完成。

五、补充内容(可以不看,与移植操作系统无关了)

        正点原子用的版本是5.26,相比于野火用的5.44版本来说,有很多功能都没有。如果想在正点原子的板子上跑5.44版本的emWin,可以直接把STemWin526_CM3_OS_keil.lib从例程模板中删掉,换成野火的STemWin_CM3_OS_wc16_ARGB.a。但是直接编译以后会报错,需要完成下面两步操作才能正常编译:

        1、右键STemWin_CM3_OS_wc16_ARGB.a文件options,将文件类型从"File Type" 改至 "Library file";

        2、在Target中把USE MicroLIB勾选上。

 

       在完成以上两步操作以后,重新编译即可使用5.44版本的一些功能了。但是使用的时候编译会出现警告,一般是警告部分函数未在头文件定义。下面是原因的解释:

 图5.1

        如图5.1所示,这是笔者本人自己编写的一段代码,主要在文本控件里面实现一个数值显示功能。如果使用第170行的TEXT_SetDec函数,会发现可以编译而且烧录了可以使用,但是编译会出现警告,原因在于TEXT.h中并没有声明这个函数,所以在TEXT.h中声明一下这个函数,编译以后警告就会消失。

图5.2 

 图5.3

       图5.2是5.26版本的TEXT.h的声明内容,在其中加入TEXT_SetDec函数的声明如图5.3报错即可解决。当然,也可以直接用野火的5.44版本的头文件,但是如果全都用野火的,在正点原子的模板上又可能带来新的问题,所以本人倾向于需要用到什么功能就去查一下手册然后5.26没有的功能,就去头文件声明一下子,这样子省去了重新移植5.44版本的麻烦,大多数需求5.26版本的stemwin已经可以完成了。至于本人为什么这样子做,因为本人用的是正点原子的开发板,如果重新修改液晶屏驱动,笔者觉得比较麻烦,又或者重新移植5.44版本的emwin笔者也觉得麻烦。

        以上就是关于FreeRTOS移植的方法以及笔者个人的理解,如有疏漏,欢迎评论留言。

DSP和标准外设库: 资源编号 : STSW-STM32065 资源名称 : STM32F4 DSP and standard peripherals library 文件名 : stm32_f105-07_f2_f4_usb-host-device_lib.zip 下载地址 : http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF257901# USB库: 资源编号 : STSW-STM32046 资源名称 : STM32F105/7, STM32F2 and STM32F4 USB on-the-go Host and device library (UM1021) 文件名 : stm32_f105-07_f2_f4_usb-host-device_lib.zip 下载地址 : http://www.st.com/web/en/catalog/tools/PF257882 ETH以太网库: 资源编号 : STSW-STM32046 资源名称 : LwIP TCP/IP stack demonstration for STM32F4x7 microcontrollers (AN3966) 文件名 : stsw-stm32070.zip 下载地址 : http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1743/PF257906 【CMSIS】 Cortex微控制器软件接口程序(Cortex Microcontroller Software Interface Standard (CMSIS). ) 版本: V4.2 发布日期: 31. July 2014 【STM32F4xx_StdPeriph_Driver】 STM32F40x系列CPU标准外设驱动程序 版本: V1.5.0 发布日期: 06-March-2015 【STM32_USB_OTG_Driver】 STM32F105/7xx, STM32F2xx and STM32F4xx USB Device Library 版本: V2.1.0 发布日期: 2012-03-19 【STM32_USB_Device_Library】 STM32F105/7xx, STM32F2xx and STM32F4xx USB Device Library 版本: V1.1.0 发布日期: 2012-03-05 【STM32_USB_HOST_Library】 STM32F105/7xx, STM32F2xx and STM32F4xx USB Host Library 版本: V2.1.0 发布日期: 2012-03-19 【STM32F4x7_ETH_Driver】 STM32F4x7 Eth Library 版本: V1.1.0 发布日期: 31-July-2013 ********************************************************************************************************* * * 版 本 : V1.0 * 说 明 : 本实验主要实现FreeRTOS+STemWin+FatFS+USB Host综合 * 实验目的: * 1. 学习FreeRTOS+STemWin+FatFS+USB Host综合 * 2. 这里的USB Host主要实现U盘相关处理,支持U盘热插拔。 * 用户可以根据需要在usb_usr.c文件中的插入检测函数: * USBH_USR_Configuration_DescAvailable或者函数USBH_USR_Init函数加入插入标志 * 拔出检测函数: * USBH_USR_DeviceDisconnected * 实验内容: * 1. 按下按键K1可以通过串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1) * ================================================= * 任务名 任务状态 优先级 剩余栈 任务序号 * vTaskUserIF R 2 272 2 * vTaskGUI R 1 657 1 * IDLE R 0 113 6 * vTaskMsgPro B 4 1957 4 * vTaskLED B 3 483 3 * vTaskStart B 5 489 5 * * * 任务名 运行计数 使用率 * vTaskUserIF 5583 1% * vTaskGUI 10782 2% * IDLE 355589 91% * vTaskLED 0 <1% * vTaskMsgPro 16770 4% * vTaskStart 17 <1% * 串口软件建议使用SecureCRT(V6光盘里面有此软件)查看打印信息。 * 各个任务实现的功能如下: * vTaskGUI 任务: emWin任务 * vTaskTaskUserIF 任务: 接口消息处理 * vTaskLED 任务: LED闪烁 * vTaskMsgPro 任务: U盘中文件处理和浏览 * vTaskStart 任务: 启动任务,也就是最高优先级任务,这里实现按键扫描和触摸检测 * 2. 任务运行状态的定义如下,跟上面串口打印字母B, R, D, S对应: * #define tskBLOCKED_CHAR ( 'B' ) 阻塞 * #define tskREADY_CHAR ( 'R' ) 就绪 * #define tskDELETED_CHAR ( 'D' ) 删除 * #define tskSUSPENDED_CHAR ( 'S' ) 挂起 * 3. 本实验的USB Host主要是对U盘的操作,通过电脑端的串口软件SecureCRT软件, * 给板子发送相关命令实现操作,具体实现在demo_fatfs文件里面。 * printf("请选择操作命令:\r\n"); * printf("1 - 显示根目录下的文件列表\r\n"); * printf("2 - 创建一个新文件armfly.txt\r\n"); * printf("3 - 读armfly.txt文件的内容\r\n"); * printf("4 - 创建目录\r\n"); * printf("5 - 删除文件和目录\r\n"); * printf("6 - 读写文件速度测试\r\n"); * printf("7 - 挂载U盘\r\n"); * printf("8 - 卸载U盘\r\n"); * 注意事项: * 1. 本实验推荐使用串口软件SecureCRT,要不串口打印效果不整齐。此软件在 * V5开发板光盘里面有。 * 2. 务必将编辑器的缩进参数和TAB设置为4来阅读本文件,要不代码显示不整齐。 * * 修改记录 : * 版本号 日期 作者 说明 * V1.0 2016-03-15 Eric2013 1. ST固件库到V1.5.0版本 * 2. BSP驱动包V1.2 * 3. FreeRTOS版本V8.2.3 * 4. STemWin版本V5.28 * 5. FatFS版本V0.11a * * Copyright (C), 2016-2020, 安富莱电子 www.armfly.com * *********************************************************************************************************
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值