当前位置: 首页 > article >正文

VSCode + GD32F407 构建烧录

前言

      最近调试一块 GD32F407VET6(168Mhz,8Mhz晶振) 板子时,踩了一些“启动失败”的坑。本以为是时钟配置有误,最后发现是链接脚本(.ld 文件)没有配置好,导致程序根本没能正常执行 main() 函数。

      顺着这个调试过程,我认真梳理了一遍裸机开发中几个关键文件的作用,也对兆易官方的工程模板、工具链支持以及主流开发方式有了更深理解。

     这篇文章记录下踩坑的点:

  • GD32F407 是什么

  • .ld、启动文件 .s、gd32f4xx.h、system_gd32f4xx.c 各自做什么

  • 为什么 Keil 用户往往感知不到这些文件

  • 用 VS Code + GCC 为什么必须掌握这些底层配置

  • 顺带了解 RT-Thread 软件包在裸机开发中的角色

具体的构建烧录可以参考我前阵写的关于STM32板子的文章:

真.从“零”搞 VSCode+STM32CubeMx+C <1>构建

真.从“零”搞 VSCode+STM32CubeMx+C <2>调试+烧录


GD32F407 是什么?

       GD32F407 是 兆易创新(GigaDevice) 出品的一款高性能、Cortex-M4F 内核的国产 MCU,很多方面与 STM32F407 十分接近,甚至寄存器定义、引脚排列都保持高度兼容。

它的核心特性包括:

  • Cortex-M4 @168MHz,支持 FPU、DSP

  • Flash:最多 1MB,SRAM:最多 192KB(我这个Flash512k,Ram192k)

  • 丰富外设:ADC、DAC、CAN、USB OTG、ETH、FSMC、USART、SPI、I2C 等

  • 多种封装:LQFP100、LQFP144、BGA 等

  • 支持 SWD/JTAG 在线调试

       兆易推出 GD32 系列,就是想打破 STM32 在中高端 MCU 的垄断,性价比很高,受到不少国产项目的青睐。许多资料表示是可以完全平替的,但是经试用,还是有一些门槛的,尤其是在迁移上。


程序是如何启动的?

       我们以“点亮一个 LED 灯”为例,要让一个空白的 GD32F407 板子成功运行 main() 函数,中间需要经历一系列复杂的初始化:

涉及的关键文件:

文件

作用

startup_gd32f407xx.s

启动汇编文件,设置栈、跳转到 main()

system_gd32f4xx.c

初始化系统时钟、PLL 等

gd32f4xx.h

寄存器定义头文件

.ld 文件

GCC 链接脚本,决定各段如何映射到内存


这些文件具体做了什么?

1. 启动文件 .s(startup_gd32f407xx.s)

启动汇编是程序真正的起点。其主要工作包括:

  • 设置 MSP(主栈指针)初始值

  • 定义中断向量表(.isr_vector 段)

  • 运行 C 程序前的初始化(拷贝 .data 段、清零 .bss 段)

  • 调用 SystemInit() 初始化系统时钟

  • 最后跳转到 main()

    注意:官方只提供了Keil版,一般例程都是Keil版的,是没有.s和.ld文件的,github上的例程大多是带两种版本的:

    • ARMCC/Keil 版(语法更偏汇编,.asm)
    • GCC 版(.s,符合 GNU 汇编语法)
    • 如果你用的是 GCC,需要选对文件,否则编译会报错。

    2. system_gd32f4xx.c

    这是一个用 C 语言写的底层初始化文件,主要负责:

    • 启用外部晶振 HSE

    • 配置 PLL、AHB/APB 分频

    • 设置 FLASH 加速参数

    • 更新全局变量 SystemCoreClock

          SystemInit() 是由启动文件在最开始调用的,它决定了你的程序到底是跑在 16MHz(HSI)还是 168MHz(PLL)上,如下图,我选择的是168Mhz和8M晶振

    3. gd32f4xx.h

    这个头文件包含了所有外设的寄存器定义和映射,宏非常多,比如:

    #define GPIOA_BASE   (0x40020000UL)
    #define GPIOA        ((gpio_reg_struct *) GPIOA_BASE)

    你能像下面这样控制 GPIO 灯,就是因为这些定义:

    GPIOA->ODCTL |= GPIO_PIN_0;

    也就是说,这个文件相当于裸机程序的“控制面板”。注意这里也有个配晶振的地方。

    4. .ld链接脚本文件(GCC 专属)

    .ld 是 GCC 编译时才需要的文件,决定了:

    • 哪些代码段放在 Flash,哪些放在 RAM

    • main() 的入口在哪(通常由 .isr_vector 决定)

    • 栈、堆、全局变量的布局是否合理

    • .data 是否正确从 Flash 拷贝到 RAM

    MEMORY {FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 1024KRAM   (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
    }

    没有正确的 .ld 文件,哪怕你 main() 写得再好,程序也跑不起来。


    Keil 用户为何“感觉不到”这些文件?

    GD32 官方对 Keil 的支持非常完善,可以说是“官方首选工具链”:

    • 提供完整的 Keil 工程模板

    • 不需要 .ld 文件,Keil 使用内部 scatter 文件自动配置

    • 启动文件、系统文件全都配置好,一键编译运行

    • 集成调试、仿真、烧录工具链非常成熟

    也正因为如此,很多初学者用 Keil 上手时,往往不需要关注 .s 和 .ld 这些底层配置文件。

    这也导致了一种错觉:“只要写代码就能跑”,一旦换到 GCC 环境就懵了。


    VS Code + GCC 

    如果你像我一样用的是:

    • VS Code + GCC + CMake 或 Makefile

    • OpenOCD 进行烧录调试

    那么你必须亲自处理:

    任务

    所需文件

    指定入口地址

    .ld 脚本

    启动中断向量表

    启动汇编 .s

    系统时钟配置

    system_gd32f4xx.c

    外设控制宏定义

    gd32f4xx.h

    这是一条“裸机开发 + 自定义构建系统”的路线,更接近真实嵌入式底层工程师的工作方式。


    RT-Thread 软件包的角色

    很多 GD32 工程也会用到 RT-Thread 软件包。它的作用:

    • 提供轻量级的实时操作系统内核(调度器、线程、定时器、信号量等)

    • 统一驱动框架(设备树、HAL 层)

    • 配合 BSP 提供板级初始化、外设驱动

    在裸机开发中,也常常只用它的 BSP 初始化和驱动部分,比如:

    rt_hw_board_init();   // 初始化引脚、时钟、串口等

           你可以只用它的初始化和驱动部分,不一定用内核调度。我也下载安装了,本以为会向资料表示的可以像STM32CubeMx那样生成代码,再和VSCode联动,没想到连BSP都没下载成功,就放弃了。


    总结

    工具链

    是否需要关注 .ld / .s

    Keil / MDK

    否,自动配置,官方模板支持

    VS Code + GCC

    是,必须手动配置

    理解 .ld 和 .s 是裸机开发的必经之路。

    如果你:

    • 用 GCC 编译工具链

    • 用 OpenOCD 烧录

    那么早点掌握这些启动流程、链接布局、外设定义,绝对会让你少踩很多坑。


    附1:VSCode EIED配置图

    附2:.s、.ld代码

    /** linker script for GD32F4xx with GNU ld* BruceOu 2021-12-14*//* Program Entry, set to mark it as "used" and avoid gc */
    MEMORY
    {CODE (rx) : ORIGIN = 0x08000000, LENGTH = 512k /* 512KB flash */DATA (rw) : ORIGIN = 0x20000000, LENGTH =  128k /* 128KB sram ,0x1000 0000 - 0x1000 FFFF TCMSRAM(64KB)*/
    }
    ENTRY(Reset_Handler)
    _system_stack_size = 0x200;SECTIONS
    {.text :{. = ALIGN(4);_stext = .;KEEP(*(.isr_vector))            /* Startup code */. = ALIGN(4);*(.text)                        /* remaining code */*(.text.*)                      /* remaining code */*(.rodata)                      /* read-only data (constants) */*(.rodata*)*(.glue_7)*(.glue_7t)*(.gnu.linkonce.t*)/* section information for finsh shell */. = ALIGN(4);__fsymtab_start = .;KEEP(*(FSymTab))__fsymtab_end = .;. = ALIGN(4);__vsymtab_start = .;KEEP(*(VSymTab))__vsymtab_end = .;. = ALIGN(4);/* section information for initial. */. = ALIGN(4);__rt_init_start = .;KEEP(*(SORT(.rti_fn*)))__rt_init_end = .;. = ALIGN(4);. = ALIGN(4);_etext = .;} > CODE = 0/* .ARM.exidx is sorted, so has to go in its own output section.  */__exidx_start = .;.ARM.exidx :{*(.ARM.exidx* .gnu.linkonce.armexidx.*)/* This is used by the startup in order to initialize the .data secion */_sidata = .;} > CODE__exidx_end = .;/* .data section which is used for initialized data */.data : AT (_sidata){. = ALIGN(4);/* This is used by the startup in order to initialize the .data secion */_sdata = . ;*(.data)*(.data.*)*(.gnu.linkonce.d*). = ALIGN(4);/* This is used by the startup in order to initialize the .data secion */_edata = . ;} >DATA.stack : {. = . + _system_stack_size;. = ALIGN(4);_estack = .;} >DATA__bss_start = .;.bss :{. = ALIGN(4);/* This is used by the startup in order to initialize the .bss secion */_sbss = .;*(.bss)*(.bss.*)*(COMMON). = ALIGN(4);/* This is used by the startup in order to initialize the .bss secion */_ebss = . ;*(.bss.init)} > DATA__bss_end = .;_end = .;/* Stabs debugging sections.  */.stab          0 : { *(.stab) }.stabstr       0 : { *(.stabstr) }.stab.excl     0 : { *(.stab.excl) }.stab.exclstr  0 : { *(.stab.exclstr) }.stab.index    0 : { *(.stab.index) }.stab.indexstr 0 : { *(.stab.indexstr) }.comment       0 : { *(.comment) }/* DWARF debug sections.* Symbols in the DWARF debugging sections are relative to the beginning* of the section so we begin them at 0.  *//* DWARF 1 */.debug          0 : { *(.debug) }.line           0 : { *(.line) }/* GNU DWARF 1 extensions */.debug_srcinfo  0 : { *(.debug_srcinfo) }.debug_sfnames  0 : { *(.debug_sfnames) }/* DWARF 1.1 and DWARF 2 */.debug_aranges  0 : { *(.debug_aranges) }.debug_pubnames 0 : { *(.debug_pubnames) }/* DWARF 2 */.debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }.debug_abbrev   0 : { *(.debug_abbrev) }.debug_line     0 : { *(.debug_line) }.debug_frame    0 : { *(.debug_frame) }.debug_str      0 : { *(.debug_str) }.debug_loc      0 : { *(.debug_loc) }.debug_macinfo  0 : { *(.debug_macinfo) }/* SGI/MIPS DWARF 2 extensions */.debug_weaknames 0 : { *(.debug_weaknames) }.debug_funcnames 0 : { *(.debug_funcnames) }.debug_typenames 0 : { *(.debug_typenames) }.debug_varnames  0 : { *(.debug_varnames) }
    }
      .syntax unified.cpu cortex-m4.fpu softvfp.thumb.global  g_pfnVectors
    .global  Default_Handler/* start address for the initialization values of the .data section.
    defined in linker script */
    .word _sidata
    /* start address for the .data section. defined in linker script */
    .word _sdata
    /* end address for the .data section. defined in linker script */
    .word _edata
    /* start address for the .bss section. defined in linker script */
    .word _sbss
    /* end address for the .bss section. defined in linker script */
    .word _ebss.section  .text.Reset_Handler.weak  Reset_Handler.type  Reset_Handler, %function
    Reset_Handler:  /* Copy the data segment initializers from flash to SRAM */  movs  r1, #0b  LoopCopyDataInitCopyDataInit:ldr  r3, =_sidataldr  r3, [r3, r1]str  r3, [r0, r1]adds  r1, r1, #4LoopCopyDataInit:ldr  r0, =_sdataldr  r3, =_edataadds  r2, r0, r1cmp  r2, r3bcc  CopyDataInitldr  r2, =_sbssb  LoopFillZerobss
    /* Zero fill the bss segment. */  
    FillZerobss:movs  r3, #0str  r3, [r2]adds r2, r2, #4LoopFillZerobss:ldr  r3, = _ebsscmp  r2, r3bcc  FillZerobss/* Call the clock system initialization function.*/bl  SystemInit   
    /* Call into static constructors (C++) */bl __libc_init_array
    /* Call the application's entry point.*/bl  mainbx  lr    
    .size  Reset_Handler, .-Reset_Handler/*** @brief  This is the code that gets called when the processor receives an *         unexpected interrupt.  This simply enters an infinite loop, preserving*         the system state for examination by a debugger.* @param  None     * @retval None       
    */.section  .text.Default_Handler,"ax",%progbits
    Default_Handler:
    Infinite_Loop:b  Infinite_Loop.size  Default_Handler, .-Default_Handler
    /******************************************************************************
    *
    * The minimal vector table for a Cortex M4. Note that the proper constructs
    * must be placed on this to ensure that it ends up at physical address
    * 0x0000.0000.
    * 
    *******************************************************************************/.section  .isr_vector,"a",%progbits.type  g_pfnVectors, %object.size  g_pfnVectors, .-g_pfnVectorsg_pfnVectors:.word     _estack                            /* Top of Stack */.word     Reset_Handler		/* Reset Handler */.word     NMI_Handler		/* NMI Handler */.word     HardFault_Handler		/* Hard Fault Handler */.word     MemManage_Handler		/* MPU Fault Handler */.word     BusFault_Handler		/* Bus Fault Handler */.word     UsageFault_Handler		/* Usage Fault Handler */.word     0		/* Reserved */.word     0		/* Reserved */.word     0		/* Reserved */.word     0		/* Reserved */.word     SVC_Handler		/* SVCall Handler */.word     DebugMon_Handler		/* Debug Monitor Handler */.word     0		/* Reserved */.word     PendSV_Handler		/* PendSV Handler */.word     SysTick_Handler		/* SysTick Handler */.word     WWDGT_IRQHandler		/* 16:Window Watchdog Timer */.word     LVD_IRQHandler		/* 17:LVD through EXTI Line detect */.word     TAMPER_STAMP_IRQHandler		/* 18:Tamper and TimeStamp through EXTI Line detect */.word     RTC_WKUP_IRQHandler		/* 19:RTC Wakeup through EXTI Line */.word     FMC_IRQHandler		/* 20:FMC */.word     RCU_CTC_IRQHandler		/* 21:RCU and CTC */.word     EXTI0_IRQHandler		/* 22:EXTI Line 0 */.word     EXTI1_IRQHandler		/* 23:EXTI Line 1 */.word     EXTI2_IRQHandler		/* 24:EXTI Line 2 */.word     EXTI3_IRQHandler		/* 25:EXTI Line 3 */.word     EXTI4_IRQHandler		/* 26:EXTI Line 4 */.word     DMA0_Channel0_IRQHandler		/* 27:DMA0 Channel0 */.word     DMA0_Channel1_IRQHandler		/* 28:DMA0 Channel1 */.word     DMA0_Channel2_IRQHandler		/* 29:DMA0 Channel2 */.word     DMA0_Channel3_IRQHandler		/* 30:DMA0 Channel3 */.word     DMA0_Channel4_IRQHandler		/* 31:DMA0 Channel4 */.word     DMA0_Channel5_IRQHandler		/* 32:DMA0 Channel5 */.word     DMA0_Channel6_IRQHandler		/* 33:DMA0 Channel6 */.word     ADC_IRQHandler		/* 34:ADC */.word     CAN0_TX_IRQHandler		/* 35:CAN0 TX */.word     CAN0_RX0_IRQHandler		/* 36:CAN0 RX0 */.word     CAN0_RX1_IRQHandler		/* 37:CAN0 RX1 */.word     CAN0_EWMC_IRQHandler		/* 38:CAN0 EWMC */.word     EXTI5_9_IRQHandler		/* 39:EXTI5 to EXTI9 */.word     TIMER0_BRK_TIMER8_IRQHandler		/* 40:TIMER0 Break and TIMER8 */.word     TIMER0_UP_TIMER9_IRQHandler		/* 41:TIMER0 Update and TIMER9 */.word     TIMER0_TRG_CMT_TIMER10_IRQHandler		/* 42:TIMER0 Trigger and Commutation and TIMER10 */.word     TIMER0_Channel_IRQHandler		/* 43:TIMER0 Channel Capture Compare */.word     TIMER1_IRQHandler		/* 44:TIMER1 */.word     TIMER2_IRQHandler		/* 45:TIMER2 */.word     TIMER3_IRQHandler		/* 46:TIMER3 */.word     I2C0_EV_IRQHandler		/* 47:I2C0 Event */.word     I2C0_ER_IRQHandler		/* 48:I2C0 Error */.word     I2C1_EV_IRQHandler		/* 49:I2C1 Event */.word     I2C1_ER_IRQHandler		/* 50:I2C1 Error */.word     SPI0_IRQHandler		/* 51:SPI0 */.word     SPI1_IRQHandler		/* 52:SPI1 */.word     USART0_IRQHandler		/* 53:USART0 */.word     USART1_IRQHandler		/* 54:USART1 */.word     USART2_IRQHandler		/* 55:USART2 */.word     EXTI10_15_IRQHandler		/* 56:EXTI10 to EXTI15 */.word     RTC_Alarm_IRQHandler		/* 57:RTC Alarm */.word     USBFS_WKUP_IRQHandler		/* 58:USBFS Wakeup */.word     TIMER7_BRK_TIMER11_IRQHandler		/* 59:TIMER7 Break and TIMER11 */.word     TIMER7_UP_TIMER12_IRQHandler		/* 60:TIMER7 Update and TIMER12 */.word     TIMER7_TRG_CMT_TIMER13_IRQHandler		/* 61:TIMER7 Trigger and Commutation and TIMER13 */.word     TIMER7_Channel_IRQHandler		/* 62:TIMER7 Capture Compare */.word     DMA0_Channel7_IRQHandler		/* 63:DMA0 Channel7 */.word     EXMC_IRQHandler		/* 64:EXMC */.word     SDIO_IRQHandler		/* 65:SDIO */.word     TIMER4_IRQHandler		/* 66:TIMER4 */.word     SPI2_IRQHandler		/* 67:SPI2 */.word     UART3_IRQHandler		/* 68:UART3 */.word     UART4_IRQHandler		/* 69:UART4 */.word     TIMER5_DAC_IRQHandler		/* 70:TIMER5 and DAC0 DAC1 Underrun error */.word     TIMER6_IRQHandler		/* 71:TIMER6 */.word     DMA1_Channel0_IRQHandler		/* 72:DMA1 Channel0 */.word     DMA1_Channel1_IRQHandler		/* 73:DMA1 Channel1 */.word     DMA1_Channel2_IRQHandler		/* 74:DMA1 Channel2 */.word     DMA1_Channel3_IRQHandler		/* 75:DMA1 Channel3 */.word     DMA1_Channel4_IRQHandler		/* 76:DMA1 Channel4 */.word     ENET_IRQHandler		/* 77:Ethernet */.word     ENET_WKUP_IRQHandler		/* 78:Ethernet Wakeup through EXTI Line */.word     CAN1_TX_IRQHandler		/* 79:CAN1 TX */.word     CAN1_RX0_IRQHandler		/* 80:CAN1 RX0 */.word     CAN1_RX1_IRQHandler		/* 81:CAN1 RX1 */.word     CAN1_EWMC_IRQHandler		/* 82:CAN1 EWMC */.word     USBFS_IRQHandler		/* 83:USBFS */.word     DMA1_Channel5_IRQHandler		/* 84:DMA1 Channel5 */.word     DMA1_Channel6_IRQHandler		/* 85:DMA1 Channel6 */.word     DMA1_Channel7_IRQHandler		/* 86:DMA1 Channel7 */.word     USART5_IRQHandler		/* 87:USART5 */.word     I2C2_EV_IRQHandler		/* 88:I2C2 Event */.word     I2C2_ER_IRQHandler		/* 89:I2C2 Error */.word     USBHS_EP1_Out_IRQHandler		/* 90:USBHS Endpoint 1 Out  */.word     USBHS_EP1_In_IRQHandler		/* 91:USBHS Endpoint 1 in */.word     USBHS_WKUP_IRQHandler		/* 92:USBHS Wakeup through EXTI Line */.word     USBHS_IRQHandler		/* 93:USBHS */.word     DCI_IRQHandler		/* 94:DCI */.word     0		/* 95:Reserved */.word     TRNG_IRQHandler		/* 96:TRNG */.word     FPU_IRQHandler		/* 97:FPU *//*******************************************************************************
    *
    * Provide weak aliases for each Exception handler to the Default_Handler. 
    * As they are weak aliases, any function with the same name will override 
    * this definition.
    *
    *******************************************************************************/
    .weak NMI_Handler
    .thumb_set NMI_Handler,Default_Handler.weak HardFault_Handler
    .thumb_set HardFault_Handler,Default_Handler.weak MemManage_Handler
    .thumb_set MemManage_Handler,Default_Handler.weak BusFault_Handler
    .thumb_set BusFault_Handler,Default_Handler.weak UsageFault_Handler
    .thumb_set UsageFault_Handler,Default_Handler.weak SVC_Handler
    .thumb_set SVC_Handler,Default_Handler.weak DebugMon_Handler
    .thumb_set DebugMon_Handler,Default_Handler.weak PendSV_Handler
    .thumb_set PendSV_Handler,Default_Handler.weak SysTick_Handler
    .thumb_set SysTick_Handler,Default_Handler.weak WWDGT_IRQHandler
    .thumb_set WWDGT_IRQHandler,Default_Handler.weak LVD_IRQHandler
    .thumb_set LVD_IRQHandler,Default_Handler.weak TAMPER_STAMP_IRQHandler
    .thumb_set TAMPER_STAMP_IRQHandler,Default_Handler.weak RTC_WKUP_IRQHandler
    .thumb_set RTC_WKUP_IRQHandler,Default_Handler.weak FMC_IRQHandler
    .thumb_set FMC_IRQHandler,Default_Handler.weak RCU_CTC_IRQHandler
    .thumb_set RCU_CTC_IRQHandler,Default_Handler.weak EXTI0_IRQHandler
    .thumb_set EXTI0_IRQHandler,Default_Handler.weak EXTI1_IRQHandler
    .thumb_set EXTI1_IRQHandler,Default_Handler.weak EXTI2_IRQHandler
    .thumb_set EXTI2_IRQHandler,Default_Handler.weak EXTI3_IRQHandler
    .thumb_set EXTI3_IRQHandler,Default_Handler.weak EXTI4_IRQHandler
    .thumb_set EXTI4_IRQHandler,Default_Handler.weak DMA0_Channel0_IRQHandler
    .thumb_set DMA0_Channel0_IRQHandler,Default_Handler.weak DMA0_Channel1_IRQHandler
    .thumb_set DMA0_Channel1_IRQHandler,Default_Handler.weak DMA0_Channel2_IRQHandler
    .thumb_set DMA0_Channel2_IRQHandler,Default_Handler.weak DMA0_Channel3_IRQHandler
    .thumb_set DMA0_Channel3_IRQHandler,Default_Handler.weak DMA0_Channel4_IRQHandler
    .thumb_set DMA0_Channel4_IRQHandler,Default_Handler.weak DMA0_Channel5_IRQHandler
    .thumb_set DMA0_Channel5_IRQHandler,Default_Handler.weak DMA0_Channel6_IRQHandler
    .thumb_set DMA0_Channel6_IRQHandler,Default_Handler.weak ADC_IRQHandler
    .thumb_set ADC_IRQHandler,Default_Handler.weak CAN0_TX_IRQHandler
    .thumb_set CAN0_TX_IRQHandler,Default_Handler.weak CAN0_RX0_IRQHandler
    .thumb_set CAN0_RX0_IRQHandler,Default_Handler.weak CAN0_RX1_IRQHandler
    .thumb_set CAN0_RX1_IRQHandler,Default_Handler.weak CAN0_EWMC_IRQHandler
    .thumb_set CAN0_EWMC_IRQHandler,Default_Handler.weak EXTI5_9_IRQHandler
    .thumb_set EXTI5_9_IRQHandler,Default_Handler.weak TIMER0_BRK_TIMER8_IRQHandler
    .thumb_set TIMER0_BRK_TIMER8_IRQHandler,Default_Handler.weak TIMER0_UP_TIMER9_IRQHandler
    .thumb_set TIMER0_UP_TIMER9_IRQHandler,Default_Handler.weak TIMER0_TRG_CMT_TIMER10_IRQHandler
    .thumb_set TIMER0_TRG_CMT_TIMER10_IRQHandler,Default_Handler.weak TIMER0_Channel_IRQHandler
    .thumb_set TIMER0_Channel_IRQHandler,Default_Handler.weak TIMER1_IRQHandler
    .thumb_set TIMER1_IRQHandler,Default_Handler.weak TIMER2_IRQHandler
    .thumb_set TIMER2_IRQHandler,Default_Handler.weak TIMER3_IRQHandler
    .thumb_set TIMER3_IRQHandler,Default_Handler.weak I2C0_EV_IRQHandler
    .thumb_set I2C0_EV_IRQHandler,Default_Handler.weak I2C0_ER_IRQHandler
    .thumb_set I2C0_ER_IRQHandler,Default_Handler.weak I2C1_EV_IRQHandler
    .thumb_set I2C1_EV_IRQHandler,Default_Handler.weak I2C1_ER_IRQHandler
    .thumb_set I2C1_ER_IRQHandler,Default_Handler.weak SPI0_IRQHandler
    .thumb_set SPI0_IRQHandler,Default_Handler.weak SPI1_IRQHandler
    .thumb_set SPI1_IRQHandler,Default_Handler.weak USART0_IRQHandler
    .thumb_set USART0_IRQHandler,Default_Handler.weak USART1_IRQHandler
    .thumb_set USART1_IRQHandler,Default_Handler.weak USART2_IRQHandler
    .thumb_set USART2_IRQHandler,Default_Handler.weak EXTI10_15_IRQHandler
    .thumb_set EXTI10_15_IRQHandler,Default_Handler.weak RTC_Alarm_IRQHandler
    .thumb_set RTC_Alarm_IRQHandler,Default_Handler.weak USBFS_WKUP_IRQHandler
    .thumb_set USBFS_WKUP_IRQHandler,Default_Handler.weak TIMER7_BRK_TIMER11_IRQHandler
    .thumb_set TIMER7_BRK_TIMER11_IRQHandler,Default_Handler.weak TIMER7_UP_TIMER12_IRQHandler
    .thumb_set TIMER7_UP_TIMER12_IRQHandler,Default_Handler.weak TIMER7_TRG_CMT_TIMER13_IRQHandler
    .thumb_set TIMER7_TRG_CMT_TIMER13_IRQHandler,Default_Handler.weak TIMER7_Channel_IRQHandler
    .thumb_set TIMER7_Channel_IRQHandler,Default_Handler.weak DMA0_Channel7_IRQHandler
    .thumb_set DMA0_Channel7_IRQHandler,Default_Handler.weak EXMC_IRQHandler
    .thumb_set EXMC_IRQHandler,Default_Handler.weak SDIO_IRQHandler
    .thumb_set SDIO_IRQHandler,Default_Handler.weak TIMER4_IRQHandler
    .thumb_set TIMER4_IRQHandler,Default_Handler.weak SPI2_IRQHandler
    .thumb_set SPI2_IRQHandler,Default_Handler.weak UART3_IRQHandler
    .thumb_set UART3_IRQHandler,Default_Handler.weak UART4_IRQHandler
    .thumb_set UART4_IRQHandler,Default_Handler.weak TIMER5_DAC_IRQHandler
    .thumb_set TIMER5_DAC_IRQHandler,Default_Handler.weak TIMER6_IRQHandler
    .thumb_set TIMER6_IRQHandler,Default_Handler.weak DMA1_Channel0_IRQHandler
    .thumb_set DMA1_Channel0_IRQHandler,Default_Handler.weak DMA1_Channel1_IRQHandler
    .thumb_set DMA1_Channel1_IRQHandler,Default_Handler.weak DMA1_Channel2_IRQHandler
    .thumb_set DMA1_Channel2_IRQHandler,Default_Handler.weak DMA1_Channel3_IRQHandler
    .thumb_set DMA1_Channel3_IRQHandler,Default_Handler.weak DMA1_Channel4_IRQHandler
    .thumb_set DMA1_Channel4_IRQHandler,Default_Handler.weak ENET_IRQHandler
    .thumb_set ENET_IRQHandler,Default_Handler.weak ENET_WKUP_IRQHandler
    .thumb_set ENET_WKUP_IRQHandler,Default_Handler.weak CAN1_TX_IRQHandler
    .thumb_set CAN1_TX_IRQHandler,Default_Handler.weak CAN1_RX0_IRQHandler
    .thumb_set CAN1_RX0_IRQHandler,Default_Handler.weak CAN1_RX1_IRQHandler
    .thumb_set CAN1_RX1_IRQHandler,Default_Handler.weak CAN1_EWMC_IRQHandler
    .thumb_set CAN1_EWMC_IRQHandler,Default_Handler.weak USBFS_IRQHandler
    .thumb_set USBFS_IRQHandler,Default_Handler.weak DMA1_Channel5_IRQHandler
    .thumb_set DMA1_Channel5_IRQHandler,Default_Handler.weak DMA1_Channel6_IRQHandler
    .thumb_set DMA1_Channel6_IRQHandler,Default_Handler.weak DMA1_Channel7_IRQHandler
    .thumb_set DMA1_Channel7_IRQHandler,Default_Handler.weak USART5_IRQHandler
    .thumb_set USART5_IRQHandler,Default_Handler.weak I2C2_EV_IRQHandler
    .thumb_set I2C2_EV_IRQHandler,Default_Handler.weak I2C2_ER_IRQHandler
    .thumb_set I2C2_ER_IRQHandler,Default_Handler.weak USBHS_EP1_Out_IRQHandler
    .thumb_set USBHS_EP1_Out_IRQHandler,Default_Handler.weak USBHS_EP1_In_IRQHandler
    .thumb_set USBHS_EP1_In_IRQHandler,Default_Handler.weak USBHS_WKUP_IRQHandler
    .thumb_set USBHS_WKUP_IRQHandler,Default_Handler.weak USBHS_IRQHandler
    .thumb_set USBHS_IRQHandler,Default_Handler.weak DCI_IRQHandler
    .thumb_set DCI_IRQHandler,Default_Handler.weak TRNG_IRQHandler
    .thumb_set TRNG_IRQHandler,Default_Handler.weak FPU_IRQHandler
    .thumb_set FPU_IRQHandler,Default_Handler

    相关文章:

    VSCode + GD32F407 构建烧录

    前言 最近调试一块 GD32F407VET6(168Mhz,8Mhz晶振) 板子时,踩了一些“启动失败”的坑。本以为是时钟配置有误,最后发现是链接脚本(.ld 文件)没有配置好,导致程序根本没能正常执行 ma…...

    Linux研学-入门命令

    一 目录介绍 1 介绍 Linux与Windows在目录结构组织上差异显著:Linux采用树型目录结构,以单一根目录/为起点,所有文件和子目录由此向下延伸形成层级体系,功能明确的目录各司其职,使文件系统层次清晰、逻辑连贯&#xf…...

    Hive在实际应用中,如何选择合适的JOIN优化策略?

    在实际应用中选择Hive JOIN优化策略时,需综合考虑数据规模、分布特征、表结构设计、集群资源及业务需求。以下是具体的决策流程和参考标准: 一、数据特征分析 1. 统计数据规模 通过DESCRIBE FORMATTED table_name查看表大小和分区信息。使用SELECT CO…...

    设计模式之结构型:桥接模式

    桥接模式(Bridge Pattern) 定义 桥接模式是一种​​结构型设计模式​​,通过​​将抽象部分与实现部分分离​​,使它们可以独立变化。它通过组合代替继承,解决多层继承导致的类爆炸问题,适用于​​多维度变化​​的场景(如形状与颜…...

    监控 Oracle Cloud 负载均衡器:使用 Applications Manager 释放最佳性能

    设想你正在运营一个受欢迎的在线学习平台,在考试前的高峰期,平台流量激增。全球的学生同时登录,观看视频、提交作业和参加测试。如果 Oracle Cloud 负载均衡器不能高效地分配流量,或者后端服务器难以应对负载,学生可能…...

    早发现=早安心!超导心磁图如何捕捉早期病变信号?

    随着生活节奏的加快,心血管疾病已成为威胁人们健康的“隐形杀手”。据国家心血管病中心发布的《中国心血管健康与疾病报告2022》显示,我国心血管病现患者人数已高达3.3亿,每5例死亡中就有2例死于心血管病。这一数据触目惊心,提醒我…...

    使用Vditor将Markdown文档渲染成网页(Vite+JS+Vditor)

    1. 引言 编写Markdown文档现在可以说是程序员的必备技能了,因为Markdown很好地实现了内容与排版分离,可以让程序员更专注于内容的创作。现在很多技术文档,博客发布甚至AI文字输出的内容都是以Markdown格式的形式输出的。那么,Mar…...

    Python打卡DAY40

    知识点回顾: 彩色和灰度图片测试和训练的规范写法:封装在函数中展平操作:除第一个维度batchsize外全部展平dropout操作:训练阶段随机丢弃神经元,测试阶段eval模式关闭dropout 作业:仔细学习下测试和训练代码…...

    OPC Client第6讲(wxwidgets):Logger.h日志记录文件(单例模式);登录后的主界面

    接上一讲三、2、2>4》,创建logger.h和helper_t.h里的gettime函数 即解决下图的报红 同时,接上一讲二、3、点击“确认”按钮后,进入MainFrame.h对应的下述界面,此讲下图进行实现 一、创建Logger.h:日志记录文件&…...

    CesiumInstancedMesh 实例

    CesiumInstancedMesh 实例 import * as Cesium from cesium;// Three.js 风格的 InstancedMesh 类, https://threejs.org/docs/#api/en/objects/InstancedMesh export class CesiumInstancedMesh {/*** Creates an instance of InstancedMesh.** param {Cesium.Geometry} geom…...

    单细胞注释前沿:CASSIA——无参考、可解释、自动化细胞注释的大语言模型

    细胞类型注释是单细胞RNA-seq分析的重要步骤,目前有许多注释方法。大多数注释方法都需要计算和特定领域专业知识的结合,而且经常产生不一致的结果,难以解释。大语言模型有可能在减少人工输入和提高准确性的同时扩大可访问性,但现有…...

    历年武汉大学计算机保研上机真题

    2025武汉大学计算机保研上机真题 2024武汉大学计算机保研上机真题 2023武汉大学计算机保研上机真题 在线测评链接:https://pgcode.cn/school 分段函数计算 题目描述 写程序计算如下分段函数: 当 x > 0 x > 0 x>0 时, f ( x ) …...

    日语学习-日语知识点小记-构建基础-JLPT-N4阶段(30):みます

    日语学习-日语知识点小记-构建基础-JLPT-N4阶段(30):みます 1、前言(1)情况说明(2)工程师的信仰2、知识点(1)ように 復習:1、ように Change12、ように Ideal state(理想(りそう)の状態(じょうたい))3、V辞書・Vない ようにしています いつも気をつけて…...

    AR-HUD 光波导方案优化难题待解?OAS 光学软件来破局

    波导-HUD系统案例分析 简介 光波导技术凭借其平板超薄结构和强大的二维扩展能力,在解决AR-HUD问题方面展现出显著优势。一方面,其独特的结构特性能够大幅减小对光机体积的需求,成为 HUD 未来发展的重要技术方向;另一方面&#xf…...

    火狐安装自动录制表单教程——仙盟自动化运营大衍灵机——仙盟创梦IDE

    打开火狐插件页面 安装完成 使用 功能 录制浏览器操作 录入地址 开始操作 录制完成 在当今快速发展的软件开发生态中,自动化测试已从一种新兴技术手段,转变为保障软件质量与开发效率不可或缺的关键环节。其重要性体现在多个维度,同时&#x…...

    线程池的详细知识(含有工厂模式)

    前言 下午学习了线程池的知识。重点探究了ThreadPoolExecutor里面的各种参数的含义。我详细了解了这部分的知识。其中有一个参数涉及工厂模式,我将这一部分知识分享给大家~ 线程池的详细介绍(含工厂模式) 结语 分享到此结束啦。byebye~...

    木愚科技闪亮第63届高博会 全栈式智能教育解决方案助力教学升级

    5月23日,第63届高等教育博览会在长春东北亚国际博览中心开幕,木愚科技积极筹备,奔赴展会现场。彼时,木愚科技企业领导及相关职能部门负责人亲临展位指导工作,通过特装展位、资料发放及现场交流等方式,全方位…...

    Proteus寻找元器件(常见)

    一 元件库 二 找元件 1 主控 32 51 输入 stm32 AT89c51 2 找屏幕 oled 3 找按键button 4 电阻、电容 res cap 5 电机驱动 l298n 6 电机 motor 7 滑动变阻器 pot 8 找电源和 GND 9 找晶振 选择 D 开头的 CRYSTAL 10 网络标签...

    RK3566 Android12 HG24C02MM/TR EEPROM适配

    一、背景 近期项目中,有一个需求,要使用RK3566 Android12平台适配一款HG24C02MM/TR EEPROM芯片,通过i2c实现主板与EEPROM芯片的数据通讯。废话不多说,来看资料。 二、芯片资料 HG24C02 / HG24C04 / HG24C08 / HG24C16是提供2048…...

    IoTDB 集成 DBeaver,简易操作实现时序数据清晰管理

    数据结构一目了然,跨库分析轻松实现,方便 IoTDB “内部构造”管理! 随着物联网场景对时序数据处理需求激增,时序数据库与数据库管理工具的集成尤为关键。作为数据资产的 “智能管家”,借助数据库管理工具的可视化操作界…...

    sqli-labs第二十八关——Trick with ‘union select‘

    一:分析 这一关的提示和上一关一样,所以我们查看源码,屏蔽了注释符,空格,union,select等关键词 分析这一条源码的几个新增添符号 \s: 匹配任何的空白字符(普通空格,\t&…...

    mapbox高阶,PMTiles介绍,MBTiles、PMTiles对比,加载PMTiles文件

    👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️Fill面图层样式1.4 ☘️PMTiles介绍1.5…...

    Go语言通道如何实现通信

    在Go语言中,通道(channel)是一种内置的数据结构,用于在不同的goroutine之间进行通信和同步。通道提供了一种安全且有效的方式来传递数据,避免了数据竞争和死锁等问题。 要在Go语言中使用通道进行通信,你需…...

    投稿 IEEE Transactions on Knowledge and Data Engineering 注意事项

    投稿 IEEE Transactions on Knowledge and Data Engineering 注意事项 要IEEE overleaf 模板私信,我直接给我自己论文,便于编辑 已经投稿完成了,有一些小坑 准备工作 注册IEEE账户:若没有IEEE账户,需前往IEEE官网注册。注册成功后,可用于登录投稿系统。现在新的系统,…...

    题目 3316: 蓝桥杯2025年第十六届省赛真题-数组翻转

    题目 3316: 蓝桥杯2025年第十六届省赛真题-数组翻转 时间限制: 3s 内存限制: 512MB 提交: 101 解决: 24 题目描述 小明生成了一个长度为 n 的正整数数组 a1, a2, . . . , an,他可以选择连续的一 段数 al , al1, ..., ar,如果其中所有数都相等即 al al1 …...

    mongodb源码分析session接受客户端find命令过程

    mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制。 现在继续研究ASIOSession和connection是怎么接受客户端命令的? mongo/transport/service_state_machine.cpp核心方法有&#xf…...

    Netty 实战篇:为自研 RPC 框架加入异步调用与 Future 支持

    我们在上篇实现了一个轻量级 RPC 框架,现在要进一步优化 —— 加入异步响应支持,让 RPC 通信变得真正高效、非阻塞、支持并发。 一、为什么需要异步调用? 上篇的 RPC 框架是“同步阻塞”的: 每次发送请求后,必须等待服…...

    python37天打卡

    知识点回顾: 过拟合的判断:测试集和训练集同步打印指标 模型的保存和加载 仅保存权重 保存权重和模型 保存全部信息checkpoint,还包含训练状态 早停策略 作业:对信贷数据集训练后保存权重,加载权重后继续训练50轮&am…...

    变焦位移计:机器视觉如何克服人工疲劳与主观影响?精准对结构安全实时监测

    变焦视觉位移监测与人工监测的对比 人工监测是依靠目测检查或借助于全站仪,水准仪,RTK等便携式仪器测量得到的信息,但是随着整个行业的发展,传统的人工监测方法已经不能满足监测需求,从人工监测到自动化监测已是必然趋…...

    嵌入式硬件篇---Ne555定时器

    文章目录 前言1. 基本概述类型功能封装形式2. 引脚功能(DIP-8 封装)内部结构阈值电压两种工作模式4. 主要特性优点:缺点:5. 典型应用场景定时控制脉冲生成检测与触发信号处理6. 关键参数速查表前言 本文简单介绍了Ne555定时器(多谐振荡器/定时器)。DIP与SOP封装。 1. 基…...