OpenEdv-开源电子网

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

对于DAC通过DMA和TIM6音频输出的一些疑问

[复制链接]

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
发表于 2014-1-8 09:29:13 | 显示全部楼层 |阅读模式
学习STM32的DAC方式的音频输出,采用FATFS和DMA、DAC、TIM6,读sd卡上的wav音频文件来播放,参考了一下网上的代码有一些不明白的地方请教一下高人。
第一个就是为什么参考代码中对TIM的设置代码只有这几句
  /* TIM6配制 */
  TIM_DeInit(TIM6);
  TIM_SetAutoreload(TIM6, TIM6ARRValue);
  /* TIM6 TRGO选择 */
  TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
然后在播放函数中有一个
  WavePlayer_Init();  //我这里应该不用配置,使用的都是一样的8位
  /* 启动TIM6 */
  TIM_Cmd(TIM6, ENABLE);
上面三句代码在waveplayer_Init函数中。
这样就可以让TIM6正常工作了吗?

第二个就是代码采用的先发上半段512字节到DMA,然后再发下半段512字节到DMA的方式,但我在学习ADC的时候都是先在NVIC中设置DMA1_Channel1_IRQn然后再在中断函数中来做上下半段的传输就像这样
void DMA1_Channel1_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA1_IT_HT1) == SET)
    {   
        DMA_ClearITPendingBit(DMA1_IT_HT1);
        DMA_ClearFlag(DMA1_FLAG_HT2);
        //检查过半标志,有效,清除标志,处理前半段数据   
        TreatData(0);
    }
    if (DMA_GetITStatus(DMA1_IT_TC1) == SET)
    {  
        DMA_ClearITPendingBit(DMA1_IT_TC1);
        DMA_ClearFlag(DMA1_FLAG_TC1);   
        //检查完成标志,有效,清除标志,处理后半段数据
        TreatData(adc_buff_size>>1);
      }
}

但是我的参考代码采用的这种方式

/* 根据wav文件信息配制播放器 -----------------------------------------------*/
  WavePlayer_Init();
  /* 启动TIM6 */
  TIM_Cmd(TIM6, ENABLE);  
  LCD_SetFrontColor(0x2A4C);
  LCD_FillRect(0,200,399,215);
  LCD_SetFrontColor(LGRAY);
  /* 开始播放 ----------------------------------------------------------------*/
  while(WaveDataLength)  //这是从WAV头文件读取到的数据长度
  {
    res = f_read(&fp, Wavebuffer2, BUF_SIZE, &br);
    printf("res = %d", res);
    if((res!=FR_OK) || (br==0))
    {
      f_close(&fp);
      return Invalid_WAVE_File;
    }
    if(WAVE_Format.BitsPerSample==BITS_PER_SAMPLE_16)  //这是16比特每秒采样精度
    {
      ChangeData(Wavebuffer2);     //这里为什么要changeData?
    }/**/
    if(WaveDataLength)
    {
      WaveDataLength -= BUF_SIZE;
    }
    if(WaveDataLength < BUF_SIZE)
    {
      WaveDataLength = 0;
    }
    while(DMA_GetFlagStatus(DMA2_FLAG_TC3) == RESET)   //转换完成标志
    {
      tmp=(u16)((u32)((WAVE_Format.DataSize-WaveDataLength)*400)/WAVE_Format.DataSize);
      LCD_DrawYLine(tmp, 202, 213);
    }
    DMA2->IFCR = DMA2_FLAG_TC3;  // 清除DMA2中断标志
    DMA2_Channel3->CCR = 0x0;  // 清除DMA2通道3设置寄存器配制
    DMA2_Reconfig((u32)&Wavebuffer2);    //这里为什么这样?
    res=f_read(&fp, Wavebuffer, BUF_SIZE, &br);
    if((res!=FR_OK) && (br==0))
    {
      f_close(&fp);
      return Invalid_WAVE_File;
    }
    if(WAVE_Format.BitsPerSample==BITS_PER_SAMPLE_16)
    {
      ChangeData(Wavebuffer);
    }/**/
    if(WaveDataLength)
    {
      WaveDataLength -= BUF_SIZE;
    }
    if(WaveDataLength < BUF_SIZE)
    {
      WaveDataLength = 0;
    }
    while(DMA_GetFlagStatus(DMA2_FLAG_TC3) == RESET)
    {
      tmp=(u16)((u32)((WAVE_Format.DataSize-WaveDataLength)*400)/WAVE_Format.DataSize);
      LCD_DrawYLine(tmp, 202, 213);
    }
    DMA2->IFCR = DMA2_FLAG_TC3;  // 清除DMA2中断标志
    DMA2_Channel3->CCR = 0x0;  // 清除DMA2通道3设置寄存器配制
    DMA2_Reconfig((u32)&Wavebuffer);     //这里为什么要这么做且和第一次不同,是在用之前重置一下吗?
  }
  /* 播放结束 ----------------------------------------------------------------*/
  DMA2_Channel3->CCR = 0x0;  // 清除DMA2通道3设置寄存器配制
  /* 禁止TIM6 */
  TIM_Cmd(TIM6, DISABLE);
  WaveDataLength = 0;
  f_close(&fp); // 关闭文件


void ChangeData(uint8_t table[])
{
  int16_t *tab = (int16_t *)&table[0];
  uint16_t i;
  for(i=0;i<(BUF_SIZE/2);i++)
  {
    tab += 32768;
  }
}

我的理解是先传512字节然后清DMA标志然后再传512字节,可是为什么要这样呢?这样怎么就能达到正确发送的目的呢,还有就是每当传到最后,后面的那个f_read就会因为if为真而退出整个函数,后面的播放结束操作无法进行。 DMA2_Reconfig的内容就是重新设置了一下DMA的传输数据大小,通道内存地址和通道设置寄存器。它的参数赋值给了DMA2_Channel3->CMAR。Wavebuffer和Wavebuffer2都是定义的长度512的数组。求教高人了!!谢谢
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-1-8 11:04:42 | 显示全部楼层
哪位大哥给我解答一下,感激不尽啊!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-1-8 11:13:06 | 显示全部楼层
回复【楼主位】csf4824521:
---------------------------------
楼主,第一个问题,你看代码不能光看函数名字就下结论吧?  那你整个代码,不只有一个main函数在运行哦...还只有一句话呢.
第二个问题,条条大路通罗马,这个没必要谁的代码一定要和你的相似吧?或者你的也没必要一定和别人的相同吧?

既然这么多疑问,何不亲自操刀,另辟蹊径,搞一个工程出来练练手呢?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-1-8 14:32:50 | 显示全部楼层
我不是说他的代码为什么和我的不一样,我只是想知道他的这种方式是不是也可以达到同样的效果,而他的思路是什么样的,阅读代码后我基本确定他使用的是双缓冲,但是为什么这么写就可以实现双缓冲,这样能够帮我更好的理解它的代码,也可以更好地理解DMA,我是菜鸟,更不可能怀疑别人的代码,请教原子了。
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-11 11:32

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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