1. 程式人生 > >zedboard上首個驅動實踐——Led

zedboard上首個驅動實踐——Led

lock ESS 設置 gpio 內核 AI 進入 上位機 dev

//  led驅動  *myled.c*
//
頭文件 #include<linux/module.h> //最基本的文件,支持動態添加和卸載模塊 #include<linux/kernel.h> //內核相關文件 #include<linux/fs.h> //包括文件操作相關struct的定義(struct file_operations和struct inode),MINOR、MAJOR的頭文件 #include<linux/init.h> //初始化頭文件 #include<linux/delay.h> //延時頭文件 #include<asm/uaccess.h> //包括copy_to_user、copy_from_user等內核訪問用戶進程內存地址的函數定義
#include<asm/irq.h> //與處理器相關的中斷 #include<asm/io.h> //包括ioremap、iowrite等內核訪問IO內存等函數的定義 #include<asm/arch/regs-gpio.h> //與處理器相關的IO口操作 #include<asm/hardware.h> //與處理器相關的硬件 #include<linux/device.h> //包括device、class等結構的定義 #include<linux/slab.h> //包括kcalloc、kzalloc內存分配函數的定義 #include<linux/semaphore.h> //使用信號量必須的頭文件
#include<linux/spinlock.h> //自旋鎖 //定義變量 #define DEVICE "myled" static struct class * myled_class; static struct class * myled_class_dev; int major; volatile unsigned long * led_reg = NULL; //open函數 //這個函數一般包括硬件的相關設置、初始化等,比如GPIO的屬性。不過zedboard的gpio在硬件定制中已經設置屬性,故此函數不需要添加 static int myled_open(struct inode * inode,struct
file * file) {   printk("Open LED_DRV\n");   return 0; } //write函數 static ssize_t myled_write(struct file * file,const char _ _user * buf,size_t count,loff_t * ppos) {   int val;   printk("Open MY_LED_write\n");   copy_from_user(&val,buf,count);//從用戶空間賦值數據到內核空間   * led_reg = val;   return 0; } //file_operations結構體 static struct file_operations myled_fops={   .owner = THIS_MODULE,   .open = myled_open,   .write = myled_write, };//註意這個分號不能少 //驅動初始化函數 static int myled_init(void) {   major=register_chrdev(0,"myled",&myled_fops);   myled_class = class_create(THIS_MODULE,"myled");   myled_class_dev = device_create(myled_class,NULL,MKDEV(major,0),NULL,"myled");   led_reg = (volatile unsigned long *)ioremap(0x6a000000,32);   * led_reg = 0x55;   printk("Open LED_init\n");   return 0; } //驅動卸載函數 static int myled_exit(void) {   unregister_chrdev(major,"myled");   device_unregister(myled_class_dev);   class_destroy(myled_class);   iounmap(led_reg);   printk("MY_LED_exit\n");   return 0; } //驅動加載和卸載入口函數 module_init(myled_init); module_exit(meled_exit); MODULE_LICENSE("GPL");

驅動程序myled.c編寫完成之後,需要對其進行編譯,為了方便編譯程序,需要編寫一個Makefile文件

Makefile文件
KERN_SRC = /zedboard/linux-digilent-3.6-digilent-13.01
boj-m:=myled.o
all:
  make -C $ (KERN_SRC) M=pwd modules
clean:
  make -C $ (KERN_SRC) M=pwd=clean

//在zedboard目錄下新建driver文件夾,並將以上myled.c和Makefile文件放到該文件夾
mkdir driver

//進入driver目錄,編譯驅動,完成後會生成myled.ko驅動模塊文件
cd driver
mak ARCH=arm  CROSS_COMPILE=arm-xilinx-linux-gnueabi- 

//驅動設計完成後,需要將其添加到設備樹中
//打開設備樹文件,並添加以下大號斜黑體內容
gedit arch/arm/boot/dts/digileng-zed.dts
spi-speed-hz = <4000000>;
spi-sclk-gpio = <&ps7_gpio_0 59 0 >;
spi-sdin-gpio = <&ps7_gpio_0 60 0 >;
};
myled{
compatible =  "dglnt,myled-1.00.a";
reg = <0x6a000000 0x10000>;
      };
   };      
};

//重新生成設備樹dtb文件
 ./scripts/dtc/dtc -I dts -O dtb -o .../devicetree.dtb   arch/arm/boot/dts/digilent-zed.dts

//將生成的設備樹文件復制到SD卡的boot分區,接下來就可以進行加載驅動測試

簡單測試驅動:
1.將SD卡插入PC,在ubuntu下降生成的myled.ko文件復制到SD卡的rootfs分區的home目錄,然後啟動zedboard;
2.啟動linaro後,在串口終端裏進入home目錄,並使用insmod命令加載驅動程序;
 cd /home/
insmod myled.ko
3.如果要卸載驅動,執行以下命令;
rmmod myled

應用程序調用驅動測試:
1.首先要編寫一個簡單的上位機測試程序ledtest.c,實現對LED的控制。
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>

int main(int argc,char * * argv)
{
  int fd;
  int val = 0xAA;
  fd = open("/dev/myled",O_PDWR);
  if(fd<0)
  {
    printf("error,can‘t open\n");
    return 0;
  }
  write(fd,&val,4);
  return 0;
}

其中fd=open就是打開myled這個設備,val是輸出到led的值,最後通過write將其值寫入到led寄存器

2.將ledtest.c復制到driver目錄下,並對其編譯
arm-xilinx-linux-gnueabi-gcc   -o   ledtest   ledtest.c
3.編譯完成後,同樣將生成的ledtest可執行文件復制到SD卡的rootfs分區的home目錄下
4.啟動zedboard,在串口下執行如下命令即完成了驅動測試
cd   /home
insmod myled.ko
./ledtest




zedboard上首個驅動實踐——Led