1. 前言
最近发现个买板子的好地方,咸鱼,阿里巴巴旗下的二手交易平台,经过再三考虑,在平台上花费了75元买了个红牛开发版,买它主要看中的是板上带nandflash、norflash、sdram,性价比很高,令我意想不到的是卖主貌似没怎么用过板子,拿到手之后外观新的不行,并且板子上外扩的 io 口排针都没焊上,心里别说有多高兴了,感觉像是捡到钱了似的,哎,最近手里有点拮据,加上了每月一还的房贷,感觉身体被掏空了。
买个板子来移植 FreeRTOS,这个想法在内心酝酿了很久,最开始的想法来源于上一个公司买来的网络转串口的小板子,在小板子上,我看到了stm32 的某款芯片和一个网络芯片就实现了我认为只有移植个操作系统,最不行也要个linux才能实现功能,让我百思不得其解,限于当时的水平,如今看来,其实只是移植个 lwip 就能实现网络 Tcp/Ip 的功能,后来看到了免费的 FreeRTOS ,在这免费盛行的当下,我想看看这个小的实时系统是如何实现的,废话不多说,正题开始
2.资源简介
【1】stm32f103zet6:
144引脚,512k flash,64k ram,板上外扩512K SRAM,2M NORFLASH,128M nandflash
【2】STM32 使用固件库,版本是3.5.0
【3】FreeRTOS 使用的版本是9.0.0
3. 移植
移植前先来确定整个目录的结构,考虑到固件库和FreeRTOS 的源码不会改动,而其中会有 gpio、i2c、spi、串口等的程序,结构定为如下的结构
最外层只有 3 个文件夹:STM32F10x_StdPeriph_Lib_V3.5.0、PROJ、FreeRTOS9.0.0。
从名字上可以看出分别放置 STM32F10X 的固件库、用户工程和 FreeRTOS 的源码,
(1)STM32F10x_StdPeriph_Lib_V3.5.0 文件夹中有 3 个文件,还是看一下的树状图图吧:
FreeRTOS_for_stm32f103/
├── FreeRTOS9.0.0
├── PROJ
│ └── gpio
│ └── usr
│ ├── main.c
│ ├── stm32f10x_conf.h
│ ├── stm32f10x_it.c
│ └── stm32f10x_it.h
└── STM32F10x_StdPeriph_Lib_V3.5.0
├── CMSIS
│ ├── core_cm3.c
│ ├── core_cm3.h
│ ├── startup_stm32f10x_hd.s
│ ├── stm32f10x.h
│ ├── system_stm32f10x.c
│ └── system_stm32f10x.h
├── inc
│ ├── misc.h
│ ├── stm32f10x_i2c.h
......这里省去了其他的大部分文件
│ └── stm32f10x_wwdg.h
└── src
├── misc.c
......这里省去了其他的大部分文件
├── stm32f10x_i2c.c
└── stm32f10x_wwdg.c
inc 和 src 文件夹的内容完全是库见库源码下边的 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver 下边的相同名字的文件夹和里边的所有内容
CMSSIS 中的内容是源码库中的路径 STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS 下的
CoreSupport 文件夹下的
和
DeviceSupport 文件夹下的
和
固件库的启动文件,我们的芯片对应这里边的是高密度的
将以下的内容放到自己工程目录下的 PROJ 目录下的 gpio 下的 usr 下
(2)FreeRTOS 目录构建
源码目录下有两个文件:FreeRTOS、FreeRTOS-Plus,FreeRTOS 是 FreeRTOS 的源码,FreeRTOS-Plus 中是提供的工具,比如有个 CLI,是命令行,在命令行中我们可以输入命令来查看FreeRTOS系统在运行的时候查看 stack 的使用情况
将以下图中内容拷贝到 FreeRTOS 目录中
我们来看看 portable 中哪些文件是需要的
common 我们暂时不要,
IAR目录下的 ARM_CM3 文件夹下有3个文件:port.c、portasm.s、portmacro.h,其中有个 .h 文件,我们为了保持统一,放到 FreeRTOS9.0.0 源码目录下的include 中,其他的两个放到 portable 下的
MemMang目录的整个文件放到 portable 下。这个文件中主要是堆栈的分配。
添加FreeRTOS 的配置文件:拷贝 FreeRTOSv9.0.0\FreeRTOS\Demo\CORTEX_STM32F103_IAR 下的 FreeRTOSConfig.h 文件拷贝到 PROJ/gpio/usr 下
至此,工程文件夹的目录 构建完成了,接下来是
(3) iar 下工程文件构建和添加
新建一个 空工程,存到 PROG/gpio 文件夹下
添加后的目录如下:
STM32F10x_StdPeriph_Lib_V3.5.0 目录下的 src 并没有展开,里边的全部内容添加进来,这里需要注意的是只添加 .c 和 .s 文件,不添加 .h 头文件
配置工程中 .c 文件中的搜索头文件的路径:
四个路径是:
D:\stm32f103_wor\FreeRTOS_for_stm32f103\STM32F10x_StdPeriph_Lib_V3.5.0\CMSIS
D:\stm32f103_wor\FreeRTOS_for_stm32f103\STM32F10x_StdPeriph_Lib_V3.5.0\inc
D:\stm32f103_wor\FreeRTOS_for_stm32f103\PROJ\gpio\usr
D:\stm32f103_wor\FreeRTOS_for_stm32f103\FreeRTOS9.0.0\include
定义两个全局的宏:
USE_STDPERIPH_DRIVER
STM32F10X_HD
如果你对 iar for arm 不是很熟,可以查看 iar for arm 第一课
配置 开发板
去掉老的CMSIS 头文件选用iar 默认新的头文件库
STM32F10x_StdPeriph_Lib_V3.5.0\CMSIS 路径下的 core_cm3.h 改成 core_cm3.h.bat 即 将这个 .h 文件去掉,
将 main.c 中的内容改成:
#include "misc.h"
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#define LED_D1_ON() GPIO_ResetBits(GPIOF, GPIO_Pin_6)
#define LED_D1_OFF() GPIO_SetBits(GPIOF, GPIO_Pin_6)
#define LED_D3_ON() GPIO_ResetBits(GPIOF, GPIO_Pin_8)
#define LED_D3_OFF() GPIO_SetBits(GPIOF, GPIO_Pin_8)
static void LED_Init(void);
static void LED_D1_Task(void *pvParameters);
static void LED_D3_Task(void *pvParameters);
int main(void)
{
LED_Init(); // 初始化 LED 引脚
xTaskCreate(LED_D1_Task, "LED_D1", 1000, NULL, tskIDLE_PRIORITY + 3, NULL);
xTaskCreate(LED_D3_Task, "LED_D3", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 3, NULL);
/* 启动调度器 */
vTaskStartScheduler();
while (1);
return 0;
}
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); // 使能 GPIOF 的时钟
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOF, &GPIO_InitStructure);
LED_D1_ON();
LED_D3_ON();
}
void LED_D1_Task(void *pvParameters)
{
while ( 1 )
{
LED_D1_ON();
vTaskDelay(500 / portTICK_RATE_MS);
LED_D1_OFF();
vTaskDelay(500 / portTICK_RATE_MS);
}
}
void LED_D3_Task(void *pvParameters)
{
while(1)
{
LED_D3_ON();
vTaskDelay(500 / portTICK_RATE_MS);
LED_D3_OFF();
vTaskDelay(500 / portTICK_RATE_MS);
}
}
更改固件库中启动文件的中断向量的入口,设置成 FreeRTOS 的 portasm.s 中定义的入口:
然后就可以 make 了:
出现如下错误:
Error[2]: Failed to open #include file 'FreeRTOSConfig.h' D:\stm32f103_wor\FreeRTOS_for_stm32f103\FreeRTOS9.0.0\portable\portasm.s 70
双击,发现时 portasm.s 文件中的头文件找不到,我们配置汇编语言的头文件查找的路径:
路径添加为 D:\stm32f103_wor\FreeRTOS_for_stm32f103\PROJ\gpio\usr 不要自己写,右边的 .. 按钮选择
再次 make , 0 个错误,通过。。。
选择调试方式,我手上有个 ST-LINK,选中,下载进去,查看运行情况
覆盖 flash 的配置文件:
【1】这个选项如果不勾选上,当你擦除了整个 flash 芯片后,如果没有勾选上这个选项时,会出现 stack pointer 指向 0xFFFF 地址
【2】当你多次更改堆栈和中断向量函数和地址,多次编译,在线调试,发现并不是自己想要的时候,选上这个选项应该作为一个尝试
下载到板子上看到 2 个灯 每隔半秒同时闪烁一次。
多说一部分:
在下载到板子的时候,你可能会想在什么地方下载到板子中的 flash 中呢?尤其是在板子上有外扩的 norflash、nandflash的时候。
这个设置还是在工程中的 Option 选项中:
此部分的值,经过查找 芯片手册中的 地址映射部分 可以得到:
4. 生成文件的大小