- Part 0 开发工具安装
- Part 1 编译环境搭建
- Part 2 调试环境搭建
VSCode下 搭建 ARM Cortex-M 开发环境 -- Part 1 编译环境搭建
前言
本章旨在记录如何在VSCode下搭建编译环境, 具体包含以下几个部分:
- Project架构搭建
- VSCode下创建同名Project
- 移植和编写程序
- VSCode下C环境配置
- Makefile编译
- VSCode下Terminal配置
- 编译程序
- 程序烧写和运行
Project架构搭建
-
首先,我们需要在搭建项目的文件夹下创建项目文件夹。
例如下图中,在E:\STMicroelectronics\workspace\stm32f429\projects下创建一个名为HAL_demo的文件夹。后续用到的所有文件等都会放到HAL_demo文件夹下。
-
然后,在项目文件夹下创建后续所需用到的各个模块的文件夹。
例如下图中,在HAL_demo文件下创建APP、CMSIS、Kernel、lib、LinkerScripts、Startup、STM32F4xx_HAL_Driver、STM32F4xx_System、STM32F429I-Discovery、tools这些文件夹。
.vscode文件夹是VSCode自动生成的保持settings的文件夹,无需创建
out文件夹下放的是待会build出来的elf文件、bin文件等,在编译程序过程中会自动生产该文件夹,无需创建
Makefile文件是整个Project的总Makefile文件,后续会详细介绍该文件,所以后续章节再创建即可 -
简单介绍下各个模块文件夹的含义。
APP: 与application相关的文件都会放到APP文件夹下,例如main.c等CMSIS: ARM Cortex™ 微控制器软件接口标准(CMSIS:Cortex Microcontroller Software Interface Standard) 是 Cortex-M 处理器系列的与供应商无关的硬件抽象层。所以,CMSIS文件夹下会放ARM Cortex-M 所需的硬件抽象层文件,例如core_cm4.h等
Kernel: OS相关的文件都会放到Kernel文件夹下,例如FreeRTOS相关的文件
lib: GNU toolchain中pre-build好的一些lib都会放到lib文件夹下,例如libc.a、libg.a、libgcc.a等
LinkerScripts: arm-none-eabi-ld所需要的memory layout文件都会放到LinkerScripts文件夹下
Startup: ARM chip所需的 startup文件会放到Startup文件夹下,例如startup_stm32f429_439xx.s
STM32F4xx_HAL_Driver: 与STM32F429芯片相关的Hardware driver程序文件都会放在STM32F4xx_HAL_Driver文件夹下,例如stm32f4xx_hal_gpio.c等
STM32F4xx_System: 与STM32F429芯片相关的system level程序文件都会放在STM32F4xx_System文件夹下,例如system_stm32f4xx.c等
STM32F429I-Discovery: 与STM32F429I-Discovery板子相关的程序文件都会放在STM32F429I-Discovery文件夹下,例如stm32f429i_discovery_eeprom.c等
tools: tool所需的文件或者所需的tool文件都放在tools文件夹下
至此,整个Project的架构已经搭建完毕。接下来章节所需做的就是:具体实现各个模块文件夹中的内容。
VSCode下创建同名Project
搭建完整个Project架构后,我们可以通过VSCode的Project+ 这个插件构建一个同名Project,方便以后在不同Projects之间来回切换。
-
首先,在VSCode内按下F1快捷键显示所有命令。
- 然后,在窗口中输入如下command,进入到project edit界面 。
>projects:Edit Configuration
-
接着,创建一个name为STM32的group。然后在group的projects下创建一个name为HAL demo的project,并且把path设为刚才创建的HAL_demo这个文件夹的路径。
- 完成上述步骤,即可在VSCode侧边栏中的PROJECTS下见到我们刚才创建的那个Project。以后需要切换到这个project只需右击该project选择open or open in New Window即可。
移植和编写程序
搭建完Project架构和在VSCode下创建好Project以后,接下来要做就是本文最重要的部分:移植和编写各个module文件夹下的程序了。
- CMSIS 文件夹下内容实现
CMSIS文件夹下主要需要移植ARM Cortex-M 所需的硬件抽象层文件
- 把STM32Cube_FW_F4_V1.18.0\Drivers\CMSIS下所有内容 都复制到 CMSIS文件夹下
至此,CMSIS 文件夹下内容已经全部实现。我们后续所用到文件 其实都在CMSIS\Include下,例如cmsis_gcc.h中会包含__disable_irq 和 __enable_irq这些内联汇编。
- Startup 文件夹下内容实现
Startup文件夹下主要需要移植一个startup_stm32f429_439xx.s文件
startup_stm32f429_439xx.s文件主要实现以下功能:
- 初始化SP和PC值;
- 设置Vector Table;
- 初始化.data 和 .bss section在memory上的data;
- 初始化C library所需环境,初始化system环境,jump到main函数等。
- 在Startup文件夹下创建一个gcc 文件夹。Makefile 和 module.mk文件后续章节会介绍
- 把之前安装好的STM32Cube中的startup_stm32f429.s(具体路径见下图,STM32Cube_FW_F4_V1.18.0\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\gcc)复制到 刚才创建的gcc文件夹下并且命名为startup_stm32f429_439xx.s(见下下图)。
- 对gcc文件夹中的startup_stm32f429_439xx.s文件作如下改动:把bl __libc_init_array 这行mask掉。
至此,Startup文件夹下的内容已经完成。startup.s文件 从第一行code到最后一行code 主要就是为了实现如下的开机FLOW:
- STM32F4xx_HAL_Driver 文件夹下内容实现
STM32F4xx_HAL_Driver文件夹下主要需要移植STM32Cube中提供的那些HAL driver文件,例如uart、i2c、spi、adc等硬件设备的驱动程序。
- 在STM32F4xx_HAL_Driver 文件夹下分别创建inc和src文件夹。Makefile 和 module.mk文件后续章节会介绍
- 把STM32Cube_FW_F4_V1.18.0\Drivers\STM32F4xx_HAL_Driver\Inc下的所有头文件和子文件夹 复制 到STM32F4xx_HAL_Driver\inc下
- 把STM32Cube_FW_F4_V1.18.0\Drivers\STM32F4xx_HAL_Driver\Src下的所有C文件 复制 到STM32F4xx_HAL_Driver\src下
- 把STM32F4xx_HAL_Driver\inc下stm32_assert_template.h和stm32f4xx_hal_conf_template.h删除
- 对stm32f4xx_ll_rcc.h做如下修改:#define HSE_VALUE (25000000U) 改为 #define HSE_VALUE (8000000U)
- 把STM32F4xx_HAL_Driver\src下stm32f4xx_hal_msp_template.c、stm32f4xx_hal_timebase_rtc_alarm_template.c、stm32f4xx_hal_timebase_rtc_wakeup_template.c 和 stm32f4xx_hal_timebase_tim_template.c删除
- 对stm32f4xx_hal.c做如下修改:mask掉HAL_InitTick(TICK_INT_PRIORITY)这行
因为FreeRTOS中会对systick进行配置,所以这边无需call HAL_InitTick去配置systick。如果是裸机开发,无需mask这行code。
至此,STM32F4xx_HAL_Driver文件夹下的内容已经完成。在应用程序中call STM32F4xx_HAL_Driver下各个文件中的API 即可实现对Hardware的控制,不再需要直接去control hardware registers了
- STM32F4xx_System 文件夹下内容实现
STM32F4xx_System文件夹下主要需要移植一些STM32 System Level所依赖的文件,例如:
- system_stm32f4xx.c 中的functions实现System Clock setting,
- stm32f4xx_it.c 中的functions实现各个Interrupt handler,
- stm32f4xx_hal_msp.c 中的functions实现low level hardware initialization,例如Uart Port GPIO Pinmux Setting等。
- 在STM32F4xx_System文件夹下分别创建inc和src文件夹。Makefile 和 module.mk文件后续章节会介绍
- 把STM32Cube_FW_F4_V1.18.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include下的stm32f4xx.h、stm32f429xx.h以及system_stm32f4xx.h 复制 到 STM32F4xx_System\inc下
- 把STM32Cube_FW_F4_V1.18.0\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates下的system_stm32f4xx.c 复制到 STM32F4xx_System\src下
- 按照如下代码,修改STM32F4xx_System\src 下的 system_stm32f4xx.c,主要是为了正确地设置system clock。
/**
******************************************************************************
* @file system_stm32f4xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-M4 Device Peripheral Access Layer System Source File.
*
* This file provides two functions and one global variable to be called from
* user application:
* - SystemInit(): This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32f4xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
*
******************************************************************************
* @attention
*
* © COPYRIGHT 2017 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f4xx_system
* @{
*/
/** @addtogroup STM32F4xx_System_Private_Includes
* @{
*/
#include "stm32f4xx.h"
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Private_Defines
* @{
*/
/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to use external SDRAM mounted
on DK as data memory */
/* #define DATA_IN_ExtSDRAM */
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x00 /*!< Vector Table base offset field.
This value must be a multiple of 0x200. */
/******************************************************************************/
/************************* PLL Parameters *************************************/
/* Select the PLL clock source */
// #define PLL_SOURCE_HSI // HSI (~16 MHz) used to clock the PLL, and the PLL is used as system clock source
#define PLL_SOURCE_HSE // HSE (8MHz) used to clock the PLL, and the PLL is used as system clock source
// #define PLL_SOURCE_HSE_BYPASS // HSE bypassed with an external clock (8MHz, coming from ST-Link) used to clock
// the PLL, and the PLL is used as system clock source
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#if defined (PLL_SOURCE_HSI)
#define PLL_M 16
#else
#define PLL_M 8
#endif
#define PLL_N 360
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P 2
/* USB OTG FS, SDIO and RNG Clock = PLL_VCO / PLLQ */
#define PLL_Q 7
/******************************************************************************/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = 180000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
* @{
*/
static void SetSysClock(void);
#if defined (DATA_IN_ExtSDRAM)
static void SystemInit_ExtMemCtl(void);
#endif /* DATA_IN_ExtSDRAM */
/** @addtogroup STM32F4xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F4xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system
* Initialize the FPU setting, vector table location and External memory
* configuration.
* @param None
* @retval None
*/
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
/* Reset the RCC clock configuration to the default reset state ------------*/
/* Set HSION bit */
RCC->CR |= (uint32_t)0x00000001;
/* Reset CFGR register */
RCC->CFGR = 0x00000000;
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* Reset PLLCFGR register */
RCC->PLLCFGR = 0x24003010;
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* Disable all interrupts */
RCC->CIR = 0x00000000;
#if defined (DATA_IN_ExtSDRAM)
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSDRAM */
/* Configure the System clock source, PLL Multiplier and Divider factors,
AHB/APBx prescalers and Flash settings ----------------------------------*/
SetSysClock();
/* Configure the Vector Table location add offset address ------------------*/
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f4xx_hal_conf.h file (default value
* 16 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f4xx_hal_conf.h file (its value
* depends on the application requirements), user has to ensure that HSE_VALUE
* is same as the real frequency of the crystal used. Otherwise, this function
* may have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
*
* @param None
* @retval None
*/
void SystemCoreClockUpdate(void)
{
uint32_t tmp = 0, pllvco = 0, pllp = 2, pllsource = 0, pllm = 2;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case 0x00: /* HSI used as system clock source */
SystemCoreClock = HSI_VALUE;
break;
case 0x04: /* HSE used as system clock source */
SystemCoreClock = HSE_VALUE;
break;
case 0x08: /* PLL used as system clock source */
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N
SYSCLK = PLL_VCO / PLL_P
*/
pllsource = (RCC->PLLCFGR & RCC_PLLCFGR_PLLSRC) >> 22;
pllm = RCC->PLLCFGR & RCC_PLLCFGR_PLLM;
if (pllsource != 0)
{
/* HSE used as PLL clock source */
pllvco = (HSE_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
}
else
{
/* HSI used as PLL clock source */
pllvco = (HSI_VALUE / pllm) * ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> 6);
}
pllp = (((RCC->PLLCFGR & RCC_PLLCFGR_PLLP) >>16) + 1 ) *2;
SystemCoreClock = pllvco/pllp;
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK frequency --------------------------------------------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK frequency */
SystemCoreClock >>= tmp;
}
/**
* @brief Configures the System clock source, PLL Multiplier and Divider factors,
* AHB/APBx prescalers and Flash settings
* @Note This function should be called only once the RCC clock configuration
* is reset to the default reset state (done in SystemInit() function).
* @param None
* @retval None
*/
static void SetSysClock(void)
{
/******************************************************************************/
/* PLL (clocked by HSE) used as System clock source */
/******************************************************************************/
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
#ifdef PLL_SOURCE_HSI
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSI) | (PLL_Q << 24);
#else /* PLL_SOURCE_HSE_BYPASS or PLL_SOURCE_HSE */
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
#ifdef PLL_SOURCE_HSE_BYPASS
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEBYP);
#endif /* PLL_SOURCE_HSE_BYPASS */
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* Configure the main PLL */
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
#endif /*PLL_SOURCE_HSI*/
/* Select regulator voltage output Scale 1 mode, System frequency up to 180 MHz */
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
/* HCLK = SYSCLK / 1*/
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK / 2*/
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
/* PCLK1 = HCLK / 4*/
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
/* Enable the main PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till the main PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Enable the Over-drive to extend the clock frequency to 180 Mhz */
PWR->CR |= PWR_CR_ODEN;
while((PWR->CSR & PWR_CSR_ODRDY) == 0)
{
}
PWR->CR |= PWR_CR_ODSWEN;
while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
{
}
/* Configure Flash prefetch, Instruction cache, Data cache and wait state */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
/* Select the main PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
/* Wait till the main PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL)
{
}
}
#if defined (DATA_IN_ExtSDRAM)
/**
* @brief Setup the external memory controller.
* Called in startup_stm32f4xx.s before jump to main.
* This function configures the external memories (SDRAM)
* This SDRAM will be used as program data memory (including heap and stack).
* @param None
* @retval None
*/
void SystemInit_ExtMemCtl(void)
{
register uint32_t tmpreg = 0, timeout = 0xFFFF;
register __IO uint32_t index;
/* Enable GPIOB, GPIOC, GPIOD, GPIOE, GPIOF and GPIOG interface
clock */
RCC->AHB1ENR |= 0x0000007E;
/* Connect PBx pins to FMC Alternate function */
GPIOB->AFR[0] = 0x0CC00000;
GPIOB->AFR[1] = 0x00000000;
/* Configure PBx pins in Alternate function mode */
GPIOB->MODER = 0x00002A80;
/* Configure PBx pins speed to 100 MHz */
GPIOB->OSPEEDR = 0x00003CC0;
/* Configure PBx pins Output type to push-pull */
GPIOB->OTYPER = 0x00000000;
/* No pull-up, pull-down for PBx pins */
GPIOB->PUPDR = 0x00000100;
/* Connect PCx pins to FMC Alternate function */
GPIOC->AFR[0] = 0x0000000C;
GPIOC->AFR[1] = 0x00000000;
/* Configure PCx pins in Alternate function mode */
GPIOC->MODER = 0x00000002;
/* Configure PCx pins speed to 100 MHz */
GPIOC->OSPEEDR = 0x00000003;
/* Configure PCx pins Output type to push-pull */
GPIOC->OTYPER = 0x00000000;
/* No pull-up, pull-down for PCx pins */
GPIOC->PUPDR = 0x00000000;
/* Connect PDx pins to FMC Alternate function */
GPIOD->AFR[0] = 0x000000CC;
GPIOD->AFR[1] = 0xCC000CCC;
/* Configure PDx pins in Alternate function mode */
GPIOD->MODER = 0xA02A000A;
/* Configure PDx pins speed to 100 MHz */
GPIOD->OSPEEDR = 0xF03F000F;
/* Configure PDx pins Output type to push-pull */
GPIOD->OTYPER = 0x00000000;
/* No pull-up, pull-down for PDx pins */
GPIOD->PUPDR = 0x00000000;
/* Connect PEx pins to FMC Alternate function */
GPIOE->AFR[0] = 0xC00000CC;
GPIOE->AFR[1] = 0xCCCCCCCC;
/* Configure PEx pins in Alternate function mode */
GPIOE->MODER = 0xAAAA800A;
/* Configure PEx pins speed to 100 MHz */
GPIOE->OSPEEDR = 0xFFFFC00F;
/* Configure PEx pins Output type to push-pull */
GPIOE->OTYPER = 0x00000000;
/* No pull-up, pull-down for PEx pins */
GPIOE->PUPDR = 0x00000000;
/* Connect PFx pins to FMC Alternate function */
GPIOF->AFR[0] = 0x00CCCCCC;
GPIOF->AFR[1] = 0xCCCCC000;
/* Configure PFx pins in Alternate function mode */
GPIOF->MODER = 0xAA800AAA;
/* Configure PFx pins speed to 100 MHz */
GPIOF->OSPEEDR = 0xFFC00FFF;
/* Configure PFx pins Output type to push-pull */
GPIOF->OTYPER = 0x00000000;
/* No pull-up, pull-down for PFx pins */
GPIOF->PUPDR = 0x00000000;
/* Connect PGx pins to FMC Alternate function */
GPIOG->AFR[0] = 0x00CC00CC;
GPIOG->AFR[1] = 0xC000000C;
/* Configure PGx pins in Alternate function mode */
GPIOG->MODER = 0x80020A0A;
/* Configure PGx pins speed to 100 MHz */
GPIOG->OSPEEDR = 0xC0030F0F;
/* Configure PGx pins Output type to push-pull */
GPIOG->OTYPER = 0x00000000;
/* No pull-up, pull-down for PGx pins */
GPIOG->PUPDR = 0x00000000;
/* FMC Configuration */
/* Enable the FMC interface clock */
RCC->AHB3ENR |= 0x00000001;
/* Configure and enable SDRAM bank2 */
FMC_Bank5_6->SDCR[0] = 0x00002ED0;
FMC_Bank5_6->SDCR[1] = 0x000001D4;
FMC_Bank5_6->SDTR[0] = 0x0F1F6FFF;
FMC_Bank5_6->SDTR[1] = 0x01010361;
/* SDRAM initialization sequence */
/* Clock enable command */
FMC_Bank5_6->SDCMR = 0x00000009;
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
while((tmpreg != 0) && (timeout-- > 0))
{
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
}
/* Delay */
for (index = 0; index<1000; index++);
/* PALL command */
FMC_Bank5_6->SDCMR = 0x0000000A;
timeout = 0xFFFF;
while((tmpreg != 0) && (timeout-- > 0))
{
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
}
/* Auto refresh command */
FMC_Bank5_6->SDCMR = 0x0000006B;
timeout = 0xFFFF;
while((tmpreg != 0) && (timeout-- > 0))
{
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
}
/* MRD register program */
FMC_Bank5_6->SDCMR = 0x0004620C;
timeout = 0xFFFF;
while((tmpreg != 0) && (timeout-- > 0))
{
tmpreg = FMC_Bank5_6->SDSR & 0x00000020;
}
/* Set refresh count */
tmpreg = FMC_Bank5_6->SDRTR;
FMC_Bank5_6->SDRTR = (tmpreg | (0x0000056A<<1));
/* Disable write protection */
tmpreg = FMC_Bank5_6->SDCR[1];
FMC_Bank5_6->SDCR[1] = (tmpreg & 0xFFFFFDFF);
}
#endif /* DATA_IN_ExtSDRAM */
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
- 把STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\Inc下的stm32f4xx_it.h 复制到 STM32F4xx_System\inc下
- 修改STM32F4xx_System\inc下的stm32f4xx_it.h:把 #include "main.h" 替换为 #include "stm32f429xx.h"
因为main.h会放到APP文件夹下,所以不希望这边直接include APP下的东西
- 把STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\Src下的stm32f4xx_it.c 复制到 STM32F4xx_System\src下
- 修改STM32F4xx_System\src下的stm32f4xx_it.c:
1) 把 #include "main.h" 这行删除
2) 对SVC_Handler, PendSV_Handler, SysTick_Handler做如下改动:
这几个function都对应着ARM Cortex-M架构下的几种exception, 在startup_stm32f429_439xx.s中定义vector table的时候会用到这几个function的起始address,而FreeRTOS 下portable部分会另外实作这几个function。为了避免Linking阶段发生重定义错误,所以特别在stm32f4xx_it.c中的这几个function前面加上weak属性,这样待会产生可执行文件的时候会优先使用FreeRTOS中的实作,而不会使用stm32f4xx_it.c中的实作。 - 把STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\Inc下的main.h 复制到 STM32F4xx_System\inc下并且 重名为 stm32f4xx_hal_msp.h
- 按照如下代码,修改STM32F4xx_System\inc下的stm32f4xx_hal_msp.h
/**
******************************************************************************
* @file UART/UART_TwoBoards_ComPolling/Inc/main.h
* @author MCD Application Team
* @brief Header for main.c module
******************************************************************************
* @attention
*
* © COPYRIGHT(c) 2017 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F4XX_HAL_MSP_H
#define __STM32F4XX_HAL_MSP_H
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* User can use this section to tailor USARTx/UARTx instance used and associated
resources */
/* Definition for USARTx clock resources */
#define USARTx USART1
#define USARTx_CLK_ENABLE() __HAL_RCC_USART1_CLK_ENABLE();
#define USARTx_RX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define USARTx_TX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()
#define USARTx_FORCE_RESET() __HAL_RCC_USART2_FORCE_RESET()
#define USARTx_RELEASE_RESET() __HAL_RCC_USART2_RELEASE_RESET()
/* Definition for USARTx Pins */
#define USARTx_TX_PIN GPIO_PIN_9
#define USARTx_TX_GPIO_PORT GPIOA
#define USARTx_TX_AF GPIO_AF7_USART1
#define USARTx_RX_PIN GPIO_PIN_10
#define USARTx_RX_GPIO_PORT GPIOA
#define USARTx_RX_AF GPIO_AF7_USART1
/* Exported functions ------------------------------------------------------- */
#endif /* __STM32F4XX_HAL_MSP_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
stm32f4xx_hal_msp.h 主要来自于main.h。在stm32f4xx_hal_msp.h中我们主要需要实现待会吐log所用的Uart Port的相关定义。
- 把STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\Src下的stm32f4xx_hal_msp.c 复制到 STM32F4xx_System\src下
- 修改STM32F4xx_System\src下的stm32f4xx_hal_msp.c: 把#include "main.h" 改为 #include "stm32f4xx_hal_msp.h"
至此,STM32F4xx_System文件夹下的内容已经完成。
如果需要配置Fault/Exception/Interrupt handler, 只需修改stm32f4xx_it.c;
如果需要修改System Clock, 只需修改system_stm32f4xx.c;
如果需要修改Log口Hardware配置,只需修改stm32f4xx_hal_msp.c。
- STM32F429I-Discovery 文件夹下内容实现
STM32F429I-Discovery文件夹下主要需要移植STM32F429I_DISCOVERY Board相关的device driver, 例如板子上的lcd、gyroscope device等设备的驱动程序
- 在STM32F429I-Discovery文件夹下分别创建inc和src文件夹。其他文件和文件夹后续章节会介绍
- 把STM32Cube_FW_F4_V1.18.0\Drivers\BSP\STM32F429I-Discovery下 所有H文件 复制到 STM32F429I-Discovery\inc下
- 把STM32Cube_FW_F4_V1.18.0\Drivers\BSP\STM32F429I-Discovery下 所有C文件 复制到 STM32F429I-Discovery\src下
- 把STM32Cube_FW_F4_V1.18.0\Drivers\BSP下 Components文件夹 直接复制到 STM32F429I-Discovery文件夹下
- 把STM32Cube_FW_F4_V1.18.0\Utilities下 Fonts文件夹 直接复制到 STM32F429I-Discovery文件夹下
- 修改STM32F429I-Discovery\src\stm32f429i_discovery_lcd.c 和 STM32F429I-Discovery\src\stm32f429i_discovery_lcd.h 文件:把其中所有 "../../../Utilities/" 替换为 ".."
修改这部分是因为我们Project中的Fonts文件夹和STM32Cube中的路径不一致,如果不按照上述方式修改会发生build error。
至此,STM32F429I-Discovery 文件夹下内容已经全部实现,如果板子是用的是STM32F429I_DISCOVERY Board,可以使用该文件夹下的设备驱动,例如待会会使用BSP_LED_Init/BSP_LED_Toggle 这些API去控制板子上的LED灯。
- Kernel 文件夹下内容实现
Kernel文件夹下主要需要移植FreeRTOS操作系统
- 在Kernel文件夹下创建FreeRTOS文件夹。其他文件后续章节会介绍
- 进入下载好的FreeRTOS Source Code路径下的Source文件夹下,例如我这边的E:\FreeRTOS\Source_Code\FreeRTOSV8.2.3\FreeRTOS\Source
- 把Source文件夹下的所有文件和文件夹都 复制到 Kernel/FreeRTOS下
- 进入到Kernel/FreeRTOS/portable下,把除了 GCC文件夹、MemMang文件夹 和 readme 以外的所有的东西都删除掉
- 进入到Kernel/FreeRTOS/portable/GCC下,把除了 ARM_CM4F文件夹 以外的所有的东西都删除掉
如果读者使用的CPU不是Cortex-M4 Core的话,那么就只需要在GCC下保留对应的CPU架构的文件夹,其他架构的文件夹都不需要。例如Cortex-M0的话,就留ARM_CM0就好了
至此,FreeRTOS Kernel已经移植好了,待会在APP文件夹下添加一个FreeRTOSConfig.h文件,整个Project即可使用FreeRTOS了。
- lib 文件夹下内容实现
lib文件夹下主要存放pre-build好的一些lib,例如libc.a、libg.a、libgcc.a等
- 打开{ARM GNU ToolChain 文件夹}\share\doc\gcc-arm-none-eabi\readme.txt发现,CM4F所使用的lib是放在v7e-m/fpv4-sp/hard下的lib
前提是使用Hard FP
- 进入到{ARM GNU ToolChain 文件夹}\lib\gcc下,把整个arm-none-eabi文件夹 复制到 lib 文件夹下
- 待会会用到lib\arm-none-eabi\6.3.1\thumb\v7e-m\fpv4-sp\hard下的libgcc.a
-
进入到{ARM GNU ToolChain 文件夹}\arm-none-eabi\lib\thumb下,把整个v7e-m文件夹 复制到 lib 文件夹下
- 待会会用到lib\v7e-m\fpv4-sp\hard下的libc.a 和 libg.a
- 进入到{ARM GNU ToolChain 文件夹}\arm-none-eabi文件夹下,把整个include文件夹 复制到 lib 文件夹下
至此,lib下内容已经完全实现。待会build code时候用到的lib, 例如libc.a、libg.a、libgcc.a等,都会在lib\arm-none-eabi\6.3.1\thumb\v7e-m/fpv4-sp/hard or lib\v7e-m/fpv4-sp/hard 下
- APP 文件夹下内容实现
APP文件夹主要实现main.c 和 syscall.c(提供libc所需的system calls, 例如_exit等)
- 在APP文件夹下分别创建inc和src文件夹。其他文件后续章节会介绍
- 在inc文件夹下 创建 main.h,具体内容如下(主要参考STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\Inc\main.h):
/**
******************************************************************************
* @file UART/UART_TwoBoards_ComPolling/Inc/main.h
* @author MCD Application Team
* @brief Header for main.c module
******************************************************************************
* @attention
*
* © COPYRIGHT(c) 2017 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "stm32f429i_discovery.h"
#include "stm32f4xx_hal_msp.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "croutine.h"
#include "event_groups.h"
#include "semphr.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* User can use this section to tailor USARTx/UARTx instance used and associated
resources */
/* Size of Transmission buffer */
#define TXBUFFERSIZE (COUNTOF(aTxBuffer) - 1)
/* Size of Reception buffer */
#define RXBUFFERSIZE TXBUFFERSIZE
/* Exported macro ------------------------------------------------------------*/
#define COUNTOF(__BUFFER__) (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))
/* Exported functions ------------------------------------------------------- */
#endif /* __MAIN_H */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
- 在inc文件夹下 创建 FreeRTOSConfig.h,具体内容如下(主要参考FreeRTOSV8.2.3\FreeRTOS\Demo\CORTEX_M4F_STM32F407ZG-SK\FreeRTOSConfig.h):
/*
FreeRTOS V8.2.3 - Copyright (C) 2015 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that is more than just the market leader, it *
* is the industry's de facto standard. *
* *
* Help yourself get started quickly while simultaneously helping *
* to support the FreeRTOS project by purchasing a FreeRTOS *
* tutorial book, reference manual, or both: *
* http://www.FreeRTOS.org/Documentation *
* *
***************************************************************************
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
the FAQ page "My application does not run, what could be wrong?". Have you
defined configASSERT()?
http://www.FreeRTOS.org/support - In return for receiving this top quality
embedded software for free we request you assist our global community by
participating in the support forum.
http://www.FreeRTOS.org/training - Investing in training allows your team to
be as productive as possible as early as possible. Now you can receive
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
Ltd, and the world's leading authority on the world's leading RTOS.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and commercial middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/
#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.
*----------------------------------------------------------*/
/* Ensure stdint is only used by the compiler, and not the assembler. */
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include
extern uint32_t SystemCoreClock;
#endif
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 1
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 5 )
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 30 * 1024 ) )
#define configMAX_TASK_NAME_LEN ( 16 )
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 0
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
//#define configCHECK_FOR_STACK_OVERFLOW 2
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
//#define configSUPPORT_DYNAMIC_ALLOCATION 1
/* Co-routine definitions. */
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
/* Software timer definitions. */
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 2 )
#define configTIMER_QUEUE_LENGTH 10
#define configTIMER_TASK_STACK_DEPTH ( configMINIMAL_STACK_SIZE * 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
#define INCLUDE_pcTaskGetTaskName 1
/* Cortex-M specific definitions. */
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4 /* 15 priority levels */
#endif
/* The lowest interrupt priority that can be used in a call to a "set priority"
function. */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
/* The highest interrupt priority that can be used by any interrupt service
routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
PRIORITY THAN THIS! (higher priorities are lower numeric values. */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! 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 ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
#define configASSERT( x ) if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#endif /* FREERTOS_CONFIG_H */
- 把STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\Inc下的stm32f4xx_hal_conf.h文件 复制到 APP\inc下
- 对APP\inc下的stm32f4xx_hal_conf.h文件做如下修改:
- 在APP\src 下创建 syscalls.c 文件,用于完成C lib所需的system calls。具体内容如下:
#include
#include
#include
#include
#undef errno
extern int errno;
// extern int __io_putchar(int ch) __attribute__((weak));
// extern int __io_getchar(void) __attribute__((weak));
int __io_putchar(int ch)
{
// return(ITM_SendChar(ch));
extern UART_HandleTypeDef UartHandle;
extern HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_UART_Transmit(&UartHandle, (uint8_t*)&ch, 1, 10);
return 0;
}
int __io_getchar(void)
{
// return(ITM_ReceiveChar());
return 0;
}
int _close(int file)
{
return -1;
}
int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
return 1;
}
int _lseek(int file, int ptr, int dir)
{
return 0;
}
int _open(const char *name, int flags, int mode)
{
return -1;
}
int _read(int file, char *ptr, int len)
{
// int DataIdx;
// for (DataIdx = 0; DataIdx < len; DataIdx++) {
// __io_putchar('+');
// *ptr++ = __io_getchar();
// __io_putchar('-');
// }
// return len;
return 0;
}
int _write(int file, char *ptr, int len)
{
// int DataIdx;
// for (DataIdx = 0; DataIdx < len; DataIdx++) {
// __io_putchar(*ptr++);
// }
extern UART_HandleTypeDef UartHandle;
extern HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_UART_Transmit(&UartHandle, (uint8_t*)ptr, len, 10);
return len;
}
caddr_t _sbrk_r(struct _reent *r, size_t nbytes)
{
extern char end; /* Defined by linker */
static char *heap_end; /* Previous end of heap or 0 if none */
char *prev_heap_end;
char *stack;
__asm volatile("MRS %0, msp\n" : "=r"(stack));
if (0 == heap_end) {
heap_end = &end; /* Initialize first time round */
}
prev_heap_end = heap_end;
if (stack < (prev_heap_end + nbytes)) {
/* heap would overlap the current stack depth.
* Future: use sbrk() system call to make simulator grow memory beyond
* the stack and allocate that
*/
//errno = ENOMEM;
return (char *) - 1;
}
heap_end += nbytes;
return (caddr_t) prev_heap_end;
}
int _execve(char *name, char **argv, char **env)
{
errno = ENOTSUP;
return -1;
}
int _fork(void)
{
errno = ENOTSUP;
return -1;
}
/*
* * getpid -- only one process, so just return 1.
* */
#define __MYPID 1
int _getpid()
{
return __MYPID;
}
/*
* * kill -- go out via exit...
* */
int _kill(int pid, int sig)
{
errno = ENOTSUP;
return -1;
}
int _wait(int *status)
{
errno = ENOTSUP;
return -1;
}
void _exit(int __status)
{
errno = ENOTSUP;
// return -1;
}
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
int _unlink(char *name)
{
errno = EMLINK;
return -1;
}
- 在syscall.c中特别有去把_write function 接到 HAL UART API上。这样,待会程序跑起来以后,所有call printf 吐出的log 都会通过UART口吐出来。所以,待会程序测试的时候可以用串口工具软件查看LOG方便调试。
- 在APP\src 下创建 main.c 文件,用于完成整个Project的主要功能。具体内容如下:
/**
******************************************************************************
* @file UART/UART_TwoBoards_ComPolling/Src/main.c
* @author MCD Application Team
* @brief This sample code shows how to use STM32F4xx UART HAL API to transmit
* and receive a data buffer with a communication process based on
* polling transfer.
* The communication is done using 2 Boards.
******************************************************************************
* @attention
*
* © COPYRIGHT(c) 2017 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/** @addtogroup STM32F4xx_HAL_Examples
* @{
*/
/** @addtogroup UART_TwoBoards_ComPolling
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define TRANSMITTER_BOARD
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* UART handler declaration */
UART_HandleTypeDef UartHandle;
/* Buffer used for transmission */
uint8_t aTxBuffer[] = " **** UART_TwoBoards_ComPolling **** **** UART_TwoBoards_ComPolling **** **** UART_TwoBoards_ComPolling **** \r\n";
/* Buffer used for reception */
uint8_t aRxBuffer[RXBUFFERSIZE];
static TaskHandle_t xHandleTaskLED3 = NULL;
static TaskHandle_t xHandleTaskLED4 = NULL;
/* Private function prototypes -----------------------------------------------*/
static void SystemClock_Config(void);
static void Error_Handler(void);
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength);
static void vTaskLED3(void *pvParameters);
static void vTaskLED4(void *pvParameters);
/* Private functions ---------------------------------------------------------*/
void vApplicationTickHook(void)
{
uint32_t i = 0;
for(i=0; i < portTICK_PERIOD_MS; i++)
{
HAL_IncTick();
}
}
/**
* @brief Main program
* @param None
* @retval None
*/
int main(void)
{
/* STM32F4xx HAL library initialization:
- Configure the Flash prefetch, instruction and Data caches
- Configure the Systick to generate an interrupt each 1 msec
- Set NVIC Group Priority to 4
- Global MSP (MCU Support Package) initialization
*/
HAL_Init();
printf("hello,world\r\n");
/* Configure LED3 and LED4 */
BSP_LED_Init(LED3);
BSP_LED_Init(LED4);
/* Configure the system clock to 180 MHz */
//SystemClock_Config();
/*##-1- Configure the UART peripheral ######################################*/
/* Put the USART peripheral in the Asynchronous mode (UART Mode) */
/* UART1 configured as follow:
- Word Length = 8 Bits
- Stop Bit = One Stop bit
- Parity = None
- BaudRate = 9600 baud
- Hardware flow control disabled (RTS and CTS signals) */
UartHandle.Instance = USARTx;
UartHandle.Init.BaudRate = 115200;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
if(HAL_UART_Init(&UartHandle) != HAL_OK)
{
Error_Handler();
}
xTaskCreate(vTaskLED3, "vTaskLED3", 512, NULL, 2, &xHandleTaskLED3 );
xTaskCreate(vTaskLED4, "vTaskLED4", 512, NULL, 2, &xHandleTaskLED4 );
vTaskStartScheduler();
/* Infinite loop */
while (1)
{
}
#if 0
#ifdef TRANSMITTER_BOARD
/* Configure USER Button */
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_GPIO);
while(1)
{
while (BSP_PB_GetState(BUTTON_KEY) == RESET)
{
}
/* The board sends the message and expects to receive it back */
/*##-2- Start the transmission process #####################################*/
/* While the UART in reception process, user can transmit data through
"aTxBuffer" buffer */
if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 5000)!= HAL_OK)
{
Error_Handler();
}
/* Turn LED3 on: Transfer in transmission process is correct */
/* then Off for next transmission */
BSP_LED_On(LED3);
HAL_Delay(200);
BSP_LED_Off(LED3);
printf("hello,world\r\n");
}
/* Wait for USER Button press before starting the Communication */
while (BSP_PB_GetState(BUTTON_KEY) == RESET)
{
}
/* The board sends the message and expects to receive it back */
/*##-2- Start the transmission process #####################################*/
/* While the UART in reception process, user can transmit data through
"aTxBuffer" buffer */
if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 5000)!= HAL_OK)
{
Error_Handler();
}
/* Turn LED3 on: Transfer in transmission process is correct */
/* then Off for next transmission */
BSP_LED_On(LED3);
HAL_Delay(200);
BSP_LED_Off(LED3);
/*##-3- Put UART peripheral in reception process ###########################*/
if(HAL_UART_Receive(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE, 5000) != HAL_OK)
{
Error_Handler();
}
/* Turn LED3 on: Transfer in transmission process is correct */
/* then Off for next transmission */
BSP_LED_On(LED3);
HAL_Delay(200);
BSP_LED_Off(LED3);
#else
/* The board receives the message and sends it back */
/*##-2- Put UART peripheral in reception process ###########################*/
if(HAL_UART_Receive(&UartHandle, (uint8_t *)aRxBuffer, RXBUFFERSIZE, 5000) != HAL_OK)
{
Error_Handler();
}
/* Turn LED3 on: Transfer in transmission process is correct */
/* then Off for next transmission */
BSP_LED_On(LED3);
HAL_Delay(200);
BSP_LED_Off(LED3);
/*##-3- Start the transmission process #####################################*/
/* While the UART in reception process, user can transmit data through
"aTxBuffer" buffer */
if(HAL_UART_Transmit(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE, 5000)!= HAL_OK)
{
Error_Handler();
}
/* Turn LED3 on: Transfer in transmission process is correct */
/* then Off for next transmission */
BSP_LED_On(LED3);
HAL_Delay(200);
BSP_LED_Off(LED3);
#endif /* TRANSMITTER_BOARD */
/*##-4- Compare the sent and received buffers ##############################*/
if(Buffercmp((uint8_t*)aTxBuffer,(uint8_t*)aRxBuffer,RXBUFFERSIZE))
{
Error_Handler();
}
/* Infinite loop */
while (1)
{
/* Toggle LED3 */
BSP_LED_Toggle(LED3);
/* Wait for 40ms */
HAL_Delay(40);
}
#endif
}
static void vTaskLED3(void *pvParameters)
{
while(1)
{
BSP_LED_Toggle(LED3);
printf("I am in Task LED3\r\n");
vTaskDelay(250/portTICK_PERIOD_MS);
}
}
static void vTaskLED4(void *pvParameters)
{
while(1)
{
BSP_LED_Toggle(LED4);
printf("I am in Task LED4\r\n");
vTaskDelay(100/portTICK_PERIOD_MS);
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 180000000
* HCLK(Hz) = 180000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 360
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* @param None
* @retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 360;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Activate the Over-Drive mode */
HAL_PWREx_EnableOverDrive();
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief UART error callbacks
* @param UartHandle: UART handle
* @note This example shows a simple way to report transfer error, and you can
* add your own implementation.
* @retval None
*/
void HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle)
{
/* Turn LED4 on: Transfer error in reception/transmission process */
BSP_LED_On(LED4);
}
/**
* @brief Compares two buffers.
* @param pBuffer1, pBuffer2: buffers to be compared.
* @param BufferLength: buffer's length
* @retval 0 : pBuffer1 identical to pBuffer2
* >0 : pBuffer1 differs from pBuffer2
*/
static uint16_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
{
while (BufferLength--)
{
if ((*pBuffer1) != *pBuffer2)
{
return BufferLength;
}
pBuffer1++;
pBuffer2++;
}
return 0;
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* Turn LED4 on */
BSP_LED_On(LED4);
while(1)
{
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
main.c 文件主要创建了两个不同frequency的task。在这两个task中会吐不同的log和control不同的LED灯。
- 同时,在FreeRTOSConfig.h中有特意打开systick hook, 而在main.c中有特别实作这个Tick Hook。这是因为:STM32 HAL API是要基于Tick Count去计算Timeout Error的。为了保证HAL API正常使用,特意在systick hook中call HAL_IncTick去增加STM32 HAL API所依赖的Tick Count值
至此,APP文件下的内容已经实现。待会程序编译好后,可以看到开发板上两个LED灯以不同频率闪动,并且COM Port上可以正确收到不同LOG。
- LinkerScripts文件夹下内容实现
LinkerScripts文件夹主要存放memory layout文件
- 把STM32Cube_FW_F4_V1.18.0\Projects\STM32F429I-Discovery\Examples\UART\UART_TwoBoards_ComPolling\SW4STM32\STM32F429I-Discovery下的 STM32F429ZITx_FLASH.ld 复制到 LinkerScripts文件夹下。
至此,LinkerScripts文件夹下内容已经实现。待会编译程序的时候,Linker会根据该文件夹下的STM32F429ZITx_FLASH.ld文件去 链接 其他各个module文件build出来的目标文件和库文件 构成 可执行文件。
VSCode下C环境配置
-
完成上述整个Project程序的移植和编写以后,会发现VSCode提示很多如下的Error:
-
无需担心,点击下“小灯泡”,选择Edit "IncludePath" settings,进入到c_cpp_properties.json(见下图)配置下include path即可。
-
按照下图修改c_cpp_properties.json后就不会出现上述Error了。
Makefile编写
Warning: 由于笔者对Makefile这块不熟悉,对CMake这些Makefile管理工具也不熟悉,所以本章所用到的Makefile文件都是笔者自己写的,所以质量比较挫,大家将就用吧!!!
整个Project的Code都准备好了以后,接下来就得写Makefile去编译整个Project了。
- 在APP模块文件夹下分别创建Makefile和module.mk文件
Makefile文件用于:把这个模块文件下的源码(.c or .s)编译出目标文件(.o)
CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar
CUR_DIR = $(shell pwd)
SRCDIR = ./src
INCDIR = ./inc
OBJDIR = ../out/objects
###########################################
# vpath %.c src
CFLAGS = -g -O0 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
CFLAGS += -I../APP/inc
CFLAGS += -I../CMSIS/Include
CFLAGS += -I../STM32F4xx_HAL_Driver/inc -I../STM32F4xx_System/inc -I../STM32F429I-Discovery/inc
CFLAGS += -I../Kernel/FreeRTOS/include -I../Kernel/FreeRTOS/portable/GCC/ARM_CM4F
CFLAGS += -I$(INCDIR)
CFLAGS += -DSTM32F429xx -DUSE_HAL_DRIVER
SRCS = $(notdir $(wildcard ${SRCDIR}/*.c))
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
.PHONY: all
all: $(OBJS)
$(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $^ $(CFLAGS) -c -o $@
clean:
rm -f $(OBJS)
module.mk文件用于:告诉顶层Makefile文件在这个模块文件夹下哪些目标文件需要被链接
APP_SRCDIR = $(PWD)/APP/src
C_FILES += $(notdir $(wildcard ${APP_SRCDIR}/*.c))
- 在Kernel模块文件夹下分别创建Makefile和module.mk文件
Makefile文件用于:把这个模块文件下的源码(.c or .s)编译出目标文件(.o)
CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar
CUR_DIR = $(shell pwd)
SRCDIR = ./FreeRTOS
INCDIR = ./FreeRTOS/include
OBJDIR = ../out/objects
###########################################
# vpath %.c src
CFLAGS = -g -O1 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
CFLAGS += -I../APP/inc
CFLAGS += -I../CMSIS/Include
CFLAGS += -I../STM32F4xx_HAL_Driver/inc -I../STM32F4xx_System/inc -I../STM32F429I-Discovery/inc
CFLAGS += -I./FreeRTOS/portable/GCC/ARM_CM4F
CFLAGS += -I$(INCDIR)
SRCS = $(notdir $(wildcard ${SRCDIR}/*.c))
SRCS += $(notdir $(wildcard ${SRCDIR}/portable/GCC/ARM_CM4F/*.c))
SRCS += $(notdir $(wildcard ${SRCDIR}/portable/MemMang/heap_4.c))
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
.PHONY: all
all: $(OBJS)
$(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $^ $(CFLAGS) -c -o $@
$(OBJDIR)/%.o : $(SRCDIR)/portable/GCC/ARM_CM4F/%.c
$(CC) $^ $(CFLAGS) -c -o $@
$(OBJDIR)/heap_4.o : $(SRCDIR)/portable/MemMang/heap_4.c
$(CC) $^ $(CFLAGS) -c -o $@
clean:
rm -f $(OBJS)
module.mk文件用于:告诉顶层Makefile文件在这个模块文件夹下哪些目标文件需要被链接
C_FILES += event_groups.c
C_FILES += list.c
C_FILES += queue.c
C_FILES += tasks.c
C_FILES += timers.c
C_FILES += port.c
C_FILES += heap_4.c
- 在Startup模块文件夹下分别创建Makefile和module.mk文件
Makefile文件用于:把这个模块文件下的源码(.c or .s)编译出目标文件(.o)
CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar
AS=arm-none-eabi-as
CUR_DIR = $(shell pwd)
SRCDIR = ./gcc
INCDIR = ./
OBJDIR = ../out/objects
###########################################
# vpath %.c src
CFLAGS = -g -O1 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
# CFLAGS += -ffreestanding -nostdlib
# CFLAGS += -DSTM32F429_439xx -DUSE_STDPERIPH_DRIVER
# CFLAGS += -I../STM32F4xx_StdPeriph_Driver/inc -I../STM32F4xx/ -I../CMSIS/Include -I../STM32F429I-Discovery
# CFLAGS += -I../Include
# CFLAGS += -I../FreeRTOS/include -I../FreeRTOS/portable/GCC/ARM_CM4F
ASFLAGS =
SRCS = $(notdir $(wildcard ${SRCDIR}/*.s))
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.s=.o))
.PHONY: all
all: $(OBJS)
$(OBJDIR)/%.o : $(SRCDIR)/%.s
$(AS) $^ $(ASFLAGS) -o $@
clean:
rm -f $(OBJS)
module.mk文件用于:告诉顶层Makefile文件在这个模块文件夹下哪些目标文件需要被链接
# S_FILES += startup_stm32f429_439xx.s
STARTUP_SRCDIR = $(PWD)/Startup/gcc
S_FILES += $(notdir $(wildcard $(STARTUP_SRCDIR)/*.s))
- 在STM32F4xx_HAL_Driver模块文件夹下分别创建Makefile和module.mk文件
Makefile文件用于:把这个模块文件下的源码(.c or .s)编译出目标文件(.o)
CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar
CUR_DIR = $(shell pwd)
SRCDIR = ./src
INCDIR = ./inc
OBJDIR = ../out/objects
###########################################
# vpath %.c src
CFLAGS = -g -O0 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
CFLAGS += -I../CMSIS/Include
CFLAGS += -I../STM32F4xx_HAL_Driver/inc -I../STM32F4xx_System/inc -I../STM32F429I-Discovery/inc
CFLAGS += -I$(INCDIR) -I$(INCDIR)/Legacy
CFLAGS += -I../APP/inc
CFLAGS += -DSTM32F429xx -DUSE_HAL_DRIVER
SRCS = $(notdir $(wildcard ${SRCDIR}/*.c))
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
.PHONY: all
all: $(OBJS)
$(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $^ $(CFLAGS) -c -o $@
clean:
rm -f $(OBJS)
module.mk文件用于:告诉顶层Makefile文件在这个模块文件夹下哪些目标文件需要被链接
STM32F4XX_HAL_SRCDIR = $(PWD)/STM32F4xx_HAL_Driver/src
C_FILES += $(notdir $(wildcard ${STM32F4XX_HAL_SRCDIR}/*.c))
- 在STM32F4xx_System模块文件夹下分别创建Makefile和module.mk文件
Makefile文件用于:把这个模块文件下的源码(.c or .s)编译出目标文件(.o)
CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar
CUR_DIR = $(shell pwd)
SRCDIR = ./src
INCDIR = ./inc
OBJDIR = ../out/objects
###########################################
# vpath %.c src
CFLAGS = -g -O0 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
CFLAGS += -I../CMSIS/Include
CFLAGS += -I../STM32F4xx_HAL_Driver/inc -I../STM32F4xx_System/inc -I../STM32F429I-Discovery/inc
CFLAGS += -I$(INCDIR)
CFLAGS += -I../APP/inc
CFLAGS += -DSTM32F429xx -DUSE_HAL_DRIVER
SRCS = $(notdir $(wildcard ${SRCDIR}/*.c))
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
.PHONY: all
all: $(OBJS)
$(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $^ $(CFLAGS) -c -o $@
clean:
rm -f $(OBJS)
module.mk文件用于:告诉顶层Makefile文件在这个模块文件夹下哪些目标文件需要被链接
STM32F4XX_SYSTEM_SRCDIR = $(PWD)/STM32F4xx_System/src
C_FILES += $(notdir $(wildcard ${STM32F4XX_SYSTEM_SRCDIR}/*.c))
- 在STM32F429I-Discovery模块文件夹下分别创建Makefile和module.mk文件
Makefile文件用于:把这个模块文件下的源码(.c or .s)编译出目标文件(.o)
CC=arm-none-eabi-gcc
AR=arm-none-eabi-ar
CUR_DIR = $(shell pwd)
SRCDIR = ./src
INCDIR = ./inc
OBJDIR = ../out/objects
###########################################
# vpath %.c src
CFLAGS = -g -O0 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
CFLAGS += -I../CMSIS/Include
CFLAGS += -I../STM32F4xx_HAL_Driver/inc -I../STM32F4xx_System/inc -I../STM32F429I-Discovery/inc
CFLAGS += -I$(INCDIR)
CFLAGS += -I../APP/inc
CFLAGS += -DSTM32F429xx -DUSE_HAL_DRIVER
SRCS = $(notdir $(wildcard ${SRCDIR}/*.c))
OBJS = $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))
.PHONY: all
all: $(OBJS)
$(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $^ $(CFLAGS) -c -o $@
clean:
rm -f $(OBJS)
module.mk文件用于:告诉顶层Makefile文件在这个模块文件夹下哪些目标文件需要被链接
STM32F4XX_DISCOVERY_SRCDIR = $(PWD)/STM32F429I-Discovery/src
C_FILES += $(notdir $(wildcard ${STM32F4XX_DISCOVERY_SRCDIR}/*.c))
- 在Project rootpath下创建一个顶层Makefile文件(代码见下)
顶层Makefile文件用于:1)进入到各个模块文件夹下编译出目标文件 2)链接所有需要使用的目标文件和库文件生产可执行文件 3)把可执行文件转换成dis文件、map文件、bin文件和hex文件
PWD= $(shell pwd)
PROJ_NAME = HAL_demo
OUTPATH = out
OBJPATH = objects
LOGPATH = logs
LIBPATH := ./lib
CC=arm-none-eabi-gcc
AS=arm-none-eabi-as
LD=arm-none-eabi-ld
AR=arm-none-eabi-ar
OBJCOPY=arm-none-eabi-objcopy
OBJDUMP=arm-none-eabi-objdump
CFLAGS = -g -O2 -Wall
CFLAGS += -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16
CFLAGS += -mlittle-endian -mthumb-interwork
CFLAGS += --specs=nosys.specs
CFLAGS += -DSTM32F429xx -DUSE_HAL_DRIVER
CFLAGS += -I../CMSIS/Include
CFLAGS += -I../STM32F4xx_HAL_Driver/inc -I../STM32F4xx_System/inc -I../STM32F429I-Discovery/inc
CFLAGS += -I../APP/inc
# LDFLAGS = --specs=nano.specs -lnosys -nostartfiles
# LDFLAGS += -Wl,-wrap=malloc -Wl,-wrap=calloc -Wl,-wrap=realloc -Wl,-wrap=free
# LDFLAGS += -Wl,-T./LinkerScripts/STM32F429ZI_FLASH.ld -Wl,--gc-sections
LDFLAGS += -nostartfiles --gc-sections
# LDFLAGS += --gc-sections
LDFLAGS += -L$(LIBPATH)/v7e-m/fpv4-sp/hard -lc
LDFLAGS += -L$(LIBPATH)/v7e-m/fpv4-sp/hard -lg
# LDFLAGS += -L$(LIBPATH)/arm-none-eabi/6.3.1/hard -lgcc
LDFLAGS += -L$(LIBPATH)/arm-none-eabi/6.3.1/thumb/v7e-m/fpv4-sp/hard -lgcc
LDFLAGS += -T./LinkerScripts/STM32F429ZI_FLASH.ld
LDFLAGS += -Map=$(OUTPATH)/$(PROJ_NAME).map
C_FILES :=
S_FILES :=
include ./APP/module.mk
include ./Kernel/module.mk
include ./Startup/module.mk
include ./STM32F4xx_HAL_Driver/module.mk
include ./STM32F4xx_System/module.mk
include ./STM32F429I-Discovery/module.mk
C_OBJS := $(addprefix $(OUTPATH)/$(OBJPATH)/, $(C_FILES:.c=.o))
S_OBJS += $(addprefix $(OUTPATH)/$(OBJPATH)/, $(S_FILES:.s=.o))
LIB_OBJS := libc.a
subdirs :=
subdirs += ./Startup ./STM32F4xx_System ./STM32F4xx_HAL_Driver ./STM32F429I-Discovery ./Kernel ./APP
all:
@mkdir $(OUTPATH)
@mkdir $(OUTPATH)/$(OBJPATH)
@mkdir $(OUTPATH)/$(LOGPATH)
@echo building $(S_OBJS) $(C_OBJS) $(LIB_OBJS)
for d in $(subdirs); do make -C $$d || exit 1; done
# for d in $(subdirs); do make -C $$d || exit 1; done > $(OUTPATH)/$(LOGPATH)/build.log
@echo building $(OUTPATH)/$(PROJ_NAME).elf
$(LD) $(C_OBJS) $(S_OBJS) $(LDFLAGS) -o $(OUTPATH)/$(PROJ_NAME).elf
@$(OBJDUMP) -D $(OUTPATH)/$(PROJ_NAME).elf > $(OUTPATH)/$(PROJ_NAME).dis
@$(OBJCOPY) -O ihex $(OUTPATH)/$(PROJ_NAME).elf $(OUTPATH)/$(PROJ_NAME).hex
@$(OBJCOPY) -O binary $(OUTPATH)/$(PROJ_NAME).elf $(OUTPATH)/$(PROJ_NAME).bin
@echo Done
clean:
@echo clean $(S_OBJS) $(C_OBJS) $(LIB_OBJS)
for d in $(subdirs); do make -C $$d $@; done
@echo cleaning $(OUTPATH)/$(PROJ_NAME).elf
@rm -rf $(OUTPATH)
至此,整个Makefile系统已经搭建完毕。在Terminal(Cygwin)下输入make指令就可以build code了。
VSCode下Terminal配置
VSCode是带有Terminal交换面板的。在Windows下,VSCode默认使用的terminal是cmd或者powershell。由于Cygwin更好使用,所有得把VSCode默认的terminal改成Cygwin。
具体修改方式如下:
- 编辑系统环境变量,把{Cygwin安装路径}\bin 加到PATH里面
- 进入到用户设置界面,然后把terminal.integrated.shell.windows 设置为 按照好的Cygwin的bash.exe
-
修改好Terminal后,按下 “Ctrl + ` ” 快捷键即可发现默认的终端已经成功切换为Cygwin了
编译程序
- gcc下编译过程如下图所示:
.c文件 经过 arm-none-eabi-gcc 编译成 .o文件
.s文件 经过 arm-none-eabi-as 编译成 .o文件
.o文件 和 .a文件 经过 arm-none-eabi-ld 链接成 .elf文件
.elf文件 经过 arm-none-eabi-objcopy 和 arm-none-eabi-objdump 转换成 hex文件/dis文件
arm-none-eabi-gdb 使用 .elf文件 进行debug
-
在Terminal下输入make指令,即会开始build程序
-
编译完成后,生成的所有文件都会放在out文件夹下
如果改了source code,需要重新编译程序,那就得先执行make clean指令去删除之前build好的所有东西。然后重新执行make指令即可。
程序烧写和运行
完成上面所有步骤,可以得到hex文件。我们只需要把hex文件download到STM32F429内部的FLASH上,就可以执行程序查看效果了。
- 程序烧写
-
把板子连接上电脑
-
打开STM32 ST-LINK Utility,连上ST-Link
-
擦除FLASH上所有数据
-
选择out文件夹下的hex文件,download到FLASH里面
至此,程序已经成功download到FLASH上了。
- 程序运行
-
查看LED等闪烁
-
查看串口LOG
本章总结
本章的主要目的:在VSCode下搭建编译环境
- 架构Project搭建
- 移植和编写各个模块文件夹下的程序
- Makefile编译
- 编译程序
- 程序烧写和运行
在下一章中,会向大家介绍如何在VSCode下搭建调试环境