前言
繼續(xù)來點燈~學了一段時間的嵌入式Linux發(fā)現(xiàn)LED程序挺香的。。
從LED程序中我們可以榨取很多知識:基本的驅動框架、驅動的簡單分層、驅動的分層+分離思想、總線設備驅動模型、設備樹等。
這大多都是結合韋老師的教程學的,這篇筆記結合第5個demo來學習、分析:
框圖
LED程序的幾個層次結構圖:
本篇筆記基于第④個圖來分析。
程序分析
關于總線設備驅動模型的理論知識我們在上一篇筆記【Linux筆記】總線設備驅動模型中也有簡單地學習過了。這篇筆記我們來分析、學習程序。
下面分析主要基于上面的框圖4:
應用程序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. 打開文件 */
fd = open(argv[1], O_RDWR);
if (fd == -1)
{
printf("can not open file %s\n", argv[1]);
return -1;
}
/* 3. 寫文件 */
if (0 == strcmp(argv[2], "on"))
{
status = 1;
write(fd, &status, 1);
}
else
{
status = 0;
write(fd, &status, 1);
}
close(fd);
return 0;
}
運行測試命令:
./ledtest /dev/100ask_led0 on
./ledtest /dev/100ask_led0 off
int main(int argc, char **argv)
形式的main函數(shù)相關筆記:main()函數(shù)有哪幾種形式?。
驅動層leddrv.c
這一層主要是放一些通用的驅動操作函數(shù),核心代碼如:
驅動程序入口函數(shù):
open、write函數(shù):
其它代碼:
其中l(wèi)ed的操作結構體如下:
硬件層2:chip_demo_gpio.c
這一層主要是一些寄存器相關的操作,及platform_driver相關。
驅動初始化函數(shù):
probe函數(shù):
platform_driver與platform_device匹配時會執(zhí)行此函數(shù)獲取資源。
led寄存器操作相關的代碼:
/* 寄存器物理地址 */
#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-哪個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))
{
/* 相關寄存器物理地址與虛擬地址之間的映射 */
/* 1、地址映射:時鐘寄存器 */
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時鐘 */
val = readl(CCM_CCGR1); /* 讀出當前CCM_CCGR1配置值 */
val &= ~(3 << 30); /* 清除以前的設置 */
val |= (3 << 30); /* 設置新值 */
writel(val, CCM_CCGR1);
/* 設置GPIO5_IO03的為IO模式 */
writel(5, SW_MUX_GPIO5_IO03);
/* 設置GPIO5_IO03方向為輸出 */
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-哪個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))
{
/* 點燈 */
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相關的代碼。
核心代碼:
Makefile文件
運行測試
首先把編譯生成以下幾個文件上傳到板子里:
board_A_led.ko
chip_demo_gpio.ko
leddrv.ko
ledtest
這里我們使用百問網(wǎng)開發(fā)的100ask_imx6ull_flashing_tool工具來上傳,如:
也可以使用開發(fā)板掛載NFS來上傳這幾個文件,關于NFS可查看往期筆記:【Linux筆記】掛載網(wǎng)絡文件系統(tǒng)
100ask_imx6ull_flashing_tool工具默認把文件上傳到根目錄,我們上傳成功的文件如下:
接下來,使用insmod命令來安裝驅動模塊leddrv.ko、chip_demo_gpio.ko、board_A_led.ko,安裝這幾個模塊是有順序的,需要先安裝leddrv.ko模塊。
假如我們先安裝chip_demo_gpio.ko模塊,就會出現(xiàn)如下提示信息:
提示說明chip_demo_gpio模塊中找不到led_class_create_device等函數(shù),那是因為這幾個函數(shù)是從leddrv模塊中導出來的:
所以需要先安裝leddrv.ko模塊,再安裝chip_demo_gpio.ko模塊。安裝模塊成功的結果如下:
最后,輸入測試命令進行測試:
打印信息表明測試成功、同時板子上的led也相應的亮、滅。
最后
以上就是本次的實驗分享,如有錯誤,歡迎指出!謝謝。
本篇筆記會同步至我的個人博客:https://www.lizhengnian.cn/中,歡迎來訪。
期待您的在看、分享~
往期筆記:
【Linux筆記】pc機_開發(fā)板_ubuntu互ping實驗
【Linux筆記】掛載網(wǎng)絡文件系統(tǒng)
后臺回復:加群。添加ZhengN微信,加入技術交流群
點個贊,證明你還愛我
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!