Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Devices
stm32l475-atk-pandora音频驱动框架疑惑
发布于 2019-09-14 19:56:35 浏览:1772
订阅该版
* 本帖最后由 北纬33度 于 2019-9-14 20:15 编辑 * 最近在学习音频驱动,看过了stm32l475-atk-pandora的代码,有几点疑惑,请指点 1、音频播放时,_audio_dev_write函数中,依次申请mem pool,并将待播放音频的buf中的数据拷贝到mem pool中,然后push入data queue```static rt_size_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) { struct rt_audio_device *audio; rt_uint8_t *ptr; rt_uint16_t block_size, remain_bytes, index = 0; RT_ASSERT(dev != RT_NULL); audio = (struct rt_audio_device *) dev; if (!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL)) return 0; /* push a new frame to replay data queue */ ptr = (rt_uint8_t *)buffer; block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE; rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER); while (index < size) { /* request buffer from replay memory pool */ if (audio->replay->write_index % block_size == 0) { audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER); memset(audio->replay->write_data, 0, block_size); } /* copy data to replay memory pool */ remain_bytes = MIN((block_size - audio->replay->write_index), (size - index)); memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes); index += remain_bytes; audio->replay->write_index += remain_bytes; audio->replay->write_index %= block_size; if (audio->replay->write_index == 0) { rt_data_queue_push(&audio->replay->queue, audio->replay->write_data, block_size, RT_WAITING_FOREVER); } } rt_mutex_release(&audio->replay->lock); /* check replay state */ if (audio->replay->activated != RT_TRUE) { _aduio_replay_start(audio); audio->replay->activated = RT_TRUE; } return index; } ```2、调用_aduio_replay_start即drv_sound.c中sound_start通过DMA送出 ```static rt_err_t sound_start(struct rt_audio_device *audio, int stream) { struct sound_device *snd_dev; RT_ASSERT(audio != RT_NULL); snd_dev = (struct sound_device *)audio->parent.user_data; if (stream == AUDIO_STREAM_REPLAY) { LOG_D("open sound device"); es8388_start(ES_MODE_DAC); HAL_SAI_Transmit_DMA(&SAI1A_Handler, snd_dev->tx_fifo, TX_FIFO_SIZE / 2); } return RT_EOK; } ```3、一次DMA传输完成后,通过回调函数执行rt_audio_tx_complete,传输下一段音频数据 _audio_send_replay_frame, data queue中无数据时,一直送出0,直到音频播放结束; 有数据时,将数据拷贝到tx_fifo(drv_sound.c中申请的一段内存),调用audio->ops->transmit通过dma送出(然而drv_sound.c中transmit未实现,数据如何发送出去??) ```static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio) { rt_err_t result = RT_EOK; rt_uint8_t *data; rt_size_t dst_size, src_size; rt_uint16_t position, remain_bytes, index = 0; struct rt_audio_buf_info *buf_info; RT_ASSERT(audio != RT_NULL); buf_info = &audio->replay->buf_info; /* save current pos */ position = audio->replay->pos; dst_size = buf_info->block_size; /* check repaly queue is empty */ if (rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK) { /* ack stop event */ if (audio->replay->event & REPLAY_EVT_STOP) rt_completion_done(&audio->replay->cmp); /* send zero frames */ memset(&buf_info->buffer[audio->replay->pos], 0, dst_size); audio->replay->pos += dst_size; audio->replay->pos %= buf_info->total_size; } else { memset(&buf_info->buffer[audio->replay->pos], 0, dst_size); /* copy data from memory pool to hardware device fifo */ while (index < dst_size) { result = rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size); if (result != RT_EOK) { LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes); audio->replay->pos -= remain_bytes; audio->replay->pos += dst_size; audio->replay->pos %= buf_info->total_size; audio->replay->read_index = 0; result = -RT_EEMPTY; break; } remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index)); memcpy(&buf_info->buffer[audio->replay->pos], &data[audio->replay->read_index], remain_bytes); index += remain_bytes; audio->replay->read_index += remain_bytes; audio->replay->pos += remain_bytes; audio->replay->pos %= buf_info->total_size; if (audio->replay->read_index == src_size) { /* free memory */ audio->replay->read_index = 0; rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO); rt_mp_free(data); /* notify transmitted complete. */ if (audio->parent.tx_complete != RT_NULL) audio->parent.tx_complete(&audio->parent, (void *)data); } } } if (audio->ops->transmit != RT_NULL) { if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size) result = -RT_ERROR; } return result; } ```4、此过程又将mempool中数据再次拷贝到tx_fifo(drv_sound.c中申请的buf),然后再启动dma送出,整个流程中数据拷贝2次,从 write buf -> mempool -> tx_fifo,个人认为无必要,且在dma传输完成的回调函数中拷贝数据到tx_fifo,占用CPU,可能会造成再次启动dma延迟,从而音频播放有停顿。 5、应用读音频文件,并播放,基本流程如下 应用中申请一段buf,从文件中读数据到buf,然后调用device_write到sound设备播放音频。 将buf中数据拷贝到mempool,并送入data queue,在dma传输完成回调中,释放本次mempool,然后pop出数据,启动下次dma传输,在dma传输期间,应用中可以再次申请到mempool,然后拷贝数据,push到data queue,继续read文件,阻塞在device write函数内(rt_mp_alloc),直到下次dma传输完成释放mempool。此过程省掉一次内存拷贝 6、或应用中直接使用mempool,但如何融合整个驱动框架,请大家指导[indent]本人为业余学习,以上理解如有错误,请指正。[/indent]
查看更多
1
个回答
默认排序
按发布时间排序
wuhanstudio
2019-09-18
这家伙很懒,什么也没写!
是指的这个吧 [https://github.com/RT-Thread/IoT_Board/blob/884be0f3c2565e765b486eb7731fe163be1bc2b1/rt-thread/components/drivers/audio/audio.c](https://github.com/RT-Thread/IoT_Board/blob/884be0f3c2565e765b486eb7731fe163be1bc2b1/rt-thread/components/drivers/audio/audio.c) 如果觉得效率低了,欢迎提 PR
撰写答案
登录
注册新账号
关注者
0
被浏览
1.8k
关于作者
北纬33度
这家伙很懒,什么也没写!
提问
2
回答
0
被采纳
0
关注TA
发私信
相关问题
1
问个问题,ili9320驱动里面rt_hw_lcd_draw_blit_line 这个函数是干什么用的
2
LCD双缓冲有什么好的办法实现
3
LCD NT35510 驱动代码
4
io设备驱动的疑惑与建议
5
液晶屏驱动 U8g2 移植
6
求助:在模板上添加LCD模块出现L6406E错误
7
hwtimer硬件定时器驱动和使用经验
8
硬件定时器超时时间计算问题
9
请教spi驱动lcd显示屏问题
10
rtt-master(3.1.1)bsp—armfly中drv_lcd.c中是不是错了啊?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
2
RT-Thread EtherKit开源以太网硬件正式发布
3
如何在master上的BSP中添加配置yml文件
4
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
5
RT-Thread 发布 EtherKit开源以太网硬件!
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
16
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
6
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部