公司待了一个下午,浑浑噩噩的,看了会android的wifi框架,还是懵懵懂懂的。都怪昨天热的睡不着,又不想开空调,唉,夏天,快过去吧。不过也算有点收获吧。吃了晚饭回到宿舍。想着,上几个实验都是看看串口的输出,没劲,好歹以前玩51,FPGA什么的时候,都是做出效果来的,于是觉得,得干出点实物来啊,好吧,记得51和FPGA是从led灯开始的,那么就。。。。。。。。。
还是先上代码了:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_MAJOR 240
int led_open(struct inode *inode, struct file *filp)
{
unsigned int tmp;
tmp = readl(S3C64XX_GPMCON);
tmp = (tmp & ~(0xffff) | (0x1111)); //set the GPIO output mode
writel(tmp, S3C64XX_GPMCON);
printk("$$$$$$$$$$$led_open$$$$$$$$$\n");
return 0;
}
ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk("$$$$$$$$$$led_read$$$$$$$$$\n");
return count;
}
ssize_t led_write(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
char mbuf[10];
unsigned int tmp;
copy_from_user(mbuf,buf,count);
switch(mbuf[0])
{
case 0:
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x1);
writel(tmp, S3C64XX_GPMDAT);
break;
case 1:
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x1);
writel(tmp, S3C64XX_GPMDAT);
break;
case 2:
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x2);
writel(tmp, S3C64XX_GPMDAT);
break;
case 3:
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x2);
writel(tmp, S3C64XX_GPMDAT);
break;
case 4:
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x4);
writel(tmp, S3C64XX_GPMDAT);
break;
case 5:
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x4);
writel(tmp, S3C64XX_GPMDAT);
break;
case 6:
tmp = readl(S3C64XX_GPMDAT);
tmp |= (0x8);
writel(tmp, S3C64XX_GPMDAT);
break;
case 7:
tmp = readl(S3C64XX_GPMDAT);
tmp &= ~(0x8);
writel(tmp, S3C64XX_GPMDAT);
break;
default:
break;
}
printk("$$$$$$$$$$led_write$$$$$$$$$\n");
return count;
}
int led_release(struct inode *inode, struct file *filp)
{
printk("$$$$$$$$$$led_release$$$$$$$$$\n");
return 0;
}
struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
static int led_init(void)
{
int rc;
printk("Test led dev\n");
rc = register_chrdev(LED_MAJOR, "led", &my_fops);
if(rc < 0)
{
printk("register %s mychar dev error\n", "led");
return -1;
}
printk("$$$$$$$$$ register led dev OK\n");
return 0;
}
static void led_exit(void)
{
unregister_chrdev(LED_MAJOR, "led");
printk("Good Bye!\n");
}
MODULE_LICENSE("GPL");
module_init(led_init);
module_exit(led_exit);
唉,代码是越来越长了,为了实现流水灯,写得搓搓的代码,其实可以不用那么复杂的。既然写复杂了也就懒得改了。其实,流水灯就是控制GPIO口,让GPIO口输出高低电平,记得51是直接P1 = 0xFF之类的。而FPGA的话,verilog也是很简单的led=8’b11111110;嵌入式就是烦,跑系统的东西嘛,总得有个门槛,要不然谁都很容易会了,那么那些嵌入式工程师不是没饭吃了?哈哈哈哈。。。
既然是控制GPIO口,那总得知道是哪个GPIO口吧?看看原理图吧。
是GPM口,对应的,GPM0-GPM4分别是LED1-LED4。接着看看GPIO的一些寄存器吧,
控制寄存器GPMCON,主要流水灯只要设置为输出就好了。所以代码中有写着
tmp = readl(S3C64XX_GPMCON);
tmp = (tmp & ~(0xffff) | (0x1111)); //set the GPIO output mode
writel(tmp, S3C64XX_GPMCON);
先读取,然后设置,然后再写进去。
然后就是控制那个GPIO输出的0、1值了。
就是这个GPMDAT了,对应的每一位就是每一个GPIO口的输出值了。这个是低电平点亮,高电平灭掉的,所以值为1是灭,值为0是亮。知道这些,看着代码,应该很容易理解了。
接着makefile
obj-m :=led.o
然后建个makemod,代码如下
make -C /home/eastmoon/work/linux2.6.28/ M=`pwd` modules
然后只要source makemod就可以编译成led.ko了
万事具备了,那么为了实现驱动,我们还得写应用啊,所以说啊,搞驱动的,也得写应用,要不然,怎么知道你写的驱动好不好用。别人来看你的驱动写应用也太累了。好了,还是上代码吧:
#include
#include
#include
#include
#define DEVICE "/dev/myled"
int main(void)
{
int fd, i;
char buf[10] = {0, 1, 2, 3, 4, 5, 6, 7};
fd = open(DEVICE, O_RDWR);
if(fd < 0)
{
printf("Open /dev/myled file error\n");
return -1;
}
while(1)
{
for(i = 0; i < 8; i += 2)
{
write(fd, &buf[i], 1);
sleep(1);
}
for(i = 7; i > 0; i -= 2)
{
write(fd, &buf[i], 1);
sleep(1);
}
}
close(fd);
return 0;
}
看看驱动,然后再看,应该还是很好理解的,就是个水水的流水灯嘛。
然后makefile
CC = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-gcc
ledapp:ledapp.o
$(CC) -o ledapp ledapp.o
ledapp.o:ledapp.c
$(CC) -c ledapp.c
clean :
rm ledapp.o
终于搞定了,累死了,还好下雷雨了,天气没有下午那么热了。然后就是板子上去看看效果了。
至于怎么把编译好的led.ko 和ledapp放到板子上,方法很多,我是用SD卡的,具体看以前的blog中。
Ok,注册成功了。
设备文件也创建了
看看,myled这个节点也有了,看来离成功不远了
接着跑跑应用看看
一直在写数据,流水灯也出来了。哈哈哈
然后结束流水灯
搞定,今天有点早,好久没下四国了,趁着周末,玩几局。收工,四国开始。。。。。