OpenEdv-开源电子网

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

为什么用SD+DMA+DAC播放WAV文件只有哒哒哒的声音

[复制链接]

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
发表于 2014-1-9 17:02:43 | 显示全部楼层 |阅读模式
我是直接在开发板的PA4引脚和一个GND引脚上接的一个8欧0.5瓦的小喇叭,喇叭上还串联了一个105的电容,播放的WAV文件是8位22KHz单声道PCM格式的文件,DMA代码是这样的
  DMA_DeInit(DMA2_Channel3);
  DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR8R1_Address; // 单通道8位右对齐     数据的来源
  DMA_InitStructure.DMA_BufferSize = BUFF_SIZE; // 缓冲大小
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 8位数据宽度
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8位数据宽度
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&Wavebuffer; // 内存基址     数据要写到哪里去
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 外设作为数据传输的目的地
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址寄存器不变
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址寄存器递增
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 工作在正常缓存模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High; // DMA通道x拥有高优先级
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // DMA通道x没有设置为内存到内存传输
  DMA_Init(DMA2_Channel3, &DMA_InitStructure);
  DMA_Cmd(DMA2_Channel3, ENABLE);     //使能DMA2通道3
  DMA_ITConfig(DMA2_Channel3, DMA_IT_TC | DMA_IT_HT, ENABLE);

TIM6的代码是这样的:
  TIM_DeInit(TIM6);
  TIM_SetAutoreload(TIM6, TIM6ARRValue);        //TIM6ARRValue的值是72000000/22050
  TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);
  TIM_Cmd(TIM6, ENABLE);

DAC的代码是这样的

  DAC_DeInit();
  DAC_StructInit(&DAC_InitStructure);

  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; //选择定时器6做外部触发源
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; // 无波形产生
  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; // 禁止输出缓冲

  DAC_Init(DAC_Channel_1, &DAC_InitStructure);         //DAC通道1初始化
  DAC_Cmd(DAC_Channel_1, ENABLE);            //使能DAC通道1:一旦使能了DAC通道1,PA.04将自动连接到DAC转换器
  DAC_DMACmd(DAC_Channel_1, ENABLE);       //使能DMA用于DAC通道1

  DAC_Init(DAC_Channel_2, &DAC_InitStructure);   //DAC通道2初始化
  DAC_Cmd(DAC_Channel_2, ENABLE);             //使能DAC通道2:一旦使能了DAC通道2,PA.05将自动连接到DAC转换器   
  DAC_DMACmd(DAC_Channel_2, ENABLE);        //使能DMA用于DAC通道2

然后使用了中断
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =3;//NVIC_PriorityGroup_1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;// NVIC_PriorityGroup_4;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

在中断函数中写数据

void PlayReadBlock(u16 offset)
{
    FRESULT res;
    res = f_read(&fp, Wavebuffer + offset, 512, &br);
    if((res!=FR_OK) || (br==0))
    {
      f_close(&fp);
    }
    else if (br < 512)
    {
        f_close(&fp);
        TIM_ITConfig(TIM6, TIM_IT_Update, DISABLE);    //禁止TIM6更新中断
          TIM_Cmd(TIM6, DISABLE);       //禁止TIM6    
    }    
}

void DMA2_Channel3_IRQHandler(void)
{
    if (DMA_GetITStatus(DMA2_IT_HT3) == SET)
    {    
        DMA_ClearITPendingBit(DMA2_IT_HT3);
        DMA_ClearFlag(DMA2_FLAG_HT3);
        //检查过半标志,有效,清除标志,处理前半段数据   
        PlayReadBlock(0);
    }
    LED3 = !LED3;
    if (DMA_GetITStatus(DMA2_IT_TC3) == SET)
    {  
        DMA_ClearITPendingBit(DMA2_IT_TC3);
        DMA_ClearFlag(DMA2_FLAG_TC3);    
        //检查完成标志,有效,清除标志,处理后半段数据
        PlayReadBlock(BUFF_SIZE>>1);
      }
}

基本上就是这些了,代码都能正常运行中断也能正常进入,不知道是不是我的配置有问题,或者是计算有问题,本人是菜鸟才入门STM32请教坛子里的各位朋友,谢谢了!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

2178

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3323
金钱
3323
注册时间
2013-7-19
在线时间
195 小时
发表于 2014-1-10 09:05:04 | 显示全部楼层
512字节数据量在8位22k下大概够维持23ms的播放。检测读取时间是不是能跟上播放速度,另外我不是太清楚你这样同时读取和写入同一个数组行不行,印象中音频还是应该用双缓冲。
回复 支持 反对

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-1-10 09:16:21 | 显示全部楼层
回复【2楼】ricefat:
---------------------------------
如果您说的是单独的f_read的读取SD卡文件的时间的话,我测试过每秒有200K以上。
您说的双缓冲是这样吗?
    res = f_read(&fp, Wavebuffer2, BUF_SIZE, &br);
    if((res!=FR_OK) || (br==0))
    {
      f_close(&fp);
  //LED1 = !LED1;
      return Invalid_WAVE_File;
    }
    
    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(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);
不知道会不会是喇叭的问题我之前用网上找到的一个代码,并且他介绍了直接移植的方法,编译通过后输出到喇叭上的声音也是哒哒哒的声音,我看人家都是接的音响或者耳机,不知道能不能驱动起来这个喇叭
回复 支持 反对

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-1-10 14:38:17 | 显示全部楼层
问题还没有解决,顶一下自己
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-1-11 05:27:38 | 显示全部楼层
DAC输出加滤波再加专用的喇叭驱动器驱动喇叭吧!
直接IO驱动,不够力的,你看看stm32的数据手册,dac直接输出,可以驱动多大电流?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
369
金钱
369
注册时间
2013-12-23
在线时间
32 小时
 楼主| 发表于 2014-1-16 10:10:55 | 显示全部楼层
回复晚了,谢谢ricefat和原子兄,原因找到了,自己都觉得丢人!我的喇叭和开发板的引脚接错了,所以一直没有声音,还需要学习啊,确实很难驱动,声音非常小,用一个C9014的三极管和4K电阻接上喇叭声音大了不少,但还是达不到要求,可能需要上驱动电路,还有ricefat兄我的应该就是双缓冲,因为我是1024的缓冲区,先写前512判断过半再写后512判断结束全部放在DMA中断中,实现后音频播放效果不错,再次感谢二位
回复 支持 反对

使用道具 举报

15

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
94
金钱
94
注册时间
2014-10-22
在线时间
24 小时
发表于 2014-11-5 20:45:22 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
原子大哥,1:使用DMA+DAC+TIM6这样的传输方式,因为外设地址不变,有木有可能DMA之前传送的一个数据还未数模转换,DMA传送的数据又到了将之前的数据覆盖了???
2:DMA使用正常模式(即不使用循环传送),缓冲区数据传送完成后将停止DMA传送,如果再次启动DMA,是不是又是从缓冲区首地址开始传送?
求解,谢谢原子大哥!
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-11-5 22:26:59 | 显示全部楼层
1,有啊,所以你不能速度太快。
2,是的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

100

主题

208

帖子

0

精华

高级会员

Rank: 4

积分
537
金钱
537
注册时间
2013-8-9
在线时间
3 小时
发表于 2014-11-29 22:14:02 | 显示全部楼层
楼主代码可分享吗,我最近也在做 WAV软件解码,跟你差不多
STM32初学者,望多指教
回复 支持 反对

使用道具 举报

1

主题

16

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2017-7-13
在线时间
22 小时
发表于 2017-8-22 11:40:17 | 显示全部楼层
csf4824521 发表于 2014-1-16 10:10
回复晚了,谢谢ricefat和原子兄,原因找到了,自己都觉得丢人!我的喇叭和开发板的引脚接错了,所以一直没 ...

我现在  单片机能输出波形 但是一接上喇叭就没有了  喇叭也没有声音  怎么回事呢
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
63
金钱
63
注册时间
2016-5-11
在线时间
17 小时
发表于 2017-11-22 18:21:35 | 显示全部楼层
原子哥和各位大师 能帮我看看为什么不能读取WAV文件吗?  成功打开文件后 读取WAV格式文件失败  但是TXT格式的可以          mf_open("0:/BEEP1",FA_OPEN_ALWAYS|FA_READ );                   res=f_read(file,fatbuf,512,&br); ,这里br为0   

下面是文件目录:0:/System Volume Information
0:/data2.txt
0:/data.txt
0:/hex.txt
0:/pwm.txt
0:/ALARM1.wav.WAV
0:/BEEP1.WAV
f_open sucess

回复 支持 反对

使用道具 举报

0

主题

6

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2018-12-15
在线时间
1 小时
发表于 2018-12-19 12:00:44 | 显示全部楼层
能不能发份源码给我学习学习啊,刚入门,我也在弄这样的实验,但是遇到好多问题,麻烦了,谢谢 870327588@qq.com
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-30 07:45

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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