stm32 - FreeRTOS系统移植
前段时间研究了一下 FreeRTOS 在 stm32 的系统移植,觉得有必要做个总结,记录这研发路上的点点滴滴。
FreeRTOS
从 FreeRTOS官网 下载最新源码,我下载的是 FreeRTOSv9.0.0 ,其文件结构如下,根目录主要包含 FreeRTOS 和 FreeRTOS-Plus 两个文件夹, Plus 版系统添加了 TCP/UDP 等网络通信功能。
D:\FREERTOSV9.0.0
│ New - Direct to Task Notifications.html
│ New - FreeRTOS+TCP.html
│ Quick_Start_Guide.html
│ Upgrading-to-FreeRTOS-9.html
│ readme.txt
│
├─FreeRTOS
│ │ links_to_doc_pages_for_the_demo_projects.html
│ │ readme.txt
│ │
│ ├─Demo
│ ├─License
│ └─Source
│
└─FreeRTOS-Plus
│ readme.txt
│
├─Demo
└─Source
暂且不考虑plus版,打开FreeRTOS文件夹,其中包含3个文件夹:
- Demo:不同处理器的FreeRTOS系统移植例程
- License:许可证,对FreeRTOS使用范围进行授权
- Source:FreeRTOS源码
Demo
Demo 包含了官方提供的所有已适配处理器的移植例程,我们可以根据自己所用芯片和开发环境选择合适的例程进行学习。
ARM7_AT91FR40008_GCC
ARM7_AT91SAM7S64_IAR
ARM7_AT91SAM7X256_Eclipse
ARM7_LPC2106_GCC
ARM7_LPC2129_IAR
ARM7_LPC2129_Keil_RVDS
ARM7_LPC2138_Rowley
ARM7_LPC2368_Eclipse
ARM7_LPC2368_Rowley
ARM7_STR71x_IAR
ARM7_STR75x_GCC
ARM7_STR75x_IAR
ARM9_AT91SAM9XE_IAR
ARM9_STR91X_IAR
AVR32_UC3
AVR_ATMega323_IAR
AVR_ATMega323_WinAVR
ColdFire_MCF51CN128_CodeWarrior
ColdFire_MCF52221_CodeWarrior
ColdFire_MCF52233_Eclipse
ColdFire_MCF52259_CodeWarrior
ColdFire_MCF5282_Eclipse
Common
CORTEX_A2F200_IAR_and_Keil
CORTEX_A2F200_SoftConsole
CORTEX_A53_64-bit_UltraScale_MPSoC
CORTEX_A5_SAMA5D2x_Xplained_IAR
CORTEX_A5_SAMA5D3x_Xplained_IAR
CORTEX_A5_SAMA5D4x_EK_IAR
CORTEX_A9_Cyclone_V_SoC_DK
CORTEX_A9_RZ_R7S72100_IAR_DS-5
CORTEX_A9_Zynq_ZC702
CORTEX_AT91SAM3U256_IAR
CORTEX_ATSAM3S-EK2_Atmel_Studio
CORTEX_ATSAM3X_Atmel_Studio
CORTEX_CY8C5588_PSoC_Creator_GCC
CORTEX_CY8C5588_PSoC_Creator_Keil
CORTEX_CY8C5588_PSoC_Creator_RVDS
CORTEX_EFM32_Giant_Gecko_Simplicity_Studio
CORTEX_EFM32_Pearl_Gecko_Simplicity_Studio
CORTEX_EFMG890F128_IAR
CORTEX_Kinetis_K60_Tower_IAR
CORTEX_LM3S102_GCC
CORTEX_LM3S102_Rowley
CORTEX_LM3S316_IAR
CORTEX_LM3S811_GCC
CORTEX_LM3S811_IAR
CORTEX_LM3S811_KEIL
CORTEX_LM3Sxxxx_Eclipse
CORTEX_LM3Sxxxx_IAR_Keil
CORTEX_LM3Sxxxx_Rowley
CORTEX_LPC1768_GCC_RedSuite
CORTEX_LPC1768_GCC_Rowley
CORTEX_LPC1768_IAR
CORTEX_M0+_Atmel_SAMD20_XPlained
CORTEX_M0_Infineon_XMC1000_IAR_Keil_GCC
CORTEX_M0_LPC1114_LPCXpresso
CORTEX_M0_STM32F0518_IAR
CORTEX_M4F_ATSAM4E_Atmel_Studio
CORTEX_M4F_CEC1302_Keil_GCC
CORTEX_M4F_CEC1302_MikroC
CORTEX_M4F_Infineon_XMC4000_GCC_Dave
CORTEX_M4F_Infineon_XMC4000_IAR
CORTEX_M4F_Infineon_XMC4000_Keil
CORTEX_M4F_Infineon_XMC4000_Tasking
CORTEX_M4F_Infineon_XMC4500_GCC_Atollic
CORTEX_M4F_M0_LPC43xx_Keil
CORTEX_M4F_MSP432_LaunchPad_IAR_CCS_Keil
CORTEX_M4F_STM32F407ZG-SK
CORTEX_M4_ATSAM4L_Atmel_Studio
CORTEX_M4_ATSAM4S_Atmel_Studio
CORTEX_M7_SAME70_Xplained_AtmelStudio
CORTEX_M7_SAMV71_Xplained_AtmelStudio
CORTEX_M7_SAMV71_Xplained_IAR_Keil
CORTEX_M7_STM32F7_STM32756G-EVAL_IAR_Keil
CORTEX_MB9A310_IAR_Keil
CORTEX_MB9B500_IAR_Keil
CORTEX_MPU_LM3Sxxxx_Rowley
CORTEX_MPU_LPC1768_GCC_RedSuite
CORTEX_MPU_Simulator_Keil_GCC
CORTEX_R4F_RZ_T_GCC_IAR
CORTEX_R4_RM48_TMS570_CCS5
CORTEX_R5_UltraScale_MPSoC
CORTEX_SmartFusion2_M2S050_SoftConsole
CORTEX_STM32F100_Atollic
CORTEX_STM32F103_GCC_Rowley
CORTEX_STM32F103_IAR
CORTEX_STM32F103_Keil
CORTEX_STM32F103_Primer_GCC
CORTEX_STM32F107_GCC_Rowley
CORTEX_STM32L152_Discovery_IAR
CORTEX_STM32L152_IAR
CORTUS_APS3_GCC
Cygnal
dsPIC_MPLAB
Flshlite
H8S
HCS12_CodeWarrior_banked
HCS12_CodeWarrior_small
HCS12_GCC_banked
IA32_flat_GCC_Galileo_Gen_2
lwIP_AVR32_UC3
lwIP_Demo_Rowley_ARM7
lwIP_MCF5235_GCC
MB91460_Softune
MB96340_Softune
MB96350_Softune_Dice_Kit
MCF5235_GCC
MicroBlaze_Kintex7_EthernetLite
MicroBlaze_Spartan-6_EthernetLite
MSP430X_MSP430F5438_CCS
MSP430X_MSP430F5438_IAR
MSP430X_MSP430FR5969_LaunchPad_IAR_CCS
msp430_CrossWorks
msp430_GCC
msp430_IAR
NEC_78K0R_IAR
NEC_V850ES_IAR
NiosII_CycloneIII_DBC3C40_GCC
PC
PIC18_MPLAB
PIC18_WizC
PIC24_MPLAB
PIC32MEC14xx_MPLAB
PIC32MX_MPLAB
PIC32MZ_MPLAB
PPC405_FPU_Xilinx_Virtex4_GCC
PPC405_Xilinx_Virtex4_GCC
PPC440_DP_FPU_Xilinx_Virtex5_GCC
PPC440_SP_FPU_Xilinx_Virtex5_GCC
PPC440_Xilinx_Virtex5_GCC
RL78_multiple_IAR
RL78_RL78G13_Promo_Board_IAR
RX100-RSK_GCC_e2studio
RX100-RSK_IAR
RX100-RSK_Renesas_e2studio
RX100_RX113-RSK_GCC_e2studio_IAR
RX100_RX113-RSK_Renesas_e2studio
RX200_RX210-RSK_Renesas
RX200_RX231-RSK_GCC_e2studio_IAR
RX200_RX231-RSK_Renesas_e2studio
RX600_RX62N-RDK_GNURX
RX600_RX62N-RDK_IAR
RX600_RX62N-RDK_Renesas
RX600_RX62N-RSK_GNURX
RX600_RX62N-RSK_IAR
RX600_RX62N-RSK_Renesas
RX600_RX630-RSK_Renesas
RX600_RX63N-RDK_Renesas
RX600_RX64M_RSK_GCC_e2studio
RX600_RX64M_RSK_Renesas_e2studio
RX700_RX71M_RSK_GCC_e2studio_IAR
RX700_RX71M_RSK_Renesas_e2studio
SuperH_SH7216_Renesas
TriCore_TC1782_TriBoard_GCC
uIP_Demo_IAR_ARM7
uIP_Demo_Rowley_ARM7
Unsupported_Demos
WIN32-MingW
WIN32-MSVC
WIN32-MSVC-Static-Allocation-Only
WizNET_DEMO_GCC_ARM7
WizNET_DEMO_TERN_186
Xilinx_FreeRTOS_BSP
Source
Source 是 FreeRTOS 的核心,包含了系统内核及各类处理器系统移植所需的源码。
D:\FREERTOSV9.0.0\FREERTOS\SOURCE
│ croutine.c
│ event_groups.c
│ list.c
│ queue.c
│ readme.txt
│ tasks.c
│ timers.c
│
├─include
│ croutine.h
│ deprecated_definitions.h
│ event_groups.h
│ FreeRTOS.h
│ list.h
│ mpu_prototypes.h
│ mpu_wrappers.h
│ portable.h
│ projdefs.h
│ queue.h
│ semphr.h
│ StackMacros.h
│ stdint.readme
│ task.h
│ timers.h
│
└─portable
│ readme.txt
│
├─BCC
│ └─16BitDOS
│ ├─common
│ │ portasm.h
│ │ portcomn.c
│ │
│ ├─Flsh186
│ │ port.c
│ │ prtmacro.h
│ │
│ └─PC
│ port.c
│ prtmacro.h
│
├─CCS
│ ├─ARM_CM4F
│ │ port.c
│ │ portasm.asm
│ │ portmacro.h
│ │
│ ├─ARM_Cortex-R4
│ │ port.c
│ │ portASM.asm
│ │ portmacro.h
│ │
│ └─MSP430X
│ data_model.h
│ port.c
│ portext.asm
│ portmacro.h
│
├─CodeWarrior
│ ├─ColdFire_V1
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │
│ ├─ColdFire_V2
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │
│ └─HCS12
│ port.c
│ portmacro.h
│
├─Common
│ mpu_wrappers.c
│
├─GCC
│ ├─ARM7_AT91FR40008
│ │ port.c
│ │ portISR.c
│ │ portmacro.h
│ │
│ ├─ARM7_AT91SAM7S
│ │ AT91SAM7X256.h
│ │ ioat91sam7x256.h
│ │ lib_AT91SAM7X256.c
│ │ lib_AT91SAM7X256.h
│ │ port.c
│ │ portISR.c
│ │ portmacro.h
│ │
│ ├─ARM7_LPC2000
│ │ port.c
│ │ portISR.c
│ │ portmacro.h
│ │
│ ├─ARM7_LPC23xx
│ │ port.c
│ │ portISR.c
│ │ portmacro.h
│ │
│ ├─ARM_CA53_64_BIT
│ │ port.c
│ │ portASM.S
│ │ portmacro.h
│ │
│ ├─ARM_CA9
│ │ port.c
│ │ portASM.S
│ │ portmacro.h
│ │
│ ├─ARM_CM0
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM3
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM3_MPU
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM4F
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM4_MPU
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM7
│ │ │ ReadMe.txt
│ │ │
│ │ └─r0p1
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CR5
│ │ port.c
│ │ portASM.S
│ │ portmacro.h
│ │
│ ├─ARM_CRx_No_GIC
│ │ port.c
│ │ portASM.S
│ │ portmacro.h
│ │
│ ├─ATMega323
│ │ port.c
│ │ portmacro.h
│ │
│ ├─AVR32_UC3
│ │ exception.S
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ColdFire_V2
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │
│ ├─CORTUS_APS3
│ │ port.c
│ │ portmacro.h
│ │
│ ├─H8S2329
│ │ port.c
│ │ portmacro.h
│ │
│ ├─HCS12
│ │ port.c
│ │ portmacro.h
│ │
│ ├─IA32_flat
│ │ ISR_Support.h
│ │ port.c
│ │ portASM.S
│ │ portmacro.h
│ │
│ ├─MCF5235
│ │ port.c
│ │ portmacro.h
│ │
│ ├─MicroBlaze
│ │ port.c
│ │ portasm.s
│ │ portmacro.h
│ │
│ ├─MicroBlazeV8
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │ port_exceptions.c
│ │
│ ├─MicroBlazeV9
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │ port_exceptions.c
│ │
│ ├─MSP430F449
│ │ port.c
│ │ portmacro.h
│ │
│ ├─NiosII
│ │ port.c
│ │ portmacro.h
│ │ port_asm.S
│ │
│ ├─PPC405_Xilinx
│ │ FPU_Macros.h
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │
│ ├─PPC440_Xilinx
│ │ FPU_Macros.h
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │
│ ├─RL78
│ │ isr_support.h
│ │ port.c
│ │ portasm.S
│ │ portmacro.h
│ │
│ ├─RX100
│ │ port.c
│ │ portmacro.h
│ │
│ ├─RX600
│ │ port.c
│ │ portmacro.h
│ │
│ ├─RX600v2
│ │ port.c
│ │ portmacro.h
│ │
│ ├─STR75x
│ │ port.c
│ │ portISR.c
│ │ portmacro.h
│ │
│ └─TriCore_1782
│ port.c
│ portmacro.h
│ porttrap.c
│
├─IAR
│ ├─78K0R
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s26
│ │ portmacro.h
│ │
│ ├─ARM_CA5_No_GIC
│ │ port.c
│ │ portASM.h
│ │ portASM.s
│ │ portmacro.h
│ │
│ ├─ARM_CA9
│ │ port.c
│ │ portASM.h
│ │ portASM.s
│ │ portmacro.h
│ │
│ ├─ARM_CM0
│ │ port.c
│ │ portasm.s
│ │ portmacro.h
│ │
│ ├─ARM_CM3
│ │ port.c
│ │ portasm.s
│ │ portmacro.h
│ │
│ ├─ARM_CM4F
│ │ port.c
│ │ portasm.s
│ │ portmacro.h
│ │
│ ├─ARM_CM7
│ │ │ ReadMe.txt
│ │ │
│ │ └─r0p1
│ │ port.c
│ │ portasm.s
│ │ portmacro.h
│ │
│ ├─ARM_CRx_No_GIC
│ │ port.c
│ │ portASM.s
│ │ portmacro.h
│ │
│ ├─ATMega323
│ │ port.c
│ │ portmacro.h
│ │ portmacro.s90
│ │
│ ├─AtmelSAM7S64
│ │ AT91SAM7S64.h
│ │ AT91SAM7S64_inc.h
│ │ AT91SAM7X128.h
│ │ AT91SAM7X128_inc.h
│ │ AT91SAM7X256.h
│ │ AT91SAM7X256_inc.h
│ │ ISR_Support.h
│ │ lib_AT91SAM7S64.h
│ │ lib_AT91SAM7X128.h
│ │ lib_AT91SAM7X256.h
│ │ port.c
│ │ portasm.s79
│ │ portmacro.h
│ │
│ ├─AtmelSAM9XE
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s79
│ │ portmacro.h
│ │
│ ├─AVR32_UC3
│ │ exception.s82
│ │ port.c
│ │ portmacro.h
│ │ read.c
│ │ write.c
│ │
│ ├─LPC2000
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s79
│ │ portmacro.h
│ │
│ ├─MSP430
│ │ port.c
│ │ portasm.h
│ │ portext.s43
│ │ portmacro.h
│ │
│ ├─MSP430X
│ │ data_model.h
│ │ port.c
│ │ portext.s43
│ │ portmacro.h
│ │
│ ├─RL78
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s87
│ │ portmacro.h
│ │
│ ├─RX100
│ │ port.c
│ │ portmacro.h
│ │ port_asm.s
│ │
│ ├─RX600
│ │ port.c
│ │ portmacro.h
│ │ port_asm.s
│ │
│ ├─RXv2
│ │ port.c
│ │ portmacro.h
│ │ port_asm.s
│ │
│ ├─STR71x
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s79
│ │ portmacro.h
│ │
│ ├─STR75x
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s79
│ │ portmacro.h
│ │
│ ├─STR91x
│ │ ISR_Support.h
│ │ port.c
│ │ portasm.s79
│ │ portmacro.h
│ │
│ └─V850ES
│ ISR_Support.h
│ port.c
│ portasm.s85
│ portasm_Fx3.s85
│ portasm_Hx2.s85
│ portmacro.h
│
├─Keil
│ See-also-the-RVDS-directory.txt
│
├─MemMang
│ heap_1.c
│ heap_2.c
│ heap_3.c
│ heap_4.c
│ heap_5.c
│ ReadMe.url
│
├─MikroC
│ └─ARM_CM4F
│ port.c
│ portmacro.h
│
├─MPLAB
│ ├─PIC18F
│ │ port.c
│ │ portmacro.h
│ │ stdio.h
│ │
│ ├─PIC24_dsPIC
│ │ port.c
│ │ portasm_dsPIC.S
│ │ portasm_PIC24.S
│ │ portmacro.h
│ │
│ ├─PIC32MEC14xx
│ │ ISR_Support.h
│ │ port.c
│ │ portmacro.h
│ │ port_asm.S
│ │
│ ├─PIC32MX
│ │ ISR_Support.h
│ │ port.c
│ │ portmacro.h
│ │ port_asm.S
│ │
│ └─PIC32MZ
│ ISR_Support.h
│ port.c
│ portmacro.h
│ port_asm.S
│
├─MSVC-MingW
│ port.c
│ portmacro.h
│
├─oWatcom
│ └─16BitDOS
│ ├─common
│ │ portasm.h
│ │ portcomn.c
│ │
│ ├─Flsh186
│ │ port.c
│ │ portmacro.h
│ │
│ └─PC
│ port.c
│ portmacro.h
│
├─Paradigm
│ └─Tern_EE
│ ├─large_untested
│ │ port.c
│ │ portasm.h
│ │ portmacro.h
│ │
│ └─small
│ port.c
│ portasm.h
│ portmacro.h
│
├─Renesas
│ ├─RX100
│ │ port.c
│ │ portmacro.h
│ │ port_asm.src
│ │
│ ├─RX200
│ │ port.c
│ │ portmacro.h
│ │ port_asm.src
│ │
│ ├─RX600
│ │ port.c
│ │ portmacro.h
│ │ port_asm.src
│ │
│ ├─RX600v2
│ │ port.c
│ │ portmacro.h
│ │ port_asm.src
│ │
│ └─SH2A_FPU
│ ISR_Support.inc
│ port.c
│ portasm.src
│ portmacro.h
│
├─Rowley
│ ├─ARM7
│ │ readme.txt
│ │
│ └─MSP430F449
│ port.c
│ portasm.h
│ portext.asm
│ portmacro.h
│
├─RVDS
│ ├─ARM7_LPC21xx
│ │ port.c
│ │ portASM.s
│ │ portmacro.h
│ │ portmacro.inc
│ │
│ ├─ARM_CA9
│ │ port.c
│ │ portASM.s
│ │ portmacro.h
│ │ portmacro.inc
│ │
│ ├─ARM_CM0
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM3
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM4F
│ │ port.c
│ │ portmacro.h
│ │
│ ├─ARM_CM4_MPU
│ │ port.c
│ │ portmacro.h
│ │
│ └─ARM_CM7
│ │ ReadMe.txt
│ │
│ └─r0p1
│ port.c
│ portmacro.h
│
├─SDCC
│ └─Cygnal
│ port.c
│ portmacro.h
│
├─Softune
│ ├─MB91460
│ │ port.c
│ │ portmacro.h
│ │ __STD_LIB_sbrk.c
│ │
│ └─MB96340
│ port.c
│ portmacro.h
│ __STD_LIB_sbrk.c
│
├─Tasking
│ └─ARM_CM4F
│ port.c
│ portmacro.h
│ port_asm.asm
│
└─WizC
└─PIC18
│ addFreeRTOS.h
│ Install.bat
│ port.c
│ portmacro.h
│
└─Drivers
└─Tick
isrTick.c
Tick.c
系统移植
以 stm32f103RCT6 为例,选择 Keil MDK v5.21.1.0 作为开发平台进行系统移植。
功能描述
- PB10 作为输出口,控制 LED 的亮灭;
- 编写延时函数 delay ,以毫秒为单位;
- 使用 USART2 循环发送数据,波特率9600,8位数据位,1位停止位,无校验,无硬件控制流;
- 系统移植,添加 3 个 task:vLEDOnTask,vLEDOffTask,vUasrtSendTask
创建项目 (BrightLed)
- 选择芯片 (stm32f103RCT6)
- 选择外设
自从 Keil MDK 更新至 v5.0 以后,软件安装完成便可使用 "Pack installer" 让其自动下载所需的软件包;新建项目也变得更加简单方便,可以使用 "manager run-time environment" 选择所需的片内外设。
Software Compoent
├─CMSIS
│ │ CORE
│ │
└─Device
│ GPIO
│ Startup
│
└─stdPeriph Drivers
│ Framework
│ GPIO
│ RCC
│ USARTs
外设说明:
- CORE(必选): 提供与 Cortex-M0、Cortex-M3、Cortex-M4、SC000 和 SC300 处理器与外围寄存器之间的接口
- Framework(必选): 标准外设驱动框架(Standard Peripheral Drivers Framework)
- RCC(必选): 提供与系统时钟相关的库函数
- GPIO: 提供与通用IO接口相关的库函数
- USART: 提供与UART/USART相关的库函数
- 设置参数
打开 Options for target
,依次设置下列参数:
- Target > Xtal(MHz)): 8.0
- C/C++ > Define: USE_STDPERIPH_DRIVER,STM32F10X_MD
- Debug > Use: ST-Link Debugger
3.1 Settings > Debug > Debug Adapter: ST-LINK/V2; Port:SW; Max: 1.8MHz
3.2 Settings > Flash Download > Reset and Run:[√]
3.3 Settings > Flash Download > Programming Algorithm: STM32f10x Med-density Flash
所有参数均设置完成后,项目创建过程就结束了。
初始化
创建项目后,需要编写代码以实现对系统时钟及所需外设的初始化。
- 初始化流程
- 首先,将默认组名称改为
USER
,并在本地项目目录下添加文件夹,命名为 "USER" 。 - 其次,新建并保存以下文件至 "USER" 文件夹,同时添加其中的 .c 文件到项目组
USER
中。
2.1 主程序:main.c / main.h
2.2 中断程序:stm32f10x_it.c / stm32f10x_it.h
2.3 延时模块: delay.c / delay.h
2.4 led控制模块:led.c / led.h
2.5 串口通信模块:usart.c / usart.h - 最后,对各个文件进行编码,完成各项初始化任务
- 项目文件结构
- 初始化程序设计
delay.c / delay.h
delay.c
#include "delay.h"
volatile u32 TimingDelay;
void delayInit(void)
{
/* SystemFrequency / 1000 1ms
* SystemFrequency / 100000 10us
* SystemFrequency / 1000000 1us
*/
#define SYSCLK_FREQ_72MHz 72000000 // 系统主频
if (SysTick_Config(SYSCLK_FREQ_72MHz / 1000000))
{
/* Capture error */
while (1);
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
// ms级延时函数
void delay(__IO u32 nTime)
{
TimingDelay = nTime * 1000;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != 0);
}
// us级延时函数
void delayMicroseconds(__IO u32 nTime)
{
TimingDelay = nTime;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(TimingDelay != 0);
}
delay.h
#ifndef DELAY_H_
#define DELAY_H_
#include "stm32f10x.h"
void delayInit(void);
void delay(__IO u32 nTime);
void delayMicroseconds(__IO u32 nTime);
#endif /* DELAY_H_ */
led.c / led.h
led.c
#include "led.h"
void ledGPIOConfiguration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
led.h
#ifndef LED_H
#define LED_H
#include "stm32f10x.h"
#define LED_PORT (GPIO_Pin_10)
void ledGPIOConfiguration(void);
#endif /* LED_H */
usart.c / usart.h
usart.c
#include "usart.h"
//串口驱动应用标志
static bool Derive_UART2SendFlag, Derive_UART2TxIntState;
//开串口 并执行初始化
//8位数据位 无校验 1位起始位/1位停止位 允许收发中断 宏定义BAUDRATE设定波特率 低优先级中断
void usart2Config(void)
{
//波特率设置
#define UART_BAUDDEF 9600
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
//管脚配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); /* TXIO */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure); /* RXIO */
//串口工作模式配置
USART_InitStructure.USART_BaudRate = UART_BAUDDEF;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
//中断设置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //低优先级别的中断
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应中断等级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
Derive_UART2TxIntState = false;
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
//START
USART_Cmd(USART2, ENABLE);
}
//从串口发送一个字节
void UARTSendByByter(u16 Data)
{
//发送数据
USART_SendData(USART2, (u8)Data);
if(!Derive_UART2TxIntState)
{
Derive_UART2TxIntState = true;
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
}
Derive_UART2SendFlag = true;
}
//串口收发中断处理函数
void UART_TRxOver_Interrupt(void)
{
if(USART_GetITStatus(USART2, USART_IT_TXE) == SET)
{
//发送中断
//清零标志
USART_ClearITPendingBit(USART2, USART_IT_TXE);
Derive_UART2SendFlag = false;
//tx interrupt..
//...
if(!Derive_UART2SendFlag)
{
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
Derive_UART2TxIntState = false;
}
}
if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//接收中断
//-------- 回传接收到的数据 --------
UARTSendByByter(USART_ReceiveData(USART2));
USART_ClearFlag(USART2,USART_FLAG_RXNE);
}
}
usart.h
#ifndef USART_H
#define USART_H
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#define false 0
#define true 1
typedef unsigned char bool;
void usart2Config(void);
void UARTSendByByter(u16 Data);
#endif /* USART_H */
stm32f10x_it.c / stm32f10x_it.h
stm32f10x_it.c
#include "stm32f10x_it.h"
void NMI_Handler(void)
{
}
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
void MemManage_Handler(void)
{
/* Go to infinite loop when Memory Manage exception occurs */
while (1)
{
}
}
void BusFault_Handler(void)
{
/* Go to infinite loop when Bus Fault exception occurs */
while (1)
{
}
}
void UsageFault_Handler(void)
{
/* Go to infinite loop when Usage Fault exception occurs */
while (1)
{
}
}
#ifndef RTE_RTOS_RTX
void SVC_Handler(void)
{
}
#endif
void DebugMon_Handler(void)
{
}
#ifndef RTE_RTOS_RTX
void PendSV_Handler(void)
{
}
#endif
extern volatile u32 TimingDelay;
void SysTick_Handler(void) {
if (TimingDelay != 0x00) {
TimingDelay--;
}
}
extern void UART_TRxOver_Interrupt(void);
void USART2_IRQHandler(void)
{
UART_TRxOver_Interrupt();
}
stm32f10x_it.h
#ifndef __STM32F10x_IT_H
#define __STM32F10x_IT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
void NMI_Handler(void);
void HardFault_Handler(void);
void MemManage_Handler(void);
void BusFault_Handler(void);
void UsageFault_Handler(void);
void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void USART2_IRQHandler(void);
#ifdef __cplusplus
}
#endif
#endif /* __STM32F10x_IT_H */
main.c / main.h
main.c
/*******************************************************************************
* Header : Learning FreeRTOS
* File Name : main.c
* Author : wgt
* Date : 2016.11.2
* Description :
*******************************************************************************/
#include "main.h"
/* ENABLE the clk of GPIO */
static void deviceInit(void);
/* setup the hardware of system */
static void prvSetupHardware(void);
/*******************************************************************************
* Function Name : main
* Description : main function,the interface of system
* Input : None
* Return : None
*******************************************************************************/
int main(void)
{
prvSetupHardware(); // 设备初始化
while(1)
{
}
}
/*******************************************************************************
* Function Name : prvSetupHardware
* Description : initial hardwares
* Input : None
* Return : None
*******************************************************************************/
static void prvSetupHardware(void)
{
deviceInit();
delayInit(); // SysTick滴答时钟初始化
ledGPIOConfiguration();
usart2Config();
}
/*******************************************************************************
* Function Name : deviceInit
* Description : ENABLE the clk of GPIO
* Input : None
* Return : None
*******************************************************************************/
static void deviceInit(void)
{
//--------------------------- CLK INIT, HSE PLL ----------------------------
ErrorStatus HSEStartUpStatus;
//RCC reset
RCC_DeInit();
//开启外部时钟 并执行初始化
RCC_HSEConfig(RCC_HSE_ON);
//等待外部时钟准备好
HSEStartUpStatus = RCC_WaitForHSEStartUp();
//启动失败 在这里等待
while(HSEStartUpStatus == ERROR);
//设置内部总线时钟
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
//外部时钟为8M 这里倍频到72M
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08);
//----------------------------- CLOSE HSI ---------------------------
//关闭内部时钟HSI
RCC_HSICmd(DISABLE);
//中断配置 2-level interrupt
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//开总中断
__enable_irq();
/****************** OPEN GPIO CLK **************/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#endif /* MAIN_H */
至此,系统时钟及外设的初始化程序已经完成。以上程序,除去 led.c/led.h, usart.c/usart.h 外,可作为无需操作系统的stm32项目模板。
内核移植
- 新建组
- 在项目中添加一个组,命名为 FreeRTOS ;
- 在本地目录新建文件夹,同样命名为 FreeRTOS ,用于存放系统内核的源文件;
- 在 FreeRTOS 文件夹下新建子文件夹 include ,用于存放系统内核的头文件。
- 复制文件
- 从系统 FreeRTOSv9.0.0 的源码
FreeRTOS\Source
中找到以下源文件,并将其复制至 FreeRTOS 文件夹;Source
中的 list.c, queue.c, tasks.cSource\portable\RVDS\ARM_CM3
中的 port.cSource\portable\MemMang
中的 heap_2.c
- 从系统 FreeRTOSv9.0.0 的源码
FreeRTOS
中找到以下头文件,并将其复制至 FreeRTOS/include 文件夹;Source\include
中的所有头文件,包括其中的 stdint.readme 文件Source\portable\RVDS\ARM_CM3
中的 portmacro.hDemo\CORTEX_STM32F103_Keil
中的 FreeRTOSConfig.h
- 在项目组 FreeRTOS 中添加以上已复制好的源文件
- 从系统 FreeRTOSv9.0.0 的源码
说明:FreeRTOS可以在很多不同编译器中编译,其中的一些编译器比同类有更高级特性。因为这个原因,FreeRTOS不使用任何非C语言标准的特性或语法。一个例外情况是头文件stdint.h。在文件夹FreeRTOS/Source/include下包含一个叫做stdint.readme的文件,如果你的编译器不提供stdint类型定义,可以将stdint.readme文件重命名为stdint.h。
完成以上步骤后,文件结构应该如下各图所示:
File - FreeRTOS
File - FreeRTOS\include
MDK - FreeRTOS
- 添加路径
再次打开 Options for target
>>C/C++
,在 Include Paths 中添加:
- .\USER
- .\FreeRTOS
- .\FreeRTOS\include
- 修改启动文件
打开文件 "startup_stm32f10x_md.s",在 50 行附近找到以下代码段:
文件修改前
修改方式如下:
在 "__heap_limit"后添加:
IMPORT xPortPendSVHandler
IMPORT xPortSysTickHandler
IMPORT vPortSVCHandler
将 75 行左右的
DCD SVC_Handler
DCD PendSV_Handler
DCD SysTick_Handler
依次修改为:
DCD vPortSVCHandler
DCD xPortPendSVHandler
DCD xPortSysTickHandler
文件修改后
内核裁剪文件
前面添加的头文件 "FreeRTOSConfig.h" 是系统内核配置文件,通过修改文件中的宏定义,可以对内核进行裁剪,保留所需功能。从例程中得到的该文件源码如下,更加详细的设置方法和各变量用途将在后续应用中介绍。
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/*-----------------------------------------------------------
* Application specific definitions.
*
* These definitions should be adjusted for your particular hardware and
* application requirements.
*
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
* FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
*
* See http://www.freertos.org/a00110.html.
*----------------------------------------------------------*/
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
/* This is the raw value as per the Cortex-M3 NVIC. Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY 255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191 /* equivalent to 0xb0, or priority 11. */
/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15. This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting. Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
#endif /* FREERTOS_CONFIG_H */
功能实现
经过以上步骤,系统移植工作已经完成,现在便可以创建多个任务,并启动任务调度器进行任务调度。
- 在 "main.h" 添加 FreeRTOS 相关的头文件
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "list.h"
- 编写任务
// 定时亮灯任务
static void vLEDOnTask(void *pvParameters)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 1000/portTICK_RATE_MS;
/* xLastWakeTime需要被初始化为当前心跳计数值,此次赋值过后,
该变量将在vTaskDelayUntil函数中自动更新 */
xLastWakeTime = xTaskGetTickCount();
while(1)
{
GPIO_ResetBits(GPIOB,LED_PORT);
UARTSendByByter('1');
vTaskDelayUntil(&xLastWakeTime,xFrequency);
}
}
// 定时灭灯任务
static void vLEDOffTask(void *pvParameters)
{
while(1)
{
GPIO_SetBits(GPIOB,LED_PORT);
UARTSendByByter('2');
vTaskDelay(2000/portTICK_RATE_MS);
}
}
// 定时串口发送任务
static void vUasrtSendTask(void *pvParameters)
{
volatile unsigned char cnt=0;
TaskHandle_t xTaskLedOffHandle = (TaskHandle_t)pvParameters;
while(1)
{
UARTSendByByter(cnt++);
if(xTaskLedOffHandle!=NULL)
{
if(cnt==50)
vTaskSuspend(xTaskLedOffHandle); // 挂起灭灯任务
else if(cnt==100)
vTaskResume(xTaskLedOffHandle); // 唤醒灭灯任务
else if(cnt==255)
{
vTaskDelete(xTaskLedOffHandle); // 删除灭灯任务
xTaskLedOffHandle=NULL;
}
}
vTaskDelay(1500/portTICK_RATE_MS);
}
}
- 创建任务并启动调度器
int main(void)
{
TaskHandle_t xTaskLedOffHandle; /* 定义灭灯任务句柄 */
prvSetupHardware(); /* 设备初始化 */
xTaskCreate(vLEDOffTask, /* 指向任务函数的指针 */
"vLEDOffTask", /* 任务的文本名字,只在调试中用到 */
configMINIMAL_STACK_SIZE, /* 分配的栈空间大小 */
NULL, /* 没有给当前任务提供参数 */
tskIDLE_PRIORITY+1, /* 设置任务优先级 */
&xTaskLedOffHandle /* 获取任务句柄,存入xTaskLedOffHandle */
);
xTaskCreate(vLEDOnTask, "vLEDOnTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, NULL);
xTaskCreate(vUasrtSendTask, "vUasrtSendTask", configMINIMAL_STACK_SIZE,
(TaskHandle_t)(xTaskLedOffHandle), tskIDLE_PRIORITY+3, NULL);
/* 启动任务调度器 */
vTaskStartScheduler();
return 0;
}
- 功能测试
从图中可以看出,16 进制数据 0x31, 0x32 交替出现,同时有一变量(假设为 y )从 0x01 逐一增至 0xff 后返回 0x01 继续增加,在 y 处于 0x32(50) 与 0x64(100) 之间时,0x32 暂停出现,后重新出现,直到 y 增至 0xff 后永不再现。此外,硬件部分,PB10 外接的 LED 也随着任务进行亮灭交替变换,最后保持在灯亮状态。
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 litreily的博客!