本節介紹如何利用板載的led和linux的核心定時器實現乙個簡單的流水燈的驅動,所使用的開發板是tq2440,核心版本2.6.30.4。
程式比較簡單,也沒涉及到什麼機制,直接上**了!關於定時器的使用模板可以參考<
驅動程式:
#include#include#include#include#include#include#include#include#include#include#include#include#define led_major 244
#define led_on 0
#define led_off 1
#define led1_pin s3c2410_gpb5
#define led2_pin s3c2410_gpb6
#define led3_pin s3c2410_gpb7
#define led4_pin s3c2410_gpb8
static unsigned long led_major = led_major;
struct led_dev
;struct led_dev *led_devp;
void led_control(int led_no)
}//定時器處理函式
static void sec_timer_handler(unsigned long arg)
else
num = atomic_read(&led_devp->led_no);
led_control(num);
atomic_inc(&led_devp->sec_counter);
num = atomic_read(&led_devp->sec_counter);
printk(kern_info "sec_count:%d\n",num); }
static int led_open(struct inode *inode,struct file *filp)
static int led_release(struct inode *inode, struct file *filp)
static ssize_t led_read(struct file *filp, char __user *buf,
size_t size, loff_t *ppos)
else }
static const struct file_operations led_fops =
;static void led_setup_cdev(struct led_dev *dev, int index)
}static int led_init(void)
if(result<0)
led_devp =(struct led_dev*)kmalloc(sizeof(struct led_dev),gfp_kernel);
if(!led_devp)
memset(led_devp, 0 ,sizeof(struct led_dev));
led_setup_cdev(led_devp,0);
/*配置io口*/
s3c2410_gpio_cfgpin(led1_pin,s3c2410_gpio_output);
s3c2410_gpio_cfgpin(led2_pin,s3c2410_gpio_output);
s3c2410_gpio_cfgpin(led3_pin,s3c2410_gpio_output);
s3c2410_gpio_cfgpin(led4_pin,s3c2410_gpio_output);
/*初始化io電平*/
s3c2410_gpio_setpin(led1_pin,led_off);
s3c2410_gpio_setpin(led2_pin,led_off);
s3c2410_gpio_setpin(led3_pin,led_off);
s3c2410_gpio_setpin(led4_pin,led_off);
return 0;
}static void led_exit(void)
module_license("gpl");
module_author("vanbreaker");
module_init(led_init);
module_exit(led_exit);
在該例程中,由於控制led亮滅的部分放在了定時器處理函式中,因此led_read函式沒有實際作用,這樣的話應用程式就簡單一些;另一種選擇是將該控制部分放在應用程式中完成,不過還得新增乙個iocntl函式,這是我之前的做法。
控制s3c2440的io口可以使用核心中已經提供的操作函式,在arch\arm\plat-s3c24xx\gpio.c中,需要包含標頭檔案相關的io口定義在arch\arm\s3c2410\include\mach\regs-gpio.h中,需要包含標頭檔案
可以分析下s3c2410_gpio_setpin()這個函式
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
#define s3c24xx_gpio_base(x) s3c2410_gpio_base(x)
#define s3c2410_gpio_base(pin) ((((pin) & ~31) >> 1) + s3c24xx_va_gpio)
s3c2410_gpio_base(pin)用來計算pin所在的gpio組的虛擬位址,s3c24xx_va_gpio是io的虛擬基址,我們分析一下 ((pin)&~31)>>1是什麼意思。首先我們得了解傳入的引數究竟是什麼形式的,以s3c2410_gpa0的定義為例:
#define s3c2410_gpa0 s3c2410_gpiono(s3c2410_gpio_banka, 0)
#define s3c2410_gpiono(bank,offset) ((bank) + (offset))
#define s3c2410_gpio_banka (32*0)
#define s3c2410_gpio_bankb (32*1)
#define s3c2410_gpio_bankc (32*2)
#define s3c2410_gpio_bankd (32*3)
#define s3c2410_gpio_banke (32*4)
#define s3c2410_gpio_bankf (32*5)
#define s3c2410_gpio_bankg (32*6)
#define s3c2410_gpio_bankh (32*7)
可以看到bank都有32位,因此傳入的pin引數實際就是離起始bank的位偏移,s3c2410_gpa0為0,s3c2410_gpb0為32.而每個gpio組都有4個暫存器,乙個gpio組所佔的記憶體大小就有4*32/8=32/2=32>>1=16個位元組大小,由此可見 (pin)&~31是先將低位遮蔽,計算出pin所在的gpio組,再將結果右移一位就是計算位元組的偏移,如gpa的偏移為0,gpb的偏移為0x10,gpc的偏移為0x20……最後將偏移加上io的虛擬基址就得到了該組io口的虛擬位址了。
計算組內偏移很簡單:
#define s3c2410_gpio_offset(pin) ((pin) & 31)
應用測試程式:
#include#include#include#include#includeint main()
else
}
將編譯好的模組和應用程式移到開發板上進行載入和執行,即可以看到流水燈的效果
第乙個linux 驅動
以前看過很多次linux相關的資料,一直沒親自動手寫,今天通過半天努力,終於完成了乙個自己的linux小驅動 hello.c include include module license dual bsd gpl static int hello init void static void hell...
Linux驅動修煉之道 流水燈
module.h包含可裝載模組需要的大量符號和函式定義,包含init.h的目的是指定初始化和清除 struct file是在中定義的。註冊字元裝置使用 int register chrdev unsigned int major,const char name,struct file operati...
linux下的第乙個驅動
前段時間忙著學python語言,其實,學得不咋滴 從習慣的底層程式設計換到上層程式設計,不用考慮記憶體的東西,還不用申請變數,總感覺不太習慣,相信久了就會好了,不過已經基本可以看懂程式了,語言確實簡單。留著以後慢慢琢磨吧。現在需要學習linux下的驅動了,一直都想學,上學期學習迷茫期中,有個機會去廣...