• 和菜鸟一起学OK6410之Led字符驱动


            公司待了一个下午,浑浑噩噩的,看了会androidwifi框架,还是懵懵懂懂的。都怪昨天热的睡不着,又不想开空调,唉,夏天,快过去吧。不过也算有点收获吧。吃了晚饭回到宿舍。想着,上几个实验都是看看串口的输出,没劲,好歹以前玩51FPGA什么的时候,都是做出效果来的,于是觉得,得干出点实物来啊,好吧,记得51FPGA是从led灯开始的,那么就。。。。。。。。。

             还是先上代码了:

     

    #include <linux/module.h>
    
    #include <linux/kernel.h>
    
    #include <linux/fs.h>
    
    #include <linux/init.h>
    
    #include <linux/miscdevice.h>
    
    #include <linux/delay.h>
    
    #include <asm/uaccess.h>
    
    #include <linux/device.h>
    
    #include <linux/cdev.h>
    
    #include <asm/irq.h>
    
    #include <mach/gpio.h>
    
    #include <plat/regs-gpio.h>
    
    #include <plat/gpio-cfg.h>
    
    #include <mach/hardware.h>
    
    #include <linux/io.h>
    
     
    
    #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输出的01值了。

            就是这个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 <stdio.h>
    
    #include <sys/types.h>
    
    #include <sys/stat.h>
    
    #include <fcntl.h>
    
     
    
    #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这个节点也有了,看来离成功不远了

            接着跑跑应用看看

            一直在写数据,流水灯也出来了。哈哈哈

     

     

            然后结束流水灯

            搞定,今天有点早,好久没下四国了,趁着周末,玩几局。收工,四国开始。。。。。

  • 相关阅读:
    SQL 操作结果集 -并集、差集、交集、结果集排序
    MongoDB系列四:解决secondary的读操作
    org.apache.hadoop.ipc.RemoteException: User: root is not allowed to impersonate root
    hive 中窗口函数row_number,rank,dense_ran,ntile分析函数的用法
    FormData上传文件同时附带其他参数
    Hive删除分区
    Hive日期格式转换用法
    HIVE 不支持group by 别名
    ODS与EDW的区别
    hive数据类型转换、字符串函数、条件判断
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300091.html
Copyright © 2020-2023  润新知