實驗一:LED燈程序
一、 實驗環境
開發機環境
操作系統:ubuntu 12.04
交叉編譯環境:arm-linux-gcc 4.3.2
6410板子內核源碼:linux-3.0.1
目標板環境:OK6410-A linux-3.0.1
二、 實驗原理
圖1-OK6410LED原理圖
圖2-LED原理圖
從上面的原理圖可以得知,LED與CPU引腳的連接方法如下,低電平點亮。
LED1 -GPM0
LED2 -GPM1
LED3 -GPM2
LED4 -GPM3
通過上面可以得知,需要先將GPM0設置為輸出方式。將相應的寄存器進行配置。然后將GPMDAT寄存器的第0位置0燈亮,置1燈滅。
三、 實驗代碼
1.編寫驅動程序
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h> /* copy_to_user,copy_from_user */
#include <linux/miscdevice.h>
#include <linux/pci.h>
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>
#include <plat/gpio-cfg.h>
#define LED_MAJOR 240
int led_open(struct inode *inode, struct file *filp)
{
unsigned tmp;
tmp = readl(S3C64XX_GPMCON);
tmp = (tmp & ~(0x7U << 1)) | (0x1U);
writel(tmp, S3C64XX_GPMCON);
printk("#########open######\n");
return 0;
}
ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk("#########read######\n");
return count;
}
ssize_t led_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
char wbuf[10];
unsigned tmp;
printk("#########write######\n");
copy_from_user(wbuf, buf, count);
switch (wbuf[0])
{
case 0: //off
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0xfU);
writel(tmp, S3C64XX_GPMDAT);
break;
case 1: //on
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0xfU);
writel(tmp, S3C64XX_GPMDAT);
break;
default:
break;
}
return count;
}
int led_release(struct inode *inode, struct file *filp)
{
printk("#########release######\n");
return 0;
}
struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
int __init led_init(void)
{
int rc;
printk("Test led dev\n");
rc = register_chrdev(LED_MAJOR, "led", &led_fops);
if (rc < 0)
{
printk("register %s char dev error\n", "led");
return -1;
}
printk("ok!\n");
return 0;
}
void __exit led_exit(void)
{
unregister_chrdev(LED_MAJOR, "led");
printk("module exit\n");
return;
}
module_init(led_init);
module_exit(led_exit);
2.編寫Makefile文件
ifneq ($(KERNELRELEASE),)
obj-m := driver_led.o
else
KDIR := /work/linux-3.0.1
all:
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
3.編寫測試文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main (void)
{
int fd;
char buf[10]={0,1,0,1};
fd = open("/dev/my_led",O_RDWR);
if (fd < 0)
{
printf ("Open /dev/my_led file error\n");
return -1;
}
while(1)
{
write(fd,&buf[0],1);
sleep(1);
write(fd,&buf[1],1);
sleep(1);
}
close (fd);
return 0;
}
四、 實驗步驟
1、編譯驅動程序和測試程序
在終端中運行:#make
命令,編譯成功生生下列文件
在終端中運行:#arm-linux-gcc test.c -o test
,編譯成功生成文件
2、將文件拷貝到SD卡
3、將SD卡插入到OK6410開發板中
4、在OK6410終端中運行程序
加載驅動:#insmod sdcard/driver_led.ko
創建設備文件:# mknod /dev/my_led c 240 0
運行測試文件:#./sdcard/test
卸載驅動程序:#rmmod sdcard/driver_led.ko
5、運行結果
此時可以看到OK6410開發板的4個LED燈一直同時點亮,然后熄滅。
6、更改驅動程序里的代碼可實現不同的功能
五、 實驗總結
本次實驗主要是熟悉交叉編譯,測試的步驟,理解驅動程序和測試代碼之間的關系,為后續更復雜的程序開發做准備。理解代碼的實際意義,可以對代碼進行二次開發。在實驗過程中遇到的困難:Makefile文件命名要正確,文件內容格式要正確,注意Tab鍵的使用。