精华内容
下载资源
问答
  • 开发环境:Widows下Vivado 2016.2 、 SDK2016.2 、 Linux机器:debin 目的:操作板载的LED灯LD9,受PS部分的MIO7控制 linux设备驱动大体分三种:字符设备、块设备、网络设备。字符设备指可以以字节为单位访问内存...

    硬件平台:XCZ7020 CLG484-1 完全适配Zedboard
    开发环境:Widows下Vivado 2016.2 、 SDK2016.2 、 Linux机器:debin
    目的:操作板载的LED灯LD9,受PS部分的MIO7控制
    linux设备驱动大体分三种:字符设备、块设备、网络设备。字符设备指可以以字节为单位访问内存,块设备只能以数据块进行访问,比如NandFlash等,网络设备就指以太网等网卡驱动了。
    在原始的设备驱动编写风格来看,主要是搭建框架,然后填充框架,填充的内容就和裸机的驱动文件一样了,所以设备驱动的核心还是设备的裸机程序。
    目前我用的设备驱动方案大体框架如下:

    #include <linux/init.h>
    #include <linux/module.h>
    MODULE_LICENSE("Dual BSD/GPL");
    static int hello_init(void)
    {
    printk("Module init complete!\nHello, Linux Driver!\n");
    return 0;
    }
    static void hello_exit(void)
    {
    printk("Module exit!\nBye, Linux Driver!\n");
    }
    module_init(hello_init);
    module_exit(hello_exit);
    MODULE_AUTHOR("Cuter@ChinaAET");
    MODULE_DESCRIPTION("HelloLinuxDriver");
    MODULE_ALIAS("It's only a test");
    

    模块刚开始加载的时候执行module_init,从而执行hello_init;模块退出的时候执行module_exit从而执行hello_exit。Linux一切皆文件,包括对应用程序对驱动的操作也都是读文件,写文件等等,所以除了模块的初始化和模块的退出,设备驱动还需要为应用程序提供读写文件的功能,这些接口的提供是通过file_operations结构体来实现的。

    static struct file_operations gpio_drv_fops = {
      .owner  =   THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
      .open   =   gpio_open,     
      .write  =   gpio_write,      
    };
    

    Gpio_open和gpio_write就是驱动中具体的实现函数,填充完结构体后,通过对注册字符设备将此结构体传递给内核,从而构建了系统对驱动的读写操作,注册是在模块的初始化中实现的,除了注册设备,为了在目标板中加载模块方便还需自动注册类与设备。
    除了注册字符设备,在init函数中最重要的操作就是内存映射。通过MMU,将设备的物理地址映射为虚拟地址,用户可以对系统的操作均为虚拟地址。下面给出全部代码。

    #include <linux/init.h>
    #include <linux/platform_device.h>
    #include <linux/module.h>
    #include <linux/miscdevice.h>
    #include <linux/ioport.h>
    #include <linux/of.h>
    #include <linux/fs.h>
    #include <asm/io.h>
    #include <asm/uaccess.h>
    
    #define DEVICE_NAME         "first_gpio"
    
    #define MY_GPIO_BASE_ADDR    0xe000a000 //Modify the address to your peripheral
    #define XGPIOPS_DIRM_OFFSET  0x00000204U  /* Direction Mode Register, RW */
    #define XGPIOPS_DATA_LSW_OFFSET  0x00000000U
    #define XGPIOPS_DATA_0_OFFSET  0x00000040U
    
    
    MODULE_AUTHOR("Xilinx XUP");
    MODULE_DESCRIPTION("LED moudle dirver");
    MODULE_VERSION("v1.0");
    MODULE_LICENSE("GPL");
    
    static int gpio_driver_major;
    static struct class* gpio_driver_class = NULL;
    static struct device* gpio_driver_device = NULL;
    
    volatile unsigned long *Gpio_DIR = NULL;
    volatile unsigned long *Gpio_EN = NULL;
    volatile unsigned long *Gpio_DATA = NULL;
    //volatile unsigned long *MIO_PIN_7 = NULL;
    volatile unsigned long *DATA = NULL;
    volatile unsigned long *CLK= NULL;
    
    
    static int gpio_open(struct inode * inode , struct file * filp)
    {
      printk("first_drv_open\n");
      //13 12 11 10 9 8 7 6 5 4 3 2 1 0 
      //1  1   0 1  1 0 0 0 0 0 0 0 0 0
      //*MIO_PIN_7 = 0x00003600;
      //*Gpio_DIR|= ((u32)1 << (u32)7); //output,pin7
      //*Gpio_EN|= ((u32)1 << (u32)7);//enable output
    
      iowrite32(0x80,Gpio_DIR);
      iowrite32(0x80,Gpio_EN);
      printk("GPIO_DIR_ADDR %x DATA %x \n",Gpio_DIR,ioread32(Gpio_DIR));
      printk("GPIO_EN_ADDR %x DATA %x \n",Gpio_EN,ioread32(Gpio_EN));
      printk("CLK_ADDR %x DATA %x \n",CLK,ioread32(CLK));
      return 0;
    }
    
    static ssize_t gpio_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
        int val;
    
        printk("first_drv_write\n");
    
        copy_from_user(&val, buf, count); //    copy_to_user();
    
        if (val == 1)
        {
            // 点灯
            *Gpio_DATA=0xff7f0080; //high 16 is mask  low 16 is data ,pin7
            //*DATA = 0x00;
        printk("GPIO_DATA_ADDR %x DATA %x \n",Gpio_DATA,ioread32(Gpio_DATA));
        }
        else
        {
            // 灭灯
            *Gpio_DATA=0xff7f0000;
            //*DATA = 0xffffffff;
        printk("GPIO_DATA_ADDR %x DATA %x \n",Gpio_DATA,ioread32(Gpio_DATA));
        }
        return 0;
    }
    
    static struct file_operations gpio_drv_fops = {
        .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open   =   gpio_open,     
        .write  =   gpio_write,    
    };
    
    int major;
    static int __init gpio_drv_init(void)
    {
        printk("first_drv_init\n");
        major = register_chrdev(0, "first_gpio", &gpio_drv_fops); // 注册, 告诉内核
        if (major < 0){
            printk("failed to register device.\n");
            return -1;
        }
        gpio_driver_class = class_create(THIS_MODULE, "firstgpio");
          if (IS_ERR(gpio_driver_class)){
            printk("failed to create pwm moudle class.\n");
            unregister_chrdev(major, "first_gpio");
            return -1;
        }
        gpio_driver_device = device_create(gpio_driver_class, NULL, MKDEV(major, 0), NULL, "first_gpio"); /* /dev/first_gpio */;
        if (IS_ERR(gpio_driver_device)){
            printk("failed to create device .\n");
            unregister_chrdev(major, "first_gpio");
            return -1;
        }
        Gpio_DIR = (volatile unsigned long *)ioremap(MY_GPIO_BASE_ADDR+XGPIOPS_DIRM_OFFSET, 16);
        Gpio_EN = Gpio_DIR+1;
        Gpio_DATA = (volatile unsigned long *)ioremap(MY_GPIO_BASE_ADDR+XGPIOPS_DATA_LSW_OFFSET,4);
        CLK = (volatile unsigned long *)ioremap(0XF800012C,4);
        //MIO_PIN_7 = (volatile unsigned long *)ioremap(0xF800071C,4);
        //DATA = (volatile unsigned long *)ioremap(MY_GPIO_BASE_ADDR+XGPIOPS_DATA_0_OFFSET,4);
        iowrite32(0x01ec044d,CLK);//时钟使能
        return 0;
    }
    static void __exit gpio_drv_exit(void)
    {
        printk("Exit gpio module.\n");
    
        device_destroy(gpio_driver_class, MKDEV(major, 0));
        class_unregister(gpio_driver_class);
        class_destroy(gpio_driver_class);
        unregister_chrdev(major, "first_gpio");
        printk("gpio module exit.\n");
        /*
        unregister_chrdev(major, "first_gpio"); // 卸载
    
        class_device_unregister(gpio_driver_device);
        class_destroy(gpio_driver_class);
        */
        iounmap(Gpio_DIR);
        iounmap(Gpio_DATA);
        iounmap(CLK);
        //iounmap(MIO_PIN_7);
        //iounmap(DATA);
    }
    module_init(gpio_drv_init);
    module_exit(gpio_drv_exit);
    

    代码中有调试过程做的注释,下面给出测试文件代码

    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    /* firstdrvtest on
      * firstdrvtest off
      */
    int main(int argc, char **argv)
    {
        int fd;
        int val = 1;
        fd = open("/dev/xyz", O_RDWR);
        if (fd < 0)
        {
            printf("can't open!\n");
        }
        if (argc != 2)
        {
            printf("Usage :\n");
            printf("%s <on|off>\n", argv[0]);
            return 0;
        }
    
        if (strcmp(argv[1], "on") == 0)
        {
            val  = 1;
        }
        else
        {
            val = 0;
        }
    
        write(fd, &val, 4);
        return 0;
    }
    

    和韦东山教程中的测试文件一致,整体的驱动编写过程也和他的教程一致,可以参考韦东山的教学视频。

    一点感悟:1、设备驱动不好调试,可以先将裸机程序调试好,再进行设备驱动的包装。2、在进行某个某块编程的时候如果遇到问题,细致查看数据手册等官方资料,比如这次遇到的问题就是没有对GPIO时钟使能,从而无法操作GPIO寄存器。3、在这次设备驱动开发中,Uboot的操作提供了很大帮助,包括直接查看某个地址寄存器的值md,以及直接在某个地址寄存器写值mm等等。

    展开全文
  • zynq linux驱动之传统开发

    千次阅读 2018-11-12 13:43:25
    PC:Windows 10 虚拟机:ubuntu 16.04 vivado:2017.04 ...-------------------------------------------------- --------------------传说中的分割线------------------------- ...zynq linux驱动之使用设备树开发

    PC:Windows 10

    虚拟机:ubuntu 16.04

    vivado:2017.04

    PetaLinux:2017.04

    开发板:黑金AX7010

    根文件系统:debian8

    -------------------------------------------------- --------------------传说中的分割线------------------------- -------------------------------------------------- ------

    新建vivado工程

    配置PS部分:

    过程略.....

    添加AXI GPIO,改名为leds

    配置AXI GPIO数据方向和位宽:

    执行这两步:

    打开顶层文件找到刚才添加的LED的名字:

    根据顶层文件里找到的引脚名字添加约束文件:

    执行生成位文件

    漫长的等待...........................................

    导入SDK,找到AXI GPIO的基地址:

    把这个文件夹拷贝到Ubuntu的的里:

    使用petalinux编译fsbl,u-boot,kernel,设备树文件(这里设备树文件单独拿出来编译成dtb文件,为下一章做准备)

    过程略.....

    用的PetaLinux制作BOOT.BIN文件,将BOOT.BIN,image.ub,system.dtb文件拷贝到SD卡的胖分区里(这里没有用的PetaLinux生成的根文件系统,用的是debian8)

    开发板上电,查看一下系统版本(4.9.0)

    在的的PetaLinux的工程目录下 

    find -name "kernel"

    进入这个目录

    发现这个貌似就是内核的源码,用VIM打开的Makefile文件查看一下

    确实是4.9的内核

    然后把这个里面的所有文件全部拷贝出去,我这里是拷贝到〜/ work / kernel / linux-4.9里

    cd arch/arm/configs
    
    ls

    确认有xilinx_zynq_defconfig文件

    cd -

    回到内核目录

    用VIM打开的Makefile文件

    找到ARCH和CROSS_COMPILE,大概是在255行

    修改

    ARCH = arm
    
    CROSS_COMPILE = arm-linux-gnueabihf-

    PS: 这里是  gnu  不是  gun

    PS: 这里是  gnu  不是  gun

    PS: 这里是  gnu  不是  gun

    保存退出

    make xilinx_zynq_defconfig

    make -j8

    (我这里CPU是8核的)

    等待.....

    编译完成.....其实这个不是重点......

    接下来切入重点,来看驱动,按照传统方法来写

    先来看驱动:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <asm/io.h>
    #include <linux/init.h>
    #include <linux/platform_device.h>
    #include <linux/miscdevice.h>
    #include <linux/ioport.h>
    #include <linux/of.h>
    #include <linux/uaccess.h>
    #include <linux/delay.h>
    
    
    //  定义设备文件名
    #define DEVICE_NAME "leds"
    
    #define LEDS_BASE_ADDR		(0x41200000)
    
    
    typedef struct{
    	volatile unsigned int ODR;
    }LEDS_T;
    
    LEDS_T* leds;
    
    
    
    static int leds_drv_open(struct inode *Inode, struct file *File)
    {
    	leds->ODR = 0xf;
    	return 0;
    }
    
    
    static ssize_t leds_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
    {
    	return 0;
    }
    
    static ssize_t leds_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
    {
    	unsigned int ret = 0;
    	unsigned int tmp_val;
    	
    	ret = copy_from_user(&tmp_val, buf, count);
    	
    	leds->ODR = (~tmp_val) & 0xf;
    	
    	return ret;
    }
    
    //  描述与设备文件触发的事件对应的回调函数指针
    static struct file_operations dev_fops =
    { 
    	.owner = THIS_MODULE, 
    	.open = leds_drv_open,
    	.read = leds_drv_read, 
    	.write = leds_drv_write,
    };
    
    //  描述设备文件的信息   
    static struct miscdevice misc =
    { 
    	.minor = MISC_DYNAMIC_MINOR, 
    	.name = DEVICE_NAME, 
    	.fops = &dev_fops 
    };
    
    
    //  初始化Linux驱动
    static int __init leds_drv_init(void)
    {
    	int ret; 
    
    	leds = ioremap(LEDS_BASE_ADDR, sizeof(LEDS_T));
    
    	//  建立设备文件
    	ret = misc_register(&misc);
    	//  输出日志信息
    	if(ret)
    	{
    		printk("leds_drv_init faiitrt!\n");
    	}
    	else
    	{
    		printk("leds_drv_init success!\n");
    	}
    
    
    	return ret;
    }
    
    // 卸载Linux驱动
    static void __exit leds_drv_exit(void)
    {
    	iounmap(leds);
    
    	//  删除设备文件  
    	misc_deregister(&misc);
    
    	//  输出日志信息
    	printk("leds_drv_exit success!\n");
    } 
    
    //  注册初始化Linux驱动的函数
    module_init( leds_drv_init);
    //  注册卸载Linux驱动的函数
    module_exit( leds_drv_exit);
    
    
    
    MODULE_LICENSE("Dual BSD/GPL");
    
    

    Makefile文件:

    export ARCH=arm
    
    KERN_DIR = /home/zynq/work/kernel/linux-4.9 
    
    
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules
    
    
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    
    obj-m  += leds_drv.o
    
    
    

    执行一下

    make

    开发板挂接一下NFS文件系统,然后加载驱动

    编写一个测试程序:

    #include <stdio.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    
    int main(int argc, char** argv)
    {
            int fd;
            fd = open("/dev/leds", O_RDWR);
            if(fd < 0)
            {
                    printf("fd = %d open fialed!\n", fd);
            }
    
            unsigned int leds = 0;
    
            while(1)
            {
    				write(fd, &leds, 4);
    				
    				leds++;
    				leds %= 0xf;
                    sleep(1);
            }
    
            close(fd);
    
            return 0;
    }
    

    编译一下

    arm-linux-gnueabihf-gcc -o leds leds.c

    换到开发板执行./leds

    就能看到4个LED做加法了

     

     

    下一篇:zynq linux驱动之使用设备树开发

    展开全文
  • zynq linux驱动之使用设备树开发

    千次阅读 2018-11-12 16:03:01
    zynq linux驱动之传统开发 基础上,实现用设备树开发驱动: 首先回到的的PetaLinux的工程目录下: find -name "system-top.dts" cd ./components/plnx_workspace/device-tree/device-tree-...

    PC:Windows 10

    虚拟机:ubuntu 16.04

    vivado:2017.04

    PetaLinux:2017.04

    开发板:黑金AX7010

    根文件系统:debian8

    -------------------------------------------------- --------------------传说中的分割线------------------------- -------------------------------------------------- ------

    在  zynq linux驱动之传统开发   基础上,实现用设备树开发驱动:

    首先回到的的PetaLinux的工程目录下:

    find -name "system-top.dts"

    cd ./components/plnx_workspace/device-tree/device-tree-generation/

    进入该目录 

    ls

    首先打开系统top.dts看一下

    发现包涵了一个系统user.dtsi

    回到工程根目录,然后查找一下系统user.dtsi

    cd -
    find -name "system-user.dtsi"

    直接打开./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi编辑

    /include/ "system-conf.dtsi"
    / {
            amba_pl: amba_pl{
                    #address-cells = <1>;
                    #size-cells = <1>;
                    compatible = "simple-bus";
                    ranges;
                    leds: leds@41200000{
                            compatible = "hello,leds";
                            reg = <0x41200000 0x1>;
                    };
            };
    
    };
    

    使用的的PetaLinux编译一下工程

    petalinux-build

    编译完成后回到开发板

    挂接NFS文件系统

    把生成的system.dts文件拷贝到SD的fat分区里

    过程略....

    重启开发板

    接下来编写驱动:

    #include <linux/module.h>
    #include <linux/platform_device.h>
    #include <linux/types.h>
    #include <linux/err.h>
    #include <linux/io.h>
    #include <linux/device.h>
    #include <linux/cdev.h>
    #include <linux/of.h>
    #include <linux/delay.h>
    
    #include <linux/dma-mapping.h>
    
    #include <linux/pm.h>
    #include <linux/fs.h>
    #include <linux/slab.h>
    #include <linux/gfp.h>
    #include <linux/mm.h>
    #include <linux/dma-buf.h>
    #include <linux/string.h>
    #include <linux/uaccess.h>
    #include <linux/dmaengine.h>
    #include <linux/completion.h>
    #include <linux/wait.h>
    #include <linux/init.h>
    
    #include <linux/sched.h>
    #include <linux/pagemap.h>
    #include <linux/errno.h>	/* error codes */
    #include <linux/clk.h>
    #include <linux/interrupt.h>
    #include <linux/vmalloc.h>
    
    #include <linux/moduleparam.h>
    #include <linux/miscdevice.h>
    #include <linux/ioport.h>
    #include <linux/notifier.h>
    #include <linux/init.h>
    #include <linux/pci.h>
    
    
    //  定义设备文件名
    #define DEVICE_NAME "leds_drv"
    
    
    
    
    //
    static char 			devname[16];
    static int 				major;
    static int             	mijor;
    static struct class*	cls;
    static void __iomem*	base_address;	
    static resource_size_t  remap_size;  
    static int	            irq;
    static struct device*	dev;           
    
    //
    
    
    
    typedef struct{
    	volatile unsigned int ODR;
    }LEDS_T;
    
    LEDS_T* leds;
    
    
    static int leds_drv_open(struct inode *Inode, struct file *File)
    {
    	leds->ODR = 0xf;
    	return 0;
    }
    
    
    static ssize_t leds_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
    {
    	return 0;
    }
    
    static ssize_t leds_drv_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
    {
    	unsigned int ret = 0;
    	unsigned int tmp_val;
    	
    	ret = copy_from_user(&tmp_val, buf, count);
    	
    	leds->ODR = (~tmp_val) & 0xf;
    	
    	return ret;
    }
    
    
    //  描述与设备文件触发的事件对应的回调函数指针
    static struct file_operations dev_fops =
    { 
    	.owner = THIS_MODULE, 
    	.open = leds_drv_open,
    	.read = leds_drv_read, 
    	.write = leds_drv_write,
    };
    
    
    static int leds_drv_probe(struct platform_device *pdev)
    {
    	struct resource 	*res;
    	struct device *tmp_dev;
    	
    	memset(devname,0,16);
    	strcpy(devname, DEVICE_NAME);
    	
    	major = register_chrdev(0, devname, &dev_fops);
    	
    	cls = class_create(THIS_MODULE, devname);
    	mijor = 0;
    	
    	tmp_dev = device_create(cls, &pdev->dev, MKDEV(major, mijor), NULL, devname);
    	if (IS_ERR(tmp_dev)) {
    		class_destroy(cls);
    		unregister_chrdev(major, devname);
    		return 0;
    	}
    	
    
    
    	//获取资源
    	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    	if(res == NULL)
    	{
    		printk(KERN_ALERT "leds_drv_probe res error!\n");
    		return -ENOENT;
    	}
    
    	
    	base_address = devm_ioremap_resource(&pdev->dev, res);
    	if (IS_ERR(base_address))
    		return PTR_ERR(base_address);
    
    	printk("base_address = 0x%08x\n", (unsigned int)base_address);
    
    
    	remap_size = resource_size(res);
    	printk("remap_size = 0x%08x\n", remap_size);
    
    
    	dev = &pdev->dev;
    
    
    	//保存dev数据
    	//platform_set_drvdata(pdev, &xxx);	
    
    	
    	leds = (LEDS_T*)base_address;
    	
    	return 0;
    }
    
    static int leds_drv_remove(struct platform_device *pdev)
    {
    	device_destroy(cls, MKDEV(major, mijor));	
    	class_destroy(cls);
    	unregister_chrdev(major, devname);
    	devm_iounmap(&pdev->dev, base_address);
    	return 0;
    }
    
    static int leds_drv_suspend(struct device *dev)
    {
    
    	return 0;
    }
    
    static int leds_drv_resume(struct device *dev)
    {
     
    	return 0;
    }
    
    static const struct dev_pm_ops leds_drv_pm_ops = {
    	.suspend = leds_drv_suspend,
    	.resume  = leds_drv_resume,
    };
    
    
    
    static const struct of_device_id leds_drv_of_match[] = {
    	{.compatible = "hello,leds" },
    	{ }
    };
    MODULE_DEVICE_TABLE(of, leds_drv_of_match);
    
    
    static struct platform_driver leds_drv_driver = {
    	.probe = leds_drv_probe,
    	.remove	= leds_drv_remove,
    	.driver = {
    		.owner   		= THIS_MODULE,
    		.name	 		= "leds@41200000",
    		.pm    			= &leds_drv_pm_ops,
    		.of_match_table	= leds_drv_of_match,		
    	},
    };
    
    module_platform_driver(leds_drv_driver);
    
    
    MODULE_LICENSE("GPL v2");
    
    
    
    

    Makefile文件:

    export ARCH=arm
    
    KERN_DIR = /home/zynq/work/kernel/linux-4.9 
    
    
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules
    
    
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    
    obj-m  += leds_drv.o
    
    
    

    执行一下

    make

    换到开发板,加载驱动:

    编写测试程序:

    #include <stdio.h>
    #include <sys/ioctl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    
    
    int main(int argc, char** argv)
    {
            int fd;
            fd = open("/dev/leds_drv", O_RDWR);
            if(fd < 0)
            {
                    printf("fd = %d open fialed!\n", fd);
            }
    
            unsigned int leds = 0;
    
            while(1)
            {
                                    write(fd, &leds, 4);
    
                                    leds++;
                                    leds %= 0xf;
                                    sleep(1);
            }
    
            close(fd);
    
            return 0;
    }
    

    编译测试程序:

    arm-linux-gnueabihf-gcc -o leds leds.c

    最后回到开发板

    执行./leds

    又一次看到4个led做加法了

     

     

     

     

     

    上一篇:zynq linux驱动之传统开发

    下一篇:zynq linux驱动之PL-PS中断

    展开全文
  • 《领航者ZYNQLinux驱动开发指南_V1.3.pdf》非常好的正点原子zynq的linux驱动资料,值得拥有,希望对你的工作学习有所帮助。
  • 1、 硬件配置 在vivado中选择启用ps端的can控制器,如下图 设置can总线的主频   2、 devicetree配置 在devicetree中需要增加can的配置信息,如下: ... compatible= "xlnx,zynq-can-1.0";

    1、  硬件配置

    在vivado中选择启用ps端的can控制器,如下图


    设置can总线的主频

     

    2、  devicetree配置

    在devicetree中需要增加can的配置信息,如下:

    can@e0008000 {
                                compatible= "xlnx,zynq-can-1.0";
                                status= "okay";
                                clocks= <0x1 0x13 0x1 0x24>;
                                clock-names= "ref_clk", "aper_clk";
                                reg = <0xe00080000x1000>;
                                interrupts= <0x0 0x1c 0x4>;
                                interrupt-parent= <0x3>;
                                tx-fifo-depth= <0x40>;
                                rx-fifo-depth= <0x40>;
    };


    实际场景中只使用了can0,故devicetree中只配置can0即可。

     

    3、  kernel配置

    在kernel中需要增加can驱动的支持




    编译内核即可。

     

    4、  测试

    加载镜像后,通过ifconfig –a能够看到can0的打印信息,如下:


    设置can0的波特率,这里设置的是100k

    >ip link set can0 type can bitrate100000

    启用can0

    >ip link set can0 up

    显示can0状态信息

    >ip -d -s link show can0


    可以通过Cantest测试工具连接开发板进行发送包测试


    选择与开发板can总线相同速率的波特率100k


    发送报文测试,发送成功


    开发板上RX有相应的计数

    开发板使用cansend函数进行数据发送



    收发正常,至此测试完成。

     

    5、  相关函数

     

    ifconfig -a

    可以查到当前can网络can0 can1,包括收发包数量、是否有错误等等

     

    //ip link set can0 type can--help

    ip link set can0 up type canbitrate 800000

    设置can0的波特率为800kbps,CAN网络波特率最大值为1Mbps

     

    ip link set can0 up type canbitrate 800000 loopback on

    设置回环模式,自发自收,用于测试是硬件是否正常,loopback不一定支持

     

    ip link set can0 down

    关闭can0 网络

     

    cansend can0 0x11 0x22 0x33 0x440x55 0x66 0x77 0x88

    发送默认ID为0x1的can标准帧,数据为0x11 22 33 44 55 66 77 88

    每次最大8个byte

     

    cansend can0 -i 0x800 0x11 0x220x33 0x44 0x55 0x66 0x77 0x88 -e

    -e 表示扩展帧,CAN_ID最大29bit,标准帧CAN_ID最大11bit

    -i表示CAN_ID

     

    cansend can0 -i 0x02 0x11 0x12--loop=20

    --loop 表示发送20个包

     

    candump can0

    接收CAN0数据

     

    附:Xilinx官网上can操作命令

    Usage For CAN

    1. Set bit-timing
    Can supports bitrates upto 1Mb/s. Xilinx CAN h/w and driver supports these bitrates
    Note: Triple sampling is not supported by Xilinx CAN H/W.
    $ ./ip link set can0 type can bitrate 200000
    or
    $ ./canconfig can0 bitrate 200000

    2. Bring up the device
    $ ./ip link set can0 up
    or
    $ ./canconfig can0 start

    3. Bring down the device
    $ ./ip link set can0 down
    or
    $ ./canconfig can0 stop

    4. Transmit and receive packetswith standard id number
    $ ./cansend can0 -i 0x14 <bytes>
    $ ./candump can0

    5. Transmit and receive packetswith extended id number (--loop argument here)
    $ ./cansend can0 -i 0x333 <bytes>
    $ ./candump can0

    6. Loopback mode
    $ ./canconfig can0 ctrlmode loopback on

    7. Checking link state (checkingbitrate/errors/packets)
    $ ./ip -d -s link show can0

    8. Checking net device state
    $ ifconfig can0

    9. Getting statistics via proc
    $ cat /proc/net/can/stats

    10. Socket CAN core uses severalfilter lists to deliver received CAN frames to CAN protocol modules. These receivelists, their filters and the count of filter matches can be checked in theappropriate receive list. All entries contain the device and a protocol moduleidentifier:
    $ cat /proc/net/can/rcvlist_all
    rcvlist_all - list for unfiltered entries (no filter operations)
    rcvlist_eff - list for single extended frame (EFF) entries
    rcvlist_err - list for error message frames masks
    rcvlist_fil - list for mask/value filters
    rcvlist_inv - list for mask/value filters (inverse semantic)
    rcvlist_sff - list for single standard frame (SFF) entries

    展开全文
  • 虚拟机软件版本:VMware14.1.1 Linux系统版本:ubuntu-...此工程是在《ZYNQ 7000 Linux工程开发》基础上进行的。 一、创建helloworld驱动 进入上次建立好的linux工程中,命令如下: cd test_project 创建hellowor...
  • 领航者ZYNQLinux开发指南 V1.2 本书我们讲解Linux,而Linux开发可以分为底层驱动开发和应用开发,本书以领航者ZYNQ为硬件平台,从实现到驱动,从底层到应用的讲解linux开发。
  •   裸奔的驱动已经满足不了更高应用范围需求了,本篇开始更新几篇赶鸭子上架的zynq Linux应用层的驱动开发(基于准备篇)。再加上由于项目的时间紧张关系(重点是有些人不信邪不得不满足的需求),将基于裸板中关于...
  • zynq自定义PL IP核linux驱动开发流程

    千次阅读 2019-10-29 17:13:25
    概述 zynq开发主要分为两个阶段: 1)硬件逻辑开发阶段:该过程与传统的fpga 软核cpu(microblaze)开发类似,在vivado中进行。...软件开发又分为裸板应用程序开发,以及带操作系统(通常是linux系统)...
  •   串口( UART)是一种非常常见的外设, 串口在嵌入式开发领域当中一般作为一种调试手段,通过串口将调试信息打印出来,或者通过串口发送指令给主机端进行处理;当然除了作为基本的调试手段之外,还可以通过串口与...
  • 先不谈如何实现用户空间的零拷贝DMA传输,光是Linux环境下的DMA传输就已经感觉比较棘手,一方面是对Linux了解不够深入,另一方面则是Linux在相关的使用说明方面的确没有比较好的官方支持。   
  •   Linux内核中有一套GPIO框架,管理和控制芯片上的GPIO管教,包括配置输入输出,配置电平高低(输出)和获取电平高低(输入),中断管理。只需要通过读取/sys/class/gpio/gpioN/value的值来获取中断。当然也不是...
  • 前面我们讲到了SPI的接口标准,以及SPI的工作模式,那么知道这些其实就可以进行SPI驱动的开发了,但是我们这里讲的是linux驱动开发,那么是不是掌握了SPI接口的一些知识就可以进行linux驱动开发呢?当然不是,linux...
  • Zynq-Linux移植学习笔记之14-RapidIO驱动开发 ...在对zynq进行linux驱动开发时,除了需要针对zynq内ARM自带的控制器适配驱动外,还需要对zynq PL部分的IP核进行驱动开发。对于ARM来说,zyn
  • 它还用于探测驱动程序,因此仅在存在该节点时才激活驱动程序。该节点具有以下属性:   compatible-这必须是字符串“ xlnx,axidma-chrdev”。这用于使驱动程序与设备树节点匹配。   dmas -Xilinx AXI DMA或...
  • 使用zynq7000系列SoC开发以太网功能比较简单,xilinx提供了完整的驱动程序,只需配置设备树中与phy相关的信息即可,本篇文章的重点并非讲解以太网驱动程序本身,而是通过对以太网驱动程序代码的分析,探索linux phy...
  • 1)实验平台:正点原子领航者ZYNQ开发板2)平台购买地址:https://item.taobao.com/item.htm?&id=6061601087613)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html4...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 131
精华内容 52
关键字:

zynqlinux驱动开发

linux 订阅