目录
源码下载请参考链接:USB -- STM32-FS-USB-Device驱动代码简述(二)
USB -- STM32F103虚拟串口bulk传输讲解(三)
USB -- STM32F103自定义HID设备及HID上位机中断传输讲解(四)
USB -- STM32F103 U盘(MassStorage)SDIO接口SCSI协议Bulk传输讲解(五)
USB -- STM32F103 USB DFU设备固件升级(IAP)控制传输讲解(六)
USB -- STM32F103 USB AUDIO(音频)Speak同步传输(Out传输)讲解(七)
????????前面两节主要是对USB的基本概念做了简单讲解,学习USB的最本质目的还是要回到USB的应用方向,接下来的几章主要讲解USB的各类应用,包括:
????????这里只讲怎么修改描述符和关键函数,具体的讲解可以查看:USB -- STM32F103 USB AUDIO(音频)Speak同步传输(Out传输)讲解(七)
? ? ? ? 我们这里使用《Audio_Speaker》例程进行修改。
????????usb_desc.h文件的描述符宏定义如下:
#define MICROPHONE_SIZ_DEVICE_DESC 18
#define MICROPHONE_SIZ_CONFIG_DESC 109
#define MICROPHONE_SIZ_INTERFACE_DESC_SIZE 9
#define MICROPHONE_SIZ_STRING_LANGID 0x04
#define MICROPHONE_SIZ_STRING_VENDOR 0x26
#define MICROPHONE_SIZ_STRING_PRODUCT 0x22
#define MICROPHONE_SIZ_STRING_SERIAL 0x1A
#define AUDIO_STANDARD_ENDPOINT_DESC_SIZE 0x09
#define AUDIO_STREAMING_ENDPOINT_DESC_SIZE 0x07
/* USB Descriptor Types */
#define USB_DEVICE_DESCRIPTOR_TYPE 0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE 0x02
#define USB_STRING_DESCRIPTOR_TYPE 0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE 0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE 0x05
#define USB_DEVICE_CLASS_AUDIO 0x01
#define AUDIO_SUBCLASS_AUDIOCONTROL 0x01
#define AUDIO_SUBCLASS_AUDIOSTREAMING 0x02
#define AUDIO_PROTOCOL_UNDEFINED 0x00
#define AUDIO_STREAMING_GENERAL 0x01
#define AUDIO_STREAMING_FORMAT_TYPE 0x02
/* Audio Descriptor Types */
#define AUDIO_INTERFACE_DESCRIPTOR_TYPE 0x24
#define AUDIO_ENDPOINT_DESCRIPTOR_TYPE 0x25
/* Audio Control Interface Descriptor Subtypes */
#define AUDIO_CONTROL_HEADER 0x01
#define AUDIO_CONTROL_INPUT_TERMINAL 0x02
#define AUDIO_CONTROL_OUTPUT_TERMINAL 0x03
#define AUDIO_CONTROL_FEATURE_UNIT 0x06
#define AUDIO_INPUT_TERMINAL_DESC_SIZE 0x0C
#define AUDIO_OUTPUT_TERMINAL_DESC_SIZE 0x09
#define AUDIO_STREAMING_INTERFACE_DESC_SIZE 0x07
#define AUDIO_CONTROL_MUTE 0x0001
#define AUDIO_FORMAT_TYPE_I 0x01
#define USB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
#define AUDIO_ENDPOINT_GENERAL 0x01
#define RX_SIZE 92
const uint8_t Speaker_DeviceDescriptor[] =
{
MICROPHONE_SIZ_DEVICE_DESC, /* bLength */
USB_DEVICE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x00, /* 2.00 */ /* bcdUSB */
0x02,
0x00, /* bDeviceClass */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize 40 */
0x83, /* idVendor */
0x04,
0x30, /* idProduct = 0x5730*/
0x57,
0x00, /* 2.00 */ /* bcdDevice */
0x02,
1, /* iManufacturer */
2, /* iProduct */
3, /* iSerialNumber */
0x01 /* bNumConfigurations */
};
?
? ? ? ? 这里包括:
/* USB Configuration Descriptor */
/* All Descriptors (Configuration, Interface, Endpoint, Class, Vendor */
const uint8_t Speaker_ConfigDescriptor[] =
{
/* Configuration 1 */
0x09, /* bLength */
USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
0x6D, /* wTotalLength 109 bytes*/
0x00,
0x02, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
0xC0, /* bmAttributes Self Powered*/
0x32, /* bMaxPower = 100 mA*/
/* 09 byte*/
/* USB Microphone Standard interface descriptor */
MICROPHONE_SIZ_INTERFACE_DESC_SIZE, /* bLength */
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
/* 09 byte*/
/* USB Microphone Class-specific AC Interface Descriptor */
MICROPHONE_SIZ_INTERFACE_DESC_SIZE, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */
0x00, /* 1.00 */ /* bcdADC */
0x01,
0x27, /* wTotalLength = 39*/
0x00,
0x01, /* bInCollection */
0x01, /* baInterfaceNr */
/* 09 byte*/
/* USB Microphone Input Terminal Descriptor */
AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */
0x01, /* bTerminalID */
0x01, /* wTerminalType AUDIO_TERMINAL_USB_STREAMING 0x0101 */
0x02,
0x00, /* bAssocTerminal */
0x01, /* bNrChannels */
0x00, /* wChannelConfig 0x0000 Mono */
0x00,
0x00, /* iChannelNames */
0x00, /* iTerminal */
/* 12 byte*/
/* USB Microphone Audio Feature Unit Descriptor */
0x09, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
0x03, /* bUnitID */
0x01, /* bSourceID */
0x01, /* bControlSize */
AUDIO_CONTROL_MUTE, /* bmaControls(0) */
0x00, /* bmaControls(1) */
0x00, /* iTerminal */
/* 09 byte*/
/*USB Microphone Output Terminal Descriptor */
0x09, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
0x02, /* bTerminalID */
0x01, /* wTerminalType 0x0101*/
0x01,
0x00, /* bAssocTerminal */
0x01, /* bSourceID */
0x00, /* iTerminal */
/* 09 byte*/
/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Zero Bandwidth */
/* Interface 1, Alternate Setting 0 */
MICROPHONE_SIZ_INTERFACE_DESC_SIZE, /* bLength */
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x00, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
/* 09 byte*/
/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Operational */
/* Interface 1, Alternate Setting 1 */
MICROPHONE_SIZ_INTERFACE_DESC_SIZE, /* bLength */
USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x01, /* bAlternateSetting */
0x01, /* bNumEndpoints */
USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
0x00, /* iInterface */
/* 09 byte*/
/* USB Microphone Audio Streaming Interface Descriptor */
AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
0x02, /* bTerminalLink */
0x01, /* bDelay */
0x02, /* wFormatTag AUDIO_FORMAT_PCM 0x0001*/
0x00,
/* 07 byte*/
/* USB Microphone Audio Type I Format Interface Descriptor */
0x0B, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
AUDIO_FORMAT_TYPE_I, /* bFormatType */
0x01, /* bNrChannels */
0x02, /* bSubFrameSize */
16, /* bBitResolution */
0x01, /* bSamFreqType */
0xF0, /* tSamFreq 22000 = 0x55F0 */
0x55,
0x00,
/* 11 byte*/
/* Endpoint 1 - Standard Descriptor */
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
0x81, /* bEndpointAddress 1 in endpoint*/
USB_ENDPOINT_TYPE_ISOCHRONOUS, /* bmAttributes */
RX_SIZE / 2, /* wMaxPacketSize 44 bytes*/
0x00,
0x01, /* bInterval */
0x00, /* bRefresh */
0x00, /* bSynchAddress */
/* 09 byte*/
/* Endpoint - Audio Streaming Descriptor*/
AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
0x00, /* bmAttributes */
0x00, /* bLockDelayUnits */
0x00, /* wLockDelay */
0x00,
/* 07 byte*/
};
????????这里只需要修改StringProduct字符串描述符,修改名称为microphone。
const uint8_t Speaker_StringProduct[SPEAKER_SIZ_STRING_PRODUCT] =
{
SPEAKER_SIZ_STRING_PRODUCT, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
'S', 0, 'T', 0, 'M', 0, '3', 0, '2', 0, ' ', 0,
'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'p', 0, 'h', 0, 'o', 0, 'n', 0, 'e', 0
};
? ? ? ? 发现修改了这些位置,会出现报错,我们继续修改,主要修改以下文件:
? ? ? ? 按照下图修改。
? ? ? ? 按照上图修改完成,在设备管理器会出现STM32 Microphone的设备,证明修改成功,如果修改之后设备管理器没有反应,大概率是D+的上拉电阻没有配对。
? ? ? ? Microphone模块使用的是Adafruit公司的3421,可以直接去淘宝搜索关键词《Adafruit 3421》查找相应的模块进行购买。
? ? ? ? 此函数在main函数调用,目的是初始化I2S,因为Microphone模块是用I2S驱动的。
/*******************************************************************************
* Function Name : I2S_GPIO_Config
* Description : Initializes the GPIO pins used by the codec application.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Microphone_I2S_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOB clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* I2S2 SD, CK and WS pins configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*******************************************************************************
* Function Name : I2S_Config
* Description : Configure the I2S Peripheral.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void Microphone_I2S_Config(void)
{
I2S_InitTypeDef I2S_InitStructure;
/* Enable I2S2 APB1 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* Deinitialize SPI2 peripheral */
SPI_I2S_DeInit(SPI2);
/* I2S2 peripheral configuration */
I2S_InitStructure.I2S_Mode = I2S_Mode_MasterRx;
I2S_InitStructure.I2S_Standard = I2S_Standard_Phillips;
I2S_InitStructure.I2S_DataFormat = I2S_DataFormat_32b;
I2S_InitStructure.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
I2S_InitStructure.I2S_AudioFreq = I2S_AudioFreq_22k;
I2S_InitStructure.I2S_CPOL = I2S_CPOL_Low;
I2S_Init(SPI2, &I2S_InitStructure);
/* Disable the I2S2 RXNE Interrupt */
SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
/* Enable the SPI2/I2S2 peripheral */
I2S_Cmd(SPI2, ENABLE);
}
? ? ? ? 并且屏蔽main函数的《Speaker_Config()》函数,修改之后的main函数如下:
/*******************************************************************************
* Function Name : main.
* Description : Main routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
int main(void)
{
Set_System();
Set_USBClock();
USB_Config();
USB_Init();
Microphone_I2S_GPIO_Config();
Microphone_I2S_Config();
while (1)
{}
}
? ? ? ? 替换以前的I2S中断函数,改为下面的中断处理函数。
uint16_t Mic_Buff[RX_SIZE]; //RX_SIZE=92
uint16_t MIn_Data_Offset;
uint16_t MOut_Data_Offset;
/**
* @brief This function handles SPI2 global interrupt request.
* @param None
* @retval None
*/
void SPI2_IRQHandler(void)
{
if ((SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) == SET))
{
if (MIn_Data_Offset > MOut_Data_Offset)
{
Mic_Buff[MOut_Data_Offset++] = SPI_I2S_ReceiveData(SPI2); //高位在前
}
}
}
extern uint16_t MIn_Data_Offset;
extern uint16_t MOut_Data_Offset;
/*******************************************************************************
* Function Name : Speaker_Reset.
* Description : Speaker reset routine.
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Speaker_Reset()
{
/* Set Microphone device as not configured state */
pInformation->Current_Configuration = 0;
/* Current Feature initialization */
pInformation->Current_Feature = Speaker_ConfigDescriptor[7];
SetBTABLE(BTABLE_ADDRESS);
/* Initialize Endpoint 0 */
SetEPType(ENDP0, EP_CONTROL);
SetEPTxStatus(ENDP0, EP_TX_NAK);
SetEPRxAddr(ENDP0, ENDP0_RXADDR);
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
SetEPTxAddr(ENDP0, ENDP0_TXADDR);
Clear_Status_Out(ENDP0);
SetEPRxValid(ENDP0);
/* Initialize Endpoint 1 */
SetEPType(ENDP1, EP_ISOCHRONOUS);
SetEPDblBuffAddr(ENDP1, ENDP1_BUF0Addr, ENDP1_BUF1Addr);
SetEPDblBuffCount(ENDP1, EP_DBUF_IN, RX_SIZE / 2);
ClearDTOG_RX(ENDP1);
ClearDTOG_TX(ENDP1);
ToggleDTOG_RX(ENDP1);
SetEPRxStatus(ENDP1, EP_RX_DIS);
SetEPTxStatus(ENDP1, EP_TX_NAK);
SetEPRxValid(ENDP0);
/* Set this device to response on default address */
SetDeviceAddress(0);
bDeviceState = ATTACHED;
MIn_Data_Offset = RX_SIZE;
MOut_Data_Offset = 0;
}
? ? ? ? 因为这个是Microphone,是同步In传输,所以需要屏蔽OUT函数(usb_endp.c文件中),并增加In函数。
? ? ? ? 因为录制的语音会有点噪声,这里对一些尖锐的声音进行了简单的处理。
#include "usb_desc.h"
#include <string.h>
extern uint16_t Mic_Buff[RX_SIZE]; //RX_SIZE=92
extern uint16_t MIn_Data_Offset;
extern uint16_t MOut_Data_Offset;
void EP1_IN_Callback(void)
{
uint16_t buff[RX_SIZE / 4];
uint8_t i = 0, j = 0;
/*录制麦克音频 ,88的原因是左右声道各占44*/
for (i = 0; i < RX_SIZE / 4; i++)
{
//滤波
while (Mic_Buff[j] <= 0xC000)
{
if (j >= MOut_Data_Offset)
{
break;
}
j++;
}
buff[i] = Mic_Buff[j];
j++;
}
buff[RX_SIZE / 4 - 1] = buff[RX_SIZE / 4 - 2] = buff[RX_SIZE / 4 - 3];
FreeUserBuffer(ENDP1, EP_DBUF_IN);
if (GetENDPOINT(ENDP1) & EP_DTOG_TX)
{
UserToPMABufferCopy((uint8_t*)buff, ENDP1_BUF0Addr, RX_SIZE / 2);
SetEPDblBuf0Count(ENDP1, EP_DBUF_IN, RX_SIZE / 2);
}
else
{
UserToPMABufferCopy((uint8_t*)buff, ENDP1_BUF1Addr, RX_SIZE / 2);
SetEPDblBuf1Count(ENDP1, EP_DBUF_IN, RX_SIZE / 2);
}
SetEPTxValid(ENDP1);
memset(Mic_Buff, 0, RX_SIZE);
MIn_Data_Offset = RX_SIZE;
MOut_Data_Offset = 0;
}
1. 正确下载程序,能够在设备管理器查看到Microphone设备。
2. 打开音乐设置,选择侦听模式。
3. 此时如果外接喇叭或者佩戴耳机,能够听见麦克风传递的声音信息。通过逻辑分析仪抓取波形,查看到IN包数据也没有ACK回复。
接下来讲解STM32 USB VIDEO Camera(照相机)同步传输通信实验,敬请期待。。。