作为嵌入式linux的开发者,很可能需要自己来制作PCB,也免不了开发自己的驱动程序,linux系统虽然内置了很多常见外设的驱动,甚至有些外设不需要开发驱动,仅仅通过配置就可以使用如:GPIO,但是在实际使用时也还是避免不了开发定制设备的驱动,很多时候设备驱动能否开发成功,可能关系到整个项目的成败,早先年见到过太多的失败案例了。所以建议在选择linux项目时一定要慎重再慎重。别人能成甚至是以前能成都不代表新项目的成功。
米尔的STM32MP135开发板内置的BSP已经较为完善了,除了没有将IIC的全部引脚引出外,其它的总线驱动都内置了。就是不常见到的ADC驱动也有内置。本次的测试是开发一个自己的内核模块,目的是测试驱动开发的环境和安装方法。这个过程中还是有很多坑地,需要十分的注意。
一、安装ST公司的SDK和源码BSP包
参考Install the SDK wiki页面的步骤安装SDK工具。为了和米尔的版本一致选择了linux 5.15.67版本。这个虽然这个没有必要,但是由于折腾一遍linux源码太费时间了,我的环境一次需要2、3个小时。这还是我把机器的硬盘升级成256固态的情况。如果是硬盘基本需要7、8个小时。等有时间了在试一试linux 6.1的版本。
如果没有错误的情况
- echo $CC
- arm-ostl-linux-gnueabi-gcc -mthumb -mfpu=neon-vfpv4 -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=/home/bigbat/stm32mp/SDK/sysroots/cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
出现上面的内容,既证明成功
二、下载ST的linux内核源码,en.SOURCES-stm32mp1-openstlinux-5.15-yocto-kirkstone-mp1-v22.11.23.tar.gz
参考 Modify, rebuild and reload the Linux® kernel wiki的步骤编译linux内核。这一步如果没有错误,就可以得到一个内核和模块。
按照步骤将设备树和内核烧录到TF卡,你会发现能够启动但是网络没有了。这是因为使用的网卡和开发板不一致所致。这个内核做模块实验很是不方便。
三、网卡的驱动设置
米尔板子的网卡使用的是1000M的“网卡”,(这么说不严谨,应该是1000M的PHY接口)。所以需要把设备树重新配置,加入新的1000M 的PHY芯片驱动。板子的PHY芯片是裕泰微YT8521SH,为国产的PHY芯片,据说和RTL8211FSI兼容,其实只要不使用芯片的特殊功能,一般的应用驱动是相似的。
参考Ethernet device tree configuration的3.3.6 RGMII with Crystal on PHY, no 125MHz from PHY一节的内容
- ðernet0 {
- status = "okay";
- pinctrl-0 = <ðernet0_rgmii_pins_a>;
- pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>;
- pinctrl-names = "default", "sleep";
- phy-mode = "rgmii";
- max-speed = <1000>;
- phy-handle = <&phy0>;
- mdio0 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,dwmac-mdio";
- phy0: ethernet-phy@0 {
- compatible = "ethernet-phy-ieee802.3-c22";
- reg = <0>;
- };
- };
- };
我只是增加了compatible = "ethernet-phy-ieee802.3-c22";内容,这是指定phy驱动的。好像有没有都没关系。
重新编译内核,
- make uImage LOADADDR=0xC2000040
完成后,参考上面的按照步骤,烧写内核就可以有网络用了。
四、编写helloworld内核模块
这个模块有两个文件,模块文件和make文件
- KERNELDIR :=<linux kernel dir>
-
- CURRENT_PATH := $(shell pwd)
-
- target := helloworld
- obj-m := $(target).o
-
- all:
- $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
-
- clean:
- $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
-
- dir_exist = $(shell if [ -d "/nfsroot/$(target)/" ]; then echo "exist"; else echo "noexist"; fi)
- $(info $(dir_exist))
-
- install:
- ifeq ("$(dir_exist)", "noexist")
- $(shell mkdir /nfsroot/$(target))
- endif
- cp *.ko /nfsroot/$(target)/
然后是模块文件helloworld.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/kernel.h>
-
-
- static int hello_init(void)
- {
- printk(KERN_INFO "[init] Can you feel me?\n");
- return 0;
- }
-
- static void hello_exit(void)
- {
- printk(KERN_INFO "[exit] Yes.\n");
- }
-
- module_init(hello_init);
- module_exit(hello_exit);
-
- MODULE_AUTHOR("Alan Wang <alan@wrcode.com>");
- MODULE_LICENSE("GPL");
- MODULE_DESCRIPTION("A simple Hello World Module");
- MODULE_ALIAS("A simple module");
编写完成后
生成了helloworld.ko文件,
- scp helloworld.ko root@<board ip address>:~/
然后加载模块:
- root@myd-yf13x:~
- [ 429.429951] helloworld: disagrees about version of symbol module_layout
- insmod: ERROR: could not insert module helloworld.ko: Invalid module format
- root@myd-yf13x:~
这里有一个大坑,如果你象我一样,没有烧写自己的内核,而是直接上传模块文件,你发现无法加载模块,网上说是版本不对,可是你的源码版本一模一样呀。很是奇怪。这个问题折腾了好多天才搞明白。这是因为你的内核和板子里的内核出处不一致造成地,这个是因为stm32mp1的安全认证机制所限制造成地。
那么你将编译好的内核编译好了,单独上传内核,也就是不上传设备树会是上面结果呢?
- root@myd-yf13x:~
- [ 52.695075] helloworld: loading out-of-tree module taints kernel.
- [ 52.700149] [init] Can you feel me?
- root@myd-yf13x:~
-
说内核受到了“污染”,还是不行。那就连设备树一块上传,还是不行!但是可以使用insmod -f,强制加载,
- root@myd-yf13x:~
- filename: /home/root/helloworld.ko
- alias: A simple module
- description: A simple Hello World Module
- license: GPL
- author: Alan Wang <alan@wrcode.com>
- depends:
- name: helloworld
- vermagic: 5.15.67 preempt mod_unload modversions ARMv7 p2v8
- root@myd-yf13x:~
这似乎没有办法了,那怎么办呢。其实有两个方案,
一是:使用米尔开发板的BSP源码,需要到米尔公司手工获得。这种办法最省事。
二是:将全套的源码,TF-A开始uboot等等文件全面的都进行一遍烧录,但是这个需要一个前提,就是这个芯片不能做证书认证。
- root@myd-yf13x:~
- [ 43.222525] helloworld: loading out-of-tree module taints kernel.
- [ 43.227780] [init] Can you feel me?
- root@myd-yf13x:~
-
|