搜索
bottom↓
回复: 3

请教一些DMA和音频codec相关的问题

[复制链接]

出0入0汤圆

发表于 2018-12-28 23:38:46 | 显示全部楼层 |阅读模式
最近在做音频codec的放音和录音,主芯片时STM32F407ZG,codec用的国产的,由于某些原因不能使用中断;对STM32F4的DMA和codec存在一些疑问:
1、用DMA读回codec的AD数据,DMA不工作;发送部分DMA配置成双缓冲模式,数据长度配置成1,接受部分也是配置成双缓冲模式,长度配置成100MS的AD数据长度;
2、用DMA发送时偶尔会出现左右通道的数据调换了,只有一个声道上发送数据,另一个通道发0,导致没有声音;
3、codec的ADC功能启用之后,如果codec还是在从机模式,那它采集数据的采样率是依据MCLK还是别的;

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2018-12-29 09:24:08 | 显示全部楼层
1. DMA不工作的话好好检查下代码,另外407的I2S和SPI是共用的,I2S做全双工的时候要注意:I2Sx做录音,I2Sx_ext做放音,因为I2Sx_ext的时钟要跟随I2Sx,否则单独录音的时候需要放音才能正常工作;数据长度配置成1也太少了,音频数据很快,开个数组也一下就填满了;
2. 左右声道调换的问题,还是I2Sx和I2Sx_ext的问题,407的I2S在启动的时候不会去检查WS的极性,就会导致左右声道数据调换;
3. 拿示波器看下WS频率,就是采样率,MCLK是256倍的采样率;

附一张407 I2S和PLL所有采样率的时钟配置表

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2018-12-29 11:12:57 | 显示全部楼层
qq854149876 发表于 2018-12-29 09:24
1. DMA不工作的话好好检查下代码,另外407的I2S和SPI是共用的,I2S做全双工的时候要注意:I2Sx做录音,I2Sx ...

录音的时候,改成发送DMA使用循环模式,接收DMA用双缓冲,但是还是没跑起来,下面是发送和接收DMA的配置,帮忙看下有没有问题;
DMA配置
void init_codec_adc(void)
{
        DMA_InitTypeDef  DMA_InitStructure;
        //
        codec_rx_tem = &codec_buf[0][0];
        codec_rx_tem = &codec_buf[1][0];
        //DMA1时钟使能
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
        //通道0,流3指向I2S_RX
        DMA_DeInit(DMA1_Stream3);
        /* 配置 DMA Stream */
        //通道0 SPI2_RX通道
        DMA_InitStructure.DMA_Channel = DMA_Channel_3;
        //外设地址为:(u32)&SPI2->DR
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&I2S2ext->DR;
        //DMA 存储器0地址 //此处可以不配置
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)codec_rx_tem;
        //外设到存储器模式
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
        //
        //数据传输量//100ms
        DMA_InitStructure.DMA_BufferSize = 3200;        //3200或者1600
        //外设非增量模式
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        //存储器增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        //外设数据长度:16位
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        //存储器数据长度:16位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        //使用循环模式        //双缓冲模式时此位无效
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        //高优先级
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        //不使用FIFO模式
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
        //
        //外设突发单次传输
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
        //存储器突发单次传输
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        //初始化DMA Stream
        DMA_Init(DMA1_Stream3, &DMA_InitStructure);
        //
        DMA_ITConfig(DMA1_Stream3,DMA_IT_TC,DISABLE);
        //
        //DMA_Memory_0首先被传输
        DMA_DoubleBufferModeConfig(DMA1_Stream3,(uint32_t)codec_rx_ok,DMA_Memory_1);
        //使能双缓冲模式
        DMA_DoubleBufferModeCmd(DMA1_Stream3,ENABLE);
        //
        cur_dma_ct = 0;
        store_dma_ct = 0;
        codec_dma_stream_is_enable = False;
}
//
void init_codec_tx_dma(void)
{
        DMA_InitTypeDef  DMA_InitStructure;
        //
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);
        //
        DMA_DeInit(DMA1_Stream4);
        /* 配置 DMA Stream */
        DMA_InitStructure.DMA_Channel = DMA_Channel_0;  //通道0 SPI2_TX通道
        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;//外设地址为:(u32)&SPI2->DR
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)codec_tx_buf;//DMA 存储器0地址 //此处可以不配置
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//存储器到外设模式
        //
        DMA_InitStructure.DMA_BufferSize = 16;//数据传输量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据长度:16位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据长度:16位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式        //双缓冲模式时此位无效
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用FIFO模式
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
        //
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//外设突发单次传输
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//存储器突发单次传输
        //
        DMA_Init(DMA1_Stream4, &DMA_InitStructure);//初始化DMA Stream
        //
        DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,DISABLE);
}
I2S配置
void init_i2s_transmission(void)
{
        I2S_InitTypeDef m_iis_para;
        //
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
        //
        I2S_Cmd(SPI2,DISABLE);
        //
        m_iis_para.I2S_Mode = I2S_Mode_MasterTx;
        m_iis_para.I2S_DataFormat = I2S_DataFormat_16b;
        m_iis_para.I2S_Standard = I2S_Standard_MSB;
        m_iis_para.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
        m_iis_para.I2S_AudioFreq = I2S_AudioFreq_8k;
        m_iis_para.I2S_CPOL = I2S_CPOL_Low;
        //
        I2S_Init(SPI2,&m_iis_para);
        //
        I2S_Cmd(SPI2, ENABLE);
}
//
void init_i2s_receiver(void)
{
        I2S_InitTypeDef m_iis_para;
        //
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
        //
        I2S_Cmd(I2S2ext,DISABLE);
        //
        m_iis_para.I2S_Mode = I2S_Mode_SlaveRx;
        m_iis_para.I2S_DataFormat = I2S_DataFormat_16b;
        m_iis_para.I2S_Standard = I2S_Standard_MSB;
        m_iis_para.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
        m_iis_para.I2S_AudioFreq = I2S_AudioFreq_8k;
        m_iis_para.I2S_CPOL = I2S_CPOL_Low;
        //
        I2S_FullDuplexConfig(I2S2ext,&m_iis_para);
        //
        I2S_Cmd(I2S2ext, ENABLE);
}
时钟配置,固定采样率时钟保持输出并且不变
void init_i2s_pm(void)
{
        I2S_Cmd(SPI2,DISABLE);
        RCC->CR &= ~(1 << 26);  //停止I2S时钟
        /*    Fvco = 12.288 * (300 / 10) -> 368.64MHZ  */
        /*    Fpll = 368.64 / 6  -> 61.44MHZ          */
        //RCC_PLLI2SConfig(240,6);
        RCC->PLLI2SCFGR = (6 << 28) | (300 << 6); //PLLI2S时钟61.44MHZ
        RCC->CR |= 1 << 26;                                          //开启I2S时钟
        while((RCC->CR&1<<27)==0);                //等待I2S时钟开启成功.
        /* bit9: I2S MCK ENABLE,bit8 : ODD 0: div * 2,1: div * 2 + 1*/
        SPI2->I2SPR = (1 << 9) | 15;       //61.44MHZ总线频率,分频到2.048MHZ | (1 << 8)
        //SPI_I2SCFGR bit11:I2S mode/ bit10:enable/ bit9-8:master send/receive slave s/r
        //bit7:PCM frame sync bit6:receive bit5-4:I2S stanted selection bit3:COPL
        //bit2-1:data len 00 16bit bit0:channel len
        //这个寄存器在配置发射和接受时再配,这里不需要开出来
        //SPI2->I2SCFGR = (1 << 11) | (2 << 8) | (0 << 4) | (0 << 3); //I2S模式,主发,MSB对齐,16bit,通道16位
        //I2S_Cmd(SPI2,ENABLE);
}

出0入0汤圆

 楼主| 发表于 2018-12-29 11:19:03 | 显示全部楼层
jueenkay 发表于 2018-12-29 11:12
录音的时候,改成发送DMA使用循环模式,接收DMA用双缓冲,但是还是没跑起来,下面是发送和接收DMA的配置 ...

I2S的DMA功能使能放在启动录音时打开
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-18 21:53

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表