基于ARM_contexA9 led驅(qū)動(dòng)編程
掃描二維碼
隨時(shí)隨地手機(jī)看文章
關(guān)于友善之臂出的這款contexA9開發(fā)板,目前在網(wǎng)絡(luò)上的資源較少,特別是內(nèi)核的,非常之少,鑒于這種情況,我將會(huì)寫一個(gè)系列的驅(qū)動(dòng)來(lái)做關(guān)于tiny4412這款板子開發(fā)的總結(jié)。
簡(jiǎn)單介紹一下:
Tiny4412是一款高性能的四核Cortex-A9核心板,由廣州友善之臂設(shè)計(jì)、生產(chǎn)和發(fā)行銷售。它采用三星Exynos4412作為主處理器,運(yùn)行主頻可高達(dá)1.5GHz,Exynos4412內(nèi)部集成了Mali-400 MP高性能圖形引擎,支持3D圖形流暢運(yùn)行,并可播放1080P大尺寸高清視頻。三星旗艦智能手機(jī)Galaxy S3即是采用此CPU設(shè)計(jì)。
我用的是普通版.也就是只有一個(gè)串口的.但是核心板是一樣的。
好了,介紹完畢,前面的文章我們已經(jīng)說(shuō)過(guò)了如何編寫一個(gè)字符設(shè)備的驅(qū)動(dòng)程序,這里就不再繼續(xù)扯字符驅(qū)動(dòng)怎么寫,非常簡(jiǎn)單了,看看就懂了。
我們進(jìn)入整題,今天,我們需要實(shí)現(xiàn)一個(gè)LED的驅(qū)動(dòng)程序。在友善之臂的核心板上,有4顆LED燈,如何編寫一個(gè)驅(qū)動(dòng)程序,讓它亮起來(lái),首先我們來(lái)看看核心板:
LED燈就位于右上角,第一個(gè)和第二個(gè)都是電源指示燈,我們不需要管它,我們只管后面那4個(gè)LED燈。
如何編寫?
1、首先找到板子的原理圖,找到對(duì)應(yīng)的引腳。
2、接著打開數(shù)據(jù)手冊(cè),找到對(duì)應(yīng)的寄存器。
3、開始編寫LED驅(qū)動(dòng)程序
4、編寫makefile
5、插入模塊insmod xxx.ko
6、查詢主設(shè)備號(hào) cat /proc/devices
7、創(chuàng)建設(shè)備節(jié)點(diǎn) mknod /dev/xxx c x x
8、執(zhí)行應(yīng)用程序app
對(duì)應(yīng)的原理圖:
從這里我們可以得出一個(gè)結(jié)論,LED燈是低電平點(diǎn)亮的,也就是往對(duì)應(yīng)的端口里寫0,LED燈就亮了。從最下面一幅圖可以知道,我們要找的寄存器是GPIO的GPM4開頭的這個(gè)寄存器,現(xiàn)在我們進(jìn)入查數(shù)據(jù)手冊(cè)的階段.
查手冊(cè):
我們找到手冊(cè)的第288頁(yè)GPIO章節(jié)的GPMCON這里:
這是我們要配置端口的模式的IO口,端口有以上的一些狀態(tài),在這里我們只考慮輸出,也就是只要配置Output那一項(xiàng)就可以了。
我們要配的寄存器有GPM4CON[0],GPM4CON[1],GPM4CON[2],GPM4CON[3],這四位,分別配置成output輸出模式.
接下來(lái)再看一個(gè)GPM4DAT,這個(gè)是端口的狀態(tài)寄存器,對(duì)狀態(tài)寄存器就是寫0或者寫1,那么LED就被驅(qū)動(dòng)了,我們來(lái)看看:
好了,寄存器我們已經(jīng)找到了,接下來(lái),可以進(jìn)入寫代碼的階段了:
首先編寫LED驅(qū)動(dòng)程序:
[cpp] view plain copy print?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
//這個(gè)是設(shè)備的名稱,也就是對(duì)應(yīng)在/dev/test-dev
#define DEV_NAME "test-dev"
//LED燈IO口的地址,也就是剛剛我們?cè)谏厦娴男酒謨?cè)看到的Address
#define GPM4COM 0x110002E0
//定義配置模式的指針變量
volatile unsigned long *led_config = NULL ;
//定義配置狀態(tài)的指針變量
volatile unsigned long *led_dat = NULL ;
//open方法,對(duì)LED燈進(jìn)行初始化
int led_open(struct inode *inode, struct file *filp)
{
printk("led_open\n");//上層程序?qū)ED進(jìn)行Open操作的時(shí)候會(huì)執(zhí)行這個(gè)函數(shù)
//先對(duì)LED的端口進(jìn)行清0操作
*led_config &= ~(0xffff);
//將4個(gè)IO口16位都設(shè)置為Output輸出狀態(tài)
*led_config |= (0x1111);
return 0;
}
//write方法
int led_write(struct file *filp , const char __user *buf , size_t count , loff_t *f_pos)
{
int val ;
//注意,這里是在內(nèi)核中進(jìn)行操作,我們需要使用copy_from_user這個(gè)函數(shù)將用戶態(tài)的內(nèi)容拷貝到內(nèi)核態(tài)
copy_from_user(&val , buf , count);
//以下就是當(dāng)val是哪個(gè)值的時(shí)候,led就執(zhí)行相應(yīng)的操作,這里不多說(shuō)
switch(val)
{
case 0 :
//對(duì)狀態(tài)寄存器進(jìn)行賦值,以下雷同
printk(KERN_EMERG"led1_on\n");
*led_dat &= ~0x1 ;
break ;
case 1 :
printk(KERN_EMERG"led2_on\n");
*led_dat &= ~0x2 ;
break ;
case 2 :
printk(KERN_EMERG"led3_on\n");
*led_dat &= ~0x4 ;
break ;
case 3 :
printk(KERN_EMERG"led4_on\n");
*led_dat &= ~0x8 ;
break ;
case 4 :
printk(KERN_EMERG"ledall_on\n");
*led_dat &= ~0xf ;
break ;
case 5 :
printk(KERN_EMERG"ledall_off\n");
*led_dat |= 0xf ;
break ;
}
}
//close方法
int led_close(struct inode *inode, struct file *filp)
{
printk("led_close\n");
*led_dat |= 0xf ; //全滅,因?yàn)楦唠娖绞菧绲模?xf ----> 1111
return 0;
}
//用ioctl這個(gè)方法也可以實(shí)現(xiàn)LED的操作的,自己去實(shí)現(xiàn)吧
#if 0
long led_ioctl(struct file *filp, unsigned int request, unsigned long arg)
{
switch(request)
{
case 0:
printk(KERN_EMERG"led1 on\n");
*led_dat &=~0x1 ;
break;
case 1:
printk(KERN_EMERG"led2 on\n");
*led_dat &=~0x2 ;
break;
case 3:
printk(KERN_EMERG"led3 on\n");
*led_dat &=~0xf ;
break;
case 4:
printk(KERN_EMERG"led4 on\n");
*led_dat &=~0x8 ;
break ;
default :
*led_dat |= 0xf ;
}
}
#endif
//對(duì)方法進(jìn)行初始化
struct file_operations fops = {
.owner = THIS_MODULE ,
.open = led_open,
.release = led_close,
// .unlocked_ioctl = led_ioctl,
.write = led_write,
};
//主設(shè)備號(hào)
int major ;
//啟動(dòng)函數(shù)
static __init int test_init(void)
{
printk("led_init\n");
major = register_chrdev(major, DEV_NAME, &fops);
led_config = (volatile unsigned long *)ioremap(GPM4COM , 16);
led_dat = led_config + 1 ;
return 0;
}
//注銷函數(shù)
static __exit void test_exit(void)
{
printk("led_exit\n");
unregister_chrdev(major, DEV_NAME);
iounmap(led_config);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Y.X.YANG");
MODULE_VERSION("2016.1.15");</span>
以上就是led這個(gè)設(shè)備驅(qū)動(dòng)的編寫框架。看不懂的可以去學(xué)學(xué)linux內(nèi)核設(shè)備驅(qū)動(dòng)再來(lái)看就很簡(jiǎn)單了。其實(shí)跟單片機(jī)的編程差不了多少的,只不過(guò)內(nèi)核驅(qū)動(dòng)是按照框架來(lái)編寫的,有所驅(qū)動(dòng)就在這里。
驅(qū)動(dòng)程序編寫完了,接下來(lái)我們編寫上層應(yīng)用層的程序:
[cpp] view plain copy print?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
int fd;
int val = 0 ;
//打開對(duì)應(yīng)的設(shè)備
fd = open("/dev/test-dev",O_RDWR) ;
if(-1 == fd)
{
printf("open fair!\n");
return -1 ;
}
while(1){
val = 0 ;
//寫write方法就會(huì)調(diào)用到驅(qū)動(dòng)程序的led_write
//最后我們能看到的結(jié)果是led燈做流水燈的實(shí)現(xiàn),然后全滅,再周而復(fù)始
write(fd , &val , 4);
sleep(1);
val = 1 ;
write(fd , &val , 4);
sleep(1);
val = 2 ;
write(fd , &val , 4);
sleep(1);
val = 3 ;
write(fd , &val , 4);
sleep(1);
val = 5 ;
write(fd , &val , 4);
sleep(1);
}
return 0;
}</span>
好了,程序已經(jīng)寫完了,我們來(lái)看看makefile怎么寫.
[cpp] view plain copy print?
#將你所寫的驅(qū)動(dòng)程序編譯成模塊形式
obj-m += leds.o
#你需要的文件系統(tǒng)
ROOTFS = /disk/A9/filesystem
#你需要的內(nèi)核
KERNEL = /disk/A9/linux-3.5/
#模塊編譯
all:
make -C $(KERNEL) M=`pwd` modules
#模塊清除
clean:
make -C $(KERNEL) M=`pwd` clean
rm -rf my_led
#模塊更新
install:
make -C $(KERNEL) M=`pwd` modules_install INSTALL_MOD_PATH=$(ROOTFS)
#編譯上層app應(yīng)用程序
my_led:
arm-linux-gcc my_led.c -o my_led</span>
好了,所有的一切都編寫完成,我們來(lái)看看接下來(lái)的操作:
1、先編譯整個(gè)工程:執(zhí)行make命令
2、編譯app
3、啟動(dòng)minicom,打開開發(fā)板的電源,開發(fā)板bootload開始啟動(dòng)
4、開發(fā)板內(nèi)核啟動(dòng)
5、進(jìn)入文件系統(tǒng),執(zhí)行insmod插入模塊和顯示插入后的模塊的操作
6、看看主設(shè)備號(hào)
從這里可以看到,我們的設(shè)備test-dev的主設(shè)備號(hào)是250
所以我們創(chuàng)建設(shè)備節(jié)點(diǎn) : mknod /dev/test-dev c 250 0 ,創(chuàng)建完成后
7、執(zhí)行app應(yīng)用程序
在這里,我們可以看到程序開始跑起來(lái)了,我們來(lái)看看開發(fā)板上的led是怎么變化的:
好,寫了好多,也整理了不少東西出來(lái)了,有點(diǎn)累了,以后還要慢慢寫.....今天就到這里...
免責(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)系我們,謝謝!