体验用VS Code 里 EIDE 进行芯片开发的快乐~ 开源、免费、更简便、支持GCC!
网站:bbs.21ic.com
单片机软件开发流程和其中一些知识点
VS Code 优势和 EIDE 插件介绍
准备资源
着手搭建环境
编译、烧录及调试演示视频
免费、开源且跨平台
轻量、解耦,本身只有编辑器的功能安装包大小仅不到100MB,但可以按需安装形形色色的插件使得整个工具链的集成度非常高
支持几乎所有语言的编辑,且有配套插件
编辑功能完善,行编辑、多行注释、多行选择、自动补全、自动跳转等功能支持到位
界面好看,不会崩溃
一块 MM32F0144C6P 芯片的核心板,这里选用灵动微官方提供的红色最小系统板
一根 Micro USB 插头的数据线,用作串口输出和供电
一个 J-Link 调试器,这里用的网上买的盗版便宜货 V9 版
Visual Studio Code for windows
gcc-arm-none-eabi for windows
JLink_Windows_V670g.exe 以及 灵动官方 J-Flash 插件安装包 (让 J-Link 可以搜索到 MM32F0144C6P 这颗芯片
不然只能选择 Cortex M0)
CH340 USB-Serial Port Driver
一份已经调试好的 KEIL template 工程代码包
MM32F0144C6P GCC 启动文件和链接文件 (由于官方不提供,所以得先办法自己编制)
MindMotion.MM32F0140_DFP.0.0.6 (可选,在 EIDE 中可以安装上它后具备芯片信息)
Mingw-w64 for windows(可选,可用于 Makefile 驱动一键 make 进行编译)
/********************************************************************************* [url=home.php?mod=space&uid=288409]@file[/url] startup_mm32f0140_gcc.s* [url=home.php?mod=space&uid=187600]@author[/url]* [url=home.php?mod=space&uid=247401]@brief[/url] MM32F014x devices vector table for GCC toolchain.* This module performs:* - Set the initial SP* - Set the initial PC == Reset_Handler,* - Set the vector table entries with the exceptions ISR address* - Branches to main in the C library (which eventually* calls main()).* After Reset the Cortex-M0 processor is in Thread mode,* priority is Privileged, and the Stack is set to Main.********************************************************************************/.syntax unified.cpu cortex-m0.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/*** [url=home.php?mod=space&uid=247401]@brief[/url] This is the code that gets called when the processor first* starts execution following a reset event. Only the absolutely* necessary set is performed, after which the application* supplied main() routine is called.* @param None* @retval : None*/.section .text.Reset_Handler.weak Reset_Handler.type Reset_Handler, %functionReset_Handler:ldr r0, =_estackmov sp, r0 /* set stack pointer *//* Copy the data segment initializers from flash to SRAM */ldr r0, =_sdataldr r1, =_edataldr r2, =_sidatamovs r3, #0b LoopCopyDataInitCopyDataInit:ldr r4, [r2, r3]str r4, [r0, r3]adds r3, r3, #4LoopCopyDataInit:adds r4, r0, r3cmp r4, r1bcc CopyDataInit/* Zero fill the bss segment. */ldr r2, =_sbssldr r4, =_ebssmovs r3, #0b LoopFillZerobssFillZerobss:str r3, [r2]adds r2, r2, #4LoopFillZerobss:cmp r2, r4bcc FillZerobss/* Call the clock system intitialization function.*/bl SystemInit/* Call static constructors */bl __libc_init_array/* Call the application's entry point.*/bl mainLoopForever:b LoopForever.size Reset_Handler, .-Reset_Handler/*** [url=home.php?mod=space&uid=247401]@brief[/url] 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",%progbitsDefault_Handler:Infinite_Loop:b Infinite_Loop.size Default_Handler, .-Default_Handler/******************************************************************************** The minimal vector table for a Cortex M0. 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.word Reset_Handler.word NMI_Handler.word HardFault_Handler.word 0.word 0.word 0.word 0.word 0.word 0.word 0.word SVC_Handler.word 0.word 0.word PendSV_Handler.word SysTick_Handler.word WWDG_IRQHandler /* Window WatchDog */.word PVD_IRQHandler /* PVD through EXTI Line detect */.word MIPI_IRQHandler /* MIPI */.word FLASH_IRQHandler /* FLASH */.word RCC_IRQHandler /* RCC */.word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */.word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */.word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */.word HWDIV_IRQHandler /* HWDIV */.word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */.word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */.word DMA1_Channel4_5_IRQHandler /* DMA1 Channel 4 and Channel 5 */.word ADC1_COMP_IRQHandler /* ADC1 & COMP */.word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */.word TIM1_CC_IRQHandler /* TIM1 Capture Compare */.word TIM2_IRQHandler /* TIM2 */.word TIM3_IRQHandler /* TIM3 */.word 0 /* Reserved */.word 0 /* Reserved */.word TIM14_IRQHandler /* TIM14 */.word 0 /* Reserved */.word TIM16_IRQHandler /* TIM16 */.word TIM17_IRQHandler /* TIM17 */.word I2C1_IRQHandler /* I2C1 */.word 0 /* Reserved */.word SPI1_IRQHandler /* SPI1 */.word SPI2_IRQHandler /* SPI2 */.word UART1_IRQHandler /* UART1 */.word UART2_IRQHandler /* UART2 */.word UART3_IRQHandler /* UART3 */.word FLEX_CAN_IRQHandler /* FLEX_CAN */.word 0 /* Reserved *//********************************************************************************* 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 SVC_Handler.thumb_set SVC_Handler,Default_Handler.weak PendSV_Handler.thumb_set PendSV_Handler,Default_Handler.weak SysTick_Handler.thumb_set SysTick_Handler,Default_Handler.weak WWDG_IRQHandler.thumb_set WWDG_IRQHandler,Default_Handler.weak PVD_IRQHandler.thumb_set PVD_IRQHandler,Default_Handler.weak MIPI_IRQHandler.thumb_set MIPI_IRQHandler,Default_Handler.weak FLASH_IRQHandler.thumb_set FLASH_IRQHandler,Default_Handler.weak RCC_IRQHandler.thumb_set RCC_IRQHandler,Default_Handler.weak EXTI0_1_IRQHandler.thumb_set EXTI0_1_IRQHandler,Default_Handler.weak EXTI2_3_IRQHandler.thumb_set EXTI2_3_IRQHandler,Default_Handler.weak EXTI4_15_IRQHandler.thumb_set EXTI4_15_IRQHandler,Default_Handler.weak HWDIV_IRQHandler.thumb_set HWDIV_IRQHandler,Default_Handler.weak DMA1_Channel1_IRQHandler.thumb_set DMA1_Channel1_IRQHandler,Default_Handler.weak DMA1_Channel2_3_IRQHandler.thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler.weak DMA1_Channel4_5_IRQHandler.thumb_set DMA1_Channel4_5_IRQHandler,Default_Handler.weak ADC1_COMP_IRQHandler.thumb_set ADC1_COMP_IRQHandler,Default_Handler.weak TIM1_BRK_UP_TRG_COM_IRQHandler.thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler.weak TIM1_CC_IRQHandler.thumb_set TIM1_CC_IRQHandler,Default_Handler.weak TIM2_IRQHandler.thumb_set TIM2_IRQHandler,Default_Handler.weak TIM3_IRQHandler.thumb_set TIM3_IRQHandler,Default_Handler.weak TIM14_IRQHandler.thumb_set TIM14_IRQHandler,Default_Handler.weak TIM16_IRQHandler.thumb_set TIM16_IRQHandler,Default_Handler.weak TIM17_IRQHandler.thumb_set TIM17_IRQHandler,Default_Handler.weak I2C1_IRQHandler.thumb_set I2C1_IRQHandler,Default_Handler.weak SPI1_IRQHandler.thumb_set SPI1_IRQHandler,Default_Handler.weak SPI2_IRQHandler.thumb_set SPI2_IRQHandler,Default_Handler.weak UART1_IRQHandler.thumb_set UART1_IRQHandler,Default_Handler.weak UART2_IRQHandler.thumb_set UART2_IRQHandler,Default_Handler.weak UART3_IRQHandler.thumb_set UART3_IRQHandler,Default_Handler.weak FLEX_CAN_IRQHandler.thumb_set FLEX_CAN_IRQHandler,Default_Handler
以下为修改好的 MM32F0144C6P_FLASH 文件:
/********************************************************************************** File : mm32_flash.ld**** Abstract : Linker script for MM32F0144C6P Device with** 64KByte FLASH, 16KByte RAM**** Set heap size, stack size and stack location according** to application requirements.**** Set memory bank area and size if external memory is used.**** Target : MM32**** Environment : VScode**** Distribution: The file is distributed “as is,” without any warranty** of any kind.******************************************************************************//* Entry Point */ENTRY(Reset_Handler)/* Highest address of the user mode stack */_estack = 0x20002000; /* end of 16K RAM *//* Generate a link error if heap and stack don't fit into RAM */_Min_Heap_Size = 0x200; /* required amount of heap */_Min_Stack_Size = 0x400; /* required amount of stack *//* Specify the memory areas */MEMORY{FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64KRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 8K}/* Define output sections */SECTIONS{/* The startup code goes first into FLASH */.isr_vector :{. = ALIGN(4);KEEP(*(.isr_vector)) /* Startup code */. = ALIGN(4);} >FLASH/* The program code and other data goes into FLASH */.text :{. = ALIGN(4);*(.text) /* .text sections (code) */*(.text*) /* .text* sections (code) */*(.glue_7) /* glue arm to thumb code */*(.glue_7t) /* glue thumb to arm code */*(.eh_frame)KEEP (*(.init))KEEP (*(.fini)). = ALIGN(4);_etext = .; /* define a global symbols at end of code */} >FLASH/* Constant data goes into FLASH */.rodata :{. = ALIGN(4);*(.rodata) /* .rodata sections (constants, strings, etc.) */*(.rodata*) /* .rodata* sections (constants, strings, etc.) */. = 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/* used by the startup to initialize data */_sidata = LOADADDR(.data);/* Initialized data sections goes into RAM, load LMA copy after code */.data :{. = ALIGN(4);_sdata = .; /* create a global symbol at data start */*(.data) /* .data sections */*(.data*) /* .data* sections */. = ALIGN(4);_edata = .; /* define a global symbol at data end */} >RAM AT> FLASH/* Uninitialized data section */. = ALIGN(4);.bss :{/* This is used by the startup in order to initialize the .bss secion */_sbss = .; /* define a global symbol at bss start */__bss_start__ = _sbss;*(.bss)*(.bss*)*(COMMON). = ALIGN(4);_ebss = .; /* define a global symbol at bss end */__bss_end__ = _ebss;} >RAM/* User_heap_stack section, used to check that there is enough RAM left */._user_heap_stack :{. = ALIGN(4);PROVIDE ( end = . );PROVIDE ( _end = . );. = . + _Min_Heap_Size;. = . + _Min_Stack_Size;. = ALIGN(4);} >RAM/* Remove information from the standard libraries *//DISCARD/ :{libc.a ( * )libm.a ( * )libgcc.a ( * )}.ARM.attributes 0 : { *(.ARM.attributes) }}
四、着手搭建环境
ARM GCC GNU tool gcc.exe 安装路径
KEIL MDK UV4.exe 安装路径和 ARM TOOLS.INI 文件路径(如果用到 AC5/AC6 作为编译器的话那就需要填写)
J-Link GDBserver 安装路径和 J-Link Device xml 路径
串口默认设置信息
void vprint(const char *fmt, va_list argp){char string[200];if(0 < vsprintf(string,fmt,argp)) // build string{for (int i = 0; i < strlen(string); i++) {while ((UART1->CSR & UART_IT_TXIEN) == 0); // The loop is sent until it is finishedUART1->TDR = (u8)string[i];}}}void my_printf(const char *fmt, ...) // custom printf() function{va_list argp;va_start(argp, fmt);vprint(fmt, argp);va_end(argp);}
源码资料点击“阅读原文”
