原创 Keil MDK-ARM 下基于 STM32 标准外设库 V3.5.0 的 FreeRTOS 移植笔记

2013-10-10 00:42 5364 21 21 分类: 消费电子

 

移植过程基于 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,截图如下。

 

t1.jpg

 

至此,设定完成,修改 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);

}

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
21
关闭 站长推荐上一条 /3 下一条