完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
公司产品使用XFS5152语音模块作为语音提示应用在RK3288 平台上,这里记录一下驱动调试过程。
XFS5152 支持 UART、I2C 、SPI 三种通讯方式,将收到的中文、英文文本进行语音合成。 产品中RK3288 使用I2C连接该模块,但存在一个问题该模块只支持低速率的I2C,速度最大只能到15KHz, 但RK3288 支持的标准I2C速率为100KHz,实际测试发现虽然可以设置到10KHZ, 但波形发生改变,只能使用GPIO模拟的方式与模块通信,Linux内核已支持该功能。 设备树配置如下: i2c-gpio { compatible = "i2c‐gpio"; gpios = <&gpio6 9 GPIO_ACTIVE_HIGH>, <&gpio6 10 GPIO_ACTIVE_HIGH>; /* i2c‐gpio,delay‐us = <5>; */ #address-cells = <1>; #size-cells = <0>; pinctrl-names = "default"; pinctrl-0 = <&i2c6_gpio>; status = "okay"; xfs5152: xfs5152@40 { status = "okay"; compatible = "XFS5152"; reg = <0x40>; stat-gpio = <&gpio6 8 GPIO_ACTIVE_LOW>; rst-gpio = <&gpio6 0 GPIO_ACTIVE_LOW>; }; }; } i2c6 { i2c6_gpio: i2c6-gpio { rockchip,pins = <6 9 RK_FUNC_GPIO &pcfg_pull_up>, <6 10 RK_FUNC_GPIO &pcfg_pull_up>; }; }; 注意如果复用硬件I2C引脚需要将原i2c节点disable !! 在内核中使能i2c-gpio 驱动: 编译内核烧录至板卡中查看驱动是否加载成功: I2c-gpio驱动没有问题,开始编写XFS5152 的驱动代码,由于公司保密限制,只贴出验证用驱动代码: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define XFS5152_CNT 1 #define XFS5152_NAME "xfs5152" struct xfs5152_dev { dev_t devid; /* 设备号 */ struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ struct device_node *nd; /* 设备节点 */ int pwr_gpio,rst_gpio,stat_gpio; int major; /* 主设备号 */ void *private_data; /* 私有数据 */ }; static struct xfs5152_dev xfs5152; static int xfs5152_gpio_init(void) { printk("now xfs5152_gpio_init() is calledrn"); xfs5152.nd = of_find_node_by_path("/i2c-gpio/xfs5152"); if (xfs5152.nd== NULL) { return -EINVAL; } /* xfs5152.pwr_gpio = of_get_named_gpio(xfs5152.nd ,"pwr-gpio", 0); if (xfs5152.pwr_gpio < 0) { printk("can't get pwr_gpio0rn"); return -EINVAL; } printk("pwr_gpio=%drn", xfs5152.pwr_gpio); */ xfs5152.stat_gpio = of_get_named_gpio(xfs5152.nd ,"stat-gpio", 0); if (xfs5152.pwr_gpio < 0) { printk("can't get stat_gpio0rn"); return -EINVAL; } printk("stat_gpio=%drn", xfs5152.stat_gpio); xfs5152.rst_gpio = of_get_named_gpio(xfs5152.nd ,"rst-gpio", 0); if (xfs5152.pwr_gpio < 0) { printk("can't get rst_gpio0rn"); return -EINVAL; } printk("rst_gpio=%drn", xfs5152.rst_gpio); /* 初始化key所使用的IO */ #if 0 gpio_request(xfs5152.pwr_gpio, "pwr_gpio0"); /* 请求IO */ gpio_direction_output(xfs5152.pwr_gpio,1); /* 设置为输入 */ #endif gpio_request(xfs5152.rst_gpio, "rst_gpio0"); /* 请求IO */ gpio_direction_output(xfs5152.rst_gpio,1); /* 设置为输入 */ gpio_request(xfs5152.stat_gpio, "stat_gpio0"); /* 请求IO */ gpio_direction_input(xfs5152.stat_gpio); /* 设置为输入 */ return 0; } static int xfs5152_reset(void) { int ret = 0; if (gpio_get_value(xfs5152.stat_gpio) != 0) { /* 申请复位IO,并且默认输出低电平 */ printk("is busy then reset xfs5152 rn"); gpio_set_value(xfs5152.rst_gpio, 0); /* 输出低电平,复位 */ msleep(100); printk("reset xfs5152 ----end rn"); gpio_set_value(xfs5152.rst_gpio, 1); /* 输出高电平,停止复位 */ } ret = gpio_get_value(xfs5152.stat_gpio); if(ret==0){ printk("after reset is not busy rn"); } else{ printk("after reset is busy NOW rn"); } return ret; } /* * @description : 向xfs5152_dev多个寄存器写入数据 * @param - dev: xfs5152_dev设备 * @param - reg: 要写入的寄存器首地址 * @param - val: 要写入的数据缓冲区 * @param - len: 要写入的数据长度 * @return : 操作结果 */ static s32 xfs5152_write_regs(struct xfs5152_dev *dev, u8 *buf, u8 len) { u8 b[15]={0xFD ,0x00 ,0x0C ,0x01 ,0x01 ,0xB1 ,0xB1 ,0xBE ,0xA9 ,0xBB ,0xB6 ,0xD3 ,0xAD ,0xC4 ,0xFA }; struct i2c_msg msg; struct i2c_client *client = (struct i2c_client *)dev->private_data; //memcpy(&b,buf,len); /* 将要写入的数据拷贝到数组b里面 */ msg.addr = 0x40; /* xfs5152地址 */ msg.flags = 0; /* 标记为写数据 */ msg.buf = b; /* 要写入的数据缓冲区 */ msg.len = 15; /* 要写入的数据长度 */ return i2c_transfer(client->adapter, &msg, 1); } /* * @description : 打开设备 * @param - inode : 传递给驱动的inode * @param - filp : 设备文件,file结构体有个叫做private_data的成员变量 * 一般在open的时候将private_data指向设备结构体。 * @return : 0 成功;其他 失败 */ static int xfs5152_open(struct inode *inode, struct file *filp) { filp->private_data = &xfs5152; return 0; } /* * @description : 从设备写数据 * @param - filp : 要打开的设备文件(文件描述符) * @param - buf : 返回给用户空间的数据缓冲区 * @param - cnt : 要读取的数据长度 * @param - offt : 相对于文件首地址的偏移 * @return : 读取的字节数,如果为负值,表示读取失败 */ static ssize_t xfs5152_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *off) { int retvalue; unsigned char databuf[50]; struct xfs5152_dev *dev = (struct xfs5152_dev *)filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0) { printk("kernel write failed!rn"); return -EFAULT; } if(xfs5152_reset()==0) { printk("The data waitting to send is %srn",databuf); xfs5152_write_regs(dev,databuf,cnt); printk("The data is sent to iic busrn"); } else{ printk("xfs5152 now is not readyrn"); } return 0; } static int xfs5152_release(struct inode *inode, struct file *filp) { return 0; } /* AP3216C操作函数 */ static const struct file_operations xfs5152_ops = { .owner = THIS_MODULE, .open = xfs5152_open, .write = xfs5152_write, .release = xfs5152_release, }; /* * @description : i2c驱动的probe函数,当驱动与 * 设备匹配以后此函数就会执行 * @param - client : i2c设备 * @param - id : i2c设备ID * @return : 0,成功;其他负值,失败 */ static int xfs5152_probe(struct i2c_client *client, const struct i2c_device_id *id) { xfs5152_gpio_init(); printk("xfs5152_probe function is calledrn"); /* 1、构建设备号 */ if (xfs5152.major) { xfs5152.devid = MKDEV(xfs5152.major, 0); register_chrdev_region(xfs5152.devid, XFS5152_CNT, XFS5152_NAME); } else { alloc_chrdev_region(&xfs5152.devid, 0, XFS5152_CNT, XFS5152_NAME); xfs5152.major = MAJOR(xfs5152.devid); } /* 2、注册设备 */ cdev_init(&xfs5152.cdev, &xfs5152_ops); cdev_add(&xfs5152.cdev, xfs5152.devid, XFS5152_CNT); /* 3、创建类 */ xfs5152.class = class_create(THIS_MODULE, XFS5152_NAME); if (IS_ERR(xfs5152.class)) { return PTR_ERR(xfs5152.class); } /* 4、创建设备 */ xfs5152.device = device_create(xfs5152.class, NULL, xfs5152.devid, NULL, XFS5152_NAME); if (IS_ERR(xfs5152.device)) { return PTR_ERR(xfs5152.device); } xfs5152.private_data = client; return 0; } /* * @description : i2c驱动的remove函数,移除i2c驱动的时候此函数会执行 * @param - client : i2c设备 * @return : 0,成功;其他负值,失败 */ static int xfs5152_remove(struct i2c_client *client) { /* 删除设备 */ cdev_del(&xfs5152.cdev); unregister_chrdev_region(xfs5152.devid, XFS5152_CNT); /* 注销掉类和设备 */ device_destroy(xfs5152.class, xfs5152.devid); class_destroy(xfs5152.class); return 0; } /* 传统匹配方式ID列表 */ static const struct i2c_device_id xfs5152_id[] = { {"XFS5152", 0}, {} }; /* 设备树匹配列表 */ static const struct of_device_id xfs5152_of_match[] = { { .compatible = "XFS5152" }, { /* Sentinel */ } }; /* i2c驱动结构体 */ static struct i2c_driver xfs5152_driver = { .probe = xfs5152_probe, .remove = xfs5152_remove, .driver = { .owner = THIS_MODULE, .name = "XFS5152", .of_match_table = xfs5152_of_match, }, .id_table = xfs5152_id, }; |
|
|
|
/*
* @description : 驱动入口函数 * @param : 无 * @return : 无 */ static int __init xfs5152_init(void) { int ret = 0; ret = i2c_add_driver(&xfs5152_driver); return ret; } /* * @description : 驱动出口函数 * @param : 无 * @return : 无 */ static void __exit xfs5152_exit(void) { i2c_del_driver(&xfs5152_driver); } /* module_i2c_driver(xfs5152_driver) */ module_init(xfs5152_init); module_exit(xfs5152_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("KuangMH"); 测试代码如下: #include #include #include #include #include #define xfs5152 "/dev/xfs5152" int main(void) { unsigned char testBuf[13]={0xFD, 0x00, 0x0A, 0x01, 0x00, 0xBF, 0xC6, 0xB4, 0xF3, 0xD1, 0xB6, 0xB7, 0xC9};//科大讯飞 int retval; int fd = open(xfs5152, O_RDWR); if (fd < 0) { printf("Open %s failure.n", xfs5152); return -1; } while(1) { retval = write(fd, testBuf, 13); printf("write to driver %d rn",retval); write(fd, testBuf, 13); sleep(3); printf("sending TTS is over!rn"); //memset(buf, 0, 64); sleep(3); } close(fd); return 0; } 调试波形时序: |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
2062 浏览 1 评论
synopsys 的design ware:DW_fpv_div,浮点数除法器,默认32位下,想提升覆盖率(TMAX),如果用功能case去提升覆盖率呢?
2649 浏览 1 评论
RK3588 GStreamer调试四路鱼眼摄像头四宫格显示报错
5421 浏览 1 评论
【飞凌嵌入式OK3576-C开发板体验】RKNN神经网络-YOLO图像识别
254 浏览 0 评论
【飞凌嵌入式OK3576-C开发板体验】SSH远程登录网络配置及CAN通讯
1336 浏览 0 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-27 09:00 , Processed in 0.442058 second(s), Total 45, Slave 38 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号