嵌入式系統內核鏡像相關(十)

文章目錄

  • 前言
  • 一、點亮多個led燈的基礎實驗以及其中的問題
    • 1.1 基礎流程
      • 1.1.1 alinx教程的問題
        • 1.1.1.1 驅動程序中的亮/滅邏輯修改!
          • 1.1.1.1.1 邏輯錯誤的修改
          • 1.1.1.1.2 多燈亮/滅
        • 1.1.1.2 驅動程序中引腳的問題以及與裸機開發的區別(重要)
        • 1.1.1.3 “AMBA外設時鐘使能寄存器”是怎么回事兒?
      • 1.1.2 全部流程
        • 1.1.2.1 編輯和編譯驅動
        • 1.1.2.2 編輯和編譯測試程序
        • 1.1.2.3 測試結果
    • 1.2 設備樹和驅動程序的優先級與延申思考
      • 1.2.1 insmod驅動以后cat /proc/devices顯示什么(回答優先級的問題)?
      • 1.2.2 延申思考——4個led的控制驅動就只有1個。
  • 二、后續魔改
  • 總結


前言

本文補全嵌入式系統內核鏡像相關(二)中提到的驅動開發和測試流程,并且也進一步探索存在的問題,并進行了額外的思考和推敲。


一、點亮多個led燈的基礎實驗以及其中的問題

1.1 基礎流程

依舊沿用嵌入式系統內核鏡像相關(二)的PS最小系統,至于設備樹,就如下:

/include/ "system-conf.dtsi"/ {  model ="ZYNQ7035"; compatible = "xlnx,zynq-7000"; usb_phy0: phy0@e0002000 {compatible = "ulpi-phy";#phy-cells = <0>;reg = <0xe0002000 0x1000>;view-port = <0x0170>;drv-vbus;};
};&usb0 {status = "okay";dr_mode = "host";usb-phy = <&usb_phy0>;
};&uart0 {
u-boot,dm-pre-reloc;
};&uart1 {
u-boot,dm-pre-reloc;
};

通過上述設備樹和petalinux-config的配置得到啟動鏡像后,略去不表,咱接著研究驅動。

開發板還是使用璞致的7035!

1.1.1 alinx教程的問題

本來大體上參考alinx的字符設備教程,但琢磨發現一些問題和疑惑了。

alinx提供的驅動程序如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/types.h>/* 驅動名稱 */
#define DEVICE_NAME "gpio_leds"
/* 驅動主設備號 */
#define GPIO_LED_MAJOR 200/* gpio 寄存器虛擬地址 */
static unsigned int gpio_add_minor;
/* gpio 寄存器物理基地址 */
#define GPIO_BASE 0xE000A000
/* gpio 寄存器所占空間大小 */
#define GPIO_SIZE 0x1000
/* gpio 方向寄存器 */
#define GPIO_DIRM_0 (unsigned int *)(0xE000A204 - GPIO_BASE + gpio_add_minor)
/* gpio 使能寄存器 */
#define GPIO_OEN_0 (unsigned int *)(0xE000A208 - GPIO_BASE + gpio_add_minor)
/* gpio 控制寄存器 */
#define GPIO_DATA_0 (unsigned int *)(0xE000A040 - GPIO_BASE + gpio_add_minor)/* 時鐘使能寄存器虛擬地址 */
static unsigned int clk_add_minor;
/* 時鐘使能寄存器物理基地址 */
#define CLK_BASE 0xF8000000
/* 時鐘使能寄存器所占空間大小 */
#define CLK_SIZE 0x1000
/* AMBA 外設時鐘使能寄存器 */
#define APER_CLK_CTRL (unsigned int *)(0xF800012C - CLK_BASE + clk_add_minor)/* open 函數實現, 對應到 Linux 系統調用函數的 open 函數 */
static int gpio_leds_open(struct inode *inode_p, struct file *file_p)
{
/* 把需要修改的物理地址映射到虛擬地址 */
gpio_add_minor = (unsigned int)ioremap(GPIO_BASE, GPIO_SIZE);
clk_add_minor = (unsigned int)ioremap(CLK_BASE, CLK_SIZE);/* MIO_0 時鐘使能 */
*APER_CLK_CTRL |= 0x00400000;
/* MIO_0 設置成輸出 */
*GPIO_DIRM_0 |= 0x00000001;
/* MIO_0 使能 */
*GPIO_OEN_0 |= 0x00000001;printk("gpio_test module open\n");return 0;
}/* write 函數實現, 對應到 Linux 系統調用函數的 write 函數 */
static ssize_t gpio_leds_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{
int rst;
char writeBuf[5] = {0};printk("gpio_test module write\n");rst = copy_from_user(writeBuf, buf, len);
if(0 != rst)
{
return -1;
}if(1 != len)
{
printk("gpio_test len err\n");
return -2;
}
if(1 == writeBuf[0])
{
*GPIO_DATA_0 &= 0xFFFFFFFE;
printk("gpio_test ON\n");
}
else if(0 == writeBuf[0])
{
*GPIO_DATA_0 |= 0x00000001;
printk("gpio_test OFF\n");
}
else
{
printk("gpio_test para err\n");
return -3;
}return 0;
}/* release 函數實現, 對應到 Linux 系統調用函數的 close 函數 */
static int gpio_leds_release(struct inode *inode_p, struct file *file_p)
{
printk("gpio_test module release\n");
return 0;
}/* file_operations 結構體聲明, 是上面 open、write 實現函數與系統調用函數對應的關鍵 */
static struct file_operations gpio_leds_fops = {
.owner = THIS_MODULE,
.open = gpio_leds_open,
.write = gpio_leds_write,
.release = gpio_leds_release,
};/* 模塊加載時會調用的函數 */
static int __init gpio_led_init(void)
{
int ret;/* 通過模塊主設備號、名稱、模塊帶有的功能函數(及 file_operations 結構體)來注冊模塊 */
ret = register_chrdev(GPIO_LED_MAJOR, DEVICE_NAME, &gpio_leds_fops);
if (ret < 0)
{
printk("gpio_led_dev_init_ng\n");
return ret;
}
else
{
/* 注冊成功 */
printk("gpio_led_dev_init_ok\n");
}
return 0;
}/* 卸載模塊 */
static void __exit gpio_led_exit(void)
{
/* 釋放對虛擬地址的占用 */
iounmap((unsigned int *)gpio_add_minor);
iounmap((unsigned int *)clk_add_minor);
/* 注銷模塊, 釋放模塊對這個設備號和名稱的占用 */
unregister_chrdev(GPIO_LED_MAJOR, DEVICE_NAME);printk("gpio_led_dev_exit_ok\n");
}/* 標記加載、卸載函數 */
module_init(gpio_led_init);
module_exit(gpio_led_exit);/* 驅動描述信息 */
MODULE_AUTHOR("Alinx");
MODULE_ALIAS("gpio_led");
MODULE_DESCRIPTION("GPIO LED driver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
1.1.1.1 驅動程序中的亮/滅邏輯修改!

主要指的是控制燈亮滅的邏輯錯誤。

1.1.1.1.1 邏輯錯誤的修改

觀察其中的:

if(1 == writeBuf[0])
{
*GPIO_DATA_0 &= 0xFFFFFFFE;
printk("gpio_test ON\n");
}
else if(0 == writeBuf[0])
{
*GPIO_DATA_0 |= 0x00000001;
printk("gpio_test OFF\n");
}

根據printk的提示,*GPIO_DATA_0 &= 0xFFFFFFFE;應該預期亮燈,但實際上觀察GPIO_DATA_0指針指向的結果末位是0。根據《ug585-Zynq-7000-TRM.pdf》,結果應該是1。對于滅燈的控制同理,因此需要修改為如下:

if(1 == writeBuf[0])
{
*GPIO_DATA_0 |= 0x00000001;
printk("gpio_test ON\n");
}
else if(0 == writeBuf[0])
{
*GPIO_DATA_0 &= 0xFFFFFFFE;
printk("gpio_test OFF\n");
}

實驗結果和預期一致。

1.1.1.1.2 多燈亮/滅

多燈的亮/滅控制其實和當初的裸機開發一致了。由于當初裸機開發使用了基于EMIO引腳的GPIO-led,所以咱肯定不能接著沿用alinx提供的驅動程序。

我先說說為什么我們不能接著用基于MIO引腳的GPIO-led,因為道理很簡單,早在制作PS最小子系統的時候,led燈全被綁定到EMIO引腳的GPIO上,所以即使照著alinx的作業抄,也不會有啥效果(已經驗證過了,實驗結果也確實如此)!

那么,怎么改?很簡單,先回到璞致提供的用戶手冊:

在這里插入圖片描述

明明白白說了EMIO屬于bank2,然后回到《ug585-Zynq-7000-TRM.pdf》。

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

所以使用0x00000284GPIO方向寄存器和0x00000288的使能寄存器,以及0x00000048的控制寄存器。關于控制寄存器/方向寄存器/使能寄存器,每一個bit都對應相應的EMIO,因此,為實現多燈亮滅控制,很顯然需要從低到高依次寫入數值。我們就以4個燈為例!

在方向/使能寄存器上:

/* MIO_0 時鐘使能 */
*APER_CLK_CTRL |= 0x00400000;
/* MIO_0 設置成輸出 */
*GPIO_DIRM_0 |= 0x0000000F;
/* MIO_0 使能 */
*GPIO_OEN_0 |= 0x0000000F;

在亮滅實現(控制寄存器)上:

if(1 == writeBuf[0])
{
*GPIO_DATA_0 |= 0x0000000F;
printk("gpio_test ON\n");
}
else if(0 == writeBuf[0])
{
*GPIO_DATA_0 &= 0xFFFFFFF0;
printk("gpio_test OFF\n");
}

因此,可以控制4個基于EMIOGPIO-led亮滅的驅動代碼如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/types.h>/* 驅動名稱 */
#define DEVICE_NAME "gpio_leds_our"
/* 驅動主設備號 */
#define GPIO_LED_MAJOR 200/* gpio 寄存器虛擬地址 */
static unsigned int gpio_add_minor;
/* gpio 寄存器物理基地址 */
#define GPIO_BASE 0xE000A000
/* gpio 寄存器所占空間大小 */
#define GPIO_SIZE 0x1000
/* gpio 方向寄存器 */
#define GPIO_DIRM_0 (unsigned int *)(0xE000A284 - GPIO_BASE + gpio_add_minor)
/* gpio 使能寄存器 */
#define GPIO_OEN_0 (unsigned int *)(0xE000A288 - GPIO_BASE + gpio_add_minor)
/* gpio 控制寄存器 */
#define GPIO_DATA_0 (unsigned int *)(0xE000A048 - GPIO_BASE + gpio_add_minor)/* 時鐘使能寄存器虛擬地址 */
static unsigned int clk_add_minor;
/* 時鐘使能寄存器物理基地址 */
#define CLK_BASE 0xF8000000
/* 時鐘使能寄存器所占空間大小 */
#define CLK_SIZE 0x1000
/* AMBA 外設時鐘使能寄存器 */
#define APER_CLK_CTRL (unsigned int *)(0xF800012C - CLK_BASE + clk_add_minor)/* open 函數實現, 對應到 Linux 系統調用函數的 open 函數 */
static int gpio_leds_open(struct inode *inode_p, struct file *file_p)
{
/* 把需要修改的物理地址映射到虛擬地址 */
gpio_add_minor = (unsigned int)ioremap(GPIO_BASE, GPIO_SIZE);
clk_add_minor = (unsigned int)ioremap(CLK_BASE, CLK_SIZE);/* MIO_0 時鐘使能 */
*APER_CLK_CTRL |= 0x00400000;
/* MIO_0 設置成輸出 */
*GPIO_DIRM_0 |= 0x0000000F;
/* MIO_0 使能 */
*GPIO_OEN_0 |= 0x0000000F;printk("gpio_test module open\n");return 0;
}/* write 函數實現, 對應到 Linux 系統調用函數的 write 函數 */
static ssize_t gpio_leds_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{
int rst;
char writeBuf[5] = {0};printk("gpio_test module write\n");rst = copy_from_user(writeBuf, buf, len);
if(0 != rst)
{
return -1;
}if(1 != len)
{
printk("gpio_test len err\n");
return -2;
}
if(1 == writeBuf[0])
{
*GPIO_DATA_0 |= 0x0000000F;
printk("gpio_test ON\n");
}
else if(0 == writeBuf[0])
{
*GPIO_DATA_0 &= 0xFFFFFFF0;
printk("gpio_test OFF\n");
}
else
{
printk("gpio_test para err\n");
return -3;
}return 0;
}/* release 函數實現, 對應到 Linux 系統調用函數的 close 函數 */
static int gpio_leds_release(struct inode *inode_p, struct file *file_p)
{
printk("gpio_test module release\n");
return 0;
}/* file_operations 結構體聲明, 是上面 open、write 實現函數與系統調用函數對應的關鍵 */
static struct file_operations gpio_leds_fops = {
.owner = THIS_MODULE,
.open = gpio_leds_open,
.write = gpio_leds_write,
.release = gpio_leds_release,
};/* 模塊加載時會調用的函數 */
static int __init gpio_led_init(void)
{
int ret;/* 通過模塊主設備號、名稱、模塊帶有的功能函數(及 file_operations 結構體)來注冊模塊 */
ret = register_chrdev(GPIO_LED_MAJOR, DEVICE_NAME, &gpio_leds_fops);
if (ret < 0)
{
printk("gpio_led_dev_init_ng\n");
return ret;
}
else
{
/* 注冊成功 */
printk("gpio_led_dev_init_ok\n");
}
return 0;
}/* 卸載模塊 */
static void __exit gpio_led_exit(void)
{
/* 釋放對虛擬地址的占用 */
iounmap((unsigned int *)gpio_add_minor);
iounmap((unsigned int *)clk_add_minor);
/* 注銷模塊, 釋放模塊對這個設備號和名稱的占用 */
unregister_chrdev(GPIO_LED_MAJOR, DEVICE_NAME);printk("gpio_led_dev_exit_ok\n");
}/* 標記加載、卸載函數 */
module_init(gpio_led_init);
module_exit(gpio_led_exit);/* 驅動描述信息 */
MODULE_AUTHOR("Alinx");
MODULE_ALIAS("gpio_led");
MODULE_DESCRIPTION("GPIO LED driver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
1.1.1.2 驅動程序中引腳的問題以及與裸機開發的區別(重要)

關于引腳問題,見1.1.1.1。注意,alinx采用的是基于MIOGPIO引腳,因此沒法兒直接用。我還是參照1.1.1.1中的流程修改!

不難看出來,裸機開發的流程中,得益于xparameters.h的存在,避免了自己去找文檔,只需要關注EMIO的起始序號和范圍即可。然而,驅動開發需要自己確認某些寄存器的引腳以實現正常功能。

所以,相比之下,從這一方面來看,驅動開發的流程更為復雜。

1.1.1.3 “AMBA外設時鐘使能寄存器”是怎么回事兒?

alinx的教程提到這個名詞的時候,我不禁愣了一下,因為這個在裸機開發中壓根兒不存在。

但還是去花了時間去確認這是個啥!回到《ug585-Zynq-7000-TRM.pdf》。

在這里插入圖片描述
在這里插入圖片描述
可以看到這里有個APER_CLK_CTRL寄存器,詳細看下該寄存器:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
所以,這個寄存器的各個bit用于控制AMBA時鐘,第23bit用于控制GPIO相關的時鐘。那好像也不奇怪了!

1.1.2 全部流程

假設啟動鏡像已經制作結束,那么就從驅動開發開始!

1.1.2.1 編輯和編譯驅動

首先使用petalinux-create -t modules --name ax-led-drv創建驅動模板文件,如下:

dention@ubuntu:~/petalinux_proj/test_peta/proj_peta$ petalinux-create -t modules --name ax-led-drv
INFO: Create modules: ax-led-drv
INFO: New modules successfully created in /home/dention/petalinux_proj/test_peta/proj_peta/project-spec/meta-user/recipes-modules/ax-led-drv

修改路徑為/home/dention/petalinux_proj/test_peta/proj_peta/project-spec/meta-user/recipes-modules/ax-led-drv/files/下的驅動模板文件ax-led-drv.c1.1.1.1.2中的驅動程序。

隨后petalinux-config -c rootfs選中驅動模塊,如下:

dention@ubuntu:~/petalinux_proj/test_peta/proj_peta$ petalinux-config -c rootfs
[INFO] sourcing bitbake
[INFO] generating plnxtool conf
[INFO] generating meta-plnx-generated layer
[INFO] generating user layers
[INFO] generating machine configuration
[INFO] configuring: rootfs
[INFO] generating kconfig for Rootfs
[INFO] menuconfig rootfs*** End of the configuration.
*** Execute 'make' to start the build or try 'make help'.[INFO] generating petalinux-user-image.bb
[INFO] successfully configured rootfs

在這里插入圖片描述

選中之后,使用petalinux-build編譯得到.ko驅動文件,如下:

dention@ubuntu:~/petalinux_proj/test_peta/proj_peta$ petalinux-build 
[INFO] building project
[INFO] sourcing bitbake
[INFO] generating user layers
INFO: bitbake petalinux-user-image
Loading cache: 100% |########################################################################################################################| Time: 0:00:02
Loaded 3811 entries from dependency cache.
Parsing recipes: 100% |######################################################################################################################| Time: 0:00:08
Parsing of 2778 .bb files complete (2774 cached, 4 parsed). 3813 targets, 163 skipped, 0 masked, 0 errors.
NOTE: Resolving any missing task queue dependencies
Initialising tasks: 100% |###################################################################################################################| Time: 0:00:07
Checking sstate mirror object availability: 100% |###########################################################################################| Time: 0:00:22
Sstate summary: Wanted 134 Found 20 Missed 228 Current 753 (14% match, 87% complete)
NOTE: Executing SetScene Tasks
NOTE: Executing RunQueue Tasks
NOTE: Tasks Summary: Attempted 3199 tasks of which 2926 didn't need to be rerun and all succeeded.
INFO: Copying Images from deploy to images
NOTE: Failed to copy built images to tftp dir:  /tftpboot
[INFO] successfully built project

可以找一下.ko文件:

dention@ubuntu:~/petalinux_proj/test_peta/proj_peta$ find ./ -name "ax-led-drv.ko"
./build/tmp/sysroots-components/plnx_zynq7/ax-led-drv/lib/modules/4.19.0-xilinx-v2019.1/extra/ax-led-drv.ko

到此為止,驅動開發部分結束!接下來編輯和編譯測試程序!

1.1.2.2 編輯和編譯測試程序

按照下述存放文件:

dention@ubuntu:~/qt_proj$ tree
.
├── axleddev_test
│   └── main.c
└── build-axleddev_test-ZYNQ-Debug└── Makefile2 directories, 2 files

為什么是這么放的,可以參考嵌入式系統內核鏡像相關(九)。

其中main.c是:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>int main(int argc, char **argv)
{
int fd;
char buf;if(3 != argc)
{
printf("none para\n");
return -1;
}fd = open(argv[1], O_RDWR);
if(fd < 0)
{
printf("Can't open file %s\r\n", argv[1]);
return -1;
}if(!strcmp("on",argv[2]))
{
printf("ps_led1 on\n");
buf = 1;
write(fd, &buf, 1);
}
else if(!strcmp("off",argv[2]))
{
printf("ps_led1 off\n");
buf = 0;
write(fd, &buf, 1);
}
else
{
printf("wrong para\n");
return -2;
}close(fd);
return 0;
}

其中Makefile是:

CC = arm-linux-gnueabihf-gcc
CFLAGS = -Wall -gall: axleddev_testaxleddev_test: main.o$(CC) $(CFLAGS) -o axleddev_test main.omain.o: ../axleddev_test/main.c$(CC) $(CFLAGS) -c ../axleddev_test/main.cclean:rm -f axleddev_test main.o

然后make all即可得到驅動模塊測試可執行文件。

1.1.2.3 測試結果

參照嵌入式系統內核鏡像相關(八)將驅動模塊文件和測試的可執行文件放到開發板側!

參考下述運行:

root@proj_peta:~# ls
ax-led-drv.ko  axleddev_test
root@proj_peta:~# chmod 777 -R axleddev_test
root@proj_peta:~# insmod ax-led-drv.ko
ax_led_drv: loading out-of-tree module taints kernel.
gpio_led_dev_init_ok
root@proj_peta:~# mknod /dev/alinx-led c 200 0
root@proj_peta:~# ls /dev/
alinx-led           mtab                ram6                tty27               tty55
block               mtd0                ram7                tty28               tty56
char                mtd0ro              ram8                tty29               tty57
console             mtd1                ram9                tty3                tty58
cpu_dma_latency     mtd1ro              random              tty30               tty59
disk                mtd2                shm                 tty31               tty6
fd                  mtd2ro              snd                 tty32               tty60
full                mtd3                stderr              tty33               tty61
gpiochip0           mtd3ro              stdin               tty34               tty62
iio:device0         mtdblock0           stdout              tty35               tty63
initctl             mtdblock1           tty                 tty36               tty7
kmsg                mtdblock2           tty0                tty37               tty8
log                 mtdblock3           tty1                tty38               tty9
loop-control        network_latency     tty10               tty39               ttyPS0
loop0               network_throughput  tty11               tty4                ttyPS1
loop1               null                tty12               tty40               udev_network_queue
loop2               port                tty13               tty41               urandom
loop3               ptmx                tty14               tty42               vcs
loop4               pts                 tty15               tty43               vcs1
loop5               ram0                tty16               tty44               vcsa
loop6               ram1                tty17               tty45               vcsa1
loop7               ram10               tty18               tty46               vcsu
mem                 ram11               tty19               tty47               vcsu1
memory_bandwidth    ram12               tty2                tty48               vga_arbiter
mmcblk0             ram13               tty20               tty49               watchdog
mmcblk0p1           ram14               tty21               tty5                watchdog0
mmcblk0p2           ram15               tty22               tty50               zero
mmcblk1             ram2                tty23               tty51
mmcblk1boot0        ram3                tty24               tty52
mmcblk1boot1        ram4                tty25               tty53
mmcblk1rpmb         ram5                tty26               tty54
root@proj_peta:~# ls
ax-led-drv.ko  axleddev_test
root@proj_peta:~# ./axleddev_test /dev/alinx-led on
gpio_test module open
ps_led1 on
gpio_test module write
gpio_test ON
gpio_test module release
root@proj_peta:~# ./axleddev_test /dev/alinx-led off
gpio_test module open
ps_led1 off
gpio_test module write
gpio_test OFF
gpio_test module release

初始情況如下:

在這里插入圖片描述

其中亮燈的時候,如下:

在這里插入圖片描述

滅燈的時候,如下:

在這里插入圖片描述
到此為止!

1.2 設備樹和驅動程序的優先級與延申思考

現在我把之前嵌入式系統內核鏡像相關(二)里面的設備樹替換掉本文一開始提到的設備樹!

注意設備樹中的compatiblegpio-leds,而驅動中的設備名稱是gpio_leds_our

1.2.1 insmod驅動以后cat /proc/devices顯示什么(回答優先級的問題)?

顯示結果如下:

root@proj_peta:~# chmod 777 -R axleddev_test
root@proj_peta:~# insmod ax-led-drv.ko
ax_led_drv: loading out-of-tree module taints kernel.
gpio_led_dev_init_ok
root@proj_peta:~# cat /proc/devices
Character devices:1 mem4 /dev/vc/04 tty5 /dev/tty5 /dev/console5 /dev/ptmx7 vcs10 misc13 input21 sg29 fb81 video4linux89 i2c90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
200 gpio_leds_our
226 drm
244 rpmb
245 uio
246 watchdog
247 iio
248 ptp
249 pps
250 media
251 rtc
252 ttyPS
253 ttyPS
254 gpiochipBlock devices:1 ramdisk7 loop8 sd31 mtdblock65 sd66 sd67 sd68 sd69 sd70 sd71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
259 blkext

根據編號200,可以證明即使設備樹變更了,但是驅動還是順利加載!

但是下一步的驅動測試失敗了,燈的狀態是10個燈按照heartbeat模式閃爍。

但沿用嵌入式系統內核鏡像相關(二)里面的內置測試可以成功!

不能排除的一點是petalinux-build將設備樹的內容編譯進內核,并且啟用了gpio-leds的內置驅動模塊。這就導致再使用insmod驅動進宏內核時,可能因為宏內核判斷gpioemio引腳被占用,即使insmod驅動模塊,無法通過測試。

可能的解決辦法是rmmod內核自帶的gpio-leds模塊,或者,單獨編譯設備樹文件并加載進入內核。但是,petalinux平臺并不支持單獨編譯設備樹文件(我確實沒找到),但是存在單獨編譯設備樹文件和設備樹插件文件的方式(可以參考野火的教程)。

這個話題值得后續研究,我在博客中標記一下!

1.2.2 延申思考——4個led的控制驅動就只有1個。

現在4個led燈的控制是由1個驅動完成的!

因此,可以確認的一點是被控制外設的數量并不絕對等于驅動數量。

此外,驅動可以控制4個led燈,也就意味著可以控制10個led燈。但是控制的邏輯被限制在驅動程序里面,導致需要控制10個led燈時,不得不重新編譯驅動模塊,這在petalinux中還是挺浪費時間的!

怎么辦?這也是后續接著研究的內容!

(很幸運的是,自己從4個led燈的例子,cover掉以往講解驅動教程中提到為什么要發展設備驅動平臺和設備樹的原因!)

二、后續魔改

這一節放在下一篇文章了,本篇內容夠多了!

另外后面幾篇就不一定會那么詳細地展開步驟,只會提及教程中需要注意的點。


總結

alinx教程中與我開發板不符的點進行詳細描述,并深度思考一些從未被教程提到的問題。

此外,這次開發將Vivado最小ps子系統、Vitis SDK上的xparameters.h和驅動開發結合在一起,相互輔助判斷驅動開發的bug究竟出在哪里,盡管怎么遇到bug和怎么解決bug的過程我并沒有展開,但從上文我怎么改進中可窺一角。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/89886.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/89886.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/89886.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Word和Excel批量轉PDF新方法,操作簡單

PDF是一種跨平臺的文檔格式&#xff0c;無論在任何設備上查看&#xff0c;其排版、字體和圖像都不會發生變化。這確保了文檔的一致性&#xff0c;避免了由于不同軟件版本或操作系統引起的顯示問題。這款小巧的工具大小不到2MB&#xff0c;使用起來異常簡單。只需要把需要轉換的…

AI搜索 MCP最佳實踐

背景 那些 LLM 不知道的事 嘗試直接詢問LLM“今天天氣如何”時&#xff0c;會發現LLM無法回答——它既不知道“今天”是哪天&#xff0c;也無法獲取地理位置信息。這揭示了LLM的局限&#xff1a;缺乏與外部工具和實時數據的交互能力。 為解決這一問題&#xff0c;MCP&#x…

JVM 簡介與作用

&#x1f680; JVM 簡介與作用 &#x1f4da; 深入理解 Java 虛擬機的核心概念與重要作用 &#x1f4d6; 目錄 &#x1f914; 什么是 Java 虛擬機&#xff08;JVM&#xff09;&#x1f310; JVM 在 Java 生態中的核心地位&#x1f500; JVM 跨平臺原理剖析&#x1f4dd; 總結 …

? OpenAudio S1:影視級文本轉語音與語音克隆Mac整合包

? OpenAudio S1&#xff1a;影視級文本轉語音與語音克隆Mac整合包 &#x1f680; OpenAudio S1 簡介 OpenAudio S1 是由 Fish Audio 開發的 Fish Speech 系列的最新一代人工智能語音生成模型。該模型旨在大幅提升 AI 語音生成的技術水平&#xff0c;為用戶提供更加自然、富有表…

spring加載外部properties文件屬性時,讀取到userName變量值和properties文件的值不一致

問題 使用spring DI注入外部properties文件屬性時&#xff0c;讀取到userName變量值和properties文件的值不一致。 bean屬性注入&#xff1a; <!--加載配置文件--> <context:property-placeholder location"classpath:*.properties"/><bean id"…

黑馬點評系列問題之基礎篇p7 06初識redis無法在虛擬機查到圖形化界面存進去的鍵

問題描述 在RESP中輸入了一些鍵(name,age等這些) 但是在圖形化界面里面輸入的&#xff0c;在非圖形化界面就找不到&#xff0c;在非圖形化界面里輸入的&#xff0c;在圖形化界面里就可以查到。 原因分析及解決 經過多次實驗&#xff0c;發現是因為在添加鍵名的時候&#xff0…

在VMware虛擬機中安裝Windows 98時,Explorer提示“該程序執行了非法操作,即將關閉”的解決辦法

在使用iso文件&#xff08;MD5: 0E496B5DCC519F550AAF0BCFBB4A11EA&#xff09;安裝Windows98時&#xff0c;遇到此提示。 雖然原因未知&#xff0c;也無需深入探究&#xff0c;但是根據網友在 https://www.bilibili.com/opus/435866522585702782 中給出的相似經驗&#xff…

在瀏覽器中使用SQLite(官方sqlite3.wasm)

有人可能會問&#xff1a;既然瀏覽器里又內置得IndexedDB&#xff0c;而且在IndexedDB里存數據&#xff0c;關了瀏覽器數據也不會丟&#xff0c;為什么還要在瀏覽器里用SQLite? 實際上&#xff0c;當 IndexedDB 內的數據量增多&#xff0c;數據和數據之間的關系變得復雜&…

數據結構(Java)--位運算

前言 本文為本小白學習數據結構的筆記&#xff0c;將以算法題為導向&#xff0c;向大家更清晰的介紹數據結構相關知識&#xff08;算法題都出自B站馬士兵教育——左老師的課程&#xff0c;講的很好&#xff0c;對于想入門刷題的人很有幫助&#xff09; 為什么要使用為位運算 位…

秋招Day14 - Redis - 應用

Redis如何實現異步消息隊列&#xff1f; List配合LPUSH和RPOP。 另外就是用 Redis 的 Pub/Sub 來實現簡單的消息廣播和訂閱。 但是這兩種方式都是不可靠的&#xff0c;因為沒有 ACK 機制所以不能保證訂閱者一定能收到消息&#xff0c;也不支持消息持久化。 Redis如何實現延時…

因果語言模型、自回歸語言模型、僅解碼器語言模型都是同一類模型

因果語言模型、自回歸語言模型、僅解碼器語言模型都是同一類模型 flyfish 因果語言模型&#xff08;causal Language Models&#xff09; 自回歸語言模型&#xff08;autoregressive language models&#xff09; 僅解碼器語言模型&#xff08;decoder-only language models&am…

jvm架構原理剖析篇

簡單題&#xff08;5道&#xff09; 考查內容&#xff1a;JVM運行時數據區域 題干&#xff1a;Java虛擬機棧的主要作用是&#xff1f; A. 存儲對象實例 B. 存儲方法調用和局部變量 C. 存儲靜態字段 D. 存儲字節碼指令 正確答案&#xff1a;B 解析&#xff1a;虛擬機棧用于存儲方…

智鏈萬物:人工智能驅動的產業智能化革命

當生成式AI在藝術與創意領域掀起風暴&#xff0c;大型語言模型重塑信息交互方式時&#xff0c;一場更為基礎、影響更為深遠的變革&#xff0c;正在全球實體經濟的根基處悄然發生并加速推進——這就是產業智能化。它并非簡單的“機器換人”&#xff0c;而是人工智能&#xff08;…

python中上下文管理器 與 try finally有什么區別

目錄 主要區別代碼對比何時使用哪種方式 主要區別 語法簡潔性 上下文管理器使用 with 語句&#xff0c;語法更簡潔優雅try-finally 需要顯式編寫異常處理代碼&#xff0c;更冗長 代碼復用性 上下文管理器可以封裝為類或函數&#xff0c;便于在多處復用try-finally 通常需要在每…

人體屬性識別+跌倒檢測:兒童行為監測與安全升級

智慧幼兒園的AI智能檢測盒應用實踐 背景&#xff1a;傳統園區管理的三大痛點 傳統幼兒園管理長期面臨三大核心挑戰&#xff1a;一是安全監控依賴人工巡查&#xff0c;存在視覺盲區與響應延遲&#xff0c;如某連鎖幼兒園曾因人工巡查疏漏&#xff0c;導致3起兒童跌倒事故未能及…

【ESP32-IDF筆記】09-UART配置和使用

環境配置 Visual Studio Code &#xff1a;版本1.98.2 ESP32&#xff1a;ESP32-S3 ESP-IDF&#xff1a;V5.4 支持型號&#xff1a;ESP32、ESP32-C2、ESP32-C3、ESP32-C5、ESP32-C6、ESP32-C61、ESP32-H2、ESP32-P4、 ESP32-S2、ESP32-S3 簡介 通用異步接收器/發送器 (UART) …

在 .NET Core 和 React 中使用 WebSockets 和 SignalR 進行實時數據傳輸

對于需要即時更新和通知的應用程序來說&#xff0c;實時數據傳輸至關重要。在 .NET Core 中&#xff0c;WebSocket 和 SignalR 提供了強大的工具來實現客戶端和服務器之間的實時通信。在本指南中&#xff0c;我們將探討如何在 .NET Core 應用程序中使用 WebSocket 和 SignalR 實…

第八十六篇 大數據排序算法:從廚房整理到分布式排序的智慧

目錄一、基礎排序算法&#xff1a;生活場景中的計算智慧1.1 冒泡排序&#xff1a;圖書館的書籍整理1.2 插入排序&#xff1a;廚房調料的整理藝術二、高效排序算法&#xff1a;大數據處理的利器2.1 快速排序&#xff1a;音樂APP的智能歌單2.2 歸并排序&#xff1a;學校成績單的合…

開源 | V3.1.1慧知開源重卡運營充電樁平臺 - 重卡運營充電樁平臺管理解決方案;企業級完整代碼 多租戶、模擬器、多運營商、多小程序;

【開源免費版】推薦一套企業級開源充電樁平臺&#xff1a;完整代碼包含多租戶、硬件模擬器、多運營商、多小程序&#xff0c;汽車 電動自行車、云快充協議&#xff1b;——(慧哥)慧知開源充電樁平臺&#xff1b;https://liwenhui.blog.csdn.net/article/details/148242725?spm…

ONLYOFFICE 協作空間 企業版使用秘籍-8.使用虛擬數據房間,處理機密文檔更安全

在當今快節奏的社會中&#xff0c;信息已成為極其關鍵的資源&#xff0c;因此&#xff0c;保護敏感數據至關重要。ONLYOFFICE 協作空間中的虛擬數據房間&#xff08;VDR&#xff09;提供了一個安全便捷的工作空間&#xff0c;確保文檔受到嚴密保護的同時&#xff0c;也能實現輕…