相信大家接触芯来的开发板后,都会有一系列疑问
(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中的输出内容