RISC-V MCU中文社区

【分享】 USART0、Banner初始化及修改

发表于 GD32VF103 MCU 2021-04-08 11:46:10
0
2343
2

相信大家接触芯来的开发板后,都会有一系列疑问

(1)我的程序里什么都没写,但是串口0上依然输出了一个Banner:

Nuclei SDK Build Time: Apr 2 2021, 11:03:00
Download Mode: FLASHXIP
CPU Frequency 108778846 Hz

(2)串口0是在哪里初始化的

能够有上述疑问的工程师们,一定都知道如何新建工程, 所以让我们从新建工程完成之后开始聊一聊这个问题。以使用NucleiStudio的默认工程目录为例,工程新建后,根目录有三个文件夹,application、Debug、nuclei_sdk。其中application目录是我们写的程序存放的默认目录,Debug目录与编译相关,一般无需手动修改,最后还有一个nuclei_sdk目录,这个目录的用途从名字就能看出来用途,存放sdk的,一般也无需修改。但是今天我们需要去这其中一探究竟。

由于分析整个工程目录及初始化流程是一个很系统的工程,我自己对整个初始化流程目前也处在一个只见树木不见森林的阶段,下文中只分析自己看明白的部分,如有错误或片面的理解,望批评指正。

进入到

PROJECT_ROOT\nuclei_sdk\SoC\gd32vf103\Common\Source

目录,其中PROJECT_ROOT表示工程的根目录,这个目录下文简称为为Source目录。

由于我们已知了一个关键的数据,串口波特率是115200,通过在工程目录中搜索115200关键词,可以轻松找到串口USART0的初始化函数gd_com_init。根据开发板的不同,这个初始化函数也会有所不同,以longan为例,该函数位于Sourece目录下gd32vf103c_longan_nano.c文件106行。

一个小备注:观察此处的初始化函数,我们看到TX、RX均已初始化,程序中如需使用串口0的接收功能,可以直接使用无需初始化。

通过搜索对该函数的调用,我们进一步找到了该函数的调用位置,system_gd32vf103.c文件528行,我们重点关注523~535行的_premain_init函数。

523 void _premain_init(void)
524 {
525     /* TODO: Add your own initialization code here, called before main */
526     SystemCoreClock = get_cpu_freq();
527     /* configure USART */
528     gd_com_init(SOC_DEBUG_UART);
529     /* Display banner after UART initialized */
530     SystemBannerPrint();
531     /* Initialize exception default handlers */
532     Exception_Init();
533     /* ECLIC initialization, mainly MTH and NLBIT */
534     ECLIC_Init();
535 }


其中,我们看到528行调用了刚刚提到的USART0初始化函数,解答了串口0在哪里初始化的疑问。接着往下看529行的注释,串口初始化完成后显示banner。第520行程序解答了为什么会输出banner的问题,至此,困扰的两个问题基本得到解决。那么,接下来的问题是,这个初始化函数_premain_init是被谁调用执行的。进一步通过搜索可知,这个函数被GCC目录startup_gd32vf103.S中调用了。通过文件名我们可以猜测,这个汇编文件,很有可能就是负责芯片初始化工作的。跳过看不懂和与问题无关的部分,观察353行附近

344    call SystemInit
345
346    /* Call global constructors */
347    la a0, __libc_fini_array
348    call atexit
349    /* Call C/C++ constructor start up code */
350    call __libc_init_array
351
352    /* do pre-init steps before main */
353    call _premain_init
354    /* ===== Call Main Function  ===== */
355    /* argc = argv = 0 */
356    li a0, 0
357    li a1, 0

看到_premain_init函数在353行被调用。由于对于整个启动流程仍然不是特别清晰,此处也就不再分析这个.S文件了。

疑问分析到此结束。接下来就该解决问题了。如果串口0我们有其他用途,不想让芯片上电初始化的过程中输出banner或者想要换一个波特率,我们需要修改system_gd32vf103.c文件中_premain_init函数。最简单的,可以直接注释掉525~530行,之后在用户程序中完成串口0的初始化。


一个小建议:

不知道能否在后续的SDK中,移除system_gd32vf103.c文件525~530行。将这banner输出相关的逻辑移到示例代码中展示。

一方面可以使sdk更纯粹,另一方面,初学者在看到helloworld程序时能更好的理解USART0中的输出内容

喜欢2
用户评论
Flagplus

Flagplus 实名认证

懒的都不写签名

积分
问答
粉丝
关注
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板