Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
I2S音频接口
WM8978
AUDIO
I2S WM8978 DMA没中断问题,参考SAI驱动改写
发布于 2020-07-08 16:33:02 浏览:2442
订阅该版
1. STM32F4XX 参考音频SAI驱动 写I2S驱动,发现I2S的DMA不进入中断,代码如下,欢迎各位测试 查看问题出在哪里了。 2. 修改了一下初始化,和使用默认的I2S的DMA传输函数,现在DMA中断只产生一次,修改后的在1楼回复里面。 3. I2S的DMA双缓存传输有问题,不能直接使用HAL的传输,必须自己定义半传输和完整传输函数,修改如下方式,可以全部进入传输数据传输中断了。 4. 发现传输数据出现I2S_DMAError 进入到这个里面,正看问题 还没测试能不能播放出声音,默认的SAI里面的WM8978好像是耳机输出,还没配置为喇叭输出,已经可以进入数据传输中断了, 5. wm8978播放还没声音,需要看下为啥没声音, 6.可以播放,录音部分也写了,但是录音有杂音,标准库没杂音,HAL库有,暂时不知道为啥 I2S通过CubeMX的DMA配置如下 暂时只是播放的配置 ```c void HAL_I2S_MspInit(I2S_HandleTypeDef* hi2s) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(hi2s->Instance==SPI2) { /* USER CODE BEGIN SPI2_MspInit 0 */ /* USER CODE END SPI2_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_SPI2_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**I2S2 GPIO Configuration PA6 ------> I2S2_MCK PB12 ------> I2S2_WS PB13 ------> I2S2_CK PB14 ------> I2S2_ext_SD PB15 ------> I2S2_SD */ GPIO_InitStruct.Pin = GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_SPI2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* I2S2 DMA Init */ /* SPI2_TX Init */ hdma_spi2_tx.Instance = DMA1_Stream4; hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0; hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_spi2_tx.Init.Mode = DMA_CIRCULAR; hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK) { //Error_Handler(); } __HAL_LINKDMA(hi2s,hdmatx,hdma_spi2_tx); /* USER CODE BEGIN SPI2_MspInit 1 */ /* USER CODE END SPI2_MspInit 1 */ } } ``` ``` /* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-07-28 Ernest the first version */ #include "board.h" #include "drv_wm8978.h" #include "drv_sound.h" #define DBG_TAG "drv.sound" #define DBG_LVL DBG_INFO #include
#define CODEC_I2C_NAME ("i2c1") #define TX_DMA_FIFO_SIZE (2048) I2S_HandleTypeDef hi2s2; DMA_HandleTypeDef hdma_spi2_tx; struct stm32_audio { struct rt_i2c_bus_device *i2c_bus; struct rt_audio_device audio; struct rt_audio_configure replay_config; int replay_volume; rt_uint8_t *tx_fifo; rt_bool_t startup; }; struct stm32_audio _stm32_audio_play = {0}; void i2s_samplerate_set(rt_uint32_t freq) { if(freq == I2S_AUDIOFREQ_8K || freq == I2S_AUDIOFREQ_11K || freq == I2S_AUDIOFREQ_16K || freq == I2S_AUDIOFREQ_22K || freq == I2S_AUDIOFREQ_32K || freq == I2S_AUDIOFREQ_44K || freq == I2S_AUDIOFREQ_48K || freq == I2S_AUDIOFREQ_96K) { hi2s2.Init.AudioFreq = freq; } else { return; } __HAL_I2S_DISABLE(&hi2s2); HAL_I2S_Init(&hi2s2); __HAL_I2S_ENABLE(&hi2s2); } void i2s_channels_set(rt_uint16_t channels) { } void i2s_samplebits_set(rt_uint16_t samplebits) { switch (samplebits) { case 16: hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; break; case 24: hi2s2.Init.DataFormat = I2S_DATAFORMAT_24B; break; case 32: hi2s2.Init.DataFormat = I2S_DATAFORMAT_32B; break; default: hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; break; } __HAL_I2S_DISABLE(&hi2s2); HAL_I2S_Init(&hi2s2); __HAL_I2S_ENABLE(&hi2s2); } void i2s_config_set(struct rt_audio_configure config) { i2s_channels_set(config.channels); i2s_samplerate_set(config.samplerate); i2s_samplebits_set(config.samplebits); } rt_err_t I2S_config_init(void) { hi2s2.Instance = SPI2; hi2s2.Init.Mode = I2S_MODE_MASTER_TX; hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_8K; hi2s2.Init.CPOL = I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_ENABLE; if (HAL_I2S_Init(&hi2s2) != HAL_OK) { rt_kprintf("HAL_I2S_Init error\n"); } } void I2S_DMAConvCplt(DMA_HandleTypeDef *hdma) { rt_audio_tx_complete(&_stm32_audio_play.audio); } void I2S_DMAError(DMA_HandleTypeDef *hdma) { rt_kprintf("DMAError\n"); } void DMA1_Stream4_IRQHandler(void) { rt_interrupt_enter(); HAL_DMA_IRQHandler(&hdma_spi2_tx); rt_interrupt_leave(); } void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s) { rt_kprintf("HAL_I2S_TxHalfCpltCallback pk 1\n"); rt_audio_tx_complete(&_stm32_audio_play.audio); } void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s) { rt_kprintf("HAL_I2S_TxCpltCallback pk 2\n"); rt_audio_tx_complete(&_stm32_audio_play.audio); } rt_err_t I2S_tx_dma(void) { HAL_DMA_DeInit(&hdma_spi2_tx); HAL_DMA_Init(&hdma_spi2_tx); __HAL_DMA_DISABLE(&hdma_spi2_tx); __HAL_DMA_ENABLE_IT(&hdma_spi2_tx,DMA_IT_TC);//开启DMA传输完成中断 __HAL_DMA_ENABLE_IT(&hdma_spi2_tx, DMA_IT_HT); //开启DMA半传输传输完成中断 __HAL_DMA_CLEAR_FLAG(&hdma_spi2_tx, DMA_FLAG_TCIF0_4); __HAL_RCC_DMA1_CLK_ENABLE(); //DMA1时钟使能 //注册回调函数,读取数据等操作在这里面处理 hdma_spi2_tx.XferCpltCallback = I2S_DMAConvCplt; hdma_spi2_tx.XferM1CpltCallback = I2S_DMAConvCplt; hdma_spi2_tx.XferErrorCallback = I2S_DMAError; HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn); return RT_EOK; } rt_err_t i2s_tx_init() { /* set I2S_TX DMA */ I2S_config_init(); I2S_tx_dma(); return RT_EOK; } static rt_err_t stm32_player_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps) { rt_err_t result = RT_EOK; struct stm32_audio *st_audio = (struct stm32_audio *)audio->parent.user_data; LOG_D("%s:main_type: %d, sub_type: %d", __FUNCTION__, caps->main_type, caps->sub_type); switch (caps->main_type) { case AUDIO_TYPE_QUERY: /* query the types of hw_codec device */ { switch (caps->sub_type) { case AUDIO_TYPE_QUERY: caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; break; default: result = -RT_ERROR; break; } break; } case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */ { switch (caps->sub_type) { case AUDIO_DSP_PARAM: caps->udata.config.channels = st_audio->replay_config.channels; caps->udata.config.samplebits = st_audio->replay_config.samplebits; caps->udata.config.samplerate = st_audio->replay_config.samplerate; break; case AUDIO_DSP_SAMPLERATE: caps->udata.config.samplerate = st_audio->replay_config.samplerate; break; case AUDIO_DSP_CHANNELS: caps->udata.config.channels = st_audio->replay_config.channels; break; case AUDIO_DSP_SAMPLEBITS: caps->udata.config.samplebits = st_audio->replay_config.samplebits; break; default: result = -RT_ERROR; break; } break; } case AUDIO_TYPE_MIXER: /* report the Mixer Units */ { switch (caps->sub_type) { case AUDIO_MIXER_QUERY: caps->udata.mask = AUDIO_MIXER_VOLUME | AUDIO_MIXER_LINE; break; case AUDIO_MIXER_VOLUME: caps->udata.value = st_audio->replay_volume; break; case AUDIO_MIXER_LINE: break; default: result = -RT_ERROR; break; } break; } default: result = -RT_ERROR; break; } return result; } static rt_err_t stm32_player_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps) { rt_err_t result = RT_EOK; struct stm32_audio *st_audio = (struct stm32_audio *)audio->parent.user_data; LOG_D("%s:main_type: %d, sub_type: %d", __FUNCTION__, caps->main_type, caps->sub_type); switch (caps->main_type) { case AUDIO_TYPE_MIXER: { switch (caps->sub_type) { case AUDIO_MIXER_MUTE: { /* set mute mode */ wm8978_mute_enabled(_stm32_audio_play.i2c_bus, RT_FALSE); break; } case AUDIO_MIXER_VOLUME: { int volume = caps->udata.value; st_audio->replay_volume = volume; /* set mixer volume */ wm8978_set_volume(_stm32_audio_play.i2c_bus, volume); break; } default: result = -RT_ERROR; break; } break; } case AUDIO_TYPE_OUTPUT: { switch (caps->sub_type) { case AUDIO_DSP_PARAM: { struct rt_audio_configure config = caps->udata.config; st_audio->replay_config.samplerate = config.samplerate; st_audio->replay_config.samplebits = config.samplebits; st_audio->replay_config.channels = config.channels; i2s_config_set(config); break; } case AUDIO_DSP_SAMPLERATE: { st_audio->replay_config.samplerate = caps->udata.config.samplerate; i2s_samplerate_set(caps->udata.config.samplerate); break; } case AUDIO_DSP_CHANNELS: { st_audio->replay_config.channels = caps->udata.config.channels; i2s_channels_set(caps->udata.config.channels); break; } case AUDIO_DSP_SAMPLEBITS: { st_audio->replay_config.samplebits = caps->udata.config.samplebits; i2s_samplebits_set(caps->udata.config.samplebits); break; } default: result = -RT_ERROR; break; } break; } default: break; } return result; } static rt_err_t stm32_player_init(struct rt_audio_device *audio) { /* initialize wm8978 */ _stm32_audio_play.i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(CODEC_I2C_NAME); i2s_tx_init(); wm8978_init(_stm32_audio_play.i2c_bus); return RT_EOK; } void I2S_Play_Start(void) { hi2s2.Instance->CR2 |= SPI_CR2_TXDMAEN; } static rt_err_t stm32_player_start(struct rt_audio_device *audio, int stream) { if (stream == AUDIO_STREAM_REPLAY) { rt_kprintf("HAL_I2S_Transmit_DMA start\n"); HAL_DMAEx_MultiBufferStart_IT(&hdma_spi2_tx, (uint32_t)_stm32_audio_play.tx_fifo, (uint32_t) & (SPI2->DR), (uint32_t)(_stm32_audio_play.tx_fifo + TX_DMA_FIFO_SIZE / 2), TX_DMA_FIFO_SIZE / 4); I2S_Play_Start(); wm8978_player_start(_stm32_audio_play.i2c_bus); } return RT_EOK; } static rt_err_t stm32_player_stop(struct rt_audio_device *audio, int stream) { if (stream == AUDIO_STREAM_REPLAY) { HAL_I2S_DMAStop(&hi2s2); } return RT_EOK; } static void stm32_player_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info) { /** * TX_FIFO * +----------------+----------------+ * | block1 | block2 | * +----------------+----------------+ * \ block_size / */ info->buffer = _stm32_audio_play.tx_fifo; info->total_size = TX_DMA_FIFO_SIZE; info->block_size = TX_DMA_FIFO_SIZE / 2; info->block_count = 2; } static struct rt_audio_ops _p_audio_ops = { .getcaps = stm32_player_getcaps, .configure = stm32_player_configure, .init = stm32_player_init, .start = stm32_player_start, .stop = stm32_player_stop, .transmit = NULL, .buffer_info = stm32_player_buffer_info, }; int rt_hw_sound_init(void) { rt_uint8_t *tx_fifo; /* player */ tx_fifo = rt_malloc(TX_DMA_FIFO_SIZE); if (tx_fifo == RT_NULL) { return -RT_ENOMEM; } rt_memset(tx_fifo, 0, TX_DMA_FIFO_SIZE); _stm32_audio_play.tx_fifo = tx_fifo; _stm32_audio_play.tx_fifo = tx_fifo; /* init default configuration */ { _stm32_audio_play.replay_config.samplerate = 44100; _stm32_audio_play.replay_config.channels = 2; _stm32_audio_play.replay_config.samplebits = 16; _stm32_audio_play.replay_volume = 30; } /* register sound device */ _stm32_audio_play.audio.ops = &_p_audio_ops; rt_audio_register(&_stm32_audio_play.audio, "sound0", RT_DEVICE_FLAG_WRONLY, &_stm32_audio_play); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_sound_init); ```
查看更多
4
个回答
默认排序
按发布时间排序
aozima
2020-07-08
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
读下DMA的状态,看DMA走没走? 也可以读下I2S的状态,看FIFO状态有变化没。 如果没走的话,主要检查时钟和使能。
肉肉肉肉肉肉多
2020-07-08
这家伙很懒,什么也没写!
I2S的状态 怎么读?
whj467467222
认证专家
2020-07-10
开源,分享,交流,共同进步
楼主标记一下已解决,肯定会方便以后别人排查问题的/微笑。
lcmsgs
2020-10-10
这家伙很懒,什么也没写!
楼主问题解决了吗? 我也想尝试 使用i2s dma 发送数据,发现开启音频驱动后,启动发送,总是不成功。不知道是什么问题
撰写答案
登录
注册新账号
关注者
1
被浏览
2.4k
关于作者
肉肉肉肉肉肉多
这家伙很懒,什么也没写!
提问
4
回答
28
被采纳
0
关注TA
发私信
相关问题
1
rtthread 中没有stm32的i2s(不是sai)的驱动?
2
rt-thread 官方可以对stm32系列添加i2s的驱动么?
3
求参考I2S 驱动与音频例程
4
咨询大家一个问题,单纯的I2S能调节音量吗?
5
STM32F407ZGT6音频I2S对接audio框架
6
STM32F407+PCM5102APWR+SD卡内播放wav或mp3音乐如何实现?
7
how to send i2s data from rk2108?
8
I2S WM8978 播放速度慢,有哒哒哒的噪声求助
9
使用bsp下的stm32f429-atk-apollo里面的wm8978驱动以及wavplay软件包没有声音
10
audio的replay模式播放时是先发一段0来启动吗?
推荐文章
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
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
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
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部