前言
目前主流开发STM32的工具有Keil等工具,但个人认为其界面复杂,操作繁琐,导致开发效率低下。故自行寻找STM32提供的交叉编译工具的使用方法,自行搭建交叉编译环境,进行STM32的开发,后续也可沿用此方法进行其他嵌入式的开发,
提示:这一套开发环境使用工具有VSCode,Make,WSL/Centos,arm-none-eabi-gcc。其中前三者的安装过程在这里不再赘述。
提示:WSL/CentOS在本文中统一名称为编译服务器
arm-none-eabi-gcc的安装请点击这里
一、准备好官方提供的库文件
在例程中,本人使用STM32C8T6开发,故下载ST官网提供相关的库函数包。
官网地址为:https://www.st.com/en/embedded-s ... edded-software.html
打开后选择标准库
随后找到自己开发板对应的型号
最后下载并解压,文件夹内容如下
二、创建工作目录
在编译服务器中,创建好文件夹,并在文件夹中创建user目录和Makefile文件,再把官方库文件的Libraries复制过来,我的目录如下:
三、编写相关文件
1.在user目录中编写main.c文件,用来进行最终的效果测试
本人使用的是stm32c8t6最小系统板,使用led灯闪烁例程进行测试。
代码如下(示例):
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/main.c
* @author MCD Application Team
* @version V3.6.0
* @date 20-September-2021
* @brief Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2011 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_conf.h"
#include "stm32f10x.h"
#include <stdio.h>
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
void GPIO_Configuration(void);
//=============================================================================
//文件名称:Delay
//功能概要:延时
//参数说明:nCount:延时长短
//函数返回:无
//=============================================================================
void Delay(uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void)
{
GPIO_Configuration();
while (1)
{
PCout(13) = 1;
Delay(0xfffff);
Delay(0xfffff);
PCout(13) = 0;
Delay(0xfffff);
Delay(0xfffff);
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC , ENABLE);
//=============================================================================
//LED -> PC13
//=============================================================================
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
/**
* @brief Retargets the C library printf function to the USART.
* @param None
* @retval None
*/
#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
/**
* @}
*/
2.stm32f10x_conf.h
把库文件的stm32f10x_conf.h 复制到user目录中。该文件在
STM32F10x_StdPeriph_Lib_V3.6.0\Project\STM32F10x_StdPeriph_Template
目录下。
3.stm32f10x_flash_extsram.ld
在Makefile平级的目录中自行创建该文件,该文件用于交叉编译的链接阶段,规定flash、ram等大小。
1
若使用的芯片不同,则该文件的内容不同
/* Default linker script for STM32F103C8T6 */
MEMORY
{
/* STM32F103C8T6 内存区域 */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}
__Stack_Size = 1024; /* 默认栈大小 */
PROVIDE ( _Stack_Size = __Stack_Size );
__Stack_Init = _estack - __Stack_Size;
PROVIDE ( _Stack_Init = __Stack_Init );
_Minimum_Stack_Size = 0x100;
_estack = 0x20005000; /* 栈的高地址,接近 RAM 的顶部 */
/* 代码段和数据段的定义 */
SECTIONS
{
/* 启动代码和中断向量表 */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* 中断向量表 */
. = ALIGN(4);
} >FLASH
/* 程序代码段,放在 Flash 中 */
.text :
{
. = ALIGN(4);
*(.text) /* 程序代码 */
*(.text.*) /* 其他代码 */
*(.rodata) /* 只读数据(常量) */
*(.rodata*)
. = ALIGN(4);
_etext = .;
_sidata = _etext; /* 用于初始化数据段 */
} >FLASH
/* 初始化数据段 */
.data : AT (_sidata)
{
. = ALIGN(4);
_sdata = .;
*(.data) /* 初始化数据 */
*(.data.*)
. = ALIGN(4);
_edata = .;
} >RAM
/* 未初始化的数据段 */
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/* 用户栈 */
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ; /* 最小栈大小 */
. = ALIGN(4);
_eusrstack = . ;
} >RAM
/* 丢弃调试信息 */
DISCARD :
{
libc.a (*)
libm.a (*)
libgcc.a (*)
}
/* 调试信息(可选) */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
}
4.编写Makefile文件
注意:在这里我把库文件的目录改为stm32f10x_lib
最终目录结构如下:
Makefile文件内容如下
# toolchain
TOOLCHAIN = arm-none-eabi-
CC = $(TOOLCHAIN)gcc
CP = $(TOOLCHAIN)objcopy
AS = $(TOOLCHAIN)gcc -x assembler-with-cpp
# all the files will be generated with this name (main.elf, main.bin, main.hex, etc)
PROJECT_NAME=stm32f10x_project
# define include dir
INCLUDE_DIRS =
# define stm32f10x lib dir
STM32F10x_LIB_DIR = ./stm32f10x_lib
# define user dir
USER_DIR = ./user
# link file
LINK_SCRIPT = ./stm32f10x_flash_extsram.ld
# user specific
SRC =
ASM_SRC =
SRC += $(USER_DIR)/main.c
# user include
INCLUDE_DIRS =
# source director
STM32F1_STD_LIB = $(STM32F10x_LIB_DIR)/STM32F10x_StdPeriph_Driver
STM32F1_CORE_DIR = $(STM32F10x_LIB_DIR)/CMSIS/CM3/CoreSupport
STM32F1_DEVICE_DIR = $(STM32F10x_LIB_DIR)/CMSIS/CM3/DeviceSupport/ST/STM32F10x
STM32F1_SRC_DIR = $(STM32F1_STD_LIB)/src
STM32F1_INC_DIR = $(STM32F1_STD_LIB)/inc
# startup
ASM_SRC += $(STM32F1_DEVICE_DIR)/startup/gcc_ride7/startup_stm32f10x_md.s
# CMSIS
SRC += $(STM32F1_DEVICE_DIR)/system_stm32f10x.c
SRC += $(STM32F1_CORE_DIR)/core_cm3.c
# use libraries, please add or remove when you use or remove it.
SRC += $(STM32F1_SRC_DIR)/stm32f10x_rcc.c
SRC += $(STM32F1_SRC_DIR)/stm32f10x_gpio.c
SRC += $(STM32F1_SRC_DIR)/stm32f10x_exti.c
SRC += $(STM32F1_SRC_DIR)/stm32f10x_usart.c
SRC += $(STM32F1_SRC_DIR)/misc.c
# include directories
INCLUDE_DIRS += $(STM32F1_CORE_DIR)
INCLUDE_DIRS += $(STM32F1_DEVICE_DIR)
INCLUDE_DIRS += $(STM32F1_INC_DIR)
INCLUDE_DIRS += $(STM32F1_STD_LIB)
INCLUDE_DIRS += $(USER_DIR)
INC_DIR = $(patsubst %, -I%, $(INCLUDE_DIRS))
OBJECTS = $(ASM_SRC:.s=.o) $(SRC:.c=.o)
# Define optimisation level here
MC_FLAGS = -mcpu=cortex-m3
AS_FLAGS = $(MC_FLAGS) -g -gdwarf-2 -mthumb -Wa,-amhls=$(<:.s=.lst)
CP_FLAGS = $(MC_FLAGS) -Os -g -gdwarf-2 -mthumb -fomit-frame-pointer -Wall -fverbose-asm -Wa,-ahlms=$(<:.c=.lst)
LD_FLAGS = $(MC_FLAGS) -g -gdwarf-2 -mthumb -nostartfiles -Xlinker --gc-sections -T$(LINK_SCRIPT) -Wl,-Map=$(PROJECT_NAME).map,--cref,--no-warn-mismatch
# makefile rules
all: $(OBJECTS) $(PROJECT_NAME).elf $(PROJECT_NAME).hex $(PROJECT_NAME).bin
$(TOOLCHAIN)size $(PROJECT_NAME).elf
%.o: %.c
$(CC) -c $(CP_FLAGS) -I . $(INC_DIR) $< -o $@
%.o: %.s
$(AS) -c $(AS_FLAGS) $< -o $@
%.elf: $(OBJECTS)
$(CC) $(OBJECTS) $(LD_FLAGS) -o $@
%.hex: %.elf
$(CP) -O ihex $< $@
%.bin: %.elf
$(CP) -O binary -S $< $@
clean:
rm -f $(OBJECTS) $(PROJECT_NAME).elf $(PROJECT_NAME).bin $(PROJECT_NAME).hex $(PROJECT_NAME).map $(PROJECT_NAME).lst
rm -f $(STM32F10x_LIB_DIR)/**/*.lst $(USER_DIR)/**/*.lst
# del /Q $(PROJECT_NAME).elf $(PROJECT_NAME).hex $(PROJECT_NAME).bin
5.相关文件的修改
如果这时候编译会报相关错误。
在stm32f10x_lib/CMSIS/CM3/DeviceSupport/ST/STM32F10x/目录下找到stm32f10x.h文件,找到67行把#define STM32F10X_MD一行注释掉不同的芯片这里解除注释的内容不同
找到该文件104行,解除掉#define USE_STDPERIPH_DRIVER的注释
找到stm32f10x_lib/CMSIS/CM3/CoreSupport下的core_cm3.c文件,736行和753行,改为如下代码
__ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
6.最后使用Make编译
成功的结果如下,可以烧录进行测试
例程模板在https://gitee.com/iFENG-123/template-stm32
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_63174648/article/details/144886503
|
|