声明

讲解stm32c8t6点灯程序从c语言到bin烧录文件的整体流程。

第一部分,比较重要,说清楚被开发工具隐藏的c语言到bin文件流程,包括交叉编译器、c语言预处理,编译,汇编,链接,各个阶段生成的文件。

第二部分,将生成的bin反向推理中断向量,代码编反汇编。

第三部分,通过bootloader+app讲解中断偏移等内容

第一部分

在window下使用交叉编译工具

  • 安装
https://developer.arm.com/downloads/-/gnu-rm
  • 配置环境变量,配置到windows环境
D:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin
  • 由于windows执行makefile比较困难,需要一步一步编译每个.c文件,再做链接,要么就要写shell脚本,比较麻烦。现在只举一些例子。以下是点灯程序,包含main.c:对应的c文件,以及startup.s:对应的汇编启动代码,还有link.ld链接脚本。

main.c

// 寄存器地址(STM32F103 固定)
#define RCC_BASE  0x40021000
#define GPIOA_BASE 0x40010800

#define RCC_APB2ENR *(volatile unsigned int *)(RCC_BASE + 0x18)
#define GPIOA_CRL   *(volatile unsigned int *)(GPIOA_BASE + 0x00)
#define GPIOA_ODR   *(volatile unsigned int *)(GPIOA_BASE + 0x0C)

void main(void)
{
  // 1. 使能 GPIOA 时钟
  RCC_APB2ENR |= 1 << 2;

  // 2. 配置 PA0 推挽输出
  GPIOA_CRL &= ~(0xF << 0);
  GPIOA_CRL |=  (0x3 << 0);

  // 3. 点灯 PA0
  GPIOA_ODR |= 1 << 0;

  // 死循环
  while(1);
}

startup.s

.equ _estack, 0x20005000

.section .isr_vector
.global _vector_table
_vector_table:
  .word _estack
  .word Reset_Handler
  .word 0
  .word 0
  .word 0
  .word 0
  .word 0

.section .text.Reset_Handler
Reset_Handler:
  bl main
  b .

link.ld


MEMORY
{
  FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 64K
  RAM   (rw)  : ORIGIN = 0x20000000, LENGTH = 20K
}


SECTIONS
{
  .text :
  {
    *(.isr_vector)     
    *(.text)           
  } > FLASH            

  .data :
  {
    *(.data)
  } > RAM AT > FLASH
}

将上面的三个文件放到同一个目录下,依次执行以下shell命令

1.将startup.s汇编文件编译成目标文件

arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c startup.s -o startup.o

2.将main.c编译成目标文件

arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c main.c -o main.o

3.使用链接文件链接生成elf文件

arm-none-eabi-ld startup.o main.o -T link.ld -o main.elf

4.elf文件转成hex文件,elf文件转成bin文件

arm-none-eabi-objcopy -O ihex main.elf main.hex
arm-none-eabi-objcopy -O binary main.elf main.bin

步骤解析:

1.将汇编文件编程成目标文件过程。

2.main.c编译成目标文件,这个步骤依赖的头文件,如果是stdio.h这种已经有的会放在arm-none-eabi\include目录下,编译器会自己引进来。如果是自己写的比如,iic.c和iic.h,main.c引入了iic.h,这时候就需要添加**-T ./**命令。把对应目录下的头文件引进来。