国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方

這篇具有很好參考價(jià)值的文章主要介紹了【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

軟件版本:Vivado2021.1
操作系統(tǒng):WIN10 64bit、Ubuntu18.04
硬件平臺(tái):ZYNQ UltraScale

1.1系統(tǒng)框圖

在 PS 端接有兩個(gè) LED 燈,這些燈接在了 MIO 上,而 MIO 可以復(fù)用成為 GPIO,因此控制 GPIO 其實(shí)就是控制了 LED 等器件。本文通過讀寫寄存器來實(shí)現(xiàn)對(duì) GPIO 的控制。
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ

1.2介紹

1.2.1寄存器查詢手冊(cè)

??使用 GPIO 需要設(shè)置兩個(gè)寄存器,一個(gè)是設(shè)置 GPIO 的管腳復(fù)用的 IOU_SLCR Module 寄存器,一個(gè)是設(shè)置GPIO 的管腳功能的 GPIO Module 寄存器。查詢寄存器地址需要用到一個(gè)官方文檔,編號(hào)的 ug1087。Xilinx 官方網(wǎng)站:https://docs.xilinx.com/r/en-US/ug1087-zynq-ultrascale-registers/MIO_PIN_41-IOU_SLCR-Register。

1.2.2物理地址與虛擬地址

??提到寄存器,那就不得不說說地址了。寄存器作為系統(tǒng)中存儲(chǔ)數(shù)據(jù)的器件,每個(gè)數(shù)據(jù)都有其自身的物理地址。而與物理地址相對(duì)的則是 Linux 系統(tǒng)下的虛擬地址。在裸機(jī)等通常程序里,是不存在虛擬地址一說的,對(duì)地址的操作就是對(duì)物理地址的操作。但是在 Linux 下,對(duì)物理地址直接訪問是行不通的,需要通過虛擬地址間接訪問,因此所有對(duì)寄存器的操作都需要通過地址映射。
??之所以要使用虛擬地址是因?yàn)橐郧暗碾娔X內(nèi)存非常小,程序也是非常小,因此靠手動(dòng)便可以管理內(nèi)存。但是日新月異,今天的程序已經(jīng)非常龐大了,雖然內(nèi)存也在飛速發(fā)展,但是無法跟上日益臃腫的應(yīng)用程序。眾所周知要想運(yùn)行一個(gè)程序,就必須將其完整地讀入內(nèi)存,如果程序本身就大于內(nèi)存,那除了加內(nèi)存可以運(yùn)行程序,那剩下的唯一辦法就是使用虛擬地址了。
虛擬地址可以模擬出幾倍于物理地址的內(nèi)存空間,當(dāng)程序運(yùn)行時(shí),被運(yùn)行的部分讀入內(nèi)存,其他部分依舊存放于外存。物理地址于虛擬地址的關(guān)系如下圖。
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ

??虛擬內(nèi)存與物理內(nèi)存是對(duì)應(yīng)的,但是沒有順序。這個(gè)順序是由 MMU 管理的,MMU 全稱 Memory Management Unit,即內(nèi)存管理單元。它的功能包括虛擬地址到物理地址的轉(zhuǎn)換(即虛擬內(nèi)存管理)、內(nèi)存保護(hù)、中央處理器高速緩存的控制等等。
??在本章驅(qū)動(dòng)編寫時(shí),會(huì)使用 ioremap、iounmap 這兩個(gè)函數(shù),是用來申請(qǐng)物理地址對(duì)應(yīng)的虛擬地址的。因?yàn)樵贚inux 內(nèi)核啟動(dòng)之后,會(huì)初始化 MMU,將物理地址映射為虛擬地址。這個(gè)時(shí)候,不能向寄存器的物理基地址寫入
數(shù)據(jù),而是應(yīng)該用 ioremap 向系統(tǒng)申請(qǐng)的虛擬地址,然后在虛擬地址上進(jìn)行寄存器的寫入和讀取操作。

1.2.3MIO介紹

??ZYNQ Ultrascale+ MPSOC PS 部分的 IO 包括 PS-MIO 和 PS-EMIO,MIO 分布在 PS 的 Bank0 、BANK1 和Bank2,EMIO 分布在 PS 的 Bank3、BANK4 和 Bank5。PS-MIO 具有 78 個(gè) GPIO ,PS-EMIO 具有最多 96 個(gè)。PS-MIO的 IO 位置是固定好的,功能也是預(yù)先定義好了,而 PS-EMIO 是通過把芯片內(nèi)部 PS 的 PS-EMIO 引線接到了 PL 部分的 FPGA Pin 腳上,所以 PS-MIO 滿足必要常用的外設(shè) IO 需求,比如串口、SDIO、以太網(wǎng)等,而 PS-EMIO 按需配置,用多少,配置多少。
??芯片有 78 個(gè) MIO(multiuse I/O),它們派發(fā)在 GPIO 的,隸屬于 PS 部分。這些 IO 與 PS 直接相連。不需要添加引腳約束,MIO 信號(hào)對(duì) PL 部分是透明的,不可見。所以對(duì) MIO 的操作可以看作是純 PS 的操作。GPIO 控制和狀態(tài)寄存器是從基地址 0xFF0A_0000 開始的存儲(chǔ)器映射,并受 XPPU 保護(hù)。
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
PS-MIO:
Bank0:MIO[0 :25] GPIO PIN 腳號(hào):0~25
Bank1:MIO[26:51] GPIO PIN 腳號(hào):26~51
Bank2:MIO[52:77] GPIO PIN 腳號(hào):52~77
PS-EMIO:
Bank3:EMIO[ 0:31] 可以分配到任意的 FPGA IO
Bank4:EMIO[32:63] 可以分配到任意的 FPGA IO
Bank5:EMIO[64:95] 可以分配到任意的 FPGA IO

注意:GPIO [92:95]四個(gè)輸出可以用作 PL 中用戶定義邏輯的復(fù)位信號(hào)。 GPIO EMIO 信號(hào)的數(shù)量取決于在 Vivado PS
配置向?qū)В≒CW)中選擇的 PL 結(jié)構(gòu)復(fù)位的數(shù)量。 例如,如果選擇一個(gè)復(fù)位,則將 GPIO [95]分配為復(fù)位信號(hào)。如果選擇兩個(gè),則分配
GPIO [95:94]。

MIO 內(nèi)部構(gòu)造:
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
DATA_RO:
此寄存器使能軟件觀察 PIN 腳,當(dāng) GPIO 被配置成輸出的時(shí)候,這個(gè)寄存器的值會(huì)反應(yīng)輸出的 PIN 腳情況。
DATA:
此寄存器控制輸出到 GPIO 的值,讀這個(gè)寄存器的值可以讀到最后一次寫入該寄存器的值。
MASK_DATA_LSW:
位操作寄存器,寫入 GPIO 低 16bit 其他沒有改變的位置保存原先的狀態(tài)
MASK_DATA_MSW:
位操作寄存器,寫入 GPIO 高 16bit 其他沒有改變的位置保存原先的狀態(tài)
DIRM:
此寄存器控制輸出的開關(guān),當(dāng) DIRM[x]==0 時(shí)候,禁止輸出
OEN:
輸出使能,當(dāng) OEN[x]==0 的時(shí)候輸出關(guān)閉,PIN 腳處于三態(tài)。
因 此 , 如果要讀 IO 狀態(tài)就得讀DATA_RO 的值 , 如果是對(duì)某一位 進(jìn)行操作就是寫
MASK_DATA_LSW/MASK_DATA_MSW

1.2.4PS的LED 引腳介紹

【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
從原理圖可以看出,當(dāng) MIO 高電平的時(shí)候,LED 可以點(diǎn)亮。低電平的時(shí)候,MIO 變暗。
還可以查到如下數(shù)據(jù):

  • LED1:MIO42
  • LED2:MIO40

查看 1.2.1寄存器手冊(cè),這四個(gè)管腳均屬于 bank1,如果有 MIO 在其他 bank 上,我們需要將一樣的代碼再寫一遍以控制全部LED,這里我們只控制 bank1 的 LED1 和 LED2。

1.3搭建工程

在IP核中勾選 GPIO1 MIO:
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
制作開發(fā)板系統(tǒng).

1.4程序分析

1.4.1驅(qū)動(dòng)程序分析

//添加頭文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>

static int led_major;
static struct class *led_cls;

/* gpio 內(nèi)存映射地址 */
static unsigned long *gpio_addr = NULL;
static unsigned long *iou_slcr = NULL;

/* gpio 寄存器物理基地址 */
#define GPIO_BASE_ADDR 0xFF0A0000
#define IOU_SLCR_ADDR 0xFF180000
/* gpio 寄存器所占空間大小 */
#define GPIO_BASE_SIZE 0x368
#define IOU_SLCR_SIZE 0x714

/* gpio 引腳設(shè)置GPIO功能*/
#define GPIO_PIN_40 (unsigned int *)((unsigned long)iou_slcr + 0x000000A0)
#define GPIO_PIN_42 (unsigned int *)((unsigned long)iou_slcr + 0x000000A8)

/* gpio 控制電流0*/
#define IOU_SLCR_BANK1_CTRL0 (unsigned int *)((unsigned long)iou_slcr + 0x00000154)
/* gpio 控制電流1*/
#define IOU_SLCR_BANK1_CTRL1 (unsigned int *)((unsigned long)iou_slcr + 0x00000158)
/* gpio 輸入引腳選擇Schmitt或CMOS*/
#define IOU_SLCR_BANK1_CTRL3 (unsigned int *)((unsigned long)iou_slcr + 0x0000015C)
/* gpio 設(shè)置上下拉*/
#define IOU_SLCR_BANK1_CTRL4 (unsigned int *)((unsigned long)iou_slcr + 0x00000160)
/* gpio 使能上下拉*/
#define IOU_SLCR_BANK1_CTRL5 (unsigned int *)((unsigned long)iou_slcr + 0x00000164)
/* gpio 引腳速率選擇*/
#define IOU_SLCR_BANK1_CTRL6 (unsigned int *)((unsigned long)iou_slcr + 0x00000168)

/* gpio 方向寄存器 */
#define GPIO_DIRM_1 (unsigned int *)((unsigned long)gpio_addr + 0x00000244)
/* gpio 使能寄存器 */
#define GPIO_OEN_1 (unsigned int *)((unsigned long)gpio_addr + 0x00000248)
/* gpio 輸出數(shù)據(jù)寄存器 */
#define GPIO_DATA_1 (unsigned int *)((unsigned long)gpio_addr + 0x00000044)
/* gpio 輸出數(shù)據(jù)控制寄存器1 */
#define GPIO_MASK_DATA_1_LSW (unsigned int *)((unsigned long)gpio_addr + 0x00000008)
/* gpio 輸出數(shù)據(jù)控制寄存器2 */
#define GPIO_MASK_DATA_1_MSW (unsigned int *)((unsigned long)gpio_addr + 0x0000000C)

const struct file_operations led_fops = {};

//實(shí)現(xiàn)裝載入口函數(shù)和卸載入口函數(shù)
static __init int led_drv_v1_init(void)
{
	printk("-------^v^-------\n");
	printk("-led drv v1 init-\n");
	//申請(qǐng)主設(shè)備號(hào)
	led_major = register_chrdev(0, "led_drv_v1", &led_fops);
	if (led_major < 0)
	{
		printk("register chrdev faile!\n");
		return led_major;
	}
	printk("register chrdev ok!\n");

	//創(chuàng)建設(shè)備節(jié)點(diǎn)
	//創(chuàng)建設(shè)備的類別
	led_cls = class_create(THIS_MODULE, "led_class");
	printk("class create ok!\n");

	//創(chuàng)建設(shè)備
	device_create(led_cls, NULL, MKDEV(led_major, 0), NULL, "Myled%d", 0);
	printk("device create ok!\n");


	//1.內(nèi)存映射
	gpio_addr = ioremap(GPIO_BASE_ADDR, GPIO_BASE_SIZE);
	iou_slcr = ioremap(IOU_SLCR_ADDR, IOU_SLCR_SIZE);
	printk("gpio_addr init over!\n");


	//2.MIO40 MIO42 設(shè)置成GPIO,參考手冊(cè)設(shè)置
	iowrite32((ioread32(GPIO_PIN_40) & 0x0), GPIO_PIN_40);
	printk("gpio MIO40 init over!\n");
	iowrite32((ioread32(GPIO_PIN_42) & 0x0), GPIO_PIN_42);
	printk("gpio MIO42 init over!\n");

	// //3.MIO40 MIO42設(shè)置輸出驅(qū)動(dòng)電流大小
	// // 將 0x3FFFFFF 和 0x0 轉(zhuǎn)換為二進(jìn)制。
	// // 0011 1111 1111 1111 1111 1111 1111
	// // 0000 0000 0000 0000 0000 0000 0000
	// // 參考手冊(cè),可以知道每一位的地址都是由 CTRL0 和 CTRL1 控制的,在這里都是 10, 查看手冊(cè)得 8 mA。
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL0) | 0x3FFFFFF), IOU_SLCR_BANK1_CTRL0);
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL1) & 0x0), IOU_SLCR_BANK1_CTRL1);

	//4.選擇引腳是Schmitt還是CMOS
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL3) & 0x0), IOU_SLCR_BANK1_CTRL3);

	//5.輸出管腳上下拉及使能
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL4) | 0x3FFFFFF), IOU_SLCR_BANK1_CTRL4);
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL5) | 0x3FFFFFF), IOU_SLCR_BANK1_CTRL5);

	//6.MIO速率的選擇
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL6) & 0x0), IOU_SLCR_BANK1_CTRL6);

	//7.MIO40 MIO42 設(shè)置成輸出
	// 40 - 26 = 14, 42 - 26 = 16
	// 0000 0000 000|0 0|000 0000 0000 0000
 	//              |16 |14   
	// 0000 0000 000 1 0 100 0000 0000 0000
	// 0000 0000 0001 0100 0000 0000 0000
	// 0x00014000
	iowrite32((ioread32(GPIO_DIRM_1) | 0x00014000), GPIO_DIRM_1);
	//MIO40 MIO42 使能
	iowrite32((ioread32(GPIO_OEN_1) | 0x00014000), GPIO_OEN_1);

	/* MASK_DATA方式按滅LED1,LED2,這個(gè)需要自己修改相關(guān)參數(shù) */
	//iowrite32((ioread32(GPIO_MASK_DATA_0_LSW ) & 0xFEFFEFFF), GPIO_MASK_DATA_0_LSW );
	//printk("GPIO_MASK_DATA_0_LSW = 0x%x\n", *GPIO_MASK_DATA_0_LSW);
	//iowrite32((ioread32(GPIO_MASK_DATA_0_MSW ) & 0xFEFFEFFF), GPIO_MASK_DATA_0_MSW );
	//printk("GPIO_MASK_DATA_0_MSW = 0x%x\n", *GPIO_MASK_DATA_0_MSW);
	
	//8.DATA方式按滅LED1,LED2
	// 1111 1111 1111 111|1 1|111 1111 1111 1111
	//                   |0  |0
	// 1111 1111 1111 1110 1011 1111 1111 1111
	// 0xFFFEBFFF
	// iowrite32((ioread32(GPIO_DATA_1) & 0xFFFEBFFF), GPIO_DATA_1);
	iowrite32((ioread32(GPIO_DATA_1) & 0xFFFEFFFF), GPIO_DATA_1);

	printk("GPIO_DATA_1 = 0x%x\n", *GPIO_DATA_1);

	return 0;
}

static __exit void led_drv_v1_exit(void)
{
	iowrite32((ioread32(GPIO_DATA_1) | 0xFFFFFFFF), GPIO_DATA_1);
	//9.內(nèi)存釋放
	iounmap(gpio_addr);
	iounmap(iou_slcr);
	//刪除設(shè)備
	device_destroy(led_cls, MKDEV(led_major, 0));
	//刪除類
	class_destroy(led_cls);
	//注銷主設(shè)備號(hào)
	unregister_chrdev(led_major, "led_drv_v1");

	printk("-------^v^-------\n");
	printk("-led drv v1 exit-\n");
}

//申明裝載入口函數(shù)和卸載入口函數(shù)
module_init(led_drv_v1_init);
module_exit(led_drv_v1_exit);

//添加GPL協(xié)議
MODULE_LICENSE("GPL");
MODULE_AUTHOR("msxbo");

行 9~11,用來儲(chǔ)存映射后虛擬地址的基地址。87、88 行賦值。
行 13~15,是我們要控制的兩個(gè)寄存器物理地址的基地址。
行 16~18,是兩個(gè)寄存器的完整大小,在地址轉(zhuǎn)換的時(shí)候直接映射整個(gè)寄存器,方便理解。
行 20~22,定義設(shè)置復(fù)用功能的寄存器。
行 24~35,六個(gè)控制電氣特性的寄存器。
行 37~46,GPIO 的控制寄存器。
行 113~117,是使用 mask_data 的方法熄滅 led,和 data 方法熄滅效果一樣。
行 119~126,使用 data 方法熄滅 led。

1:內(nèi)存映射
static __init int led_drv_v1_init(void)
{

	//1.內(nèi)存映射
	gpio_addr = ioremap(GPIO_BASE_ADDR, GPIO_BASE_SIZE);
	iou_slcr = ioremap(IOU_SLCR_ADDR, IOU_SLCR_SIZE);
	printk("gpio_addr init over!\n");


	return 0;
}

含義:內(nèi)存映射的目的是為了把物理地址映射為虛擬地址,方便對(duì)寄存器進(jìn)行操作。

  • GPIO_BASE_ADDR:這是寄存器手冊(cè)中查詢到的“GPIO Module”的“Base Address”。
    【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
  • GPIO_BASE_SIZE:這是該寄存器的容量,也就是“GPIO Module”的容量。從“GPIO Module”的最后一行可以看到,它的最后一位是“0x0000000364”,位寬是 32 位。簡單的算下,就是 4 字節(jié),所以“GPIO Module”的容量為“0x0000000368”。
2:設(shè)置 MIO 功能
static __init int led_drv_v1_init(void)
{
	//2.MIO40 MIO42 設(shè)置成GPIO,參考手冊(cè)設(shè)置
	iowrite32((ioread32(GPIO_PIN_40) & 0x0), GPIO_PIN_40);
	printk("gpio MIO40 init over!\n");
	iowrite32((ioread32(GPIO_PIN_42) & 0x0), GPIO_PIN_42);
	printk("gpio MIO42 init over!\n");


	return 0;
}

含義:將 MIO 的功能設(shè)置為 GPIO。
具體分析:

? iowrite32:這個(gè)函數(shù)會(huì)把前面的值寫入到后面的目的地址。
? ioread32:這個(gè)函數(shù)則是讀取目的地址的值。
? 0x0:這個(gè)部分需要查詢寄存器手冊(cè)的“IOU_SLCR Module”部分,找到需要設(shè)置的 MIO 引腳的序號(hào),然后根據(jù)自己的需要設(shè)置手冊(cè)中的相應(yīng)的值。
?GPIO_PIN_40:這是在之前確定好的“iou_slcr”進(jìn)行偏移的地址。偏移地址可以在寄存器手冊(cè)中查詢到
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ

3:設(shè)置 MIO 輸出電流的大小
static __init int led_drv_v1_init(void)
{
	// //3.MIO40 MIO42設(shè)置輸出驅(qū)動(dòng)電流大小
	// // 將 0x3FFFFFF 和 0x0 轉(zhuǎn)換為二進(jìn)制。
	// // 0011 1111 1111 1111 1111 1111 1111
	// // 0000 0000 0000 0000 0000 0000 0000
	// // 參考手冊(cè),可以知道每一位的地址都是由 CTRL0 和 CTRL1 控制的,在這里都是 10, 查看手冊(cè)得 8 mA。
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL0) | 0x3FFFFFF), IOU_SLCR_BANK1_CTRL0);
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL1) & 0x0), IOU_SLCR_BANK1_CTRL1);


	return 0;
}

含義:將 Bank1 的電流都設(shè)置為 8mA,Bank1 控制的是 MIO 引腳 [26:51]。
具體分析:
寄存器部分的操作都是按位計(jì)算的,想要什么功能,在手冊(cè)中查到之后,就需要通過寄存器把想要控制的引腳的地址寫入對(duì)應(yīng)功能所需的設(shè)置。這里以控制電流為例。因?yàn)樾枰刂频囊_為 MIO40 和 MIO42,40 和 42 都是 bank1 所負(fù)責(zé)的區(qū)域。因此,在寄存器手冊(cè)中找到對(duì)應(yīng)的bank1 部分。
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
??這個(gè)部分的寄存器都是控制 bank1 部分功能的,我們先介紹 ctrl0 和 ctrl1 兩個(gè)部分。這兩個(gè)部分是控制電流的。
??通過查看“bank1_crtl0 (IOU_SLCR) Register”的“Description”可以知道,ctrl0 得和 ctrl1 兩個(gè)部分才能控制電流的大小。
【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
我們需要控制的是 MIO40 和 MIO42,這里為了方便起見,將 ctrl0 全部設(shè)置為 1,將 ctrl1 全部設(shè)置為 0,查表可以知道是 8mA。

  • &:按位與,可以理解為交集,交集是指 A 與 B 共有的。
  • | :按位或,可以理解為并集,并集是指 A 和 B 所有的。
4:設(shè)置引腳是 Schmitt Trigger 還是 CMOS Input
static __init int led_drv_v1_init(void)
{
	//4.選擇引腳是Schmitt還是CMOS
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL3) & 0x0), IOU_SLCR_BANK1_CTRL3);


	return 0;
}

含義:設(shè)置 MIO 引腳的功能,這里選擇 CMOS Input。

5:設(shè)置引腳的上下拉及使能
static __init int led_drv_v1_init(void)
{
	//5.輸出管腳上下拉及使能
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL4) | 0x3FFFFFF), IOU_SLCR_BANK1_CTRL4);
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL5) | 0x3FFFFFF), IOU_SLCR_BANK1_CTRL5);


	return 0;
}

含義:設(shè)置 MIO 引腳的上拉或者下拉,并且使能。
具體分析:在 ctrl4 部分將其全部設(shè)置為 1,對(duì)照寄存器手冊(cè)可以知道是上拉,并且 bank1 上所有的都是上拉。同理在 ctrl5部分也將其全部設(shè)置為 1,對(duì)照寄存器手冊(cè)可以看到 bank1 上 [26:51] 的 MIO 都被啟動(dòng)了。

6:設(shè)置 MIO 的速率
static __init int led_drv_v1_init(void)
{
	//6.MIO速率的選擇
	iowrite32((ioread32(IOU_SLCR_BANK1_CTRL6) & 0x0), IOU_SLCR_BANK1_CTRL6);


	return 0;
}

Ctrl6 可以設(shè)置 MIO 的速率,0 為低速,1 為高速。

7:設(shè)置 GPIO 的輸入輸出
static __init int led_drv_v1_init(void)
{
	//7.MIO40 MIO42 設(shè)置成輸出
	// 40 - 26 = 14, 42 - 26 = 16
	// 0000 0000 000|0 0|000 0000 0000 0000
 	//              |16 |14   
	// 0000 0000 000 1 0 100 0000 0000 0000
	// 0000 0000 0001 0100 0000 0000 0000
	// 0x00014000
	iowrite32((ioread32(GPIO_DIRM_1) | 0x00014000), GPIO_DIRM_1);
	//MIO40 MIO42 使能
	iowrite32((ioread32(GPIO_OEN_1) | 0x00014000), GPIO_OEN_1);


	return 0;
}

含義:將 GPIO 的輸入輸出部分,MIO40 和 MIO42 的地方設(shè)置為輸出。
具體分析
這個(gè)部分設(shè)置的是 GPIO 的相關(guān)功能,所以要去“GPIO Module”部分去找相關(guān)的寄存器的功能。

  • GPIO_DIRM_1:是指控制 GPIO 的輸入輸出方向。

  • GPIO_OEN_1:則是用來控制使能,也就是 enable 的意思。

8:通過 Data 的方式熄滅 LED
static __init int led_drv_v1_init(void)
{
	/* MASK_DATA方式按滅LED1,LED2,這個(gè)需要自己修改相關(guān)參數(shù) */
	//iowrite32((ioread32(GPIO_MASK_DATA_0_LSW ) & 0xFEFFEFFF), GPIO_MASK_DATA_0_LSW );
	//printk("GPIO_MASK_DATA_0_LSW = 0x%x\n", *GPIO_MASK_DATA_0_LSW);
	//iowrite32((ioread32(GPIO_MASK_DATA_0_MSW ) & 0xFEFFEFFF), GPIO_MASK_DATA_0_MSW );
	//printk("GPIO_MASK_DATA_0_MSW = 0x%x\n", *GPIO_MASK_DATA_0_MSW);
	
	//8.DATA方式按滅LED1,LED2
	// 1111 1111 1111 111|1 1|111 1111 1111 1111
	//                   |0  |0
	// 1111 1111 1111 1110 1011 1111 1111 1111
	// 0xFFFEBFFF
	// iowrite32((ioread32(GPIO_DATA_1) & 0xFFFEBFFF), GPIO_DATA_1);
	iowrite32((ioread32(GPIO_DATA_1) & 0xFFFEFFFF), GPIO_DATA_1);

	printk("GPIO_DATA_1 = 0x%x\n", *GPIO_DATA_1);


	return 0;
}

含義:將已經(jīng)配置 GPIO 的 MIO40,MIO42 的輸出設(shè)置為 0,也就是關(guān)閉輸出。
具體分析
這是通過控制 DATA 寄存器的方式熄滅 LED,還可以使用 MASK_DATA 的方式熄滅 LED。具體的設(shè)置的值需要自己查寄存器手冊(cè)修改。DATA 寄存器的說明在介紹部分。

9:內(nèi)存釋放
static __init int led_drv_v1_init(void)
{
	//9.內(nèi)存釋放
	iounmap(gpio_addr);
	iounmap(iou_slcr);


	return 0;
}

含義:將申請(qǐng)的虛擬內(nèi)存資源進(jìn)行釋放。
具體分析
在通過 ioremap 向系統(tǒng)申請(qǐng)了系統(tǒng)資源之后,在驅(qū)動(dòng)退出的時(shí)候,需要將資源釋放。釋放用 iounmap 函數(shù)。文章來源地址http://www.zghlxwxcb.cn/news/detail-622203.html

1.5交叉編譯

  1. led_drv_v1.cMakefile文件在虛擬機(jī)中進(jìn)行編譯。
  2. 將編譯生成的led_drv_v1.ko文件上傳到開發(fā)板的Linux中。

1.6演示

  • 在終端中使用輸入“l(fā)s”,查看是否存在“l(fā)ed_drv_v1.ko”文件。
    【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
  • 確認(rèn)存在之后,進(jìn)入 root 權(quán)限,然后在終端輸入“insmod led_drv_v1.ko”。
    【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ輸入
  • “l(fā)smod”查看是否安裝成功。
    【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ
  • 在終端輸入“rmmod led_drv_v1.ko”,PS的燈會(huì)亮起。
    【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方,linux,fpga,ZYNQ

到了這里,關(guān)于【ZYNQ】Linux驅(qū)動(dòng)之夢(mèng)開始的地方的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 現(xiàn)在開始學(xué)linux驅(qū)動(dòng)內(nèi)核好嗎?

    現(xiàn)在開始學(xué)linux驅(qū)動(dòng)內(nèi)核好嗎?

    一開始是覺得,內(nèi)核誒,高大上。然后看了幾個(gè)月驅(qū)動(dòng)后,是認(rèn)認(rèn)真真的鉆了幾個(gè)月源碼,寫了很多學(xué)習(xí)筆記的那種。 先說好處吧,對(duì)基礎(chǔ)能力的提升很明顯。比如內(nèi)核數(shù)據(jù)結(jié)構(gòu),指針,以及如何用c需要去完成面向?qū)ο蟮木幊趟枷搿_€有硬件底層的認(rèn)識(shí)??粗约簩懙拇a

    2024年02月12日
    瀏覽(22)
  • FPGA PCIE接口的Linux DMA Engine驅(qū)動(dòng)

    FPGA PCIE接口的Linux DMA Engine驅(qū)動(dòng)

    英創(chuàng)嵌入式主板,如ESM7000系列、ESM8000系列等,均可配置標(biāo)準(zhǔn)的PCIE×1高速接口。連接NVMe模塊作高速大容量數(shù)據(jù)存儲(chǔ)、連接多通道高速網(wǎng)絡(luò)接口模塊都是PCIE接口的典型應(yīng)用。此外,對(duì)于工控領(lǐng)域中的高速數(shù)據(jù)采集,還可采用FPGA的PCIE IP核實(shí)現(xiàn)PCIE EP端點(diǎn),與英創(chuàng)嵌入式主板構(gòu)成

    2024年02月15日
    瀏覽(20)
  • Linux下grep通配容易混淆的地方

    Linux下grep通配容易混淆的地方

    先上一張圖: ?我希望找到某個(gè)版本為8的一個(gè)libXXX.8XXX.so?,那么應(yīng)該怎么寫呢? 先看這種寫法對(duì)不對(duì): ?是不是結(jié)果出乎你的意料之外? 那么我們來看一下規(guī)則: ?這里的 \\\"*\\\"? 表示匹配前一個(gè)字符的零個(gè)或多個(gè)? 于是我們就不難理解了:? ? ?lib*8*.so? ?表示? ??? 包含l

    2024年02月12日
    瀏覽(21)
  • ZYNQ7045從flash啟動(dòng)linux

    ZYNQ7045從flash啟動(dòng)linux

    自行安裝linux版本的vivado,和xilinx開發(fā)環(huán)境。linux版本我選擇的是Ubuntu18.04,ubuntu系統(tǒng)下xilinx開發(fā)環(huán)境我安裝的是vivado 2018.3(安裝時(shí)候要記得勾選SDK),安裝好vivado后也就包含了xilinx的ARM部分交叉編譯器。 petalinux 并不是一個(gè)特殊 Linux 內(nèi)核,而是一套開發(fā)環(huán)境配置的工具,降低 ubo

    2023年04月12日
    瀏覽(25)
  • petalinux定制ZYNQ的Linux操作系統(tǒng)

    在進(jìn)行Zynq-7000的Linux系統(tǒng)開發(fā)時(shí),Xilinx官方提供了一個(gè)名為petalinux的工具。該工具運(yùn)行在pc端的linux環(huán)境下,使用這個(gè)工具可以為目標(biāo)板有量身定制kernel、rootfs等。該工具可與vivado設(shè)計(jì)工具一起配合使用,旨在簡化 Zynq-7000 的Linux系統(tǒng)開發(fā)過程,提高設(shè)計(jì)生產(chǎn)力。本文將介紹pe

    2024年02月16日
    瀏覽(24)
  • 【C++】main開始的地方

    【C++】main開始的地方

    目錄 1. C++ 2. 命名空間 2.1 命名空間定義 2.2 命名空間使用 3. C++輸入輸出 4. 缺省參數(shù) 4.1 缺省參數(shù)概念 4.2 缺省參數(shù)分類 5. 函數(shù)重載 5.1 函數(shù)重載概念 5.2 C++支持函數(shù)重載的原理--名字修飾(name Mangling) 6. 引用 6.1 引用概念 6.2 引用特性 6.3 常引用 6.4 使用場景 6.5 傳值、傳

    2024年02月06日
    瀏覽(18)
  • ZYNQ-Linux開發(fā)之(三)Vivado SDK使用,裸機(jī)開發(fā)調(diào)試,不帶linux

    ZYNQ-Linux開發(fā)之(三)Vivado SDK使用,裸機(jī)開發(fā)調(diào)試,不帶linux

    生成bit文件時(shí)候的開發(fā)和調(diào)試需要使用SDK,導(dǎo)出工程到SDK: 包含bit文件,點(diǎn)擊OK:? 工程目錄下會(huì)新增一個(gè).sdk的目錄: 啟動(dòng)SDK: 使用SDK進(jìn)行調(diào)試,SDK中,新建應(yīng)用工程,選擇File-New-Application Project: 在彈出的窗口中,輸入Project name,單擊Next: 在彈出的窗口中,默認(rèn)選擇He

    2024年02月10日
    瀏覽(26)
  • zynq Linux 啟動(dòng)之后動(dòng)態(tài)布署PL方法摸索

    zynq Linux 啟動(dòng)之后動(dòng)態(tài)布署PL方法摸索

    簡介:在使用zynq 運(yùn)行Linux時(shí),如何在Linux啟動(dòng)之后,再布署PL,本教程在參考了正點(diǎn)原子領(lǐng)航者ZYNQ之嵌入式Linux開發(fā)指南第二十章,開源平臺(tái)創(chuàng)龍的部分教程,結(jié)合Xilinx wiki官方教程。初步實(shí)現(xiàn)了zynq在Linux啟動(dòng)之后再加載PL。純屬摸索實(shí)現(xiàn),有什么描述不正確的地方或者有更好

    2023年04月08日
    瀏覽(62)
  • ZYNQ AXI-DMA Linux Cache 一致

    ZYNQ AXI-DMA Linux Cache 一致

    平臺(tái)為 ZYNQ MPSOC 項(xiàng)目使用到AXI-DMA ,ADC模塊傳輸數(shù)據(jù)到DDR,應(yīng)用層進(jìn)行數(shù)據(jù)的讀取。在此做些記錄 用到了AXI-Stream , IP核用的 米聯(lián)客的ui_axisbufw,可以把流數(shù)據(jù)轉(zhuǎn)為AXI-Stream 接口 比較重要的參考鏈接 1.UltraScale+MPSoC+Cache+Coherency https://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/18842098/Zynq+

    2024年02月03日
    瀏覽(14)
  • 在ZYNQ-Linux下操作GPIO和VDMA

    在ZYNQ-Linux下操作GPIO和VDMA

    此前的文章介紹如何利用petalinux定制ZYNQ-Linux操作系統(tǒng)。當(dāng)ZYNQ-Linux系統(tǒng)搭建完畢后,需要在這個(gè)系統(tǒng)上開發(fā)應(yīng)用程序以完成特定任務(wù),這里面就涉及到如何在ZYNQ-Linux系統(tǒng)上去操作系統(tǒng)硬件資源的問題。目前,網(wǎng)上介紹的比較多的是需要改寫Linux操作系統(tǒng)底層的設(shè)備樹,并編寫

    2024年02月04日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包