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

韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型)

這篇具有很好參考價(jià)值的文章主要介紹了韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。


本人學(xué)習(xí)完韋老師的視頻,因此來復(fù)習(xí)鞏固,寫以筆記記之。
韋老師的課比較難,第一遍不知道在說什么,但是堅(jiān)持看完一遍,再來復(fù)習(xí),基本上就水到渠成了。
看完視頻復(fù)習(xí)的同學(xué)觀看最佳!
基于 IMX6ULL-PRO
參考視頻 Linux快速入門到精通視頻
參考資料:01_嵌入式Linux應(yīng)用開發(fā)完全手冊(cè)V5.1_IMX6ULL_Pro開發(fā)板.pdf

2024.4.18更新 利用圖解方式探索內(nèi)核函數(shù)調(diào)用
代碼上傳到git網(wǎng)站驅(qū)動(dòng)代碼

一、Hello 驅(qū)動(dòng)編程

1-1 APP 打開的文件在內(nèi)核中如何表示

APP打開文件時(shí),得到一個(gè)整數(shù)fd,被稱為文件句柄。對(duì)于APP的每一個(gè)文件句柄,在內(nèi)核里面都有一個(gè)struct file結(jié)構(gòu)體(include/linux/fs.h)與之對(duì)應(yīng)。
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
open打開文件時(shí),傳入的flags、mode等參數(shù)會(huì)被記錄在內(nèi)核中對(duì)應(yīng)的struct file 結(jié)構(gòu)體里f_flagsf _mode。
去讀寫文件時(shí),文件的當(dāng)前偏移地址也會(huì)保存在f _pos 成員里。

int open(const char *pathname, int flags, mode_t mode);
1-2 打開字符設(shè)備節(jié)點(diǎn)時(shí),內(nèi)核中也有對(duì)應(yīng)的 struct file

struct file_operations *f_op,由驅(qū)動(dòng)程序提供。struct file_operations結(jié)構(gòu)體是Linux內(nèi)核中用于描述文件操作函數(shù)集合的結(jié)構(gòu)體。它包含了許多函數(shù)指針成員,每個(gè)成員對(duì)應(yīng)于不同的文件操作。
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

1-3 Hello 驅(qū)動(dòng)程序

如何編寫驅(qū)動(dòng)程序步驟
1、確定主設(shè)備號(hào),也可讓內(nèi)核分配
2、定義自己file_operations結(jié)構(gòu)體
3、實(shí)現(xiàn)drv_open()、drv_read()、drv_write()等函數(shù),寫入file_operations結(jié)體
4、file_operations結(jié)構(gòu)體告訴內(nèi)核:register_chrdev()
5、誰來注冊(cè)驅(qū)動(dòng)程序?。康糜幸粋€(gè)入口函數(shù):安裝驅(qū)動(dòng)程序時(shí),就會(huì)去調(diào)用這個(gè)入口函數(shù)
6、有入口函數(shù)就應(yīng)該有出口函數(shù):卸載驅(qū)動(dòng)程序時(shí),出口函數(shù)調(diào)用unregister_chrdev
7、其他完善:提供設(shè)備信息,自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn):class_create, device_create

分析Hello 驅(qū)動(dòng)程序代碼

/*頭文件省略,記得找到源碼添加即可*/
#define MIN(a,b) ((a < b) ? a: b)

/*驅(qū)動(dòng)程序*/
/*1、確定主設(shè)備號(hào),也可以讓內(nèi)核分配*/
static int major = 0;   //設(shè)備號(hào)為0 系統(tǒng)自動(dòng)分配
static char kernel_buf[1024];
static struct class *hello_class;

/*3、實(shí)現(xiàn)對(duì)應(yīng)的 drv_open/drv_read/drv_write等函數(shù),填入 file_operations結(jié)構(gòu)體*/
static ssize_t hello_drv_read(struct file *file, char __user * buf, size_t size, loff_t * offset)
{
	int err;
	/*驅(qū)動(dòng)調(diào)試 屏幕打印文件名,函數(shù)名,行號(hào)*/
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_to_user(buf, kernel_buf, MIN(1024, size));  //內(nèi)核存儲(chǔ)的數(shù)據(jù)讀到用戶buf中
	return MIN(1024, size);
}

static ssize_t hello_drv_write(struct file *file, const char __user * buf, size_t size, loff_t * offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(kernel_buf,  buf, MIN(1024, size));  //用戶buf的數(shù)據(jù)寫到內(nèi)核中
	return MIN(1024, size);
}

static int hello_drv_open(struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int hello_drv_close(struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

/*2、定義自己的 file_operations結(jié)構(gòu)體*/
static struct file_operations hell_drv = {
	 .owner = THIS_MODULE,
	 .open = hello_drv_open,
	 .read = hello_drv_read,
	 .write = hello_drv_write,
	 .release = hello_drv_close,
};

/*4、把 file_operations結(jié)構(gòu)體告訴內(nèi)核: register_chrdev 誰來注冊(cè)驅(qū)動(dòng)程序???*/
/*5、得有一個(gè)入口函數(shù):安裝驅(qū)動(dòng)程序時(shí),就會(huì)去調(diào)用這個(gè)入口函數(shù)*/
static int __init hello_init(void)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	
	/*注冊(cè)驅(qū)動(dòng)程序*/
	major = register_chrdev(0, "hello", &hell_drv);  
	/*創(chuàng)建設(shè)備節(jié)點(diǎn)*/
	hello_class = class_create(THIS_MODULE, "hello_class");
	
	err = PTR_ERR(hello_class);  /*錯(cuò)誤處理函數(shù)*/
	if (IS_ERR(hello_class)){
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(0, "hello");
		return -1;
	}
	//device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");  /* /dev/hello */

	return 0;
}

/*6、有入口函數(shù)就應(yīng)該有出口函數(shù):卸載驅(qū)動(dòng)程序時(shí),出口函數(shù)調(diào)用 unregister_chrdev */
static void __exit hello_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	device_destroy(hello_class, MKDEV(major, 0)); //MKDEV(major, 0)主設(shè)備號(hào) 次設(shè)備號(hào)
	class_destroy(hello_class);
	
	unregister_chrdev(0, "hello");
}

/*7、其他完善:提供設(shè)備信息,自動(dòng)創(chuàng)建設(shè)備節(jié)點(diǎn): class_create, device_create*/
module_init(hello_init);   	//修飾為入口函數(shù)
module_exit(hello_exit);
MODULE_LICENSE("GPL");	//遵守GPL協(xié)議

register_chrdev()是Linux內(nèi)核中用于注冊(cè)字符設(shè)備驅(qū)動(dòng)程序的函數(shù)。在Linux系統(tǒng)中,字符設(shè)備是一種提供面向字符的I/O操作的設(shè)備,例如終端、打印機(jī)、鼠標(biāo)、鍵盤、LED、I2C、SPI等。

int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
major = register_chrdev(0, "hello", &hell_drv);  

其中參數(shù)含義如下:
major: 主設(shè)備號(hào),用于唯一標(biāo)識(shí)該字符設(shè)備驅(qū)動(dòng)程序。
name: 設(shè)備名稱,用于在/proc/devices中顯示。
fops: 指向struct file_operations結(jié)構(gòu)體的指針,包含了該字符設(shè)備支持的操作函數(shù)。
當(dāng)調(diào)用register_chrdev()函數(shù)時(shí),內(nèi)核會(huì)為指定的字符設(shè)備注冊(cè)一個(gè)主設(shè)備號(hào),并將其與對(duì)應(yīng)的操作函數(shù)關(guān)聯(lián)起來。這樣,在用戶空間通過設(shè)備文件和系統(tǒng)調(diào)用就能夠訪問和操作這個(gè)字符設(shè)備了。

class_create()是Linux內(nèi)核中用于創(chuàng)建一個(gè)新的設(shè)備類的函數(shù)。在Linux系統(tǒng)中,設(shè)備類是一種將相關(guān)設(shè)備實(shí)例進(jìn)行組織和分類的機(jī)制。

struct class *class_create(struct module *owner, const char *name);
hello_class = class_create(THIS_MODULE, "hello_class");

其中參數(shù)含義如下:
owner: 指向struct module類型的指針,表示擁有該設(shè)備類的模塊。
name: 設(shè)備類的名稱,用于在/sys/class/目錄下創(chuàng)建相應(yīng)的子目錄。
成功調(diào)用class_create()函數(shù)后,會(huì)在/sys/class/目錄下創(chuàng)建一個(gè)與指定名稱對(duì)應(yīng)的子目錄,用于存放屬于該設(shè)備類的設(shè)備實(shí)例。

device_create()是Linux內(nèi)核中用于創(chuàng)建一個(gè)設(shè)備實(shí)例的函數(shù)。在Linux系統(tǒng)中,設(shè)備實(shí)例是設(shè)備類中的具體設(shè)備對(duì)象。通過device_create()函數(shù)可以創(chuàng)建一個(gè)新的設(shè)備實(shí)例,并將其與指定的設(shè)備類進(jìn)行關(guān)聯(lián)。

struct device *device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *format, ...);
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");  /* /dev/hello */

其中參數(shù)含義如下:
class: 指向struct class類型的指針,表示要?jiǎng)?chuàng)建設(shè)備實(shí)例所屬的設(shè)備類。
parent: 指向struct device類型的指針,表示要?jiǎng)?chuàng)建設(shè)備實(shí)例的父設(shè)備。通常為NULL,表示沒有父設(shè)備。
devt: 設(shè)備號(hào),用于標(biāo)識(shí)設(shè)備實(shí)例的唯一性。
drvdata: 指向設(shè)備驅(qū)動(dòng)程序特定的數(shù)據(jù)結(jié)構(gòu)的指針,可以傳遞給設(shè)備實(shí)例。
format: 設(shè)備名稱的格式化字符串,用于在/sys/class/<class_name>/目錄下創(chuàng)建相應(yīng)的設(shè)備實(shí)例目錄。
成功調(diào)用device_create()函數(shù)后,會(huì)在/sys/class/<class_name>/目錄下創(chuàng)建一個(gè)與指定格式化字符串對(duì)應(yīng)的設(shè)備實(shí)例目錄,通過在/dev目錄下創(chuàng)建相應(yīng)的設(shè)備節(jié)點(diǎn)。

1-4 測(cè)試

(1) 修改makefile文件,內(nèi)核路徑對(duì)應(yīng)于自己系統(tǒng)上的

KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88

(2) 打印內(nèi)核信息,在串口處設(shè)置快捷方式
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

echo "7 4 1 7" > /proc/sys/kernel/printk

控制內(nèi)核打印信息級(jí)別,>7的才輸出。即不輸出內(nèi)核打印信息

/include/linux/kern_levels.h 
#define KERN_SOH    "\001"      /* ASCII Start Of Header */
 
#define KERN_EMERG  KERN_SOH "0"    /* system is unusable 系統(tǒng)崩潰前的信息*/
#define KERN_ALERT  KERN_SOH "1"    /* action must be taken immediately 需要立即處理的消息 */
#define KERN_CRIT   KERN_SOH "2"    /* critical conditions 嚴(yán)重情況*/
#define KERN_ERR    KERN_SOH "3"    /* error conditions 錯(cuò)誤*/
#define KERN_WARNING    KERN_SOH "4"    /* warning conditions 警告*/
#define KERN_NOTICE KERN_SOH "5"    /* normal but significant condition 注意 */
#define KERN_INFO   KERN_SOH "6"    /* informational 普通信息*/
#define KERN_DEBUG  KERN_SOH "7"    /* debug-level messages 調(diào)試*/

(3) 裝載驅(qū)動(dòng)insmod
(4)顯示的當(dāng)前內(nèi)核已經(jīng)加載的模塊和驅(qū)動(dòng)lsmod
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
(5)卸載驅(qū)動(dòng)rmmod
(6)顯示主設(shè)備號(hào) register_chrdev()

cat /proc/devices

韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
(7)創(chuàng)建設(shè)備節(jié)點(diǎn)class_create()和device_create()
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

1-5 補(bǔ)充知識(shí)
(1) module_init/module_exit 的實(shí)現(xiàn)

一個(gè)驅(qū)動(dòng)程序有入口函數(shù)、出口函數(shù)。驅(qū)動(dòng)程序可以被編進(jìn)內(nèi)核里,也可以被編譯為ko文件后手工加載。

module_init(hello_init)
module_exit(hello_exit);

當(dāng)編譯為ko文件時(shí),使用insmod 命令加載驅(qū)動(dòng)時(shí),內(nèi)核調(diào)用 init_module 函數(shù),實(shí)際上就是調(diào)用hello_init函數(shù);使用rmmod命令卸載驅(qū)動(dòng)時(shí),內(nèi)核都是調(diào)用cleanup_module 函數(shù),實(shí)際上就是調(diào)用hello_ exit 函數(shù)。

(2) register_chrdev 的內(nèi)部實(shí)現(xiàn)

chrdevs[i]數(shù)組項(xiàng)是一個(gè)鏈表頭,鏈表里每一個(gè)元素都是一個(gè)char_device_struct 結(jié)構(gòu)體,每個(gè)元素表示一個(gè)驅(qū)動(dòng)程序。

struct char_device_struct {
	struct char_device_struct *next;
	unsigned int major;
	unsigned int basem inor;
	int minorct;
	char name[64];
	struct cdev *cdev; /* will die */
}*chrdevs[CHRDEV_MAJOR_HASH_SIZE];

它指定了主設(shè)備號(hào)major 、次設(shè)備號(hào) baseminor 、個(gè)數(shù) minorct ,在 cdev中含有 file_operations 結(jié)構(gòu)體。因此,內(nèi)核通過主、次設(shè)備號(hào),找到對(duì)應(yīng)的file_operations 結(jié)構(gòu)體”。
APP 打開某個(gè)字符設(shè)備節(jié)點(diǎn)時(shí),進(jìn)入內(nèi)核。在內(nèi)核里根據(jù)字符設(shè)備節(jié)點(diǎn)的主、次設(shè)備號(hào),通過cdev_add()函數(shù)調(diào)用在cdev_map鏈表中快速得到cdev,再從cdev中得到file_operations結(jié)構(gòu)體。
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

(3) class_destroy/device_create 淺析

在/sys目錄下創(chuàng)建一些目錄、文件,這樣 Linux 系統(tǒng)中的 APP就可以根據(jù)這些目錄或文件來創(chuàng)建設(shè)備節(jié)點(diǎn)。
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

二、GPIO基礎(chǔ)知識(shí)

GPIO: General purpose input/output ,通用的輸入輸出口

2-1 GPIO結(jié)構(gòu)

(1) 有多組GPIO,每組有多個(gè)GPIO。例如:GPIO2_IO15。
(2) 使能:電源/時(shí)鐘
(3) 模式(Mode):引腳可用于GPIO或其他功能
(4) 方向:引腳Mode設(shè)置為GPIO時(shí),可以繼續(xù)設(shè)置它是輸出引腳,還是輸入引腳
(5) 數(shù)值:
? 對(duì)于輸出引腳,可以設(shè)置寄存器讓它輸出高、低電平
? 對(duì)于輸入引腳,可以讀取寄存器得到引腳的當(dāng)前電平

將某一位置1,采用操作

val = val |(1<<n)
val |= (1<<n)

將某一位清0,用與且取反操作

val = val & ~(1<<n)
val &= ~(1<<n)

GPIO控制涉及CCM、IOMUXC、GPIO模塊本身等三個(gè)部分。
CCM:Clock Controller Module (時(shí)鐘控制模塊),用于設(shè)置是否向GPIO模塊提供時(shí)鐘。參考資料:芯片手冊(cè)《Chapter 18: Clock Controller Module (CCM) 》

IOMUXC:IOMUX Controller,IO復(fù)用控制器。引腳的模式和功能,參考資料:芯片手冊(cè)《Chapter 32: IOMUX Controller (IOMUXC) 》。
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

2-2 GPIO模塊內(nèi)部

韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
① GPIOx_GDIR:設(shè)置引腳方向,每位對(duì)應(yīng)一個(gè)引腳 1-output,0-input
② GPIOx_DR:設(shè)置輸出引腳的電平,每位對(duì)應(yīng)一個(gè)引腳 ,1-高電平, 0-低電平
③ GPIOx_PSR:讀取引腳的電平,每位對(duì)應(yīng)一個(gè)引腳 1-高電平, 0-低電平
GPIO設(shè)置步驟
1、使能時(shí)鐘/電源
2、選擇GPIO模式
3、 設(shè)置IO方向
4、設(shè)置高/低電平

三、LED驅(qū)動(dòng)

3-1 最簡(jiǎn)單的LED驅(qū)動(dòng)程序

韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
SVC用于生成系統(tǒng)函數(shù)調(diào)用.例如,用戶程序不允許直接訪問硬件,操作系統(tǒng)可以通過SVC提供對(duì)硬件的訪問。 因此,當(dāng)用戶程序想要使用某些硬件時(shí),可以使用SVC指令,然后執(zhí)行操作系統(tǒng)中的軟件異常處理程序,并提供用戶應(yīng)用程序請(qǐng)求的服務(wù)。
(1) 驅(qū)動(dòng)怎么操作硬件?
通過ioremap映射寄存器的物理地址得到虛擬地址,讀寫虛擬地址。
(2) 驅(qū)動(dòng)怎么和APP傳輸數(shù)據(jù)?
通過 copy to_user()、copy_from_user() 這2個(gè)函數(shù)。

volatile關(guān)鍵字,防止程序被優(yōu)化,如某一變量的點(diǎn)燈、滅燈(寫操作:*p=0;*p=1讀操作亦是如此)

ioremap()可以將物理地址映射為虛擬地址

 virt_addr = ioremap(phys_addr, size);

把物理地址phys_addr 開始的一段空間 ,映射為虛擬地址返回值是該段虛擬地址的首地址。實(shí)際上,它是按頁4096字節(jié)進(jìn)行映射的,即整頁整頁地映射的。

/*頭文件參考源碼即可*/
static int major;
static struct class *led_class;

/*register*/
//IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

//GPIO5_GDIR地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR;

//GPIO5_DR地址:0x020AC000
static volatile unsigned int *GPIO5_DR;

static ssize_t led_write(struct file *file, const char __user *buf,
			 size_t count, loff_t *ppos)
{
	char val;
	int ret;
	/*copy_from_user : get data from app 用戶空間的數(shù)據(jù)拷貝到內(nèi)核空間
	*status中的數(shù)據(jù)在buf中
	*/
	ret = copy_from_user(&val, buf, 1);/*buf里的值是用戶空間的state buf=&state*/

	/*to set GPIO register:out 1 or 0*/
	if(val){
		/*set gpio to let led on*/
		*GPIO5_DR &= ~(1<<3);	//輸出0
	}
	else{
		/*set gpio to let led off 熄滅*/
		*GPIO5_DR |=(1<<3);	//輸出1
	}

	return 1;
}

static int led_open(struct inode *inode, struct file *filp)
{
	/*enable gpio
	*configure gpio5_io3 as gpio
	*configure gpio5_io3 as output
	*/
	/*配置為GPIO引腳功能*/
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf; //清零
	*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x05;

	/*GPIO引腳配置為輸出方式*/
	*GPIO5_GDIR |= (1<<3);
	return 0;
}

static struct file_operations led_fops = {
	.owner	= THIS_MODULE,
	.write	= led_write,
	.open	= led_open,
};

/*入口函數(shù)*/
static int __init led_init(void)
{

	printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	/*注冊(cè)字符設(shè)備*/
	major = register_chrdev(0, "100ask_led", &led_fops);
	
	/*ioremap 將物理地址映射為虛擬地址*/
	//IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3地址:0x02290000 + 0x14
	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);
	
	//GPIO5_GDIR地址:0x020AC004
	GPIO5_GDIR = ioremap(0x020AC004, 4);
	
	//GPIO5_DR地址:0x020AC000
	GPIO5_DR = ioremap(0x020AC000, 4);
	
	led_class = class_create(THIS_MODULE, "myled");
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); /*系統(tǒng)會(huì)創(chuàng)建 /dev/myled的設(shè)備節(jié)點(diǎn)*/

	return 0;
}

static void __exit led_exit(void)
{
	iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
	iounmap(GPIO5_GDIR);
	iounmap(GPIO5_DR);
	device_destroy(led_class, MKDEV(major, 0));
	class_destroy(led_class);
	
	unregister_chrdev(major, "100ask_led");
};
3-2 LED驅(qū)動(dòng)程序框架

字符設(shè)備框架
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
LED驅(qū)動(dòng)框架
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
應(yīng)用程序訪問驅(qū)動(dòng)程序,會(huì)打開一個(gè)設(shè)備節(jié)點(diǎn),根據(jù)設(shè)備節(jié)點(diǎn)的主、次設(shè)備號(hào),在內(nèi)核里找到file_operations結(jié)構(gòu)體。
LED 驅(qū)動(dòng)能支持多個(gè)板子的基礎(chǔ): 分層 思想
這里的目的其實(shí)就是把硬件部分代碼剝離出來,這種構(gòu)思的方法以此來引出后面的設(shè)備樹。
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

程序解析
(1) led_opr.h 面向?qū)ο缶幊?,將LED抽象為一個(gè)led_operations 結(jié)構(gòu)體

#ifndef _LED_OPR_H
#define _LED_OPR_H

struct led_operations{
	int(*init)(int which); /*初始化LED, which-哪個(gè)LED*/   /*函數(shù)指針*/
	int (*ctl)(int which, char status); /*控制LED,which-哪個(gè)LED,status:1 亮,0 滅*/
};
struct led_operations *get_board_led_opr(void); /*指針函數(shù) 返回值是結(jié)構(gòu)體類型的指針*/

#endif
/*宏定義作用:防止頭文件重復(fù)定義*/

#ifndef 宏名(_LED_OPR)
#define 宏名(_LED_OPR)

#endif
作用:防止頭文件重復(fù)定義出錯(cuò),即當(dāng)a.h和b.h引用了該頭文件,但是d.c又引用a.h和b.h文件,會(huì)導(dǎo)致引用兩次。

(2) board_demo.c

#include <linux/gfp.h>
#include "led_opr.h"

static int board_demo_led_init(int which) /*初始化LED,which-哪個(gè)LED*/
{
	printk("%s %s line %d, led %d\n", __FILE__,__FUNCTION__, __LINE__, which);
	return 0;
}

static int board_demo_led_ctl(int which, char status) /*控制LED,which-哪個(gè)LED,status:1 亮 0滅*/
{
	printk("%s %s line %d, led %d\n", __FILE__,__FUNCTION__, __LINE__, which);
	return 0;
}

static struct led_operations board_demo_led_opr = {
	.init = board_demo_led_init,
	.ctl = board_demo_led_ctl,
};

struct led_operations *get_board_led_opr(void)
{
	return &board_demo_led_opr;
}

對(duì)led_operations結(jié)構(gòu)體的實(shí)例化board_demo_led_opr以及函數(shù)體的實(shí)現(xiàn)

(3) lederv.c

p_led_opr = get_board_led_opr();

最終p_led_opr指向board_demo_led_opr結(jié)構(gòu)體,通過調(diào)用其結(jié)構(gòu)體成員(2個(gè)函數(shù)指針來實(shí)現(xiàn)相應(yīng)內(nèi)容)

3-3 課后作業(yè)1

實(shí)現(xiàn)讀LED狀態(tài)的功能:涉及APP和驅(qū)動(dòng)。
思路單獨(dú)編寫read部分代碼
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言

3-4 具體單板的LED驅(qū)動(dòng)程序

位于02_led_drv_for_boards文件夾中
其實(shí)就是在01文件夾中抽象的結(jié)構(gòu)體對(duì)應(yīng)的函數(shù)中的基礎(chǔ)上添加了iMX6ULL具體硬件LED的信息,部分下面代碼所示

		//效率太低 進(jìn)行了兩次讀-修改-寫操作
		//*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~(0xf); //清零
		//*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= (5);

		//2、設(shè)置GPIO5_IO03用于GPIO
		//只進(jìn)行一次讀操作 一次寫操作
		val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
		val &= ~(0xf);
		val |= (5);
		*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;

課后作業(yè)1:在出口函數(shù)處添加iounmap()函數(shù)

static void __exit led_exit(void)
{
	iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
	iounmap(GPIO5_GDIR);
	iounmap(GPIO5_DR);
	int i;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	for(i = 0; i < p_led_opr->num; i++){
		device_destroy(led_class, MKDEV(major, i)); //MKDEV(major, i)主設(shè)備號(hào) 次設(shè)備號(hào)
	}
	
	class_destroy(led_class);
	unregister_chrdev(0, "100ask_led"); /*注銷驅(qū)動(dòng)*/
}

課后作業(yè)2

/*部分代碼*/
static int board_demo_led_init(int which) /*初始化LED,which-哪個(gè)LED*/
{
	unsigned int val;
	int i = 0;
	//printk("%s %s line %d, led %d\n", __FILE__,__FUNCTION__, __LINE__, which);
	if(which == 0){   /*which==次設(shè)備號(hào)*/
		if(!i){
		CCM_CCGR1 = ioremap(0x20C406C, 4);
		IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290014, 4);
		GPIO5_GDIR = ioremap(0x020AC004, 4);
		GPIO5_DR = ioremap(0x020AC000, 4);
		i++;
		}

		//1、使能GPIO5
		*CCM_CCGR1 |= (3<<30);

		//效率太低 進(jìn)行了兩次讀-修改-寫操作
		//*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~(0xf); //清零
		//*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= (5);
		
		//2、設(shè)置GPIO5_IO03用于GPIO
		//只進(jìn)行一次讀操作 一次寫操作
		val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
		val &= ~(0xf);
		val |= (5);
		*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;
		
		//3、設(shè)置GPIO5_IO03作為output引腳
		*GPIO5_GDIR |= (1<<3);
	}
	else{
		/*由于IM6ULL只有一個(gè)燈可以點(diǎn),故難以找到對(duì)應(yīng)LED的GIIO口,所以提供思路即可。若有LED,在此處配置第二個(gè)LED即可*/
	}
	return 0;
}

static int board_demo_led_ctl(int which, char status) /*控制LED,which-哪個(gè)LED,status:1 亮 0滅*/
{
	//printk("%s %s line %d, led %d\n", __FILE__,__FUNCTION__, __LINE__, which);
	if(which == 0){
		if(status){		/*on: output 0 點(diǎn)燈*/
			*GPIO5_DR &= ~(1<<3);
		}
		else{			/*off: output 1 熄滅*/
			*GPIO5_DR |= (1<<3);
		}	
	}
	else{
		if(status){		/*on: output 0 點(diǎn)燈*/
			//同理,若有LED燈,在此處配置即可 *GPIO5_DR &= ~(1<<3);
		}
		else{			/*off: output 1 熄滅*/
			//*GPIO5_DR |= (1<<3);
		}		
	}
	return 0;
}
static struct led_operations board_demo_led_opr = {
	.num = 2,
	.init = board_demo_led_init,
	.ctl = board_demo_led_ctl,

};

四、驅(qū)動(dòng)設(shè)計(jì)的思想

在面向?qū)ο髸r(shí),字符設(shè)備驅(qū)動(dòng)程序抽象出一個(gè)file_operations結(jié)構(gòu)體;LED驅(qū)動(dòng)程序針對(duì)硬件部分抽象出led_operations結(jié)構(gòu)體。
分層思想:
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
分離思想:
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
對(duì)于引腳的操作是相同的,那可以針對(duì)該芯片寫出比較通用的硬件操作代碼;
比如board_A.c 使用芯片Y ,那就可以寫出 chipY_gpio.c,它實(shí)現(xiàn)芯片Y的GPIO 操作,適用于芯片Y的所有GPIO引腳。使用時(shí),我們只需要在board_A_led.c 中指定使用哪一個(gè)引腳即可。

五、總線設(shè)備驅(qū)動(dòng)模型

5-1 簡(jiǎn)介

對(duì)于硬件資源,用platform_device結(jié)構(gòu)體來表示;對(duì)于硬件的操作,用platform_driver結(jié)構(gòu)體表示。
內(nèi)核源碼: include\linux\platform_device.h
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
在內(nèi)核中有一個(gè)虛擬的總線platform_bus_type,它有2個(gè)鏈表結(jié)構(gòu),左邊是
設(shè)備Dev鏈表,右邊是驅(qū)動(dòng)Drv鏈表。左邊的設(shè)備鏈表和右邊的驅(qū)動(dòng)鏈表會(huì)進(jìn)行一一比較(通過platform_match函數(shù)),若匹配成功,就會(huì)調(diào)用platform_driver中的probe函數(shù)。
如何進(jìn)行匹配?

(1) platform_device結(jié)構(gòu)體
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
(2) platform_driver結(jié)構(gòu)體
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
(3) platform_match
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
總線設(shè)備驅(qū)動(dòng)編寫程序步驟
(1) 分配、設(shè)置、注冊(cè)platform_device結(jié)構(gòu)體,在里面定義所用資源,指定設(shè)備名字。
(2) 分配、設(shè)置、注冊(cè)platform_driver結(jié)構(gòu)體,在其中的probe函數(shù)里,分配、設(shè)置、注冊(cè)file_operations結(jié)構(gòu)體,并從platform_device 中確實(shí)所用硬件資源,指定platform_driver的名字。

5-2 LED總線設(shè)備驅(qū)動(dòng)模型

之前的LED驅(qū)動(dòng)框架
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
現(xiàn)目標(biāo)框架如下
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
解釋:
1、leddrv.c注冊(cè)驅(qū)動(dòng)程序,創(chuàng)建設(shè)備節(jié)點(diǎn)類,platform_device(相當(dāng)于后面的設(shè)備樹)指定硬件信息,platform_driver指定對(duì)硬件信息進(jìn)行操作(初始化、控制)。
2、注冊(cè)平臺(tái)設(shè)備驅(qū)動(dòng)兩個(gè)結(jié)構(gòu)體,并且調(diào)用register_led_operations(&board_demo_led_opr)()提前為leddrv.c打開接口。平臺(tái)總線設(shè)備驅(qū)動(dòng)匹配后,調(diào)用chip_demo_gpio_probe()來獲取硬件資源信息,并且再調(diào)用led_class_create_device(),創(chuàng)建設(shè)備節(jié)點(diǎn)。/dev/100ask_led0,1,…
3、此時(shí)應(yīng)用層open函數(shù)可以打開設(shè)備,在調(diào)用驅(qū)動(dòng)程序的led_drv_open(),在函數(shù)中初始化硬件p_led_opr->init(minor),最終調(diào)用到底層board_demo_led_init()函數(shù)。

1、返回該dev中某類型type資源中的第幾個(gè)num

struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)

2、返回該dev所用的第幾個(gè)num中斷

int platform_get_irq(struct platform_device *dev, unsigned int num)

3、通過名字name)返回該 dev的某類型type資源

struct resource *platform_get_resource_byname(struct platform_device *dev, unsigned int type, const char *name)

4、通過名字name)返回該dev的中斷號(hào)

int platform_get_irq_byname(struct platform_device *dev const char *name)

程序解析
board_A_led.c中構(gòu)造platform_device,提供LED硬件相關(guān)資源

static void led_dev_release(struct device *dev)
{
}

static struct resource resources[] = {
        {
                .start = GROUP_PIN(3,1),
                .flags = IORESOURCE_IRQ, /*表示是哪一類資源 這里是假設(shè)IRQ表示引腳*/
                .name = "100ask_led_pin",
        },
        {
                .start = GROUP_PIN(5,8),
                .flags = IORESOURCE_IRQ,
                .name = "100ask_led_pin",
        },
};

static struct platform_device board_A_led_dev = {
        .name = "100ask_led",
        .num_resources = ARRAY_SIZE(resources),
        .resource = resources,
        .dev = {
                .release = led_dev_release, /*防止在調(diào)用
platform_device_unregister 時(shí)會(huì)出現(xiàn)警告*/
         },
};

static int __init led_dev_init(void)
{
    int err;
    err = platform_device_register(&board_A_led_dev);   /*注冊(cè)platform_device*/
    return 0;
}

static void __exit led_dev_exit(void)
{
    platform_device_unregister(&board_A_led_dev);
}

module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");

chip_demo_gpio.c中構(gòu)造platform_device結(jié)構(gòu)體與之匹配

static int g_ledpins[100];
static int g_ledcnt = 0;

/*
*省略部分代碼
*/

static struct led_operations board_demo_led_opr = {
    .init = board_demo_led_init,
    .ctl  = board_demo_led_ctl,
};

struct led_operations *get_board_led_opr(void)
{
    return &board_demo_led_opr;
}

static int chip_demo_gpio_probe(struct platform_device *pdev)
{
    struct resource *res;
    int i = 0;

    while (1){
        res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
        if (!res)
            break;
        
        g_ledpins[g_ledcnt] = res->start; 	/*記錄引腳 */
        led_class_create_device(g_ledcnt);  /*創(chuàng)建device_create 有多少引腳,創(chuàng)建多少個(gè)*/
        g_ledcnt++;
    }
    return 0;
    
}

static int chip_demo_gpio_remove(struct platform_device *pdev)
{
    struct resource *res;
    int i = 0;

    while (1){
        res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
        if (!res)
            break;
        
        led_class_destroy_device(i);
        i++;
        g_ledcnt--;
    }
    return 0;
}

static struct platform_driver chip_demo_gpio_driver = {
    .probe      = chip_demo_gpio_probe,
    .remove     = chip_demo_gpio_remove,
    .driver     = {
        .name   = "100ask_led",
    },
};

static int __init chip_demo_gpio_drv_init(void)
{
    int err;
    err = platform_driver_register(&chip_demo_gpio_driver); 
    register_led_operations(&board_demo_led_opr);
    
    return 0;
}

static void __exit lchip_demo_gpio_drv_exit(void)
{
    platform_driver_unregister(&chip_demo_gpio_driver);
}

module_init(chip_demo_gpio_drv_init);
module_exit(lchip_demo_gpio_drv_exit);

MODULE_LICENSE("GPL");

a.c編譯為a.ko ,里面定義了func_a;如果它想讓b.ko使用該函數(shù),那
么a .c里需要導(dǎo)出此函數(shù)。并且,使用時(shí)要先加載a.ko 。如果先加載b.ko

EXPORT_SYMBOL(led_device_create);
5-3 平臺(tái)總線驅(qū)動(dòng)函數(shù)關(guān)系調(diào)用圖解

韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言
韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型),Linux嵌入式,驅(qū)動(dòng)開發(fā),ubuntu,linux,嵌入式,c語言文章來源地址http://www.zghlxwxcb.cn/news/detail-857277.html

到了這里,關(guān)于韋東山嵌入式Liunx入門驅(qū)動(dòng)開發(fā)一(Hello 驅(qū)動(dòng)編程、GPIO基礎(chǔ)知識(shí)、LED驅(qū)動(dòng)、總線設(shè)備驅(qū)動(dòng)模型)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(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)文章

  • 嵌入式LinuxLED驅(qū)動(dòng)開發(fā)實(shí)驗(yàn)

    嵌入式LinuxLED驅(qū)動(dòng)開發(fā)實(shí)驗(yàn)

    我們?cè)诼銠C(jī)實(shí)驗(yàn)的時(shí)候,都是通過配置底層的寄存器來進(jìn)行點(diǎn)亮LED燈的操作的。我們現(xiàn)在還沒有學(xué)習(xí)到設(shè)備樹的相關(guān)知識(shí),所以,我們也是通過在字符設(shè)備驅(qū)動(dòng)框架的基礎(chǔ)上來配置底層寄存器來實(shí)現(xiàn)LED燈的點(diǎn)亮,但是,與之前不同的是,在Linux系統(tǒng)中會(huì)存在地址映射的方式,

    2024年02月15日
    瀏覽(24)
  • 全志V3S嵌入式驅(qū)動(dòng)開發(fā)(驅(qū)動(dòng)開發(fā)準(zhǔn)備)

    全志V3S嵌入式驅(qū)動(dòng)開發(fā)(驅(qū)動(dòng)開發(fā)準(zhǔn)備)

    【 聲明:版權(quán)所有,歡迎轉(zhuǎn)載,請(qǐng)勿用于商業(yè)用途。 聯(lián)系信箱:feixiaoxing @163.com】 ? ? ? ? 之前的文章都是教大家怎么搭建環(huán)境、看原理圖、編譯內(nèi)核和根文件系統(tǒng)、做鏡像,直到現(xiàn)在才進(jìn)入驅(qū)動(dòng)開發(fā)的主題。 畢竟整個(gè)專欄的目的,還是希望大家能夠?qū)W會(huì)驅(qū)動(dòng)外部硬件。

    2024年02月13日
    瀏覽(37)
  • 嵌入式:驅(qū)動(dòng)開發(fā) Day4

    嵌入式:驅(qū)動(dòng)開發(fā) Day4

    驅(qū)動(dòng)程序:myled.c 應(yīng)用程序:test.c 頭文件:head.h

    2024年02月09日
    瀏覽(22)
  • 嵌入式Linux驅(qū)動(dòng)開發(fā)之點(diǎn)燈

    嵌入式Linux驅(qū)動(dòng)開發(fā)之點(diǎn)燈

    ? 使用驅(qū)動(dòng)開發(fā)的方式點(diǎn)亮一個(gè)LED燈??纯磧烧哂猩秴^(qū)別不? 首先查看原理圖,看看我們的板子上的LED等接在哪一個(gè)IO口上面。 好了,看原理圖我們知道LED燈接在芯片的GPIO1的第三個(gè)引腳上面,也就是GPIO1_IO03。 先掌握三個(gè)名詞 CCM: Clock Controller Module (時(shí)鐘控制模塊) IOMUXC : I

    2024年02月01日
    瀏覽(28)
  • 嵌入式Linux開發(fā)-USB驅(qū)動(dòng)

    嵌入式Linux開發(fā)-USB驅(qū)動(dòng)

    哥們馬上就要被裁了,總得整理一下技術(shù)方面的積累,準(zhǔn)備開始下一輪的面試和找工作之旅了。。。。 通用串行總線(USB)是主機(jī)和外圍設(shè)備之間的一種連接。 從拓?fù)渖蟻砜?,是一顆由幾個(gè)點(diǎn)對(duì)點(diǎn)的連接構(gòu)建而成的樹。這些連接是連接設(shè)備和集線器(hub)的四線電纜(底線、電源線

    2024年02月20日
    瀏覽(26)
  • 嵌入式驅(qū)動(dòng)開發(fā)需要會(huì)哪些技能?

    嵌入式驅(qū)動(dòng)開發(fā)是指在嵌入式系統(tǒng)中編寫驅(qū)動(dòng)程序,實(shí)現(xiàn)設(shè)備與計(jì)算機(jī)之間的通信。嵌入式驅(qū)動(dòng)開發(fā)是指編寫設(shè)備驅(qū)動(dòng)程序,實(shí)現(xiàn)設(shè)備與計(jì)算機(jī)之間的通信。 以下是一些嵌入式驅(qū)動(dòng)開發(fā)的具體操作方法:? 1)了解硬件設(shè)備結(jié)構(gòu): 在進(jìn)行嵌入式驅(qū)動(dòng)開發(fā)之前,需要對(duì)所使用的硬

    2024年01月25日
    瀏覽(26)
  • 嵌入式Linux驅(qū)動(dòng)開發(fā) 04:基于設(shè)備樹的驅(qū)動(dòng)開發(fā)

    嵌入式Linux驅(qū)動(dòng)開發(fā) 04:基于設(shè)備樹的驅(qū)動(dòng)開發(fā)

    前面文章 《嵌入式Linux驅(qū)動(dòng)開發(fā) 03:平臺(tái)(platform)總線驅(qū)動(dòng)模型》 引入了資源和驅(qū)動(dòng)分離的概念,這篇文章將在前面基礎(chǔ)上更進(jìn)一步,引入設(shè)備樹的概念。 在平臺(tái)總線驅(qū)動(dòng)模型中資源和驅(qū)動(dòng)已經(jīng)從邏輯上和代碼組織上進(jìn)行了分離,但每次調(diào)整資源還是會(huì)涉及到內(nèi)核,所以現(xiàn)

    2024年02月16日
    瀏覽(27)
  • 【嵌入式Linux驅(qū)動(dòng)】驅(qū)動(dòng)開發(fā)調(diào)試相關(guān)的關(guān)系記錄

    【嵌入式Linux驅(qū)動(dòng)】驅(qū)動(dòng)開發(fā)調(diào)試相關(guān)的關(guān)系記錄

    https://www.processon.com/mindmap/64537772b546c76a2f37bd2f

    2024年02月02日
    瀏覽(26)
  • 嵌入式Linux驅(qū)動(dòng)開發(fā)——常見框架梳理

    嵌入式Linux驅(qū)動(dòng)開發(fā)——常見框架梳理

    本文主要介紹了Linux驅(qū)動(dòng)開發(fā)中一些常用的驅(qū)動(dòng)框架,platform、input、iic、spi等,硬件平臺(tái)使用的是正點(diǎn)原子的imx6ull開發(fā)板。 不管什么框架最后都是要追溯到配置IO的電氣屬性和復(fù)用功能 如果要使用外部中斷,設(shè)備樹節(jié)點(diǎn)中還需添加相關(guān)信息,什么邊沿觸發(fā) 1:module_init和mod

    2024年02月15日
    瀏覽(31)
  • 華清遠(yuǎn)見嵌入式學(xué)習(xí)——驅(qū)動(dòng)開發(fā)——作業(yè)1

    華清遠(yuǎn)見嵌入式學(xué)習(xí)——驅(qū)動(dòng)開發(fā)——作業(yè)1

    通過字符設(shè)備驅(qū)動(dòng)分步注冊(cè)過程實(shí)現(xiàn)LED驅(qū)動(dòng)的編寫,編寫應(yīng)用程序測(cè)試,發(fā)布到CSDN

    2024年02月20日
    瀏覽(28)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包