讯飞XFS5152 语音模块在RK3288 上的应用

2024-09-07 16:58

本文主要是介绍讯飞XFS5152 语音模块在RK3288 上的应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

公司产品使用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 <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#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 called\r\n");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_gpio0\r\n");return -EINVAL;}printk("pwr_gpio=%d\r\n", 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_gpio0\r\n");return -EINVAL;}printk("stat_gpio=%d\r\n", 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_gpio0\r\n");return -EINVAL;}printk("rst_gpio=%d\r\n", xfs5152.rst_gpio);/* 初始化key所使用的IO */#if 0gpio_request(xfs5152.pwr_gpio, "pwr_gpio0");	/* 请求IO */gpio_direction_output(xfs5152.pwr_gpio,1);	/* 设置为输入 */#endifgpio_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 \r\n");gpio_set_value(xfs5152.rst_gpio, 0);	/* 输出低电平,复位 */msleep(100);printk("reset xfs5152 ----end \r\n");gpio_set_value(xfs5152.rst_gpio, 1);	/* 输出高电平,停止复位 */}ret = gpio_get_value(xfs5152.stat_gpio);if(ret==0){printk("after reset is not busy \r\n");		}else{printk("after reset is  busy NOW \r\n");		}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!\r\n");return -EFAULT;}if(xfs5152_reset()==0){printk("The data waitting to send is %s\r\n",databuf);xfs5152_write_regs(dev,databuf,cnt);printk("The data is sent to iic bus\r\n");}else{printk("xfs5152 now is not ready\r\n");}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 called\r\n");/* 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 <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>#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 \r\n",retval);write(fd, testBuf, 13);sleep(3);printf("sending TTS is over!\r\n");//memset(buf, 0, 64);sleep(3);}close(fd);return 0;	
}

调试波形时序:

 

 

这篇关于讯飞XFS5152 语音模块在RK3288 上的应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145627

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

阿里开源语音识别SenseVoiceWindows环境部署

SenseVoice介绍 SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。富文本识别:具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。高效推

zoj3820(树的直径的应用)

题意:在一颗树上找两个点,使得所有点到选择与其更近的一个点的距离的最大值最小。 思路:如果是选择一个点的话,那么点就是直径的中点。现在考虑两个点的情况,先求树的直径,再把直径最中间的边去掉,再求剩下的两个子树中直径的中点。 代码如下: #include <stdio.h>#include <string.h>#include <algorithm>#include <map>#

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、