OpenEdv-开源电子网

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

【正点原子探索者STM32F407开发板例程连载+教学】第57章 USB声卡(Slave)实验

[复制链接]

230

主题

1950

帖子

10

精华

论坛元老

Rank: 8Rank: 8

积分
4562
金钱
4562
注册时间
2010-12-14
在线时间
32 小时
发表于 2014-12-9 14:25:57 | 显示全部楼层 |阅读模式

第五十七章 USB声卡(Slave)实验

 

1.硬件平台:正点原子探索者STM32F407开发板 
2.软件平台:MDK5.1
 3.固件库版本:V1.4.0 

上一章我们向大家介绍了如何利用STM32F4USB接口来做一个USB读卡器,本章我们将利用STM32F4USB来做一个声卡。本章分为如下几个部分:

57.1 USB声卡简介

57.2 硬件设计

57.3 软件设计

57.4 下载验证

 

57.1 USB声卡简介

ALIENTEK探索者STM32F4开发板板载了一颗高性能CODEC芯片:WM8978,我们可以利用STM32F4IIS,控制WM8978播放音乐,同样,如果结合STM32F4USB功能,就可以实现一个USB声卡。

同上一章一样,我们直接移植官方的USB AUDIO例程,官方例程路径:8STM32参考资料àSTM32 USB 学习资料àSTM32_USB-Host-Device_Lib_V2.1.0àProjectàUSB_De

vice_ExamplesàAUDIO,该例程采用USB同步传输来传输音频数据流并且支持某些控制命令(比如静音控制),例程仅支持USB FS模式(不支持HS),同时例程不需要特殊的驱动支持,大多数操作系统直接就可以识别。

57.2 硬件设计

本节实验功能简介:开机的时候先显示一些提示信息,之后开始USB配置,在配置成功之后就可以在电脑上发现多出一个USB声卡。我们用DS1来指示USB是否连接成功,并在液晶上显示USB连接状况,如果成功连接,我们可以将耳机插入开发板的PHONE端口(或者喇叭接P1(SPK)端子也行),听到来自电脑的音频信号。同样我们还是用DS0来指示程序正在运行。

所要用到的硬件资源如下:

1)  指示灯DS0 DS1

2)  串口

3)  TFTLCD模块

4)  USB SLAVE接口

5)  WM8978 

这几个部分,在之前的实例中都已经介绍过了,我们在此就不多说了。这里再次提醒大家,P11的连接,要通过跳线帽连接PA11D-以及PA12D+

57.3 软件设计

本章,我们在第四十八章实验 (实验43 )的基础上修改,先打开实验43 的工程,在HARDWARE文件夹所在文件夹下新建一个USB的文件夹,同上一章一样,对照官方AUDIO例子,将相关文件拷贝到USB文件夹下。

然后,我们在工程里面去掉一些不必要的代码,并添加USB相关代码,最终得到如图57.3.1所示的工程:

57.3.1 USB声卡工程截图

可以看到,USB部分代码,同上一章的在结构上是一模一样的,只是.c文件稍微有些变化。同样,我们移植需要修改的代码,就是USB_APP里面的这四个.c文件了。

其中usb_bsp.cusbd_usr.c的代码,和上一章基本一样,可以用上一章的代码直接替换即可正常使用。

usb_desc.c代码,同上一章不一样,上一章描述符是大容量存储设备,本章变成了USB声卡了,所以直接用ST官方的就行。

最后stm324xg_usb_audio_codec.c,这里面的代码,是重点要修改的,该文件是配合USB声卡的CS43L22底层驱动相关代码,官方STM32F4xG的板子,用的是CS43L22,而我们用的是WM8978,所以这里面代码要大改,修改后代码如下:

u8 volume=0;                                                  //当前音量 

vu8 audiostatus=0;                                            //bit0:0,暂停播放;1,继续播放  

vu8 i2splaybuf=0;                                            //即将播放的音频帧缓冲编号

vu8 i2ssavebuf=0;                                            //当前保存到的音频缓冲编号

#define AUDIO_BUF_NUM        100                //由于采用的是USB同步传输数据播放

//STM32 IIS的速度和USB传送过来数据的速度存在差异,

//比如在48Khz,实际IIS是低

//48Khz(47.991Khz),所以电脑送过来的数据流,会比STM32播放速度快,缓冲区写位置

//追上播放位置(i2ssavebuf==i2splaybuf),就会出现混叠.设置尽量大的AUDIO_BUF_NUM

//,可以尽量减少混叠次数.                                                      

u8 *i2sbuf[AUDIO_BUF_NUM];

//音频缓冲帧,占用内存数=AUDIO_BUF_NUM*AUDIO_OUT_PACKET 字节

//音频数据I2S DMA传输回调函数

void audio_i2s_dma_callback(void)

{     

       if((i2splaybuf==i2ssavebuf)&&audiostatus==0) I2S_Play_Stop();

else

       {

              i2splaybuf++;//指向下一个buf

              if(i2splaybuf>(AUDIO_BUF_NUM-1))i2splaybuf=0;//溢出

              if(DMA1_Stream4->CR&(1<<19))

DMA_MemoryTargetConfig(DMA1_Stream4,(u32)i2sbuf[i2splaybuf],DMA_Memory_0);          else

DMA_MemoryTargetConfig(DMA1_Stream4,(u32)i2sbuf[i2splaybuf],DMA_Memory_1);

}

}  

//配置音频接口

//OutputDevice:输出设备选择,未用到.

//Volume:音量大小,0~100

//AudioFreq:音频采样率

uint32_t EVAL_AUDIO_Init(uint16_t OutputDevice, uint8_t Volume, uint32_t AudioFreq)

{  

       u16 t=0;

       for(t=0;t<AUDIO_BUF_NUM;t++)            //内存申请

       {

              i2sbuf[t]=mymalloc(SRAMIN,AUDIO_OUT_PACKET);

       }

       if(i2sbuf[AUDIO_BUF_NUM-1]==NULL)  //内存申请失败

       {

              printf("Malloc Error!\r\n");

              for(t=0;t<AUDIO_BUF_NUM;t++)myfree(SRAMIN,i2sbuf[t]);

              return 1;

       }

       I2S2_Init(I2S_Standard_Phillips,I2S_Mode_MasterTx,I2S_CPOL_Low,

I2S_DataFormat_16bextended);             

//飞利浦标准,主机发送,时钟低电平有效,16位扩展帧长度

       I2S2_SampleRate_Set(AudioFreq);             //设置采样率

       EVAL_AUDIO_VolumeCtl(Volume);          //设置音量

       I2S2_TX_DMA_Init(i2sbuf[0],i2sbuf[1],AUDIO_OUT_PACKET/2);

      i2s_tx_callback=audio_i2s_dma_callback;    //回调函数指wav_i2s_dma_callback

       I2S_Play_Start();                                      //开启DMA 

       printf("EVAL_AUDIO_Init:%d,%d\r\n",Volume,AudioFreq);

       return 0;

}

//开始播放音频数据

//pBuffer:音频数据流首地址指针

//Size:数据流大小(单位:字节)

uint32_t EVAL_AUDIO_Play(uint16_t* pBuffer, uint32_t Size)

       printf("EVAL_AUDIO_Play:%x,%d\r\n",pBuffer,Size);

       return 0;

}

//暂停/恢复音频流播放

//Cmd:0,暂停播放;1,恢复播放

//Addr:音频数据流缓存首地址

//Size:音频数据流大小(单位:harf word,也就是2个字节

//返回值:0,成功

//    其他,设置失败

uint32_t EVAL_AUDIO_PauseResume(uint32_t Cmd, uint32_t Addr, uint32_t Size)

{   

       u16 i;u8 *p=(u8*)Addr;

       if(Cmd==AUDIO_PAUSE) audiostatus=0;

       else

       {

              audiostatus=1;

              i2ssavebuf++;

              if(i2ssavebuf>(AUDIO_BUF_NUM-1))i2ssavebuf=0;

              for(i=0;i<AUDIO_OUT_PACKET;i++) i2sbuf[i2ssavebuf]=p;//拷贝数据

              I2S_Play_Start();//开启DMA 

       }

       return 0;

}

//停止播放

//Option:控制参数,1/2,详见:CODEC_PDWN_HW定义

//返回值:0,成功

//    其他,设置失败

uint32_t EVAL_AUDIO_Stop(uint32_t Option)

{

       printf("EVAL_AUDIO_Stop:%d\r\n",Option);

       audiostatus=0;return 0;

}

//音量设置

//Volume:0~100

//返回值:0,成功

//    其他,设置失败

uint32_t EVAL_AUDIO_VolumeCtl(uint8_t Volume)

{

       volume=Volume;

       WM8978_HPvol_Set(volume*0.63,volume*0.63);

       WM8978_SPKvol_Set(volume*0.63);

       return 0;

}

//静音控制

//Cmd:0,正常

//    1,静音

//返回值:0,正常

//    其他,错误代码

uint32_t EVAL_AUDIO_Mute(uint32_t Cmd)

       if(Cmd==AUDIO_MUTE_ON) {

WM8978_HPvol_Set(0,0); WM8978_SPKvol_Set(0);}

       else

       {

              WM8978_HPvol_Set(volume*0.63,volume*0.63);

              WM8978_SPKvol_Set(volume*0.63);

       }

       return 0;

//播放音频数据流

//Addr:音频数据流缓存首地址

//Size:音频数据流大小(单位:harf word,也就是2个字节)

void Audio_MAL_Play(uint32_t Addr, uint32_t Size)

       u16 i;  u8 t=i2ssavebuf;

       u8 *p=(u8*)Addr;

       u8 curplay=i2splaybuf;  //当前正在播放的缓存帧编号

       if(curplay)curplay--;

       else curplay=AUDIO_BUF_NUM-1;

       audiostatus=1;

       t++;

       if(t>(AUDIO_BUF_NUM-1))t=0;

       if(t==curplay)               //写缓存碰上了当前正在播放的帧,跳到下一帧

       {

              t++;

              if(t>(AUDIO_BUF_NUM-1))t=0;  

              printf("bad position:%d\r\n",t);

       }

       i2ssavebuf=t;

       for(i=0;i<Size*2;i++) i2sbuf[i2ssavebuf]=p;//拷贝数据

       I2S_Play_Start();          //开启DMA 

}

       这里特别说明一下,USB AUDIO我们使用的是USB同步数据传输,音频采样率固定为:48Khz(通过USBD_AUDIO_FREQ设置,在usbd_conf.h里面),这样,USB传输过来的数据都是48Khz的音频数据流,STM32F4必须以同样的频率传输数据给IIS,以同步播放音乐。

       但是,STM32F4我们采用的是内部8M时钟倍频后分频作为IIS时钟的,在使能主时钟(MCK)输出的时候,只能以47.991Khz频率播放,稍微有点误差,这样,导致USB送过来的数据,会比传输给IIS的数据快一点点,如果不做处理,就很容易产生数据混叠,产生噪音。

因此,我们这里提供了一个简单的解决办法:建立一个类似FIFO结构的缓冲数组,USB传输过来的数据全部存放在这些数组里面,同时通过IIS DMA双缓冲机制,播放这些数组里面的音频数据,当混叠发生时(USB传过来的数据,赶上IIS播放的数据了),直接越过当前正在播放的数组,继续保存。这样,虽然会导致一些数据丢失(混叠时),但是避免了混叠,保证了良好的播放效果(听不到噪音),同时,数组个数越多,效果就越好(越不容易混叠)。

       以上代码AUDIO_BUF_NUM就是我们定义的FIFO结构数组的大小,越大,效果越好,这里我们定义成100,每个数组的大小由音频采样率和位数决定,计算公式为:

(USBD_AUDIO_FREQ * 2 * 2) /1000

       单位为字节,其中USBD_AUDIO_FREQ即音频采样率:48Khz,这样,每个数组大小就是192字节。100个数组,我们总共用了19200字节。

       audio_i2s_dma_callback函数是IIS播放音频的回调函数,完成IIS数据流的发送,其他函数则基本都是在usbd_audio_out_if.c里面被调用,这里就不再详细介绍了。

最后在main.c里面,我们修改main函数如下:

USB_OTG_CORE_HANDLE USB_OTG_dev;

extern vu8 bDeviceState;              //USB连接 情况

extern u8 volume;                       //音量(可通过按键设置)

int main(void)

       u8 key; u8 t=0;u8 Divece_STA=0XFF;

       NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2

       delay_init(168);  //初始化延时函数

       uart_init(115200);         //初始化串口波特率为115200

       LED_Init();                         //初始化LED

       usmart_dev.init(84);             //初始化USMART

      LCD_Init();                         //LCD初始化 

      KEY_Init();                         //按键初始化 

      WM8978_Init();                   //初始化WM8978

       WM8978_ADDA_Cfg(1,0);  //开启DAC

       WM8978_Input_Cfg(0,0,0);  //关闭输入通道

       WM8978_Output_Cfg(1,0);  //开启DAC输出

       my_mem_init(SRAMIN);     //初始化内部内存池

       my_mem_init(SRAMCCM);  //初始化CCM内存池

      POINT_COLOR=RED;//设置字体为红色     

       LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");      

       LCD_ShowString(30,70,200,16,16,"USB Sound Card TEST");

       LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");

       LCD_ShowString(30,110,200,16,16,"2014/7/22");    

       LCD_ShowString(30,130,200,16,16,"KEY2:Vol-  KEY0:vol+");   

      POINT_COLOR=BLUE;//设置字体为蓝色

      LCD_ShowString(30,160,200,16,16,"VOLUME:");           //音量显示     

       LCD_ShowxNum(30+56,160,DEFAULT_VOLUME,3,16,0X80);//显示音量

       LCD_ShowString(30,180,200,16,16,"USB Connecting...");//提示正在建立连接   

       USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,&USR_desc,&AUDIO_cb,

&USR_cb);   

       while(1)

       {

              key=KEY_Scan(1);       //支持连按

              if(key)

              {

                     if(key==KEY0_PRES)         //KEY0按下,音量增加

                     {

                            volume++;

                            if(volume>100)volume=100;

                     }else if(key==KEY2_PRES)//KEY2按下,音量减少

                     {

                            if(volume)volume--;

                            else volume=0;

                     }

                     EVAL_AUDIO_VolumeCtl(volume);

                     LCD_ShowxNum(30+56,160,volume,3,16,0X80);//显示音量

                     delay_ms(20);

              }

              if(Divece_STA!=bDeviceState)//状态改变了

              {

                     if(bDeviceState==1)

                     {

                            LED1=0;

                            LCD_ShowString(30,180,200,16,16,"USB Connected    ");//连接建立

                     }else

                     {

                            LED1=1;

                            LCD_ShowString(30,180,200,16,16,"USB DisConnected ");//连接失败

                     }

                     Divece_STA=bDeviceState;

              }    

              delay_ms(20); t++;

              if(t>10) {t=0; LED0=!LED0;}

              }

       }

}    

此部分代码比较简单,同上一章一样定义了USB_OTG_dev结构体,然后通过USBD_Init初始化USB,不过本章实现的是USB声卡功能。本章我们保留了原例程(实验43)的USMART部分,同样可以通过串口1设置WM8978相关参数。

其他部分我们就不详细介绍了,软件设计部分就为大家介绍到这里。

57.4 下载验证

在代码编译成功之后,我们通过下载代码到探索者STM32F4开发板上,在USB配置成功后(注意:USB数据线,要插在USB_SLAVE端口!不是USB_232端口!另外,USB_HOST接口不要插任何外设!),LCD显示效果如图57.4.1所示:

说明: 说明: C:\Users\Administrator\Desktop\F407教程文档资料\例程图片\USB声卡实验.jpg

57.4.1 USB连接成功

此时,电脑提示发现新硬件,并自动完成驱动安装,如图57.4.2所示:

57.4.2 电脑找到ALIENTEK USB声卡

    USB配置成功后,DS1常亮,DS0闪烁,并且在设备管理器à声音、视频和游戏控制器里面看到多了ALIENTEK STM32F407 USB AUDIO设备,如图57.4.3所示:

57.4.3 设备管理器找到ALIENTEK USB声卡

       此时,电脑的所有音频输出都被切换到USB声卡输出,将耳机插入探索者STM32F4开发板的PHONE端口(或者接喇叭到P1端子(SPK)),即可听到来自电脑的声音。

       通过按键KEY0/KEY2可以增大/减少音量,默认音量设置的是65,大家可以自己调节(范围:0~100)。

 

实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm 

正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779

  

第五十七章 USB声卡(Slave)实验-STM32F4开发指南-正点原子探索者STM32开发板.pdf

575.22 KB, 下载次数: 1613

实验52 USB声卡(Slave)实验.zip

835.12 KB, 下载次数: 1750

我是开源电子网?网站管理员,对网站有任何问题,请与我联系!QQ:389063473Email:389063473@qq.com
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

11

帖子

0

精华

新手上路

积分
44
金钱
44
注册时间
2014-9-12
在线时间
0 小时
发表于 2015-7-13 17:52:56 | 显示全部楼层
原子哥,stm32f407的这个板子可以直接利用USB传输音频使用WM8978播放么?就是去掉sd卡以后可以利用usb传输音频数据并直接播放么
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-7-13 23:06:29 | 显示全部楼层
回复【2楼】燕清扬:
---------------------------------
可以的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
22
金钱
22
注册时间
2015-12-15
在线时间
0 小时
发表于 2015-12-15 19:28:12 | 显示全部楼层
原子哥,usb_slave接口链接电脑后只能充电,没法安装驱动,是接口出现问题了吗?还是我手动安装驱动可以解决?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2015-12-15 22:21:25 | 显示全部楼层
回复【4楼】沐小佳:
---------------------------------
你要下载对应例程才行。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
22
金钱
22
注册时间
2015-12-15
在线时间
0 小时
发表于 2015-12-16 21:22:14 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
就是用jlink下载了,LCD上的显示和开发指南写的一样,就是连接usbslave接口电脑没有装驱动的反应,只是不出声,但是板子插耳机也不出声音,在设备管理器里也没有显示,我用usb232下载了例程情况也是一样的,slave接口还是没法配置usb。。。。。
回复 支持 反对

使用道具 举报

4

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2013-8-26
在线时间
1 小时
发表于 2016-1-20 19:27:02 | 显示全部楼层
stm32F4能实现24位192k iis输出么
usb输入
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-23 12:39

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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