MYD-YA157C系列定制板RM500Q-GL驅動移植筆記 2021.8.12
一、准備工作
(1)YA157C開發板一塊
(2) Ipex1代轉SMA母,轉接線若干
(3) Ipex4代轉SMA母,轉接線若干
(4) 跳線帽若干,並安裝到如下圖所示的指定位置
(5G模塊硬件拉高開機,默認狀態)
(藍色帶包5G模塊軟件拉高開機)
(5) 准備一個linux環境用來交叉編譯,這里我使用了deepin系統,並將其安裝在VMware虛擬機環境下
(6) 參考《MYD-YA157C_Linux軟件開發指南V2.0.pdf》准備交叉編譯環境
- l 安裝米爾定制的 SDK
我們在使用 Yocto 構建完系統鏡像之后,還可以使用 Yocto 構建一套可擴展的 SDK。在米爾提供的光盤鏡像中包含一個編譯好的 SDK 包,位於:03-Tools/Complie Toolchain/QT-SDK/sdk-qt.tar.xz,這個 SDK 中除了包含一個獨立的交叉開發工具鏈還提供 qmake, 目標平台的 sysroot, Qt 應用開發所依賴的庫和頭文件等。用戶可以直接使用這個 SDK 來建立一個獨立的開發環境,單獨編譯 Bootloader,Kernel 或者編譯自己的應用程序。
- l 拷貝 SDK 到 Linux 目錄並解壓
將 SDK 壓縮包拷貝到deepin 下的用戶工作目錄,如$HOME/work 下,解壓文件,得
到安裝腳本文件,如下:
PC$ cd $HOME/work PC$ tar -Jxvf sdk-qt.tar.xz sdk
- l 查看腳本文件
進入 SDK 目錄,可以看到下面安裝腳本文件:
meta-toolchain-qt5-openstlinux-eglfs-myir-x86_64-toolchain-3.1-snapshot.host.manifest meta-toolchain-qt5-openstlinux-eglfs-myir-x86_64-toolchain-3.1-snapshot.sh meta-toolchain-qt5-openstlinux-eglfs-myir-x86_64-toolchain-3.1-snapshot.target. manifest meta-toolchain-qt5-openstlinux-eglfs-myir-x86_64-toolchain-3.1-snapshot.testdata.json
- l 執行安裝腳本
PC$ ./meta-toolchain-qt5-openstlinux-eglfs-myir-x86_64-toolchain-2.6-snapshot.sh
- l 選擇安裝目錄
SDK 默認被安裝到/opt/st/myir/3.1-snapshot 目錄下,用戶也可以根據提示自己選擇合適的目錄,具體根據提示進行操作:
ST OpenSTLinux - EGLfs - (A Yocto Project Based Distro) SDK installer version 3.1- snapshot =============================================== Enter target directory for SDK (default: /opt/st/myir/3.1-snapshot): You are about to install the SDK to "/opt/st/myir/3.1-snapshot". Proceed [Y/n]? y [sudo] password for licy: Extracting SDK ........................................................................................................................................... done Setting it up...done SDK has been successfully set up and is ready to be used. Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g. $ . /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
- l 測試SDK
安裝完成后,使用以下命令設置環境變量,測試 SDK 是否完成:
PC$ source /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfp v4-ostl-linux-gnueabi PC$ $CC --version arm-ostl-linux-gnueabi-gcc (GCC) 8.2.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
米爾提供的 SDK 中除了包含交叉工具鏈,還包含 Qt 庫,qmake 等開發 Qt 應用程序所需的資源,這些是后續使用 QT Creator 進行應用程序開發和調試的基礎。
二、上電開機,通過網絡連接開發板,登陸后,執行lsusb命令,正常情況下可以識別移遠RM500Q-GL的VID與PID如圖所示(我已經移植了驅動,所以可以正常識別型號,如果未做驅動移植,這里可能只會顯示2c7c:0800)。
三、參考官方文檔《Quectel_LTE&5G_Linux_USB_Driver_User_Guide_V2.0.pdf》移植驅動
(1)為了識別模塊,需要將下圖最后一行RM500Q的VID和PID信息添加到[KERNEL]/drivers/usb/serial/option.c文件的指定位置中(米爾提供的內核中已添加RM500Q的VID和PID,可省略此步驟)
(2) 添加Zero Packet Mechanism
根據USB協議的要求,需要在bulk-out傳輸過程中增加處理零包的機制,添加如下語句(米爾提供的內核中已定義,可省略此步驟)。
- l For Linux kernel version higher than 2.6.34, add the following statements to the file
[KERNEL]/drivers/usb/serial/usb_wwan.c. static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len,void (*callback) (struct urb *)) { …… usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); #if 1 //Added by Quectel for zero packet if (dir == USB_DIR_OUT) { struct usb_device_descriptor *desc = &serial->dev->descriptor; if (desc->idVendor == cpu_to_le16(0x2C7C)) urb->transfer_flags |= URB_ZERO_PACKET ; } #endif return urb; }
- l For Linux kernel version lower than 2.6.35, add the following statements to the file
[KERNEL]/drivers/usb/serial/option.c. /* Helper functions used by option_setup_urbs */ static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint, int dir, void *ctx, char *buf, int len, void (*callback)(struct urb *)) { …… usb_fill_bulk_urb(urb, serial->dev, usb_sndbulkpipe(serial->dev, endpoint) | dir, buf, len, callback, ctx); #if 1 //Added by Quectel for zero packet if (dir == USB_DIR_OUT) { struct usb_device_descriptor *desc = &serial->dev->descriptor; if (desc->idVendor == cpu_to_le16(0x2C7C)) urb->transfer_flags |= URB_ZERO_PACKET ; #endif return urb; }
(3) 配置重置機制
當MCU進入Suspend/Sleep模式時,部分USB主機控制器/USB hub會斷電或復位,當MCU退出Suspend/Sleep模式后,部分USB主機控制器/USB hub將無法用於USB恢復。需要通過添加以下語句啟用reset-resume機制。
- l For Linux kernel version higher than 3.4, add the following statements to the file
[KERNEL]/drivers/usb/serial/option.c. static struct usb_serial_driver option_1port_device = { …… #ifdef CONFIG_PM .suspend = usb_wwan_suspend, .resume = usb_wwan_resume, #if 1 //Added by Quectel .reset_resume = usb_wwan_resume, #endif #endif };
- l For Linux kernel version lower than 3.5, add the following statements to the file
[KERNEL]/drivers/usb/serial/usb-serial.c. /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { .name = "usbserial", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .suspend = usb_serial_suspend, .resume = usb_serial_resume, #if 1 //Added by Quectel .reset_resume = usb_serial_resume, #endif .no_dynamic_id = 1, .supports_autosuspend = 1, };
(4) 添加對MBIM, GobiNet和QMI_WWWAN驅動的支持
當需要使用MBIM、GobiNet或QMI_WWAN驅動時,需要添加如下語句,防止模塊接口4作為USB串口設備使用。
- l For Linux kernel version higher than 2.6.30, add the following statements to the file
[KERNEL]/drivers/usb/serial/option.c. static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { struct usb_wwan_intf_private *data; …… #if 1 //Added by Quectel //Quectel modules’s interface 4 can be used as USB network device if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { //some interfaces can be used as USB Network device (ecm, rndis, mbim) if (serial->interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { return -ENODEV; } //interface 4 can be used as USB Network device (qmi) else if (serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) { return -ENODEV; } } #endif /* Store device id so we can use it during attach. */ usb_set_serial_data(serial, (void *)id); return 0; }
- l For Linux kernel version lower than 2.6.31, add the following statements to the file
[KERNEL]/drivers/usb/serial/option.c. static int option_startup(struct usb_serial *serial) { …… dbg("%s", __func__); #if 1 //Added by Quectel if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { //some interfaces can be used as USB Network device (ecm, rndis, mbim) if (serial->interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { return -ENODEV; } //interface 4 can be used as USB Network device (qmi) else if (serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) { return -ENODEV; } } #endif …… }
(5) 配置內核
解壓米爾提供的iso文件,進入04_Sources,找到MYiR-STM32-kernel.tar.bz2,放入即將進行交叉編譯的linux環境中(在這里指安裝了deepin的虛擬機),並解壓
- l 進入內核目錄
cd myir-st-linux
- l 創建輸出文件夾
mkdir -p ../build
- l 配置內核
make -j16 ARCH=arm O="$PWD/../build" myc-ya157c_defconfig #注意:此處的-j16是指使用16個處理器進行多線程同時編譯,如果你只給虛擬機分配了兩個處理器,這里就改為-j2依次類推。
#如果出現linux-內核導入配置 lexer.lex.c錯誤,請進行如下操作:
#sudo apt-get install bison
#sudo apt-get install flex
- l 打開USB driver for GSM and CDMA modems
進入剛創建的build目錄
cd ../build
使用下面的命令編譯內核
make menuconfig
#注意:ncurses庫是一個Linux系統下的圖形支持的函數庫,如果缺少該庫可能會報錯,解決方法:
#執行sudo apt install libncurses5-dev
使用以下選項啟用CONFIG_USB_SERIAL_OPTION。
make menuconfig [*] Device Drivers → [*] USB Support → [*] USB Serial Converter support → [*] USB driver for GSM and CDMA modems
使用TAB鍵,移動光標至Save,然后按照提示保存,保存后執行多次ESC鍵以退出界面。
(6) 配置GobiNet驅動
- l 在模塊中安裝GobiNet驅動程序后,將創建一個網絡設備和一個QMI通道。網絡設備命名為ethX(內核版本為2.6.39及以下為usbX), QMI通道命名為/dev/ qcqmix。網絡設備用於數據傳輸,QMI通道用於QMI消息交互。
- l 解壓Quectel_Linux&Android_GobiNet_Driver_V1.6.zip,將里面的文件除了Makefile、makefile、兩個txt文件之外,全部復制到[KERNEL]/drivers/net/usb/(或者[KERNEL]/drivers/usb/net/如果內核版本低於2.6.22
- l 修改內核配置
在build目錄下再次執行make menuconfig,進入
[*] Device Drivers → -*- Network device support → USB Network Adapters → {*} Multi-purpose USB Networking Framework
確保Multi-purpose USB Networking Framework為打開狀態(按Y即可打開)
保存並退出,系統生成.config文件。
- l 在[KERNEL]/drivers/net/usb/Makefile(如果內核版本低於2.6.22,則為[KERNEL]/drivers/usb/net/Makefile)文件中添加以下語句。
-
obj-y += GobiNet.o GobiNet-objs := GobiUSBNet.o QMIDevice.o QMI.o
請注意:對於米爾的這個開發板子,需要使用obj-m的方式,obj-m表示把文件test.o作為"模塊"進行編譯,不會編譯到內核,但是會生成一個獨立的 "test.ko" 文件;obj-y表示把test.o文件編譯進內核;本人在這里卡頓了許久,編譯成功后一直打不上驅動,最后在這個地方得到了解決,即在上述文件夾中,添加以下內容:
-
obj-m += GobiNet.o GobiNet-objs := GobiUSBNet.o QMIDevice.o QMI.o
保存並退出。
(7) 編譯內核
- l 加載SDK環境變量
Source /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
- l 配置內核
make ARCH=arm O="$PWD/../build" myc-ya157c_defconfig
- l 編譯內核
make -j16 ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000040 O="$PWD/../build" make -j16 ARCH=arm modules O="$PWD/../build"
以16線程同時編譯,大約編譯兩分鍾。以單線程運行時,編譯過程大約需要15-20分鍾,請合理分配虛擬機CPU,保證最大化的利用系統資源,節省編譯時間。
- l 生成輸出文件
make -j16 ARCH=arm INSTALL_MOD_PATH="$PWD/../build/install_artifact" modules_install O="$PWD/../build" mkdir -p $PWD/../build/install_artifact/boot/ cp $PWD/../build/arch/arm/boot/uImage $PWD/../build/install_artifact/boot/ cp $PWD/../build/arch/arm/boot/dts/st*.dtb $PWD/../build/install_artifact/boot/
l 將編譯完成的文件傳輸到開發板並更新kernel
進入build/install_artifact/目錄,執行以下命令
scp -r boot/* root@192.168.2.66:/boot #更新 uImage 與設備樹,此處假設開發板的ip為192.168.2.66,如果有密碼,還需輸入密碼
rm lib/modules/5.4.31/source lib/modules/5.4.31/build #刪除編譯生成文件 build/install_artifact/lib 下的軟連接文件
scp -r lib/modules/* root@192.168.2.66:/lib/modules/ #更新內核 modules
- l 連接到開發板,執行同步&重啟命令
使用finalshell等軟件,連接到開發板
執行以下命令完成同步&重啟
sync & reboot
四、測試驅動是否正常安裝
(1) 使用lsusb命令,查看能否正常顯示RM500Q-GL的型號
(2) 使用ifconfig命令,查看是否新增“eth1”網卡
五、交叉編譯撥號軟件
(1) 解壓Quectel_QConnectManager_Linux_V1.6.0.6
(2) 進入Quectel_QConnectManager_Linux_V1.6.0.6,在此處打開終端,加載環境變量
source /opt/st/myir/3.1-snapshot/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
(3) 執行編譯
make CROSS_COMPILE=arm-hisiv300-linux-
編譯完成后,將該文件夾拷貝至開發板/home/root目錄下
(4) 給該目錄下的.sh文件添加可執行權限
chmod a+x *.sh
(5) 運行撥號軟件
./quectel-CM &
(出現以上信息代表驅動已經成功移植,5G模塊已能夠被系統識別,此處我沒有插入SIM卡,所以是sim_absent狀態)