【Linux筆記】LED驅(qū)動(dòng)實(shí)驗(yàn)(總線(xiàn)設(shè)備驅(qū)動(dòng)模型)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
前言
繼續(xù)來(lái)點(diǎn)燈~(yú)學(xué)了一段時(shí)間的嵌入式Linux發(fā)現(xiàn)LED程序挺香的。。
從LED程序中我們可以榨取很多知識(shí):基本的驅(qū)動(dòng)框架、驅(qū)動(dòng)的簡(jiǎn)單分層、驅(qū)動(dòng)的分層+分離思想、總線(xiàn)設(shè)備驅(qū)動(dòng)模型、設(shè)備樹(shù)等。
這大多都是結(jié)合韋老師的教程學(xué)的,這篇筆記結(jié)合第5個(gè)demo來(lái)學(xué)習(xí)、分析:
框圖
LED程序的幾個(gè)層次結(jié)構(gòu)圖:
本篇筆記基于第④個(gè)圖來(lái)分析。
程序分析
關(guān)于總線(xiàn)設(shè)備驅(qū)動(dòng)模型的理論知識(shí)我們?cè)谏弦黄P記【Linux筆記】總線(xiàn)設(shè)備驅(qū)動(dòng)模型中也有簡(jiǎn)單地學(xué)習(xí)過(guò)了。這篇筆記我們來(lái)分析、學(xué)習(xí)程序。
下面分析主要基于上面的框圖4:
應(yīng)用程序ledtest.c:
int main(int argc, char **argv)
{
int fd;
char status;
/* 1. 判斷參數(shù) */
if (argc != 3)
{
printf("Usage: %s <dev> <on | off>\n", argv[0]);
return -1;
}
/* 2. 打開(kāi)文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
/* 3. 寫(xiě)文件 */
if (0 == strcmp(argv[2], "on"))
{
status = 1;
write(fd, &status, 1);
}
else
{
status = 0;
write(fd, &status, 1);
}
close(fd);
return 0;
}
運(yùn)行測(cè)試命令:
./ledtest /dev/100ask_led0 on
./ledtest /dev/100ask_led0 off
int main(int argc, char **argv)
形式的main函數(shù)相關(guān)筆記:main()函數(shù)有哪幾種形式?。
驅(qū)動(dòng)層leddrv.c
這一層主要是放一些通用的驅(qū)動(dòng)操作函數(shù),核心代碼如:
驅(qū)動(dòng)程序入口函數(shù):
open、write函數(shù):
其它代碼:
其中l(wèi)ed的操作結(jié)構(gòu)體如下:
硬件層2:chip_demo_gpio.c
這一層主要是一些寄存器相關(guān)的操作,及platform_driver相關(guān)。
驅(qū)動(dòng)初始化函數(shù):
probe函數(shù):
platform_driver與platform_device匹配時(shí)會(huì)執(zhí)行此函數(shù)獲取資源。
led寄存器操作相關(guān)的代碼:
/* 寄存器物理地址 */
#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO5_IO03_BASE (0X02290014)
#define GPIO5_DR_BASE (0X020AC000)
#define GPIO5_GDIR_BASE (0X020AC004)
/* 映射后的寄存器虛擬地址指針 */
static void __iomem *CCM_CCGR1;
static void __iomem *SW_MUX_GPIO5_IO03;
static void __iomem *GPIO5_DR;
static void __iomem *GPIO5_GDIR;
/* 初始化LED, which-哪個(gè)LED */
static int board_demo_led_init (int which)
{
int group, pin;
unsigned int val;
group = GROUP(g_ledpins[which]);
pin = PIN(g_ledpins[which]);
printk("init gpio: group %d, pin %d\n", group, pin);
/* 100ask_IMX6uLL_Board LED:GPIO5_3 */
if ((5 == group) && (3 == pin))
{
/* 相關(guān)寄存器物理地址與虛擬地址之間的映射 */
/* 1、地址映射:時(shí)鐘寄存器 */
CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
/* 2、地址映射:模式寄存器 */
SW_MUX_GPIO5_IO03 = ioremap(SW_MUX_GPIO5_IO03_BASE, 4);
/* 3、地址映射:數(shù)據(jù)寄存器 */
GPIO5_DR = ioremap(GPIO5_DR_BASE, 4);
/* 地址映射:方向寄存器 */
GPIO5_GDIR = ioremap(GPIO5_GDIR_BASE, 4);
/* 使能GPIO5時(shí)鐘 */
val = readl(CCM_CCGR1); /* 讀出當(dāng)前CCM_CCGR1配置值 */
val &= ~(3 << 30); /* 清除以前的設(shè)置 */
val |= (3 << 30); /* 設(shè)置新值 */
writel(val, CCM_CCGR1);
/* 設(shè)置GPIO5_IO03的為IO模式 */
writel(5, SW_MUX_GPIO5_IO03);
/* 設(shè)置GPIO5_IO03方向?yàn)檩敵?nbsp;*/
val = readl(GPIO5_GDIR);
val &= ~(1 << 3);
val |= (1 << 3);
writel(val, GPIO5_GDIR);
}
else
{
printk("This is not 100ask_IMX6ULL_Board!\n");
}
return 0;
}
/* 控制LED, which-哪個(gè)LED, status:1-亮,0-滅 */
static int board_demo_led_ctl (int which, char status)
{
int group, pin;
unsigned int val;
group = GROUP(g_ledpins[which]);
pin = PIN(g_ledpins[which]);
printk("init gpio: group %d, pin %d\n", group, pin);
/* 100ask_IMX6uLL_Board LED:GPIO5_3 */
if ((5 == group) && (3 == pin))
{
/* 點(diǎn)燈 */
if (1 == status)
{
printk("<<<<<<<<led on>>>>>>>>>>\n");
val = readl(GPIO5_DR);
val &= ~(1 << 3);
writel(val, GPIO5_DR);
}
/* 滅燈 */
else if (0 == status)
{
printk("<<<<<<<<led off>>>>>>>>>>\n");
val = readl(GPIO5_DR);
val|= (1 << 3);
writel(val, GPIO5_DR);
}
else{}
}
else
{
printk("This is not 100ask_IMX6ULL_Board!\n");
}
return 0;
}
硬件層1:board_A_led
這一層主要是一些資源及platform_device相關(guān)的代碼。
核心代碼:
Makefile文件
運(yùn)行測(cè)試
首先把編譯生成以下幾個(gè)文件上傳到板子里:
board_A_led.ko
chip_demo_gpio.ko
leddrv.ko
ledtest
這里我們使用百問(wèn)網(wǎng)開(kāi)發(fā)的100ask_imx6ull_flashing_tool工具來(lái)上傳,如:
也可以使用開(kāi)發(fā)板掛載NFS來(lái)上傳這幾個(gè)文件,關(guān)于NFS可查看往期筆記:【Linux筆記】掛載網(wǎng)絡(luò)文件系統(tǒng)
100ask_imx6ull_flashing_tool工具默認(rèn)把文件上傳到根目錄,我們上傳成功的文件如下:
接下來(lái),使用insmod命令來(lái)安裝驅(qū)動(dòng)模塊leddrv.ko、chip_demo_gpio.ko、board_A_led.ko,安裝這幾個(gè)模塊是有順序的,需要先安裝leddrv.ko模塊。
假如我們先安裝chip_demo_gpio.ko模塊,就會(huì)出現(xiàn)如下提示信息:
提示說(shuō)明chip_demo_gpio模塊中找不到led_class_create_device等函數(shù),那是因?yàn)檫@幾個(gè)函數(shù)是從leddrv模塊中導(dǎo)出來(lái)的:
所以需要先安裝leddrv.ko模塊,再安裝chip_demo_gpio.ko模塊。安裝模塊成功的結(jié)果如下:
最后,輸入測(cè)試命令進(jìn)行測(cè)試:
打印信息表明測(cè)試成功、同時(shí)板子上的led也相應(yīng)的亮、滅。
最后
以上就是本次的實(shí)驗(yàn)分享,如有錯(cuò)誤,歡迎指出!謝謝。
本篇筆記會(huì)同步至我的個(gè)人博客:https://www.lizhengnian.cn/中,歡迎來(lái)訪。
期待您的在看、分享~
往期筆記:
基于LiteOS的智慧農(nóng)業(yè)案例實(shí)驗(yàn)分享
【Linux筆記】通俗易懂的Linux驅(qū)動(dòng)基礎(chǔ)
【Linux筆記】pc機(jī)_開(kāi)發(fā)板_ubuntu互ping實(shí)驗(yàn)
【Linux筆記】掛載網(wǎng)絡(luò)文件系統(tǒng)
學(xué)習(xí)STM32的一些經(jīng)驗(yàn)分享
后臺(tái)回復(fù):加群。添加ZhengN微信,加入技術(shù)交流群
點(diǎn)個(gè)贊,證明你還愛(ài)我
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!