ubuntu16.04
petalinux2018.3
vscode编辑器
之前写过imx28的驱动,这次因为毕设要用zcu106的vcu,涉及到驱动的部分,所以再来回顾下开发流程,petalinux工具提供了极大的便利,对于开发来说,但也有自己的坏处,每次编译贼慢,想直接载kenrel中编译写makefile又出问题,算了就这样吧。
1、创建linux,见上一篇文章,这里硬件平台挂载一个PL的自定义gpio输出,硬件框图如下所示:
这里的gpio全部挂载到pl的led上,然后4个一组,挂载两组,查看他们的地址线,如下
2、修改设备树,这里加一个led,根目录加上如下:
/include/ "system-conf.dtsi"
/ {
zynqmp-ledctl {
#address-cells = <0x1>;
#size-cells = <0x1>;
compatible = "xlnx,zynqmp-ledctl";
status = "okay";
reg = < 0x80000000 0x04 /* data 0*/
0x80001000 0x04 >; /* oen 0*/
};
};
3、创建自己的module,这里起一个zynqmp-ledctl
petalinux-create -t modules --name zynqmp-ledctl --enable
4、核心驱动部分如下,open、read自己写吧,下面主要是创建设备、类、驱动啥的
static int setup_ledctl_cdev(void)
{
alloc_chrdev_region(&zynqmp_ledctl_dev.dev_id, 0, DEVLED_CNT, DRIVER_NAME);
zynqmp_ledctl_dev.major = MAJOR(zynqmp_ledctl_dev.dev_id);
cdev_init(&zynqmp_ledctl_dev.cdev, &zynmp_ledctl_fops);
cdev_add(&zynqmp_ledctl_dev.cdev, zynqmp_ledctl_dev.dev_id, DEVLED_CNT);
zynqmp_ledctl_dev.class = class_create(THIS_MODULE, DRIVER_NAME);
if (IS_ERR(zynqmp_ledctl_dev.class)) {
return PTR_ERR(zynqmp_ledctl_dev.class);
}
zynqmp_ledctl_dev.device = device_create(zynqmp_ledctl_dev.class, NULL,\
zynqmp_ledctl_dev.dev_id, NULL, DRIVER_NAME);
if (IS_ERR(zynqmp_ledctl_dev.device)) {
return PTR_ERR(zynqmp_ledctl_dev.device);
}
return 0;
}
static int zynqmp_ledctl_probe(struct platform_device *dev)
{
u32 val = 0;
int ret;
u32 regdata[6];
const char *str;
struct property *proper;
/* 获取设备树中的属性数据 */
/* 1、获取设备节点 */
zynqmp_ledctl_dev.nd = of_find_node_by_path("/zynqmp-ledctl");
if(zynqmp_ledctl_dev.nd == NULL) {
printk("zynqmp-ledctl node nost find!\r\n");
return -EINVAL;
} else {
printk("zynqmp-ledctl node find!\r\n");
}
/* 2、获取 compatible 属性内容 */
proper = of_find_property(zynqmp_ledctl_dev.nd, "compatible", NULL);
if(proper == NULL) {
printk("compatible property find failed\r\n");
} else {
printk("compatible = %s\r\n", (char*)proper->value);
}
/* 3、获取 status 属性内容 */
ret = of_property_read_string(zynqmp_ledctl_dev.nd, "status", &str);
if(ret < 0){
printk("status read failed!\r\n");
} else {
printk("status = %s\r\n",str);
}
ret = of_property_read_u32_array(zynqmp_ledctl_dev.nd, "reg", regdata, 4);
if(ret < 0) {
printk("reg property read failed!\r\n");
} else {
u8 i = 0;
printk("reg data:\r\n");
for(i = 0; i < 4; i++)
printk("%#X ", regdata[i]);
printk("\r\n");
}
data_r = ioremap(regdata[0], regdata[1]);
printk("%#X ", data_r);
data1_r = ioremap(regdata[2], regdata[3]);
printk("%#X ", data1_r );
setup_ledctl_cdev();
if(data_r)
zynqmp_ledctl_set_dir(1, 1);
return 0;
}
5、编译
petalinux-build -c zynqmp-ledctl#only for moudule
petalinux-build -c device-tree#only for device-tree
petalinux-build #for all
petalinux-package --boot --format BIN --fsbl images/linux/zynqmp_fsbl.elf --u-boot images/linux/u-boot.elf --pmufw images/linux/pmufw.elf --fpga images/linux/*.bit --force
#combine to image
5、开机加载驱动,zynqmp-ledctl就是我们编写的驱动
加载驱动之后可以在/dev下查看到我们的设备zynqmp-ledctl
6、测试app编写,因为主机超级终端啥的都是在win10,所以app在win10上交叉编译了,之前有过教程怎么配环境,编写app
int main(char argc, char *argv[])
{
printf("Joydon Jiang@[email protected]\n");
if(argc < 3){
printf("app : %s ,error input!\r\n", argv[0]);
return -1;
}
char* file_name = argv[1];
printf("app : %s\r\n", file_name);
int fd = open(file_name, O_RDWR);
if(fd < 0){
printf("app : %s , file %s open failed!\r\n", argv[1]);
return -1;
}
unsigned char val = atoi(argv[2]);
int ret = write(fd, &val, sizeof(val));
if(ret < 0){
printf("app : %s , file %s write failed!\r\n", argv[1]);
close(fd);
return -1;
}
ret = close(fd);
return 0;
}
很简单一看就懂,下面进行代码测试,然后再win10下make
通过lrz工具通过串口传输到开发板
正常传统配置Linux默认内核加载项是在Makefile记忆Kconfig中修改,参考链接
https://blog.csdn.net/cediy2088long/article/details/7409236
现在是加一条命令:
donce@donce:~/project/linux_img/nohdmi$ petalinux-build -x mrproper
donce@donce:~/project/linux_img/nohdmi$ petalinux-build -c zynqmp-ledctl -x do_install
这里就是点灯的驱动安装在内核中,然后进行编译测试,失败,哈哈,以后再搞吧,先记录下。