nanopi s2 驱动开发心得(一)

来源:互联网 发布:淘宝图片水印大小 编辑:程序博客网 时间:2024/05/16 18:37

nanopi s2自带系统为3.4.39,处理器为s5p4418,自带gcc 版本是4.9.2。系统为Debin 4.9.2-10

(一)根据wiki上的说明,交叉编译器需要用Friendlyarm在git库中的arm-cortexa9-linux-gnuebihf-4.9.3.tar.xz,但下载下来后,发现centos系统不能识别xz格式的归档文件,就下载xz-4.999.9beta.tar.bz2文件解压后利用xz命令解压交叉编译器的压缩包,得到arm-cortexa9-linux-gnuebihf-4.9.3.tar文件,然后tar -xvf arm-cortexa9-linux-gnuebihf-4.9.3.tar -C

/opt/FriendlyARM/toolschain, 然后将编译器的路径加入到PATH中,vim ~/.bash_profile 最后加入export PATH=/opt/FriendlyARM/toolschain/4.9.3/bin:$PATH,然后#source ~/.bash_profile让环境变量起作用(当然也可以修改其他文件设置环境变量),利用echo $PATH 命令查看环境变量是否包含了…4.9.3/bin,但此时用file 命令发现其中的程序都是64位的,不能在我的32位的centos上运行。又重新在网上下载了gcc-linaro-arm-linux-gnueabihf-4.9-2014.07_linux.tar.xz,关键是要是gnueabihf格式的,中间的命名没有关系,然后解压设置环境变量。至此,我的centos系统上同时安装了4.5.3和4.9.1两个版本的交叉编译器,查看各自的bin文件夹4.5.3中arm-linux-gcc 实际上是arm-none-linux-gnueabi-gcc的链接文件;4.9.1中没有arm-linux-gcc,只有arm-linux-gnueabihf-gcc,它是arm-linux-gnueabihf-gcc-4.9.1的链接文件。这样就不存在两个版本的冲突,arm-linux-gcc对应4.5.3,arm-linux-gnueabihf-gcc对应4.9.1。这样交叉编译器搞定。

(二)在https://github.com/friendlyarm/linux-3.4.y.git的nanopi2-lollipop-mrl分支上下载内核源代码linux-3.4.y-nanopi2-lollipop-mr1.zip,解压后的文件夹linux-3.4.y-nanopi2-lollipop-mr1随便放在自己方便的文件夹中开始编译内核,Friendlyarm公司已经针对nanopi s2的相关硬件把系统进行了移植和配置,默认配置在./arch/arm/configs/中的nanopi2_linux_defconfig文件,cp ./arch/arm/configs/nanopi2_linux_defconfig  ./.config,将默认配置设置为系统主目前下的配置,这时再打开make menuconfig时其中的选项就都选好了,如system type->ARM system type选项选定的是SLsiAP S5P4418D/Q,platform board类型已选定为NANOPI2…。然后需要设置主目录inux-3.4.y-nanopi2-lollipop-mr1下的Makefile文件,交叉编译改为CROSS_COMPILE    ?= arm-linux-gnueabihf-,保存后,此时直接make zImage就可以编译成功了。

(三)编制驱动程序源文件drv_frame_misc.c(采用的是杂项设备注册方法),放在./drivers/char/目录中,修改该目录中的Kconfig文件,这个文件不像tiny6410中的,已经有了类似的CONFIG项,有明确的depends on CPU_S3C6410项可以借鉴。我也不知道在nanopi s2 中应该depends on什么,查看了主目录中的.config文件# CPU feature项中有CONFIG_CPU_S5P4418_SMP_ISR=y项,那就让我的驱动依赖于CPU_S5P4418_SMP_ISR的配置吧,为我的驱动增加如下内容(default状态为m,就不需要再去menuconfig中点选了):

然后配置./drivers/char/目录中的makefile文件,在文件尾部增加obj-$(CONFIG_CUMTZD_DRIVER)    +=drv_frame_misc.o,保存后就可以make modules编译驱动了。

(四)驱动编译成功后,得到drv_frame_misc.ko,可以通过modinfo drv_frame_misc.ko命令查看其VERMAGIC 版本号,通过scureCRT rz加载到nanopi s2开发板上,insmod drv_frame_misc.ko命令得到错误结果如下

但是没有细节,通过命令dmesg |tail,显示上述错误的细节如下:

即版本号不对应。这时得返回虚拟机,修改linux-3.4.y-nanopi2-lollipop-mr1/include/linux/vermagic.h部分如下:

修改linux-3.4.y-nanopi2-lollipop-mr1/makefile开头如下:

重新make zImage、make modules出来的驱动就可以在nanopi开发板上insmod了。在虚拟机上arm-linux-gnueabihf-gcc交叉编译的测试程序也在开发板能正确执行。搞定!

驱动程序drv_frame_misc.c源码:

ifndef __KERNEL__#define __KERNEL__#endif#ifndef MODULE#define MODULE#endif#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>   /* printk() */#include <linux/fs.h>       /* everything... */#include <linux/errno.h>    /* error codes */#include <linux/types.h>    /* size_t */#include <linux/poll.h>     /* COPY_TO_USER */#include <linux/ioctl.h>#include <linux/miscdevice.h>#define DEVICE_NAME     "drv_f"static char drv_buf[8];static ssize_t  demo_write(struct file *filp,const char *buffer, size_t count, loff_t *ppos){        count = copy_from_user(drv_buf , buffer, 1);        drv_buf[0]++;        printk("user write data to driver\n");        return count;}static ssize_t  demo_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){        count = copy_to_user(buffer, (const void*)drv_buf,1);        printk("user read data from driver\n");        return count;}static long demo_ioctl(struct file *file, unsigned int cmd, unsigned long arg){        printk("ioctl runing\n");        switch(cmd){                case 1:printk("<0>""runing command 1 \n");break;                case 2:printk("<0>""runing command 2 \n");break;                default:                        printk("<0>""error cmd number\n");break;        }        return 0;}static int demo_open(struct inode *inode, struct file *file){        printk("device open sucess!\n");        return 0;}static int  demo_release(struct inode *inode, struct file *filp){        printk("device release\n");        return 0;}static struct file_operations demo_fops = {        .write=         demo_write,        .read=          demo_read,        .unlocked_ioctl=demo_ioctl,        .open=          demo_open,        .release=       demo_release,};static struct miscdevice misc = {        .minor = MISC_DYNAMIC_MINOR,        .name  = "drv_fam",        .fops  = &demo_fops,};static int __init demo_init(void){    int  result;    result = misc_register(&misc);    if (result < 0) {        printk("<0>""demo init error\n");        return result;    }    printk(DEVICE_NAME " initialized\n");    return 0;}static void __exit  demo_exit(void){    misc_deregister(&misc);    printk(DEVICE_NAME " unloaded\n");}module_init(demo_init);module_exit(demo_exit);MODULE_LICENSE("GPL");


测试程序源码:
//================drv_f_test.c==================//

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
int main()
{
        int fd;
        char buf=5;
        fd=open("/dev/drv_fam",O_RDWR);
        if(fd < 0){
                printf("####DEMO  device open fail####\n");
                return (-1);

        }
        printf("write to driver ,buf=%d\n",buf);
        write(fd,&buf,1);
        read(fd,&buf,1);
        printf("read from driver,buf=%d\n",buf);
        sleep(3);
        ioctl(fd,1,NULL);
        ioctl(fd,4,NULL);
        close(fd);
        return 0;

}

原创粉丝点击