commit f8c5203f93ee5e399dd3e2cea275fe6d3eb5e5ad Author: yuquanjun Date: Wed Oct 21 16:55:42 2026 +0800 加入 STM32F103ZET6 驱动 80x40 点阵屏的编译与烧录工程。 用 Arm GCC 生成固件,并通过 DAP Link 烧录。 Co-authored-by: Cursor diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e39cbff --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +-p/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c40369b --- /dev/null +++ b/Makefile @@ -0,0 +1,97 @@ +TARGET = hub75_80x40 +BUILD = build + +PREFIX = arm-none-eabi- +CC = $(PREFIX)gcc +AS = $(PREFIX)gcc -x assembler-with-cpp +OBJCOPY = $(PREFIX)objcopy +SIZE = $(PREFIX)size + +SRC_ROOT = ../RGB-Matrix-Px-xx/example/STM32/STM32F103RB + +C_SOURCES = \ + $(SRC_ROOT)/Core/Src/main.c \ + $(SRC_ROOT)/Core/Src/gpio.c \ + $(SRC_ROOT)/Core/Src/tim.c \ + $(SRC_ROOT)/Core/Src/usart.c \ + $(SRC_ROOT)/Core/Src/stm32f1xx_it.c \ + $(SRC_ROOT)/Core/Src/stm32f1xx_hal_msp.c \ + $(SRC_ROOT)/Core/Src/system_stm32f1xx.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c \ + $(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c \ + $(SRC_ROOT)/User/GUI/GUI_Paint.c \ + $(SRC_ROOT)/User/Driver_HUB75/Driver_RGBMatrix.c \ + $(SRC_ROOT)/User/image/image.c \ + $(SRC_ROOT)/User/Fonts/font8.c \ + $(SRC_ROOT)/User/Fonts/font12.c \ + $(SRC_ROOT)/User/Fonts/font12CN.c \ + $(SRC_ROOT)/User/Fonts/font16.c \ + $(SRC_ROOT)/User/Fonts/font20.c \ + $(SRC_ROOT)/User/Fonts/font24.c \ + $(SRC_ROOT)/User/Fonts/font24CN.c \ + syscalls.c + +ASM_SOURCES = startup_stm32f103zet6.s + +C_INCLUDES = \ + -I$(SRC_ROOT)/Core/Inc \ + -I$(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Inc \ + -I$(SRC_ROOT)/Drivers/STM32F1xx_HAL_Driver/Inc/Legacy \ + -I$(SRC_ROOT)/Drivers/CMSIS/Device/ST/STM32F1xx/Include \ + -I$(SRC_ROOT)/Drivers/CMSIS/Include \ + -I$(SRC_ROOT)/User/GUI \ + -I$(SRC_ROOT)/User/Driver_HUB75 \ + -I$(SRC_ROOT)/User/Fonts \ + -I$(SRC_ROOT)/User/image + +CPU = -mcpu=cortex-m3 -mthumb -mfloat-abi=soft +DEFS = -DSTM32F103xB -DUSE_HAL_DRIVER -DHSE_VALUE=8000000U -DHUB75_PANEL_PROFILE=HUB75_PANEL_PROFILE_80X40_1_20 +OPT = -Os + +CFLAGS = $(CPU) $(DEFS) $(C_INCLUDES) $(OPT) -Wall -ffunction-sections -fdata-sections -fno-common -g +ASFLAGS = $(CPU) -g +LDFLAGS = $(CPU) -TSTM32F103ZET6.ld -Wl,--gc-sections -Wl,-Map=$(BUILD)/$(TARGET).map --specs=nano.specs --specs=nosys.specs + +OBJECTS = $(addprefix $(BUILD)/,$(notdir $(C_SOURCES:.c=.o))) +OBJECTS += $(addprefix $(BUILD)/,$(notdir $(ASM_SOURCES:.s=.o))) + +vpath %.c $(sort $(dir $(C_SOURCES))) +vpath %.s $(sort $(dir $(ASM_SOURCES))) + +all: $(BUILD)/$(TARGET).elf $(BUILD)/$(TARGET).bin $(BUILD)/$(TARGET).hex + $(SIZE) $(BUILD)/$(TARGET).elf + +$(BUILD)/%.o: %.c | $(BUILD) + $(CC) -c $(CFLAGS) $< -o $@ + +$(BUILD)/%.o: %.s | $(BUILD) + $(AS) -c $(ASFLAGS) $< -o $@ + +$(BUILD)/$(TARGET).elf: $(OBJECTS) + $(CC) $(OBJECTS) $(LDFLAGS) -o $@ + +$(BUILD)/$(TARGET).bin: $(BUILD)/$(TARGET).elf + $(OBJCOPY) -O binary $< $@ + +$(BUILD)/$(TARGET).hex: $(BUILD)/$(TARGET).elf + $(OBJCOPY) -O ihex $< $@ + +$(BUILD): + mkdir -p $(BUILD) + +clean: + rm -rf $(BUILD) + +.PHONY: all clean diff --git a/STM32F103ZET6.ld b/STM32F103ZET6.ld new file mode 100644 index 0000000..7e9de53 --- /dev/null +++ b/STM32F103ZET6.ld @@ -0,0 +1,109 @@ +ENTRY(Reset_Handler) + +_estack = ORIGIN(RAM) + LENGTH(RAM); + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K +} + +SECTIONS +{ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) + . = ALIGN(4); + } >FLASH + + .text : + { + . = ALIGN(4); + *(.text) + *(.text*) + *(.glue_7) + *(.glue_7t) + *(.eh_frame) + KEEP(*(.init)) + KEEP(*(.fini)) + . = ALIGN(4); + _etext = .; + } >FLASH + + .rodata : + { + . = ALIGN(4); + *(.rodata) + *(.rodata*) + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN(__preinit_array_start = .); + KEEP(*(.preinit_array*)) + PROVIDE_HIDDEN(__preinit_array_end = .); + } >FLASH + + .init_array : + { + PROVIDE_HIDDEN(__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array*)) + PROVIDE_HIDDEN(__init_array_end = .); + } >FLASH + + .fini_array : + { + PROVIDE_HIDDEN(__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array*)) + PROVIDE_HIDDEN(__fini_array_end = .); + } >FLASH + + _sidata = LOADADDR(.data); + + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data) + *(.data*) + . = ALIGN(4); + _edata = .; + } >RAM AT> FLASH + + .bss : + { + . = ALIGN(4); + _sbss = .; + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + __bss_end__ = _ebss; + } >RAM + + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE(end = .); + PROVIDE(_end = .); + . = . + 0x400; + . = . + 0x1000; + . = ALIGN(8); + } >RAM + + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } +} diff --git a/flash.ps1 b/flash.ps1 new file mode 100644 index 0000000..bd83b80 --- /dev/null +++ b/flash.ps1 @@ -0,0 +1,26 @@ +param( + [string]$Port = "COM18", + [int]$Baud = 115200 +) + +$ErrorActionPreference = "Stop" +$here = Split-Path -Parent $MyInvocation.MyCommand.Path +$bin = Join-Path $here "build\hub75_80x40.bin" + +if (-not (Test-Path $bin)) { + throw "Firmware not found: $bin`nRun make in stm32f103zet6 first." +} + +python -m pip show stm32loader *> $null +if ($LASTEXITCODE -ne 0) { + python -m pip install stm32loader +} + +Write-Host "Flashing $bin to $Port" +Write-Host "BOOT0 must be at 3.3V, then press RESET before this script." +python -m stm32loader -p $Port -b $Baud -e -w -v $bin -g 0x08000000 +if ($LASTEXITCODE -ne 0) { + throw "Flash failed. Set BOOT0 to 3.3V, press RESET, and confirm $Port is the CH340." +} + +Write-Host "Flash done. Move BOOT0 back to GND and press RESET." diff --git a/startup_stm32f103zet6.s b/startup_stm32f103zet6.s new file mode 100644 index 0000000..8462ce5 --- /dev/null +++ b/startup_stm32f103zet6.s @@ -0,0 +1,186 @@ +.syntax unified +.cpu cortex-m3 +.fpu softvfp +.thumb + +.global g_pfnVectors +.global Default_Handler + +.word _sidata +.word _sdata +.word _edata +.word _sbss +.word _ebss + +.section .text.Reset_Handler +.weak Reset_Handler +.type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + mov sp, r0 + bl SystemInit + + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit + + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + + bl __libc_init_array + bl main + +LoopForever: + b LoopForever + +.size Reset_Handler, .-Reset_Handler + +.section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop +.size Default_Handler, .-Default_Handler + +.macro def_irq handler +.weak \handler +.thumb_set \handler, Default_Handler +.endm + +def_irq NMI_Handler +def_irq HardFault_Handler +def_irq MemManage_Handler +def_irq BusFault_Handler +def_irq UsageFault_Handler +def_irq SVC_Handler +def_irq DebugMon_Handler +def_irq PendSV_Handler +def_irq SysTick_Handler +def_irq WWDG_IRQHandler +def_irq PVD_IRQHandler +def_irq TAMPER_IRQHandler +def_irq RTC_IRQHandler +def_irq FLASH_IRQHandler +def_irq RCC_IRQHandler +def_irq EXTI0_IRQHandler +def_irq EXTI1_IRQHandler +def_irq EXTI2_IRQHandler +def_irq EXTI3_IRQHandler +def_irq EXTI4_IRQHandler +def_irq DMA1_Channel1_IRQHandler +def_irq DMA1_Channel2_IRQHandler +def_irq DMA1_Channel3_IRQHandler +def_irq DMA1_Channel4_IRQHandler +def_irq DMA1_Channel5_IRQHandler +def_irq DMA1_Channel6_IRQHandler +def_irq DMA1_Channel7_IRQHandler +def_irq ADC1_2_IRQHandler +def_irq USB_HP_CAN1_TX_IRQHandler +def_irq USB_LP_CAN1_RX0_IRQHandler +def_irq CAN1_RX1_IRQHandler +def_irq CAN1_SCE_IRQHandler +def_irq EXTI9_5_IRQHandler +def_irq TIM1_BRK_IRQHandler +def_irq TIM1_UP_IRQHandler +def_irq TIM1_TRG_COM_IRQHandler +def_irq TIM1_CC_IRQHandler +def_irq TIM2_IRQHandler +def_irq TIM3_IRQHandler +def_irq TIM4_IRQHandler +def_irq I2C1_EV_IRQHandler +def_irq I2C1_ER_IRQHandler +def_irq I2C2_EV_IRQHandler +def_irq I2C2_ER_IRQHandler +def_irq SPI1_IRQHandler +def_irq SPI2_IRQHandler +def_irq USART1_IRQHandler +def_irq USART2_IRQHandler +def_irq USART3_IRQHandler +def_irq EXTI15_10_IRQHandler +def_irq RTC_Alarm_IRQHandler +def_irq USBWakeUp_IRQHandler + +.section .isr_vector,"a",%progbits +.type g_pfnVectors, %object +g_pfnVectors: + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler + .word PVD_IRQHandler + .word TAMPER_IRQHandler + .word RTC_IRQHandler + .word FLASH_IRQHandler + .word RCC_IRQHandler + .word EXTI0_IRQHandler + .word EXTI1_IRQHandler + .word EXTI2_IRQHandler + .word EXTI3_IRQHandler + .word EXTI4_IRQHandler + .word DMA1_Channel1_IRQHandler + .word DMA1_Channel2_IRQHandler + .word DMA1_Channel3_IRQHandler + .word DMA1_Channel4_IRQHandler + .word DMA1_Channel5_IRQHandler + .word DMA1_Channel6_IRQHandler + .word DMA1_Channel7_IRQHandler + .word ADC1_2_IRQHandler + .word USB_HP_CAN1_TX_IRQHandler + .word USB_LP_CAN1_RX0_IRQHandler + .word CAN1_RX1_IRQHandler + .word CAN1_SCE_IRQHandler + .word EXTI9_5_IRQHandler + .word TIM1_BRK_IRQHandler + .word TIM1_UP_IRQHandler + .word TIM1_TRG_COM_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM2_IRQHandler + .word TIM3_IRQHandler + .word TIM4_IRQHandler + .word I2C1_EV_IRQHandler + .word I2C1_ER_IRQHandler + .word I2C2_EV_IRQHandler + .word I2C2_ER_IRQHandler + .word SPI1_IRQHandler + .word SPI2_IRQHandler + .word USART1_IRQHandler + .word USART2_IRQHandler + .word USART3_IRQHandler + .word EXTI15_10_IRQHandler + .word RTC_Alarm_IRQHandler + .word USBWakeUp_IRQHandler +.size g_pfnVectors, .-g_pfnVectors diff --git a/syscalls.c b/syscalls.c new file mode 100644 index 0000000..244aa21 --- /dev/null +++ b/syscalls.c @@ -0,0 +1,91 @@ +#include +#include +#include + +extern char _end; + +static char *heap_end; + +caddr_t _sbrk(int incr) +{ + extern char _estack; + char *prev; + + if (heap_end == NULL) + { + heap_end = &_end; + } + + prev = heap_end; + if ((heap_end + incr) >= (&_estack - 0x800)) + { + errno = ENOMEM; + return (caddr_t)-1; + } + + heap_end += incr; + return (caddr_t)prev; +} + +int _write(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + return len; +} + +int _read(int file, char *ptr, int len) +{ + (void)file; + (void)ptr; + (void)len; + return 0; +} + +int _close(int file) +{ + (void)file; + return -1; +} + +int _fstat(int file, void *st) +{ + (void)file; + (void)st; + return 0; +} + +int _isatty(int file) +{ + (void)file; + return 1; +} + +int _lseek(int file, int ptr, int dir) +{ + (void)file; + (void)ptr; + (void)dir; + return 0; +} + +void _exit(int status) +{ + (void)status; + while (1) + { + } +} + +int _kill(int pid, int sig) +{ + (void)pid; + (void)sig; + errno = EINVAL; + return -1; +} + +int _getpid(void) +{ + return 1; +}