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个文件夹:

  1. Demo:不同处理器的FreeRTOS系统移植例程
  2. License:许可证,对FreeRTOS使用范围进行授权
  3. 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 作为开发平台进行系统移植。

功能描述

  1. PB10 作为输出口,控制 LED 的亮灭;
  2. 编写延时函数 delay ,以毫秒为单位;
  3. 使用 USART2 循环发送数据,波特率9600,8位数据位,1位停止位,无校验,无硬件控制流;
  4. 系统移植,添加 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

外设说明:

  1. CORE(必选): 提供与 Cortex-M0、Cortex-M3、Cortex-M4、SC000 和 SC300 处理器与外围寄存器之间的接口
  2. Framework(必选): 标准外设驱动框架(Standard Peripheral Drivers Framework)
  3. RCC(必选): 提供与系统时钟相关的库函数
  4. GPIO: 提供与通用IO接口相关的库函数
  5. USART: 提供与UART/USART相关的库函数

选择外设

  • 设置参数

打开 Options for target,依次设置下列参数:

  1. Target > Xtal(MHz)): 8.0
  2. C/C++ > Define: USE_STDPERIPH_DRIVER,STM32F10X_MD
  3. 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

所有参数均设置完成后,项目创建过程就结束了。

设置Processing Symbols

选择flash大小

初始化

创建项目后,需要编写代码以实现对系统时钟及所需外设的初始化。

  • 初始化流程
  1. 首先,将默认组名称改为 USER ,并在本地项目目录下添加文件夹,命名为 "USER" 。
  2. 其次,新建并保存以下文件至 "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
  3. 最后,对各个文件进行编码,完成各项初始化任务
  • 项目文件结构

项目目录

  • 初始化程序设计

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.c
      • Source\portable\RVDS\ARM_CM3 中的 port.c
      • Source\portable\MemMang 中的 heap_2.c
    • 从系统 FreeRTOSv9.0.0 的源码 FreeRTOS 中找到以下头文件,并将其复制至 FreeRTOS/include 文件夹;
      • Source\include 中的所有头文件,包括其中的 stdint.readme 文件
      • Source\portable\RVDS\ARM_CM3 中的 portmacro.h
      • Demo\CORTEX_STM32F103_Keil 中的 FreeRTOSConfig.h
    • 在项目组 FreeRTOS 中添加以上已复制好的源文件

说明:FreeRTOS可以在很多不同编译器中编译,其中的一些编译器比同类有更高级特性。因为这个原因,FreeRTOS不使用任何非C语言标准的特性或语法。一个例外情况是头文件stdint.h。在文件夹FreeRTOS/Source/include下包含一个叫做stdint.readme的文件,如果你的编译器不提供stdint类型定义,可以将stdint.readme文件重命名为stdint.h。

参考:FreeRTOS编码标准及风格指南

完成以上步骤后,文件结构应该如下各图所示:
File - FreeRTOS

本地文件中的FreeRTOS文件夹

File - FreeRTOS\include

本地文件中的include文件夹

MDK - FreeRTOS

MDK中的FreeRTOS组

  • 添加路径

再次打开 Options for target>>C/C++,在 Include Paths 中添加:

  1. .\USER
  2. .\FreeRTOS
  3. .\FreeRTOS\include

添加路径

  • 修改启动文件

打开文件 "startup_stm32f10x_md.s",在 50 行附近找到以下代码段:

文件修改前

添加Export之前的启动文件

修改方式如下:

在 "__heap_limit"后添加:

IMPORT xPortPendSVHandler
IMPORT xPortSysTickHandler
IMPORT vPortSVCHandler

将 75 行左右的

DCD     SVC_Handler
DCD     PendSV_Handler
DCD     SysTick_Handler

依次修改为:

DCD     vPortSVCHandler
DCD     xPortPendSVHandler
DCD     xPortSysTickHandler

文件修改后

添加Export之前的启动文件

内核裁剪文件

前面添加的头文件 "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 也随着任务进行亮灭交替变换,最后保持在灯亮状态。

LedOn
LedOff