• 替代STM32的GD32,替代KEIL的Eclipse配置---连载1


    前言

        GD32替代STM32原因:

        (1)前段时间stm32系列芯片涨价厉害,只能用国产替代,管脚兼容的并且做的不错的只有兆易创新的GD32;

        (2)国产化是个趋势,最好在stm32禁止之前替代掉,符合现在的困境。

        Eclipse替代KEIL原因:

        (1)KEIL和IAR都是商业软件,用的久了就会收钱,没有办法的事情,关键是还很贵;

        (2)还是国产化的原因,将来软件不让用了,你也是干着急。

        所以:STM32替换成了国产的GD32,KEIL替换成了开源的eclipse。

        不用ST自带的IDE原因:

        (1)用途有限。ST自带的IDE(编译软件)用起来也很方便,但是仅仅支持ST的芯片,如果换个芯片还是卡脖子。

        (2)ST自带的IDE也是基于eclipse的,所以抱薪救火不如釜底抽薪,直接用开源的得了。加上eclipse在LINUX上也能用,将来WINDOWS不让用了,也可以搞定这个东西。

        写文章的原因:

        (1)网上搜寻到的GD32的配置eclipse的文章很少,能搜寻到的都是直接配置的,不能解决其他芯片问题,比如配置GD32F407,做一次得找一次文件,不如直接釜底抽薪,修改底层文件,将修改变为一种普遍使用的方法。

        (2)配置过程中会遇到很多问题,可以和小伙伴们交流。也希望小伙伴关注下以前文章的公众号。电力电子嵌入式,图片没有办法发上来,希望小伙伴们能翻看以前的文章,加下关注,以后还会有后续文章。

         在下面这篇文章里有具体的图片,可以关注一波:QT串口动态实时显示大量数据波形曲线(四)========“界面的美化与处理”_透明的光的博客-CSDN博客_qt实时显示曲线

    第一章:处境

        替代过程必须将以前的代码再做一次,但是还是需要有改动的地方。内部东西都不一样,基于的东西也不一样,所以思维方式还是得改变。STM32用久了,KEIL用久了都会产生依赖,感觉这个东西不错,用着还方便。但是网上说其他的用着也不错,感觉仅仅是习惯问题。改变习惯也是不得已的事情,充满无奈和心酸。

        STM32替代成GD32,这个过程还是比较舒服点,毕竟上层软件还是KEIL。用的方式还是一样的。但是将编译软件替换掉,这个就比较累。

        GD32写的程序还是比较人性化,什么东西又封装了一层,调用起来还算可以。这部分前段时间已经做了一下,出来的东西还是能用的。

        其实STM32的程序直接烧写到GD32上也没什么大的问题,已经试验过了。但是就是害怕将来某个时间点出现不知道的BUG,那就不好解决了。

        至于eclipse替代KEIL这个事情,现在正在做,估计要花费2周的时间,反正以最快的速度做出来吧。弄一次估计就没啥问题了,并且将来用其他芯片的时候也可以直接怼上去。

        不过真是难。一点一点的做吧。

    第二章:STM和GD文件架构

        原因:eclipse的文件架构以前没见过,所以必须对每个东西都得很熟悉才行。

        下面分别介绍下KEIL下的STM32和GD32的架构,然后再介绍下eclipse下的架构。

        注意1:架构都是以103为硬件基础,至于407的,看了下,都用了HAL库,这个等103的基础版的弄完了,再给介绍下。

        注意2:eclipse的安装和配置,这个东西等做完之后再说,我试着在不同的电脑上装了2次,都可以用,所以按照介绍的步骤应该没什么问题。需要的小伙伴可以关注下,等程序做完之后就写这篇文章。这个东西属于不定因素,按照网上的教程,有的说不行,有的说行。所以按照我自己的步骤也真是不一定能装上。所以还得需要小伙伴自己努力的装下软件,并且配置好能正确编译的配置。

    第1节:STM32F103文件架构

        STM32的文件架构非常固定。其中红色部分是.h文件,蓝色部分是.C文件。

         包含四部分:

        (1)main文件,当然这里还会包含自己写的全部文件;

        (2)内核文件,这部分会是cm3 或者cm4,这个看你用的什么片子;

        (3)stm32f103对应的配置文件,一共有四个;

        (4)103的库函数,在main文件夹里自己写的文件就是调用了这部分库函数。

        还有一个文件不属于任何部分,就是.s文件。这个文件很重要,咱们后面再说。

    第2节:GD103文件架构

        GD32的文件架构和STM32的类似。

         也包含四部分:

        (1)main文件,当然这里还会包含自己写的全部文件;再有GD32独有的systick文件,这个在编程的时候用不到,只是在程序初始化的时候用到,不用管。

        (2)内核文件,这部分会是cm3 或者cm4,这个看你用的什么片子;里面还包含了内核需要的其他文件,怎么调用也不用管,放进去就好。

        (3)GD32f103对应的配置文件,一共有六个;功能和STM的一样,只是多了eval文件,这个文件是自己配置用的,用到了就配置进去,不用就不用配置。这点比较人性化,自己编写的东西都放到一起,将来修改的时候就只看这一个文件就行。

        (4)103的库函数,在main文件夹里自己写的文件就是调用了这部分库函数。

    第3节:对比

        对比两个芯片用的文件,大体上类似,并且文件里面的内容也是大同小异。只不过GD32用的函数又在STM32的基础上包含了一层。更加的符合使用习惯。

        编写心得:GD32程序编写开始时会不太习惯,用的多了就感觉编写的还是很不错的。只不过是和STM32的不太一样罢了。用的多了就知道多香了!这个还是看自己的习惯,每个人有不同的感受,我自己的感觉是还挺好。

    第4节:启动文件.s

        重点介绍下这个文件,因为在移植到eclipse的时候,这个文件挺重要,并且挺麻烦。这部分STM32和GD32是一样的,小伙伴可以自己逐行去看看。

    1. Stack_Size EQU 0x00000400
    2. AREA STACK, NOINIT, READWRITE, ALIGN=3
    3. Stack_Mem SPACE Stack_Size
    4. __initial_sp
    5. ; Heap Configuration
    6. ; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
    7. ;
    8. Heap_Size EQU 0x00000200
    9. AREA HEAP, NOINIT, READWRITE, ALIGN=3
    10. __heap_base
    11. Heap_Mem SPACE Heap_Size
    12. __heap_limit

        先是堆和栈的大小设置,这个是每个软件必须要定义的。至于多少,看自己心情,别超出范围就行了,当然也不能太小,太小了不够自己用的,会出错的。

    1. ; Vector Table Mapped to Address 0 at Reset
    2. AREA RESET, DATA, READONLY
    3. EXPORT __Vectors
    4. EXPORT __Vectors_End
    5. EXPORT __Vectors_Size
    6. __Vectors DCD __initial_sp ; Top of Stack
    7. DCD Reset_Handler ; Reset Handler
    8. DCD NMI_Handler ; NMI Handler
    9. DCD HardFault_Handler ; Hard Fault Handler
    10. DCD 0 ; Reserved
    11. DCD PendSV_Handler ; PendSV Handler
    12. DCD SysTick_Handler ; SysTick Handler
    13. ; External Interrupts
    14. DCD WWDG_IRQHandler ; Window Watchdog
    15. DCD PVD_IRQHandler ; PVD through EXTI Line detect
    16. DCD TAMPER_IRQHandler ; Tamper
    17. DCD RTC_IRQHandler ; RTC
    18. DCD FLASH_IRQHandler ; Flash
    19. DCD RCC_IRQHandler ; RCC
    20. DCD EXTI0_IRQHandler ; EXTI Line 0
    21. DCD EXTI1_IRQHandler ; EXTI Line 1
    22. DCD EXTI2_IRQHandler ; EXTI Line 2
    23. DCD EXTI3_IRQHandler ; EXTI Line 3
    24. DCD EXTI4_IRQHandler ; EXTI Line 4

        然后就是中断的端口,也就是中断向量表。用不准确的话说也就是自己系统自己的中断的地址。这部分每个芯片不一样,有中断多的,有中断少的,不过中断的端口就放在这里。

    1. ; Reset handler
    2. Reset_Handler PROC
    3. EXPORT Reset_Handler [WEAK]
    4. IMPORT __main
    5. IMPORT SystemInit
    6. LDR R0, =SystemInit
    7. BLX R0
    8. LDR R0, =__main
    9. BX R0
    10. ENDP

        然后是启动引导,先系统的初始化,然后进入main函数。这部分知道就行,知道程序是从这里进,然后才到自己看到的while(1)那里的main函数。

    1. ; Dummy Exception Handlers (infinite loops which can be modified)
    2. NMI_Handler PROC
    3. EXPORT NMI_Handler [WEAK]
    4. B .
    5. ENDP
    6. HardFault_Handler\
    7. PROC
    8. EXPORT HardFault_Handler [WEAK]
    9. B .
    10. ENDP
    11. PendSV_Handler PROC
    12. EXPORT PendSV_Handler [WEAK]
    13. B .
    14. ENDP
    15. SysTick_Handler PROC
    16. EXPORT SysTick_Handler [WEAK]
    17. B .
    18. ENDP
    19. Default_Handler PROC
    20. EXPORT WWDG_IRQHandler [WEAK]
    21. EXPORT PVD_IRQHandler [WEAK]
    22. EXPORT TAMPER_IRQHandler [WEAK]
    23. EXPORT RTC_IRQHandler [WEAK]
    24. EXPORT FLASH_IRQHandler [WEAK]
    25. EXPORT RCC_IRQHandler [WEAK]
    26. EXPORT EXTI0_IRQHandler [WEAK]
    27. EXPORT EXTI1_IRQHandler [WEAK]
    28. EXPORT EXTI2_IRQHandler [WEAK]
    29. EXPORT EXTI3_IRQHandler [WEAK]
    30. EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK]
    31. EXPORT USART3_IRQHandler [WEAK]
    32. EXPORT EXTI15_10_IRQHandler [WEAK]
    33. EXPORT RTCAlarm_IRQHandler [WEAK]
    34. EXPORT USBWakeUp_IRQHandler [WEAK]
    35. WWDG_IRQHandler
    36. PVD_IRQHandler
    37. TAMPER_IRQHandler
    38. RTC_IRQHandler
    39. FLASH_IRQHandler
    40. RCC_IRQHandler
    41. EXTI0_IRQHandler
    42. EXTI1_IRQHandler
    43. EXTI2_IRQHandler
    44. EXTI3_IRQHandler
    45. CAN1_SCE_IRQHandler
    46. EXTI9_5_IRQHandler
    47. TIM1_BRK_IRQHandler
    48. TIM1_UP_IRQHandler
    49. TIM1_TRG_COM_IRQHandler
    50. TIM1_CC_IRQHandler

        再然后是弱定义。这部分的作用呢,类似于前面声明了中断函数,后面来了函数的主体,也就是.h里面先声明下,然后.c里面的函数主体。当然这里的弱定义的意思就是:中断函数给你写好了,你自己想加自己的中断就加,不想加也不会报错,因为已经先定义了一下函数主体。

    1. ;*******************************************************************************
    2. ; User Stack and Heap initialization
    3. ;*******************************************************************************
    4. IF :DEF:__MICROLIB
    5. EXPORT __initial_sp
    6. EXPORT __heap_base
    7. EXPORT __heap_limit
    8. ELSE
    9. IMPORT __use_two_region_memory
    10. EXPORT __user_initial_stackheap
    11. __user_initial_stackheap
    12. LDR R0, = Heap_Mem
    13. LDR R1, =(Stack_Mem + Stack_Size)
    14. LDR R2, = (Heap_Mem + Heap_Size)
    15. LDR R3, = Stack_Mem
    16. BX LR

        最后是堆和栈的开始点,和上面main的入口一样,定位到堆和栈的开始,并且还计算着大小之类的,别使用超了。

        总结下启动文件的内容:(1)堆和栈的大小设定,指向堆和栈的开始;(2)程序所有的中断定义和中断主体;(3)程序main的开始入口,也就是启动入口。

        至于后面怎么运行的不用管,只看到c代码就行,至于怎么编译成汇编,然后再怎么编译成01代码,然后怎么再在单片机里面跑的不用管,只需要知道顶层这样设计就好。

        注意:这里强调一点,不用管下层怎么弄的,上层这样弄,下层就会这样执行。并且就是这个格式。其他格式行不行,行,但是别人这样做的,大家都这样做了,咱们就按照这个格式来。就类似于电视,知道开关机、选台就行了,至于信号怎么传输的,都不用管,别人做好了,就可以用。自己只需要接好线,接好电源,然后点遥控器就行。

    第三章:ECLIPSE文件架构

    第1节:文件架构

        采用eclipse生成STM32F10x的文件架构如下:

         一共分为5个部分:

        (1)与上章介绍的共同的部分,main文件,103库函数文件,103系统文件,core相同文件;

        (2)core不同部分,有cmsisdevice,cmsisgcc,还有另外三个core的文件,这部分只是系统的文件,可以不用涉及。具体里面也看不懂,知道是内核文件就好。

        (3)内核调用文件:-cxx,-exit,-sbrk,-startup,-syscalls,assert这几个文件,这部分和core是配套的,在其他函数中也会调用,里面内容看不懂,也不用管。

        (4)其余不同文件:三个ld文件,verctor_stm32f10x,_initializehardware,_resethardware,exceptionhander;

        (5)debug和跟踪文件:semihosting和trace文件。这几个文件是调试和断点用的,这部分作用还不知道,网上说是这样。目前还不太清楚具体作用,当删除之后对原有编程没有影响,应该就是debug或者数据传输用的。可以不用管。

        这5个部分的第1部分可以参看前面的介绍,都是原有的程序,第235部分都是不用管的程序,其中第4部分需要很注意。这部分和上一章介绍的.s文件有很大关联,所以必须单独介绍,并且这部分是修改程序必须看懂的程序,所以需要和小伙伴们分享下。

    第2节:不同启动文件对比

        只介绍前文的第4个部分,先看vector文件:

    1. void __attribute__((weak))
    2. Default_Handler(void);
    3. void __attribute__ ((weak, alias ("Default_Handler")))
    4. WWDG_IRQHandler(void);
    5. void __attribute__ ((weak, alias ("Default_Handler")))
    6. PVD_IRQHandler(void);
    7. void __attribute__ ((weak, alias ("Default_Handler")))
    8. TAMPER_IRQHandler(void);
    9. void __attribute__ ((weak, alias ("Default_Handler")))
    10. RTC_IRQHandler(void);
    11. void __attribute__ ((weak, alias ("Default_Handler")))
    12. FLASH_IRQHandler(void);
    13. void __attribute__ ((weak, alias ("Default_Handler")))
    14. RCC_IRQHandler(void);
    15. void __attribute__ ((weak, alias ("Default_Handler")))
    16. EXTI0_IRQHandler(void);
    17. void __attribute__ ((weak, alias ("Default_Handler")))
    18. EXTI1_IRQHandler(void);
    19. void __attribute__ ((weak, alias ("Default_Handler")))
    20. EXTI2_IRQHandler(void);
    21. void __attribute__ ((weak, alias ("Default_Handler")))
    22. EXTI3_IRQHandler(void);
    23. void __attribute__ ((weak, alias ("Default_Handler")))
    24. EXTI4_IRQHandler(void);
    25. (pHandler) &_estack, // The initial stack pointer
    26. Reset_Handler, // The reset handler
    27. NMI_Handler, // The NMI handler
    28. HardFault_Handler, // The hard fault handler
    29. BusFault_Handler, // The bus fault handler
    30. PendSV_Handler, // The PendSV handler
    31. SysTick_Handler, // The SysTick handler
    32. WWDG_IRQHandler, // Window WatchDog
    33. PVD_IRQHandler, // PVD through EXTI Line detection
    34. TAMPER_IRQHandler, // Tamper through the EXTI line
    35. RTC_IRQHandler, // RTC Wakeup through the EXTI line
    36. FLASH_IRQHandler, // FLASH
    37. RCC_IRQHandler, // RCC
    38. EXTI0_IRQHandler, // EXTI Line0
    39. EXTI1_IRQHandler, // EXTI Line1
    40. EXTI2_IRQHandler, // EXTI Line2
    41. EXTI3_IRQHandler, // EXTI Line3
    42. EXTI4_IRQHandler, // EXTI Line4

        这个文件和前面.s文件里面的中断向量弱定义对应,所以如果需要修改中断种类和数量的话,必须从这里修改。

        再看看resethardware文件:

    1. extern void
    2. __attribute__((noreturn))
    3. NVIC_SystemReset(void);
    4. void
    5. __reset_hardware(void);
    6. void
    7. __attribute__((weak,noreturn))
    8. __reset_hardware()
    9. {
    10. NVIC_SystemReset();
    11. }

        这部分应该是对应中断向量表的指向,也就是中断初始化执行入口。

        再看看initializehardware文件:

    1. extern unsigned int __vectors_start;
    2. // Forward declarations.
    3. void
    4. __initialize_hardware_early(void);
    5. void
    6. __initialize_hardware(void);
    7. void
    8. __attribute__((weak))
    9. __initialize_hardware_early(void)
    10. {
    11. // Call the CSMSIS system initialisation routine.
    12. SystemInit();
    13. }
    14. void
    15. __attribute__((weak))
    16. __initialize_hardware(void)
    17. {
    18. // Call the CSMSIS system clock routine to store the clock frequency
    19. // in the SystemCoreClock global RAM location.
    20. SystemCoreClockUpdate();
    21. }

        这部分是初始化系统的,也就是是执行main函数的入口,里面的函数和前面的.s是对应起来的,先初始化硬件,然后再进入系统的入口:systeminit,从这个地方进入main程序。

        再看看exceptionhandler文件:

    1. extern void
    2. __attribute__((noreturn,weak))
    3. _start (void);
    4. void __attribute__ ((section(".after_vectors"),noreturn))
    5. Reset_Handler (void)
    6. {
    7. _start ();
    8. }
    9. void __attribute__ ((section(".after_vectors"),weak))
    10. NMI_Handler (void)
    11. {
    12. #if defined(DEBUG)
    13. __DEBUG_BKPT();
    14. #endif
    15. while (1)
    16. {
    17. }
    18. }
    19. void __attribute__ ((section(".after_vectors"),weak,naked))
    20. HardFault_Handler (void)
    21. {
    22. asm volatile(
    23. " tst lr,#4 \n"
    24. " ite eq \n"
    25. " mrseq r0,msp \n"
    26. " mrsne r0,psp \n"
    27. " mov r1,lr \n"
    28. " ldr r2,=HardFault_Handler_C \n"
    29. " bx r2"
    30. : /* Outputs */
    31. : /* Inputs */
    32. : /* Clobbers */
    33. );
    34. }

        里面具体定义了中断函数,其中都是一些汇编的语言,具体的对比了eclipse生成的其他芯片的文件,发现这部分都是一样的,应该是向量表的地址都一样。并且里面有很多sem文件的函数,应该是发生错误的时候能在上位机的地方看到错误。

        然后看三个ld文件:

        section文件:

    1. __stack = ORIGIN(RAM) + LENGTH(RAM);
    2. _estack = __stack; /* STM specific definition */
    3. __Main_Stack_Size = 1024 ;
    4. PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ;
    5. __Main_Stack_Limit = __stack - __Main_Stack_Size ;
    6. PROVIDE ( _Heap_Begin = _end_noinit ) ;
    7. PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ;

        对比下,这部分定义了堆和栈的大小,已经文件的存储位置,里面有code段,data段还有bss段的位置,具体的位置全部都是全局变量,具体变量的值在mem的ld文件里,具体:

    1. MEMORY
    2. {
    3. RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
    4. CCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0
    5. FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
    6. FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
    7. EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
    8. EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
    9. EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
    10. EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
    11. MEMORY_ARRAY (xrw) : ORIGIN = 0x00000000, LENGTH = 0
    12. }

        里面定义了ram和其他文件的存储地址等,这部分是在KEIL里面通过魔法棒定义的,里面有内存分配的一个文件,通过下载器下载进去的。

    第3节:总结

        通过上述介绍,小伙伴应该对eclipse产生的文件有个大概的了解,其文件也是一一对应的,只不过放到了不同的c文件和h文件里。

    第四章:修改原则

    现有条件:

        已做:将STM32F103的程序修改为STM32F407的HAL库程序。

        步骤:(1)生成103程序;(2)删除不用函数和文件夹;(3)407文件代替103文件;(4)编译;(5)下载。

        结果:认真点话可以将103的程序修改成407的程序,编译没有任何错误和警告,下载到407开发板中可以运行,具体的灯可以中断点亮,串口可以中断发送。

        问题:观察波形发现了问题。串口发送会影响灯的翻转,这个问题有点大啊!不知道是不是串口发送的HAL库发送的时候必须等发送完才能出中断,如果是的话就没啥问题。

         编写程序:

    1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    2. {
    3. if(htim==(&TIM3_Handler))
    4. {
    5. LED0_Toggle;
    6. }
    7. if(htim==(&TIM4_Handler))
    8. {
    9. gnUartTxTemp1++;
    10. HAL_UART_Transmit(&UART1_Handler, &gnUartTxTemp1, 1, 1000);
    11. }
    12. }

        按照程序的话,两个定时器中断执行时间都很短,串口发送不应该影响灯的翻转,但是现在影响了,不知道是什么问题。到时候还的分析下。

    原则:

        (1)ST103移植到ST407,成功的话说明移植地方正确;

        (2)ST103移植到GD103,看看这个能不能成功,如果能成功证明修改的地方正确;

        (3)ST103移植到STH730,和ST103移植到STH750,如果都可以移植,证明方法正确,可以总结出移植点。

        (4)换其他厂家的芯片,看是否能移植成功。

        (5)后续使用LINUX虚拟机上的eclipse,初步摆脱windows的平台。

    第五章:结论与展望

        涉及到一个新的东西,学习和修改都是需要勇气的。其实移植前我也很害怕,担心自己做不成功,并且移植本身就是需要在错误上修正错误,这个过程很煎熬。但是没有办法的事,总需要去接受新的东西。现在做到的程度仅仅是移植差不多的STM系列的东西,真的到GD上面不知道会出现什么情况,但愿生活对我好点,能快点移植出来。

        正在做这方面的小伙伴可以持续关注,后续文章将会陆续发出。

  • 相关阅读:
    Java String、StringBuffer 和 StringBuilder 的区别和理解
    家电生产线数控机床上下料长臂机器人组设计
    聊聊云原生数据平台
    苹果给国内用户提供了最好的5G手机,一机在手畅通全球
    Python进阶——JSON
    php: centos+apache 启动php项目
    数据可视化项目1
    求解平面上物体的有向3d包围盒
    DXF笔记:线型CENTER的格式及绘制思想
    2024-06-24力扣每日一题
  • 原文地址:https://blog.csdn.net/weixin_45426095/article/details/126519746