替代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是一样的,小伙伴可以自己逐行去看看。

Stack_Size      EQU     0x00000400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size       EQU     0x00000200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

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

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler

                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                DCD     EXTI4_IRQHandler           ; EXTI Line 4

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

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

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

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP


PendSV_Handler  PROC
                EXPORT  PendSV_Handler             [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP

Default_Handler PROC

                EXPORT  WWDG_IRQHandler            [WEAK]
                EXPORT  PVD_IRQHandler             [WEAK]
                EXPORT  TAMPER_IRQHandler          [WEAK]
                EXPORT  RTC_IRQHandler             [WEAK]
                EXPORT  FLASH_IRQHandler           [WEAK]
                EXPORT  RCC_IRQHandler             [WEAK]
                EXPORT  EXTI0_IRQHandler           [WEAK]
                EXPORT  EXTI1_IRQHandler           [WEAK]
                EXPORT  EXTI2_IRQHandler           [WEAK]
                EXPORT  EXTI3_IRQHandler           [WEAK]

                EXPORT  USB_LP_CAN1_RX0_IRQHandler [WEAK]

                EXPORT  USART3_IRQHandler          [WEAK]
                EXPORT  EXTI15_10_IRQHandler       [WEAK]
                EXPORT  RTCAlarm_IRQHandler        [WEAK]
                EXPORT  USBWakeUp_IRQHandler       [WEAK]

WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler

CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler

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

;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
                 IF      :DEF:__MICROLIB           
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE
                
                 IMPORT  __use_two_region_memory
                 EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap

                 LDR     R0, =  Heap_Mem
                 LDR     R1, =(Stack_Mem + Stack_Size)
                 LDR     R2, = (Heap_Mem +  Heap_Size)
                 LDR     R3, = Stack_Mem
                 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文件:

void __attribute__((weak))
Default_Handler(void);


void __attribute__ ((weak, alias ("Default_Handler")))
WWDG_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
PVD_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
TAMPER_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
RTC_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
FLASH_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
RCC_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
EXTI0_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
EXTI1_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
EXTI2_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
EXTI3_IRQHandler(void);
void __attribute__ ((weak, alias ("Default_Handler")))
EXTI4_IRQHandler(void);

      (pHandler) &_estack, // The initial stack pointer
      Reset_Handler, // The reset handler

      NMI_Handler, // The NMI handler
      HardFault_Handler, // The hard fault handler
      BusFault_Handler,                        // The bus fault handler
      PendSV_Handler, // The PendSV handler
      SysTick_Handler, // The SysTick handler

      WWDG_IRQHandler, // Window WatchDog
      PVD_IRQHandler, // PVD through EXTI Line detection
      TAMPER_IRQHandler, // Tamper through the EXTI line
      RTC_IRQHandler, // RTC Wakeup through the EXTI line
      FLASH_IRQHandler, // FLASH
      RCC_IRQHandler, // RCC
      EXTI0_IRQHandler, // EXTI Line0
      EXTI1_IRQHandler, // EXTI Line1
      EXTI2_IRQHandler, // EXTI Line2
      EXTI3_IRQHandler, // EXTI Line3
      EXTI4_IRQHandler, // EXTI Line4

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

    再看看resethardware文件:

extern void
__attribute__((noreturn))
NVIC_SystemReset(void);

void
__reset_hardware(void);

void
__attribute__((weak,noreturn))
__reset_hardware()
{
  NVIC_SystemReset();
}

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

    再看看initializehardware文件:

extern unsigned int __vectors_start;

// Forward declarations.

void
__initialize_hardware_early(void);

void
__initialize_hardware(void);

void
__attribute__((weak))
__initialize_hardware_early(void)
{
  // Call the CSMSIS system initialisation routine.
  SystemInit();
}

void
__attribute__((weak))
__initialize_hardware(void)
{
  // Call the CSMSIS system clock routine to store the clock frequency
  // in the SystemCoreClock global RAM location.
  SystemCoreClockUpdate();
}

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

    再看看exceptionhandler文件:

extern void
__attribute__((noreturn,weak))
_start (void);
void __attribute__ ((section(".after_vectors"),noreturn))
Reset_Handler (void)
{
  _start ();
}

void __attribute__ ((section(".after_vectors"),weak))
NMI_Handler (void)
{
#if defined(DEBUG)
  __DEBUG_BKPT();
#endif
  while (1)
    {
    }
}
void __attribute__ ((section(".after_vectors"),weak,naked))
HardFault_Handler (void)
{
  asm volatile(
      " tst lr,#4       \n"
      " ite eq          \n"
      " mrseq r0,msp    \n"
      " mrsne r0,psp    \n"
      " mov r1,lr       \n"
      " ldr r2,=HardFault_Handler_C \n"
      " bx r2"

      : /* Outputs */
      : /* Inputs */
      : /* Clobbers */
  );
}

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

    然后看三个ld文件:

    section文件:

__stack = ORIGIN(RAM) + LENGTH(RAM);

_estack = __stack; 	/* STM specific definition */

__Main_Stack_Size = 1024 ;

PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ;

__Main_Stack_Limit = __stack  - __Main_Stack_Size ;

PROVIDE ( _Heap_Begin = _end_noinit ) ;
PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ;


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

MEMORY
{
  RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
  CCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
  FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  MEMORY_ARRAY (xrw)  : ORIGIN = 0x00000000, LENGTH = 0
}

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

第3节:总结

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

第四章:修改原则

现有条件:

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

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

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

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

     编写程序:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim==(&TIM3_Handler))
    { 
        LED0_Toggle;
	}
    if(htim==(&TIM4_Handler))
    { 
    	gnUartTxTemp1++;
    	HAL_UART_Transmit(&UART1_Handler, &gnUartTxTemp1, 1, 1000);
	}	
}

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

原则:

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

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

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

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

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

第五章:结论与展望

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

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值