热度 21
2013-10-10 00:42
5367 次阅读|
0 个评论
移植过程基于 STM32 标准外设库,在库内提供的例程基础上,将 FreeRTOS 移植进去。 相关资源: 1.STM32 标准外设库 V3.5.0 ( 直接下载地址 http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stsw-stm32054.zip )。 2.FreeRTOS V7.5.2 ( 直接下载地址 http://jaist.dl.sourceforge.net/project/freertos/FreeRTOS/V7.5.2/FreeRTOSV7.5.2.zip )。 3.FreeRTOS Real Time Kernel (RTOS) 最新版本下载地址( http://sourceforge.net/projects/freertos/files/ )。 4.STM32F10x standard peripheral library 最新相关信息地址( http://www.st.com/web/cn/catalog/tools/FM147/CL1794/SC961/SS1743/PF257890 )。 移植过程: 以下以 STM32F103VCT6 为例进行移植,其他型号类似。 解压 FreeRTOS,打开关于 STM32F103 的例程(Keil版本),目录“..\FreeRTOSV7.5.2\FreeRTOS\Demo\CORTEX_STM32F103_Keil”。 解压 STM32 标准外设库,进入工程模板目录“..\STM32F10x_StdPeriph_Lib_V3.5.0\Project”,复制“STM32F10x_StdPeriph_Template”并根据项目重命名。进入目录“..\STM32F10x_StdPeriph_Lib_V3.5.0\Project\ProjectRoot\MDK-ARM” 下打开工程文件,对应STM32F103VCT6,选择“STM3210E-EVAL”。 目录“..\STM32F10x_StdPeriph_Lib_V3.5.0\Project\ProjectRoot\” (以下用..\ProjectRoot\表示)下新建“FreeRTOS”文件夹,拷贝Source(直接copy FreeRTOS源码Source目录)、Common(直接copy FreeRTOS源码\demo\Common目录)到”..\ProjectRoot\FreeRTOS\”下。 在Source/portable目录下,保留RVDS和MemMang目录,其余删除。复制 FreeRTOS目录\Demo\CORTEX_STM32F103_Keil\FreeRTOSConfig.h 到 ..\ProjectRoot\ 下。 在 MDK-ARM 中进行设置: Target options -Device中,选择STM32F103VC。 Target options - C/C++ 中 Preprocessor Symbols 中 Include path 设定头文件路径: ..\ ..\..\..\Libraries\CMSIS\CM3\CoreSupport ..\..\..\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x ..\..\..\Libraries\STM32F10x_StdPeriph_Driver\inc ..\..\..\Utilities\STM32_EVAL ..\..\..\Utilities\STM32_EVAL\Common ..\..\..\Utilities\STM32_EVAL\STM3210E_EVAL ..\FreeRTOS\Source\include ..\FreeRTOS\Source\portable\RVDS\ARM_CM3 ..\FreeRTOS\Common\include 复制 Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm\startup_stm32f10x_hd.s 至 ..\ProjectRoot\ 。若使用其他容量器件,请自行选择对应的startup files。 参照 FreeRTOS 中的 STM32F10x.s 修改startup_stm32f10x_hd.s 在 __heap_limit 区段添加: IMPORT xPortPendSVHandler IMPORT xPortSysTickHandler IMPORT vPortSVCHandler ;IMPORT vUARTInterruptHandler ;IMPORT vTimer2IntHandler 后两个不要添加,因为这不是 FreeRTOS 核心代码,是他demo用到的。 __Vectors区段中断向量表,将SVCall Handler、PendSV_Handler、SysTick Handler更名,改由 RTOS 管理,这样 stm32f10x_it.c 就不会影响到这三个中断。后面相应的中断入口地址需要更改 DCD vPortSVCHandler ; SVCall Handler ... DCD xPortPendSVHandler ; PendSV Handler DCD xPortSysTickHandler ; SysTick Handler 两者还有一点小小的不同,复位时进入main函数之前的那段代码,新版本外设库的启动代码中,在进入main()函数之前执行函数SystemInit()初始化了时钟,这个根据目标板不同,注意此段代码。 使用修改后的 startup_stm32f10x_hd.s 替换MDK-ARM组下的同名文件。参照 FreeRTOS 例程在 STM32 的外设库例程中加入 FreeRTOS 组,并加入文件: tasks.c、list.c、queue.c、port.c、heap_2.c,截图如下。 至此,设定完成,修改 main.c 文件,内容如下。需根据使用的开发板修改相关外设设置。因为 FreeRTOS 使用 configTOTAL_HEAP_SIZE 为 0x4400,IRAM的 SIZE 需超过 0x4400(17K),所以选择STM32要注意RAM大小是否满足。 /* main.c */ /* Standard includes. */ #include stdio.h /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" #include "queue.h" #include "misc.h" /* Library includes. */ #include "stm32f10x_it.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" #include "stm32f10x_usart.h" #define LED0_ON() GPIO_ResetBits(GPIOA,GPIO_Pin_8); #define LED0_OFF() GPIO_SetBits(GPIOA,GPIO_Pin_8); #define LED0B() GPIOA-ODR ^= 0x0100; #define LED1_ON() GPIO_ResetBits(GPIOD,GPIO_Pin_2); #define LED1_OFF() GPIO_SetBits(GPIOD,GPIO_Pin_2); #define LED1B() GPIOD-ODR ^= 0x04; static void prvSetupHardware( void ); /* Two demo Tasks*/ static void vLEDTask( void *pvParameters ); static void vCOMMTask( void *pvParameters ); void Led_Init(void); void Comm_Init(void); int main( void ) { prvSetupHardware(); xTaskCreate( vLEDTask, ( signed portCHAR * ) "LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+3, NULL ); xTaskCreate( vCOMMTask, ( signed portCHAR * ) "COMM", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, NULL ); /* Start the scheduler. */ vTaskStartScheduler(); return 0; } /*-----------------------------------------------------------*/ void vLEDTask( void *pvParameters ) { Led_Init(); LED0_ON(); LED1_OFF() for( ;; ) { LED0B(); LED1B(); vTaskDelay( 100 / portTICK_RATE_MS); } } void vCOMMTask( void *pvParameters ) { Comm_Init(); for(;;) { USART_SendData(USART1, '@'); vTaskDelay(1000 / portTICK_RATE_MS); } } /*-----------------------------------------------------------*/ static void prvSetupHardware( void ) { SystemInit(); } /*-----------------------------------------------------------*/ void Led_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE ); /*LED0 @ PA8*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init( GPIOA, GPIO_InitStructure ); /*LED0 @ PD2*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init( GPIOD, GPIO_InitStructure ); } void Comm_Init(void) { USART_InitTypeDef USART_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /*UART1 TX @ PA9*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init( GPIOA, GPIO_InitStructure ); /*UART1 RX @ PA10*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init( GPIOA, GPIO_InitStructure ); /*UART1 Cfg.*/ USART_InitStructure.USART_BaudRate = 57600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_Init(USART1, USART_InitStructure); USART_ClearFlag(USART1, USART_FLAG_TC); /*UART1 NIVC Cfg.*/ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(NVIC_InitStructure); USART_Cmd(USART1, ENABLE); }