uclinux FM3芯片的移植

时间:2022-01-01 20:14:58

uclinux ethernt FM3芯片的移植这个移植是把uclinux下面的本来支持stm32芯片的代码修修改改让它支持FM3芯片。

移植开发环境搭建:

开始我们隔壁项目组做uclinux相关的,我们把它们的工作正常的uclinux版本拿过来。在里面找到stm32相关的代码,开始这个版本的uclinux是配着uboot去执行的,是标准的嵌入式linux执行流程,必须有uboot去引导。而我们的开发板片内有1M的flash,片外有1M的RAM空间,我们想改成不用uboot,并且自启动的模式。所以开始找到那个uboot加载uclinux后第一个执行的no-mmu文件,然后因为它不是自启动模式,我们看过CM3arm手册,再加上以前组内另外一人做过FM3 reference code 的GCC版移植,有现成的GCC版代码参考,所以轻松改成自启动模式,另外因为要放到flash上去执行,所以又修改内核配置选项,改成xip模式去执行。还有为了将程序正确烧写到flash中,我们用Jlink+Jflash,将程序改成rec模式,就可以烧写了。在虚拟机里面用破解版Jflash,破解版DS-4,又能避免版权问题,呵呵。

这期间还得配着调试器,我们用的realview-ice+rvds4,开始能在调试窗口中看到代码,并且执行reset 命令后,还能正常开始往下执行。因为往下执行时,首先要关掉看门狗,并且设置XPSP处于thumb态,在执行完初始化片外ram脚本后,为了提前看到串口输出信息,又把以前uart代码拿过来塞到printk里面。

还有这种调试方式太过于简陋,只能看汇编代码调,不方便。我们到后期调试往往时,加入printk语句,烧写完,又自启动后看Putty屏幕输出的串口信息。后来,我们又改用DS-5工具,这时方便多了,就用一个ds-5加上review-ice就可以烧写带调试了,需要改uclinux配置,把debuginfo信息加上去,这样而我们还可以看到源代码调试的。

还有要用到版本管理工具的,我们用的git,做这个项目时我观察周围人用git,我才发现用GIT确实在版本管理方面很灵活作用很大。

这样uclinux的开发环境简简单单搭建起来了。

移植开发:

先搞timer中断,这个一开始没经验比较难些,当时我们开始先试下普通中断能不能起来。普通中断起来后,开始搞timer。经过这一搞,我们原来想着得修改很多文件的,最后发现整个搞uclinux只用修改两大地方:arch/arm/kernel/head-nommu.S和arch/arm/mach-stm32/*.* 。 只用修改这两个地方就行了。原来uclinux有他自己中断框架。

我们要做的只是修改下底层配置寄存器的地方和硬件相关的框架吧。我们把以前的testset中设置timer中断的代码搬过来,填充到uclinux timer框架里。并且把之前做Donet设置的time主频的代码也搬过来。修改文件有arch/arm/mach-stm32/{clock.c和timer.c}就行了。本来还想着修改arch/arm/kernel/entry-v7m.S, arch/arm/mm/proc-v7m.S这两个文件,还想着会修改中断框架的底层部分(setup_irq里面的东西)现在看来也不用修改了。它是靠__irq_entry这个玩意统一再去查另外一个表里的终端号,去逐个识别中断号15以后的具体功能中断的。我们所做的是给setup_irq配个中断号(FM3_DUAL_TIME_IRQ)就行了。

下来搞uart开发:

我们搭建开发环境时做的uart是临时用的简易uart,下来我们要把uart代码整到uclinux框架中,并且把console打通。

我们修改的文件有driver/serial/stm32_usart.c,arch/arm/mach-stm32/uart.c.h。通过这个uart框架整合,再加上以前在学校期间对嵌入式驱动开发有个知识基础,我深刻理解了linux kernel 2.6 driver驱动模型。

先设备初始化,最早执行arch/arm/mach-stm32/stm32_platform.c文件里的stm32_init函数,然后初始化各个设备,中间调用uart_init初始化串口设备,这个最终调用platform_device_register注册串口设备。设备初始化时,要把设备一些硬件资源信息填好。

然后在start_kernel里面最后一个函数里间接调用设备驱动程序初始化时,会到driver/serial/stm32_usart.c中调用stm32_usart_init函数,这个函数最终调用driver_register函数,在和总线上的设备binding的时候,查到一有uart硬件设备,就会最终调用stm32_uart_probe函数,去初始化好uart的各个结构体和功能。

然后初始化完以后,调用uart_add_one_port——》uart_configure_port——》register_console——》stm_console_setup-》stm_port_set_termios最后函数里面因为我们没做改造,所以如果按正规的prink框架调用时,之前保存在console缓冲区里面的信息就不会被输出来。

这个我是通过DS-5调试时,看程序运行时的函数调用链窗口,看出stm32_uart_probe走完,缓冲区里的信息是不会被及时输出来的,并且关键是程序卡在stm32_xmit_char中。这是因为串口刚被初始化完后,缓冲区的信息想及时输出来,所以得调用stm32_xmit_char,但此时串口寄存器又没被设置好,所以串口没准备好接受,就卡在这个函数里,整个程序不能往下面执行。

所以在这个stm_port_set_termios里加个开启串口的操作。然后程序就不卡了。接着往下面会执行到sysopen打开console,里面会间接调用stm_port_startup函数,这回又打开了一个串口操作工作。然后屏幕上显示console enbled.然后串口功能就正常了。

上面说的是调试过程中遇到的问题。

至于开始阶段的串口代码移植就是关键把stm32的寄存器操作语句扫描出,然后替换FM3的寄存器操作语句。其他东西不去改变。还有我们还有了一个FM3 UART参考代码

之前做DONET移植时的FM3 UART参考代码。这个代码还是中端模式下的串口输出的,里面串口功能设置的挺全的。所以我们移植起来也相对轻松些。

要想开启串口具体需要设置好GPIO串口相关的引脚寄存器,设置好波特率,设置波特率时,芯片手册上有个波特率的计算公式,按上面选好系统主频,波特率填写好就行了。

一般屏幕上出现乱码就说明波特率没设置好,系统主频没设置好。然后下来再做些打开串口寄存器的工作就行了。如果在中断模式的时候,还需要注册中断号。

根文件系统开发:

之前我们组一个人说这个uclinux FM3移植文件系统如何难,说是xip模式下,uclinux只能支持一种文件系统,其他的都不行。后来其实搞工作思路应该简化。我们隔壁组搞过嵌入式linux根文件系统。所以就问问他。原来是很简单的。

就用kernel自带的initramfs就行了。这样kernel启动时,加载initramfs,在这个里面放些程序,kernel启动后第一个就会执行它。后来还搞了busybox裁剪,因为存储空间不够。

在调试时,还想结合systemtap文件,这个相当于之前搞嵌入式测试时经常要对照的map文件,如果程序越界或出错的话。