S3C2410——LED燈實驗

一、S3C2410輸入/輸出的原理

Linux主要有字元設備、塊設備和網路設備3類驅動程式,我們一般編寫的驅動都是字元設備驅動程式。

二、程式部分

編寫程式控制3個LED燈,程式碼分為2個部分:控制LED的驅動程式、調用驅動程式的應用程式

1. 控制LED的驅動程式

(1) 常量和結構體的定義:

//定義設備名字,分配設備號時使用
#define DEVICE_NAME "UP-LED"
//定義次設備號
#define LEDRAW_MINOR 0
//定義埠C配置暫存器
#define GPCCON (*(volatile unsigned int *)S3C2410_GPCCON)
//定義埠C數據暫存器
#define GPCDAT (*(volatile unsigned int *)S3C2410_GPCDAT)
//定義字元設備結構體
struct cdev *mycdev;
//定義設備號變數,由主設備號和次設備號組成
dev_t devno;
//文件操作結構體定義使用設備的文件操作
static struct file_operations led_fops = {
    owner: THIS_MODULE,
    ioctl: led_ioctl, //只定義ioctl一個
};

(2) 驅動載入時的程式碼:

//定義載入驅動時執行的函數
module_init(led_init);
static int __init led_init(void)
{
    int result,err;
    //分配字元設備號
    result=alloc_chrdev_region(&devno,LEDRAW_MINOR,1,DEVICE_NAME);
    if(result < 0)
        printk(KERN_ERR "can't get device number \n");
    else
        printk("get device number\n");
    //設置GPC5、GPC6、GPC7為輸出狀態
    GPCCON=(GPCCON|0x5400)&0xffff57ff;
    //分配字元設備結構體
    mycdev = cdev_alloc();
    //初始化結構體,關聯文件操作
    cdev_init(mycdev,&led_fops);
    //將字元設備驅動註冊到內核
    err=cdev_add(mycdev,devno,1);
    if (err < 0)
        printk(KERN_ERR "can't add led device");
    return 0;
}

(3) 定義控制LED的文件操作:

static int led_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 
unsigned long arg)
{    switch(cmd){
        case 1:
            if(arg==1) GPCDAT=GPCDAT&0xffffffdf;//第一個led亮
            if(arg==0) GPCDAT=GPCDAT|0x20;      //第一個led滅
            break;
        case 2:
            if(arg==1) GPCDAT=GPCDAT&0xffffffbf;//第二個led亮
            if(arg==0) GPCDAT=GPCDAT|0x40;      //第二個led滅
            break;
        case 3:
            if(arg==1) GPCDAT=GPCDAT&0xffffff7f;//第三個led亮
            if(arg==0) GPCDAT=GPCDAT|0x80;      //第三個led滅
            break;
        default:
            printk("error cmd number\n");break;
      }
      return 0;
}

2. 調用驅動程式的應用程式

//相關頭文件的引用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{   //相關常量變數定義
    int on;
    int led_number;
    int fd;
    //讀入命令行參數
    sscanf(argv[1], 「%d」, &led_number);
    sscanf(argv[2],"%d", &on);
    //打開設備文件
    fd = open("/dev/leds", 0);
    if (fd < 0) { 
        perror("open device /dev/leds");
        exit(1);
    }
    //根據參數操作設備
    ioctl(fd, led_number, on);
    usleep(1000);
    //關閉設備文件
    close(fd);
    return 0;
}

3. makefile文件

ARGET = test_led
CROSS_COMPILE = arm-linux
CC            = $(CROSS_COMPILE)gcc
ifeq ($(KERNELRELEASE),)
  KERNELDIR ?= /root/kernel/linux-2.6.24.4
  PWD := $(shell pwd)
all:   $(TARGET) modules
$(TARGET):
      $(CC) -o $(TARGET) $(TARGET).c
modules:
      $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
      rm -rf *.o *~ *.ko Module.symvers *.mod.c $(TARGET)
.PHONY:modules clean
else
obj-m := led.o
endif

三、實驗過程

在主機(虛擬機)上進行交叉編譯:

根據makefile編譯得到可執行文件test_led。

在主機上輸入下面兩行程式碼,將下面的兩個文件上傳到tftp伺服器

cp led.ko /tftpboot/
cp test_led /tftpboot/

利用xshell超級終端,在目標機上接收led.ko和test_led文件,並且載入驅動程式

手動創建led設備節點,並給test_led文件可執行許可權

實驗現象: