打印
[应用相关]

VSCode+GCC开发STM32

[复制链接]
103|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2025-1-8 13:48 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
前言
目前主流开发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

使用特权

评论回复
沙发
sfd123| | 2025-1-8 13:57 | 只看该作者
如果需要调试怎么办?这个方式可以吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2049

主题

15997

帖子

15

粉丝