智能手表上的音频(二):驱动

news2025/1/17 22:53:10

上一篇讲了智能手表上音频系统的架构和应用场景。从本篇开始讲具体的,首先讲音频相关的驱动,主要包括IPC(inter-processor communication,核间通信, 即AP/CP/ADSP之间的通信)的driver 和audio的driver。首先说明一下,由于codec是我们公司自己设计的,内置在SOC里,且driver在ADSP(ADSP用的是RTOS)上,driver代码不会像Linux ALSA那样普适。

讲驱动之前,先看用了哪些中断和memory。 用到的中断主要有IPC中断和ADMA(Audio DMA)中断。IPC本质上是中断加Ring Buffer,用到内置codec以及蓝牙通话时,系统就是靠ADMA中断(这个中断等间隔来)驱动的,即等间隔的ADMA 中断驱动音频系统转起来,后面具体讲。用到的memory主要有5块,具体如下:1,ITCM(片内,放代码)。2,DTCM(片内,放数据)。 3,ADSP与其他core做数据交互用的share memory,这块memory在SRAM上,对于做数据交互的双方来说,都要能访问,且双方都要设成uncacheable。4,存放codec采集到的音频数据的memory,这块memory ASIC设计时就是音频专用的,对audio来说latency很小,不会有其他竞争导致audio 被卡。5,DDR中给audio用的memory,这块memory属于片外,在设计时就分配给audio用,既可以放代码,也可以放数据,根据需要将其中的部分设成cacheable或者uncacheable。下图显示了哪些memory要设成cacheable,哪些要设成uncacheable:

1,  IPC driver

IPC就是核间通信(AP/CP/ADSP之间的通信),即核间进行数据交互。要进行数据交互,首先得定义好数据格式,让交互的双方都能解析。 交互数据包括控制数据(如使能一个stream)和音频数据。上面说过,IPC本质上就是中断加Ring Buffer(既然是Ring Buffer,就得有读写index)。Ring Buffer及其控制变量(读写index等)都在要通信的两核都能访问的share memory上(上面说的第3种memory)。如果核间是单向通信,则只需要一个Ring Buffer。如果是双向通信,就需要两个Ring Buffer。下图给出了常见的双向交互的示意图:

 

发送方把数据按照规定的格式组好后放在Ring Buffer内write index开始的地方,同时更新write index,然后给接收方发一个中断。接收方收到中断后进入中断服务程序,从Ring Buffer内read index开始的地方取指定大小的数据,同时更新read index,然后解析收到的数据,进行下一步的操作。

AP与ADSP之间就是以如上的方式交互控制命令和音频数据的。此外IPC还有的作用包括输出ADSP的log到UART以及把要dump的音频数据从ADSP发给AP保存成文件等。由于ADSP的log没法直接输出,就需要把log通过IPC发给AP,AP再输出到UART等。Dump音频数据是音频调试的一个非常重要的手段。ADSP上也没法直接dump,只能借助于IPC发到AP上保存成文件。调驱动时首先调的就是AP与ADSP之间的IPC,确保AP和ADSP之间通信正常,ADSP的log输出正常,能正常dump音频数据,在IPC好的基础上再去调其他的。新手在调IPC时常犯错的是没把用到的share memory设成uncacheable,导致有时候通信正确,有时候通信不正确,从而花不少时间去调查,有经验的一看现象就大概知道原因了。

ADSP与CP之间仅仅交互语音数据(只有语音通话时才会用到,语音控制命令相关的都是ADSP与AP之间的交互),就对IPC进行了简化,用固定的buffer(这块buffer也是在双方都能访问的share memory上)代替Ring Buffer,且只用一个中断(ADSP给CP发中断)。示意如下图:

上面说过语音通话时系统是靠ADMA中断驱动的。通常10ms一个ADMA中断,这个中断驱动音频系统转起来。在一个loop里,ADSP先从上图中的Play buffer里取CP放进去的要播放的语音数据,然后从ADSP audio buffer里取采集到的语音数据,采集到的语音数据经处理(比如重采样)后送到上图中的Record Buffer里,最后给CP发一个IPC中断。CP收到中断后先从Record buffer里取出采集到的数据并做处理,然后把要播放的数据放进Play buffer里。

2,  audio driver

下图是在上一篇架构(智能手表上的音频(一):架构)中的硬件框图:

从上图看出在用内置codec和BT时音频驱动是有差异的,下面就分两种case来讲。

2.1 内置codec

下图是内置codec下驱动硬件框图:

从上图看出,驱动主要包括两部分,内置codec和ADMA(audio DMA)。先看内置codec相关的。内置codec内部可分成模拟部分(analog, 包括ADC和DAC)和数字部分(digital, 即DFE(digital front-end,数字前端))。内置codec的驱动主要是配置寄存器:包括配置音频时钟、DFE和ADC、DAC等。再看ADMA相关的。既然是DMA,就得有descriptor。下图是其结构体定义:

byte_counts是指ADMA buffer的大小。这个值定好了也就定好了ADMA中断的间隔。 以ADMA中断产生的条件是ADMA buffer为空为例,当ADMA buffer空了就产出一个中断。ADMA buffer的大小通常以毫秒计(这样就可知道ADMA的中断间隔是多少毫秒),知道了采样率和通道数,就可算出字节数。假设ADMA buffer 10ms,48K采样,双声道,则ADMA buffer的大小是1920bytes (10*48*4 = 1920),所以说ADMA buffer的大小定好了也就定好了ADMA中断的间隔。Src_addr是原地址,dst_addr是目的地址,会把音频数据从原地址搬到目的地址。在采集方向上,src_addr是硬件地址, dst_addr是adsp里audio buffer的地址。在播放方向上,src_addr是adsp里audio buffer的地址硬件地址, dst_addr是硬件地址。next_desc指向下一个descriptor,通常在一个方向上有两个descriptor,两个descriptor互指。ADMA的驱动主要包括挂中断、寄存器配置(上面descriptor里内容以及中断产生条件等)以及音频数据的搬运。在采集方向上音频数据主要是从硬件地址上搬到adsp的audio buffer里,在播放方向上音频数据主要是从adsp的audio buffer里搬到硬件地址上。ADSP的audio buffer,两个方向上既可以用不同的两块,也可以用相同的一块。用两块时需要两个ADMA中断(一个方向上一个),相应的就有两个中断服务程序。因为两个方向上不相关,处理相对简单,缺点是浪费memory(ADSP上的memory是非常宝贵的)。用一块时只需要一个ADMA中断,因为两个方向上相关,处理就复杂些(处理不好就造成数据踩踏),优点是节省memory。

2.2 蓝牙

下图是蓝牙下驱动硬件框图:

 

从上图看出,驱动主要包括两部分,ASSP(audio SSP(Synchronous Serial Port, 同步串行接口))和ADMA。ADMA跟内置codec的一样,这里就不讲了。ASSP说白了就是配置是PCM总线还是I2S总线,配置的内容有音频采样的数据长度、采样方式(上升沿采样还是下降沿采样)、对齐方式(左对齐还是右对齐)、帧同步宽度等。

上面的两种case,不管哪一种,首先要确保的是配好寄存器后ADMA中断要有规律的等时长(比如10ms)来,如不是说明寄存器配置有问题,需要再去仔细看datasheet,理解配置的意思。可以在ISR(中断服务程序)里加个log,如果log等间隔出现,就基本说明ADMA中断等间隔来了。

先调内置codec下的音频驱动。中断正常后先调播放方向上的。往ADSP audio buffer里写正弦波,speaker里放出tone音就说明播放方向上调好了。再调采集方向上的,把ADSP audio buffer里采集到的数据通过IPC发给AP保存成文件,用音频软件(如CoolEdit)去听,跟对着mic说的话一致就说明调好了。由于牵涉到硬件,调试过程中需要ASIC、analog和hardware相关人员的支持,比如寄存器是否配对了、某个PIN输出是否符合期望等,毕竟在硬件上他们更有经验。BT下的驱动只在蓝牙语音通话时才用到,把内置codec下的语音通话调好了再去调BT下的驱动更容易,因为整个链路上只需要把内置codec下的驱动换成BT下的驱动,更方便验证是否调好。BT下的驱动相对内置codec下的,ADMA等做些值的修改,主要调ASSP。ASSP配好寄存器后用示波器量信号(SCLK/SYNC/DIN/DOUOT等),符合预期就可以了。最终用蓝牙打电话,收发方向上声音都正常就说明调好了。

Audio driver相当于地基,地基好了后就开始盖楼(开发具体功能)了。从下篇开始讲具体的功能,首先讲音频文件播放。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1104257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

讯飞星火3.0版发布前瞻,生产力将大幅提升

AI头部企业科大讯飞宣布,即将在10月24日发布讯飞星火认知大模型3.0版。新版本将极大提升生产力,并开启大规模AI应用产业落地。 一、讯飞星火大模型3.0版即将升级发布 科大讯飞是AI人工智能技术、智能语音识别技术领域的全球领先企业,也是大…

垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程

文章目录 🍊 垃圾回收器、垃圾回收算法、空间分配担保🎉 Serial🎉 ParNew🎉 Parallel scavenge🎉 复制算法🎉 分代收集算法🎉 进入老年代的几种情况📝 空间分配担保 🎉 S…

PCI认证:为什么它对你的业务至关重要,以及如何成功获得认证?

PCI认证是保障你的业务安全和合规性的重要工具。它是一个由支付卡行业安全标准委员会(PCI SSC)提供的全球性标准,旨在保护持卡人信息和资金的安全。如果你的企业处理、存储或传输持卡人信息,那么PCI认证就对你的业务至关重要。 为什么PCI认证对你的业务至…

拼接屏新时代:了解OLED透明拼接屏的尺寸与定制选择

在当今科技迅速发展的时代,OLED透明拼接屏作为一项引人注目的创新技术,正在改变我们对于显示屏的认知。 它以其独特的透明性和高清晰度,为用户提供了前所未有的视觉体验。 一、OLED透明拼接屏原理 OLED(Organic Light Emitting …

基于 Servlet 的博客系统

基于 Servlet 的博客系统 一、准备工作1、创建项目2、创建包3、导入前端静态页面 二、数据库设计1、blog(博客表)2、user(用户表)3、建库建表的 SQL 语句 三、封装数据库操作1、为什么要封装数据库?2、封装数据库的连接…

最高频的五个面试题

目录 1.JavaSE阶段:谈谈啥是多态 2.数据结构阶段:谈谈哈希表 3.数据库阶段:谈谈事务 4.操作系统阶段:谈谈进程和线程的区别联系 5.网络阶段:TCP三次握手和四次挥手 1.JavaSE阶段:谈谈啥是多态 多态&a…

解决方案-LBS用户位置Redis-GEO附近人/店铺

附近人 windows安装附近人列表功能mysqlredis GEO CNNVD-201511-230 未授权访问python 多线程 redis大端模式与小端模式IP地址的不同表现形式1.字符串表现形式2. 整数表现形式3.大小端模式下的IP地址 0x01 进入python正题Python的socket库1.socket.socket(family,type)2.socket…

【前端学习】—多种方式实现数组拍平(十一)

【前端学习】—多种方式实现数组拍平(十一) 一、数组拍平 数组拍平也叫数组扁平化、数组拉平、数组降维,指的是把多维数组转化为一维数组。 二、使用场景 复杂场景下的数据处理(echarts做大屏数据展示) 三、如何实…

华硕U盘盘重装Win10系统步骤图解

重装操作系统是在电脑系统遇到问题或者需要清除所有数据时的一种常见解决方法。但是,很多使用华硕电脑的新手用户,不清楚具体的操作步骤,接下来小编就给介绍关于利用U盘给华硕电脑重装Win10系统的方法,帮助用户们更快地完成系统的…

Shader Graph25-UV移动旋转缩放(自定义函数)

我们将UV操作放入函数内,该函数的内容来自我之前的文章 Shader Graph24-摇晃树叶-CSDN博客 一、UE在Material中右键,新建Material Function。 增加输入 二、新建Material,命名为DemoUVRotationUseFunction Offset为偏移值,Rotat…

VMware虚拟机安装Linux系统的介绍

许多新手连 Windows 的安装都不太熟悉,更别提 Linux 的安装了;即使安装成功了,也有可能破坏现有的 Windows 系统,比如导致硬盘数据丢失、Windows 无法开机等。所以一直以来,安装 Linux 系统都是初学者的噩梦。 然而&a…

填充颜色游戏

无语死了这题。 题目描述 小明最近迷上下面一款游戏。游戏开始时, 系统将随机生成一个 N N 的 正方形棋盘, 棋盘的每个格子都由六种颜色中的一种绘制。在每个步骤中, 玩家选择一种颜色, 并将与左上角连接的所有网格更改为该特…

MSQL系列(四) Mysql实战-索引 Explain实战

Mysql实战-索引 Explain实战 前面我们讲解了索引的存储结构,我们知道了BTree的索引结构,也了解了索引最左侧匹配原则,到底最左侧匹配原则在我们的项目中有什么用?或者说有什么影响?今天我们来实战操作一下&#xff0c…

Yakit工具篇:子域名收集的配置和使用

简介(来自官方文档) 子域名收集是指通过各种技术手段,收集某个主域名下所有的子域名列表。子域名是指在主域名前面添加一级或多级名称的域名。例如,对于主域名example.com,其子域名可以是www.example.com、mail.example.com、blog.example.c…

MIT6.5830 Lab0-Go tutorial实验记录(二)

MIT6.5830 Lab0-Go tutorial实验记录(二) – WhiteNights Site 标签:Golang, 数据库 在将数据库的数据转换为图表前,我们需要先测试是否能正常访问数据库文件。 写者注 为什么要怎么做?因为这块 非常容易出问题。在h…

计算机基础知识33

进程基础(操作系统中的概念) 进程它是操作系统总最重要的概念,线程也是 进程和线程都是有操作系统来调度使用的,我们程序员是不能控制的 # 进程和程序是两码事、完全不一样 程序:其实一个死的东西、一堆代码就是程序,它也没有生命…

【5】c++11新特性(稳定性和兼容性)—>override关键字

override关键字很简单,就是起到一个检查的作用,父类中有一个虚函数,子类要去重写这个虚函数,那么在子类重写时,函数后面加上override,就会检查子类中重写的这个函数和父类中这个虚函数名是否一样&#xff0…

FISCO过程中存在的的问题

问题1:端口被占 报错:Exceed waiting time. Please try again to start node0 initConfig for P2PInitializer failed,check Port30303,EINFOThrow location unknown (consider using BOOST_THROW_EXCEPTION) Dynamic exception type: boost::exception_…

80026-044-06-R 数字伺服驱动器提供了更好的配置和性能

80026-044-06-R 数字伺服驱动器提供了更好的配置和性能 由于它们的精密性能,伺服驱动器被用于机器人,自动化,数控加工,甚至在过程中制造半导体. 一些运动控制应用使用模拟伺服驱动器,这是一项久经考验的技术。虽然它…

数据结构之顺序表的模拟实现

💕"世事犹如书籍,一页页被翻过去。人要向前看,少翻历史旧账。"💕 作者:Mylvzi 文章主要内容:数据结构之顺序表的模拟实现 /*** Created with IntelliJ IDEA.* Description:* User: 绿字* Date:…