Linux驅動程序入門 三

版權聲明 : 本文爲博主隨手筆記,歡迎評論和轉載。 http://www.javashuo.com/article/p-wdhdndze-u.html html

 

LED驅動程序node

第一步:看懂 PCB 原理圖和 芯片datasheetlinux

第二步:尋找對應 Pin 的寄存器地址shell

 第三步:匹配有效的信息bash

 

下面以 iTOP4412 ARM9開發板爲例 :函數

找出對應的 LED 引腳this

 

 

經過 KP_COL0 和 VDD50_EN 匹配芯片上對應的 Pin :spa

 

 

 

從上圖可知 : KP_COL0 對應在 chip 上的 Pin :GPL2_0  ; VDD50_EN  對應在 chip 上的 Pin :GPK1_1 3d

 

而後經過 chip datasheet 去匹配對應的寄存器 : code

 

 

從上圖可知GPL2對應的個寄存器的功能。可知這些 datasheet 都是英文的,建議志同道合的夥伴們記得去提高一下本身的英語文化水平。

 從匹配的信息來看,須要的是 GPL2_0

GPL_CON 寄存器 :

從上圖可知 GPL2CON 的 Base Address  :0x1100_0000

地址對應的偏移爲:Base Address + 0x1000

重置值爲 : 0x0000_0000

 LED, 那麼則須把 GPL2CON[0]設置成 : 0x1 = Output --->輸出模式

GPL_DAT 寄存器 : 

Description 處要仔細讀, 裏面涉及了對應寄存器的用法。

GPK1_1 配信息的原理同上!!!!

綜述 : 

GPL2_CON      地址爲 : 0x11000100 

GPL_DAT         地址爲:0x11000104

GPK1_CON      地址爲 : 0x11000060 

GPK_DAT         地址爲:0x11000064

 

驅動原理 :就是操做 open read write ioctl close 等函數,因此在 Linux驅動程序入門 二 時說過,學驅動很簡單!

用戶層 open read write ioctl  
file_operation   || || || ||  
驅動層 led_open led_read led_write led_ioctl  

 

 

 

 

 

 用戶層有一個 open 函數,則驅動層有對應的 led_open 函數,二者經過 file_operation結構關聯起來!!!

led 的驅動程序爲 : 

 1 #include <linux/module.h>
 2 #include <linux/kernel.h>
 3 #include <linux/fs.h>
 4 #include <linux/init.h>
 5 #include <linux/delay.h>
 6 #include <asm/uaccess.h>
 7 #include <asm/io.h>
 8 #include <linux/device.h>
 9 
10 int major;
11 
12 volatile unsigned long *gpl2con = NULL;
13 volatile unsigned long *gpl2dat = NULL;
14 
15 volatile unsigned long *gpk1con = NULL;
16 volatile unsigned long *gpk1dat = NULL;
17 
18 static int led_open(struct inode *inode, struct file *file)
19 {
20     /*配置GPL2爲輸出,先清零,再配置*/
21     *gpl2con &= ~0x03;
22     *gpl2con |= 0x01;
23     
24     /*配置GPK1爲輸出,先清零,再配置*/
25     *gpk1con &= ~(0x03<<4);
26     *gpk1con |=  (0x01<<4);
27     return 0;
28 }
29 static int led_write(struct file *filp, 
30         /const char __user *buf, size_t count, loff_t *ppos)
31 {
32     int val;
33     
34     /*從用戶拷貝到內核///copy_to_user()從內核拷貝到用戶*/
35     copy_from_user(&val, buf, count);   
36     if(val == 1)
37     {
38         //點燈
39         *gpl2dat |= 1;
40         //點燈
41         *gpk1dat |= 0x02;        
42     }
43     else
44     {
45         //滅燈
46         *gpl2dat &= ~1;
47         //滅燈
48         *gpk1dat &= ~0x02;
49     }
50     return 0;
51 }
52 static struct file_operations led_fops = {
53     /*這是一個宏,推向編譯環境時自動建立的__this_module*/
54     .owner = THIS_MODULE,           
55     .open = led_open,
56     .write = led_write,
57 };
58 static int led_drv_init(void)
59 {
60     /*註冊驅動程序,告訴內核這個函數來被誰調用*/
61     register_chrdev(0, "first_drv", &first_drv_fops); 
62     
63     gpl2con = (volatile unsigned long *)ioremap(0x11000100, 4);
64     gpl2dat = gpl2con + 1;
65     
66     gpk1con = (volatile unsigned long *)ioremap(0x11000060, 4);
67     gpk1dat = gpk1con + 1;
68 
69     return 0;
70 }
71 static void led_drv_exit(void)
72 {
73     unregister_chrdev(major, "first_drv");
74     device_unregister(firstdrv_class_dev);
75     class_destroy(firstdrv_class);
76     iounmap(gpl2con);
77     iounmap(gpk1con);
78 }
79 
80 module_init(led_drv_init);
81 module_exit(led_drv_exit);
82 
83 MODULE_LICENSE("Dual BSD/GPL");
84 MODULE_AUTHOR("stormeli");
85 MODULE_DESCRIPTION("LEDdriver");

對應的Makefile,即編譯內核爲 : 

#!/bin/bash
obj-m += led_drv.o

KDIR := /home/topeet/Android/Android4.0/iTop4412_Kernel_3.0

PWD ?= $(shell pwd)

all:
    make -C $(KDIR) M=$(PWD) modules

clean:
    rm -rf *.o
    

用戶層程序爲 :  

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

/*
 *firstdrvtest on
 *firstdrvtest off
 */
int main(int argc, char **argv)
{
    int fd;
    int val = 1;
    fd = open("/dev/led", O_RDWR);
    
    if(fd < 0)
    {
        printf("can't open!\n");
    }
    
    if(argc != 2)
    {
        printf("Usage :\n");
        printf("%s <on|off>\n", argv[0]);
        return 0;
    }
    
    if(strcmp(argv[1], "on") == 0)
    {
        val = 1;
    }
    else
    {
        val = 0;
    }
    
    write(fd, &val, 4);
    return 0;
}

編譯過程爲:

1、編譯驅動程序 : 使用 make 指令,獲得 .ko 文件,即模塊驅動文件

 

2、編譯用戶程序 : 使用 arm-none-linux-guneabi- gcc -o led_device led_device.c -static 指令編譯

獲得可執行文件 led_device

 

把編譯獲得的 可執行文件 led_device 和 led_drv.ko 文件拷貝進 iTOP4412 板子裏(可以使用的方法有 U盤拷貝, nfs協議傳輸,tftp協議傳輸)

 

板子上的操做:

加載內核模塊的指令 : insmod xxx.ko

查看內核模塊的指令:lsmod

卸載內核模塊的指令:rmmod xxx

 

經過 insmod xxx.ko 加載內核模塊, 而後 lsmod 查詢,是否加載成功, 再使用 cat /proc/device 查看分配的 主設備號 跟 次設備號「此關於設備文件的建立」

「驅動匹配得有 設備文件『由用戶層可知建立 /dev/led 文件跟驅動文件

建立設備文件的指令爲 : mknod /dev/led c 主設備號 次設備號             c「表明是字符 character 設備驅動」

最後執行用戶可執行文件 ./led_device 

 

 

可知 led_drv 主設備號爲 248, 次設備號爲 0 

 

 

板子 LED 點亮

 

相關文章
相關標籤/搜索