OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4984|回复: 3

stm32l系列单片机驱动WM8978的问题

[复制链接]

4

主题

17

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2018-5-18
在线时间
20 小时
发表于 2020-10-29 18:13:44 | 显示全部楼层 |阅读模式
1金钱
项目用了L496单片机,参考了原子哥的“潘多拉STM32L475”的例程,驱动WM8978
用的是SAI2,在用示波器量出LRC=44.6M,BLCK=2.85M,MCLK=11.43M,可以看出,SAI初始化应该没有问题
现在问题来了:在程序跑起来之后,只有几个时钟的波形正常显示,但是ADC没有采样,或者说SAIB的DMA中断没有进去
由于L系列没有双缓存,所以按照潘多拉例程,使用半完成中断
录音模式的进入函数和例程如出一辙
//进入PCM 录音模式                  
void recoder_enter_rec_mode(void)
{
        WM8978_ADDA_Cfg(0,1);                //开启ADC   关闭DAC
        WM8978_Input_Cfg(1,1,0);        //开启输入通道(MIC&LINE IN) 这里就说明两个地方都使用 不管是麦克风输入 说着数据线输入都可以接收
        WM8978_Output_Cfg(1,1);                //开启BYPASS输出 DAC输出要不要也开着?
        WM8978_MIC_Gain(46);                //MIC增益设置
        WM8978_SPKvol_Set(0);                //关闭喇叭.
        WM8978_I2S_Cfg(2,0);                //飞利浦标准,16位数据长度
      
        MX_SAI2_Init();//SAI1 Block A,主发送,16位数据
        SAIA_TX_DMA_Init();
        __HAL_DMA_DISABLE_IT(&hdma_sai2_a_TX_Handler, DMA_IT_TC);
        SAIA_RX_DMA_Init();
    sai_rx_callback = rec_sai_dma_rx_callback;//初始化回调函数指sai_rx_callback
    HAL_SAI_Transmit(&hsai_BlockA2, (uint8_t *)&saiplaybuf[0], 2, 0);
    HAL_SAI_Receive_DMA(&hsai_BlockB2, sairecbuf, SAI_RX_DMA_BUF_SIZE);
    SAI_Play_Start();                        //开始SAI数据发送(主机),为SAI1B通道提供时钟
}


于是我想是不是DMA初始化部分出现了问题
static void SAIA_TX_DMA_Init(void)
{
        __HAL_RCC_DMA1_CLK_ENABLE();
    __HAL_LINKDMA(&hsai_BlockA2,hdmatx,hdma_sai2_a_TX_Handler);
    hdma_sai2_a_TX_Handler.Instance = DMA1_Channel6;
    hdma_sai2_a_TX_Handler.Init.Request = DMA_REQUEST_1;
    hdma_sai2_a_TX_Handler.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_sai2_a_TX_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sai2_a_TX_Handler.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sai2_a_TX_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //此处是音频采样码率 8位:DMA_PDATAALIGN_BYTE /32位:DMA_PDATAALIGN_WORD
    hdma_sai2_a_TX_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;    //此处是音频采样码率 8位:DMA_MDATAALIGN_BYTE /32位:DMA_MDATAALIGN_WORD
    hdma_sai2_a_TX_Handler.Init.Mode = DMA_CIRCULAR;                           //循环模式?
    hdma_sai2_a_TX_Handler.Init.Priority = DMA_PRIORITY_HIGH;                   //优先级之后再排
    if (HAL_DMA_Init(&hdma_sai2_a_TX_Handler) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }
    __HAL_DMA_DISABLE(&hdma_sai2_a_TX_Handler);                         //先关闭DMA
    delay_us(10);                                                   //10us延时,防止-O2优化出问题        
    __HAL_DMA_ENABLE_IT(&hdma_sai2_a_TX_Handler,DMA_IT_TC);             //开启传输完成中断
        __HAL_DMA_ENABLE_IT(&hdma_sai2_a_TX_Handler,DMA_IT_HT);             //开启半传输完成中断
      
    __HAL_DMA_CLEAR_FLAG(&hdma_sai2_a_TX_Handler,DMA_FLAG_TC6);             //清除DMA传输完成中断标志位
        __HAL_DMA_CLEAR_FLAG(&hdma_sai2_a_TX_Handler,DMA_FLAG_HT6);             //清除DMA半传输完成中断标志位

        HAL_NVIC_SetPriority(DMA1_Channel6_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel6_IRQn);
}

static void SAIA_RX_DMA_Init(void)
{
        __HAL_RCC_DMA2_CLK_ENABLE();
        __HAL_LINKDMA(&hsai_BlockB2,hdmarx,hdma_sai2_b_RX_Handler);
        hdma_sai2_b_RX_Handler.Instance = DMA2_Channel4;
        hdma_sai2_b_RX_Handler.Init.Request = DMA_REQUEST_1;
        hdma_sai2_b_RX_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_sai2_b_RX_Handler.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_sai2_b_RX_Handler.Init.MemInc = DMA_MINC_ENABLE;
        hdma_sai2_b_RX_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;//此处需要和A block对应,多少码率采集就用多少码率播放
        hdma_sai2_b_RX_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
        hdma_sai2_b_RX_Handler.Init.Mode = DMA_CIRCULAR;
        hdma_sai2_b_RX_Handler.Init.Priority = DMA_PRIORITY_LOW;
        if (HAL_DMA_Init(&hdma_sai2_b_RX_Handler) != HAL_OK)
        {
          _Error_Handler(__FILE__, __LINE__);
        }
      
        HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 0, 1);
        HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
}

使用的半传输完成中断,基本和例程相同,区别在于DMA通道使用的不一样,经检查,DMA1_6和DMA2_4都应该使用正确
最后是DMA中断处理和回调函数
void DMA1_Channel6_IRQHandler(void)
{
        DMA1_Channel6_Callback(&hdma_sai2_a_TX_Handler);      
}

void DMA2_Channel4_IRQHandler(void)
{
        DMA2_Channel4_Callback(&hdma_sai2_b_RX_Handler);
}


问题点就在此处,程序仿真,打断点于两个DMA中断函数,发现无论怎样,DMA都不进中断,啊,想得我头秃
望大佬们或者原子哥能帮着看看

最佳答案

查看完整内容[请看2#楼]

自问自答系列: 出现了以下几个问题,修改后基本正常了: 1、原子参考例程用的软件模拟iic,我原本使用硬件iic,修改为软件模拟后,成功驱动WM8978 2、录音功能SAIB必须有SAIA发送一个0x0000去使能,这点教程里写了,问题出在HAL_SAI_Receive_DMA(&hsai_BlockB2, sairecbuf, SAI_RX_DMA_BUF_SIZE);中的“sairecbuf”,定义为一个指针,改为数组“sairecbuf[SAI_RX_DMA_BUF_SIZE]”,成功使能DMA中断。 其实以上两个问题的原因, ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

17

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2018-5-18
在线时间
20 小时
 楼主| 发表于 2020-10-29 18:13:45 | 显示全部楼层
自问自答系列:
出现了以下几个问题,修改后基本正常了:
1、原子参考例程用的软件模拟iic,我原本使用硬件iic,修改为软件模拟后,成功驱动WM8978
2、录音功能SAIB必须有SAIA发送一个0x0000去使能,这点教程里写了,问题出在HAL_SAI_Receive_DMA(&hsai_BlockB2, sairecbuf, SAI_RX_DMA_BUF_SIZE);中的“sairecbuf”,定义为一个指针,改为数组“sairecbuf[SAI_RX_DMA_BUF_SIZE]”,成功使能DMA中断。
其实以上两个问题的原因,我也不是很明白,同一个代码,其他硬件IIC驱动就是正常,以及,数组本来就和指针是相同的作用。
为什么修改后能够成功驱动8978,就又值得思考思考了
原子哥看到了希望解答下
回复

使用道具 举报

4

主题

17

帖子

0

精华

初级会员

Rank: 2

积分
69
金钱
69
注册时间
2018-5-18
在线时间
20 小时
 楼主| 发表于 2020-10-30 13:44:08 | 显示全部楼层
自定一下
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2020-11-1 00:50:16 | 显示全部楼层
帮顶
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-21 15:10

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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