最近项目进入收尾阶段,USB Microphone 部分代码不是我所实现,接口较为松散,所以决定优化这部分代码,啃一啃USB部分知识点,一两天肯定不能完全了解清晰,毕竟万能USB,其协议必然是复杂的,所以就先从音频麦克风的实现开始。
其实是币圈大跌,努力搬砖中…
调试工具
usbtreeview(一款方便查看USB设备相关信息的免安装绿色工具)
Audacity (音频频谱查看工具,可查看麦克风设备列表,进行音频录制)
资料书籍
<<圈圈教你玩USB 第二版>>
音频描述符中的简称及分类
- AC:Audio Control
- AS:Audio Stream
拓扑图如下:
控制接口下,默认为端点0
接口描述符
查看位置:usbd_xxx
.h,xxx代表某个功能如:audio
在这个文件中可以找到这个USB功能类的相关描述符定义
-
Terminal 以设备为视角看待
- Terminal 的输入输出成对出现
-
endpoint 以HOST为视角看待
下图为一个speeaker即扬声器 USB拓扑
endpoint 以HOST为视角看待,即主机的输出口 endpoint1 的音频数据流,转入了设备端的输入口Terminal IN
那么麦克风的配置
usbd_audio.c
iConfiguration
iTerminal iInterface
iChannelNames其数值,都是在说明本描述符的字符串说明符,所在索引号,若为0则没有字符串说明(没有文字说明)
-
wTerminalType
- 音频流:0x0101
- 麦克风:0x0201
- 电话线:0x0501
- 手持电话筒的输入麦克风:0x0401
如果麦克风数据需要通过USB上传至PC那么:
麦克风数据 --》(USB设备)MCU -》(USB主机)PC
麦克风数据 --》 terminal IN -》terminal OUT -》 Endpoint IN
STM32配置
打开USB设备功能 FS( Full Speed 全速设备)
配置USB Audio库,配置音频的采样率
一般CubeMX会自动打开USB的全局中断,生成代码后,自己最好确认一下(位于usbd_config.c)。
以下usbd_audio.c和对应头文件可直接替换,自动生成的。
修改usbd_audio.c文件
/**
******************************************************************************
* @file usbd_audio.c
* @author MCD Application Team
* @brief This file provides the Audio core functions.
*
* @verbatim
*
* ===================================================================
* AUDIO Class Description
* ===================================================================
* This driver manages the Audio Class 1.0 following the "USB Device Class Definition for
* Audio Devices V1.0 Mar 18, 98".
* This driver implements the following aspects of the specification:
* - Device descriptor management
* - Configuration descriptor management
* - Standard AC Interface Descriptor management
* - 1 Audio Streaming Interface (with single channel, PCM, Stereo mode)
* - 1 Audio Streaming Endpoint
* - 1 Audio Terminal Input (1 channel)
* - Audio Class-Specific AC Interfaces
* - Audio Class-Specific AS Interfaces
* - AudioControl Requests: only SET_CUR and GET_CUR requests are supported (for Mute)
* - Audio Feature Unit (limited to Mute control)
* - Audio Synchronization type: Asynchronous
* - Single fixed audio sampling rate (configurable in usbd_conf.h file)
* The current audio class version supports the following audio features:
* - Pulse Coded Modulation (PCM) format
* - sampling rate: 48KHz.
* - Bit resolution: 16
* - Number of channels: 2
* - No volume control
* - Mute/Unmute capability
* - Asynchronous Endpoints
*
* @note In HS mode and when the DMA is used, all variables and data structures
* dealing with the DMA during the transaction process should be 32-bit aligned.
*
*
* @endverbatim
*
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2015 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* BSPDependencies
- "stm32xxxxx_{eval}{discovery}.c"
- "stm32xxxxx_{eval}{discovery}_io.c"
- "stm32xxxxx_{eval}{discovery}_audio.c"
EndBSPDependencies */
/* Includes ------------------------------------------------------------------*/
#include "usbd_audio.h"
#include "usbd_ctlreq.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_AUDIO
* @brief usbd core module
* @{
*/
/** @defgroup USBD_AUDIO_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBD_AUDIO_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBD_AUDIO_Private_Macros
* @{
*/
#define AUDIO_SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16))
#define AUDIO_PACKET_SZE(frq) (uint8_t)(((frq * 2U * 2U)/1000U) & 0xFFU), \
(uint8_t)((((frq * 2U * 2U)/1000U) >> 8) & 0xFFU)
/**
* @}
*/
/** @defgroup USBD_AUDIO_Private_FunctionPrototypes
* @{
*/
static uint8_t USBD_AUDIO_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_AUDIO_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
static uint8_t USBD_AUDIO_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req);
static uint8_t *USBD_AUDIO_GetCfgDesc(uint16_t *length);
static uint8_t *USBD_AUDIO_GetDeviceQualifierDesc(uint16_t *length);
static uint8_t USBD_AUDIO_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_AUDIO_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_AUDIO_EP0_RxReady(USBD_HandleTypeDef *pdev);
static uint8_t USBD_AUDIO_EP0_TxReady(USBD_HandleTypeDef *pdev);
static uint8_t USBD_AUDIO_SOF(USBD_HandleTypeDef *pdev);
static uint8_t USBD_AUDIO_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
static uint8_t USBD_AUDIO_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum);
static void AUDIO_REQ_GetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
static void AUDIO_REQ_SetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req);
/**
* @}
*/
/** @defgroup USBD_AUDIO_Private_Variables
* @{
*/
USBD_ClassTypeDef USBD_AUDIO =
{
USBD_AUDIO_Init,
USBD_AUDIO_DeInit,
USBD_AUDIO_Setup,
USBD_AUDIO_EP0_TxReady,
USBD_AUDIO_EP0_RxReady,
USBD_AUDIO_DataIn,
USBD_AUDIO_DataOut,
USBD_AUDIO_SOF,
USBD_AUDIO_IsoINIncomplete,
USBD_AUDIO_IsoOutIncomplete,
USBD_AUDIO_GetCfgDesc,
USBD_AUDIO_GetCfgDesc,
USBD_AUDIO_GetCfgDesc,
USBD_AUDIO_GetDeviceQualifierDesc,
};
/* USB AUDIO device Configuration Descriptor */
__ALIGN_BEGIN static uint8_t USBD_AUDIO_CfgDesc[USB_AUDIO_CONFIG_DESC_SIZ] __ALIGN_END =
{
/* Configuration 1 */
0x09, /* bLength */
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType */
LOBYTE(USB_AUDIO_CONFIG_DESC_SIZ), /* wTotalLength 109 bytes*/
HIBYTE(USB_AUDIO_CONFIG_DESC_SIZ),
0x02, /* bNumInterfaces */
0x01, /* bConfigurationValue */
0x00, /* iConfiguration */
#if (USBD_SELF_POWERED == 1U)
0xC0, /* bmAttributes: Bus Powered according to user configuration */
#else
0x80, /* bmAttributes: Bus Powered according to user configuration */
#endif
USBD_MAX_POWER, /* bMaxPower = 100 mA */
/* 09 byte*/
/* USB Microphone Standard interface descriptor */
AUDIO_INTERFACE_DESC_SIZE, /* bLength */
USB_DESC_TYPE_INTERFACE, /* 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 */
AUDIO_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 */
AUDIO_PORT_INPUT_TERMINAL_ID_1, /* bTerminalID */
AUDIO_PORT_MICRO_PHONE_TERMINAL_L, /* wTerminalType AUDIO_TERMINAL_USB_Microphone 0x0201 */
AUDIO_PORT_MICRO_PHONE_TERMINAL_H,
0x00, /* bAssocTerminal */
AUDIO_PORT_CHANNEL_NUMS, /* bNrChannels */
AUDIO_PORT_CHANNEL_CONFIG_L, /* wChannelConfig 0x0000 Mono or L+R or L or R*/
AUDIO_PORT_CHANNEL_CONFIG_H,
0x00, /* iChannelNames */
0x00, /* iTerminal */
/* 12 byte*/
/* USB Microphone Audio Feature Unit Descriptor */
0x09, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
AUDIO_PORT_INPUT_CTL_ID_2, /* bUnitID */
AUDIO_PORT_INPUT_TERMINAL_ID_1, /* bSourceID */
0x01, /* bControlSize */
AUDIO_CONTROL_MUTE, /* bmaControls(0) */
0, /* bmaControls(1) */
0x00, /* iTerminal */
/* 09 byte*/
/*USB Microphone Output Terminal Descriptor */
0x09, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
AUDIO_PORT_OUTPUT_TERMINAL_ID_3, /* bTerminalID */
AUDIO_PORT_STREAM_TERMINAL_TYPE_L, /* wTerminalType 音频流0x0101*/
AUDIO_PORT_STREAM_TERMINAL_TYPE_H,
0x00, /* bAssocTerminal */
AUDIO_PORT_INPUT_CTL_ID_2, /* bSourceID */
0x00, /* iTerminal */
/* 09 byte*/
/* USB Microphone Standard AS Interface Descriptor - Audio Streaming Zero Bandwidth */
/* Interface 1, Alternate Setting 0 */
AUDIO_INTERFACE_DESC_SIZE, /* bLength */
USB_DESC_TYPE_INTERFACE, /* 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 */
AUDIO_INTERFACE_DESC_SIZE, /* bLength */
USB_DESC_TYPE_INTERFACE, /* 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 */
AUDIO_PORT_OUTPUT_TERMINAL_ID_3, /* bTerminalLink */
0x01, /* bDelay */
0x01, /* wFormatTag AUDIO_FORMAT_PCM 0x0001 */
0x00,
/* 07 byte*/
/* USB Microphone Audio Type III Format Interface Descriptor */
0x0B, /* bLength */
AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
AUDIO_FORMAT_TYPE_I, /* bFormatType */
AUDIO_PORT_CHANNEL_NUMS, /* bNrChannels */
0x02, /* bSubFrameSize : 2 Bytes per frame (16bits) */
16, /* bBitResolution (16-bits per sample) */
0x01, /* bSamFreqType only one frequency supported */
AUDIO_SAMPLE_FREQ(USBD_AUDIO_FREQ), /* Audio sampling frequency coded on 3 bytes */
/* 11 byte*/
/* Endpoint 1 - Standard Descriptor */
AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType */
AUDIO_PORT_IN_EP_DIR_ID, /* bEndpointAddress 1 in endpoint */
USBD_EP_TYPE_ISOC, /* bmAttributes */
AUDIO_PORT_PACKET_SZE(USBD_AUDIO_FREQ),/* wMaxPacketSize in Bytes (Freq(Samples)*2(Stereo)*2(HalfWord)) */
AUDIO_PORT_FS_BINTERVAL, /* 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*/
} ;
/* USB Standard Device Descriptor */
__ALIGN_BEGIN static uint8_t USBD_AUDIO_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
{
USB_LEN_DEV_QUALIFIER_DESC,
USB_DESC_TYPE_DEVICE_QUALIFIER,
0x00,
0x02,
0x00,
0x00,
0x00,
0x40,
0x01,
0x00,
};
/**
* @}
*/
/** @defgroup USBD_AUDIO_Private_Functions
* @{
*/
/**
* @brief USBD_AUDIO_Init
* Initialize the AUDIO interface
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_AUDIO_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
return USB_Audio_Port_EP_IN_Init(pdev, cfgidx);
}
/**
* @brief USBD_AUDIO_Init
* DeInitialize the AUDIO layer
* @param pdev: device instance
* @param cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_AUDIO_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
/* Open EP OUT */
(void)USBD_LL_CloseEP(pdev, AUDIO_OUT_EP);
pdev->ep_out[AUDIO_OUT_EP & 0xFU].is_used = 0U;
pdev->ep_out[AUDIO_OUT_EP & 0xFU].bInterval = 0U;
/* DeInit physical Interface components */
if (pdev->pClassData != NULL)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->DeInit(0U);
(void)USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return (uint8_t)USBD_OK;
}
/**
* @brief USBD_AUDIO_Setup
* Handle the AUDIO specific requests
* @param pdev: instance
* @param req: usb requests
* @retval status
*/
static uint8_t USBD_AUDIO_Setup(USBD_HandleTypeDef *pdev,
USBD_SetupReqTypedef *req)
{
USBD_AUDIO_HandleTypeDef *haudio;
uint16_t len;
uint8_t *pbuf;
uint16_t status_info = 0U;
USBD_StatusTypeDef ret = USBD_OK;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if (haudio == NULL)
{
return (uint8_t)USBD_FAIL;
}
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS:
switch (req->bRequest)
{
case AUDIO_REQ_GET_CUR:
AUDIO_REQ_GetCurrent(pdev, req);
break;
case AUDIO_REQ_SET_CUR:
AUDIO_REQ_SetCurrent(pdev, req);
break;
default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
break;
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_STATUS:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
(void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U);
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_GET_DESCRIPTOR:
if ((req->wValue >> 8) == AUDIO_DESCRIPTOR_TYPE)
{
pbuf = USBD_AUDIO_CfgDesc + 18;
len = MIN(USB_AUDIO_DESC_SIZ, req->wLength);
(void)USBD_CtlSendData(pdev, pbuf, len);
}
break;
case USB_REQ_GET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
(void)USBD_CtlSendData(pdev, (uint8_t *)&haudio->alt_setting, 1U);
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_SET_INTERFACE:
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
if ((uint8_t)(req->wValue) <= USBD_MAX_NUM_INTERFACES)
{
haudio->alt_setting = (uint8_t)(req->wValue);
}
else
{
/* Call the error management function (command will be NAKed */
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
}
else
{
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
}
break;
case USB_REQ_CLEAR_FEATURE:
break;
default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
break;
default:
USBD_CtlError(pdev, req);
ret = USBD_FAIL;
break;
}
return (uint8_t)ret;
}
/**
* @brief USBD_AUDIO_GetCfgDesc
* return configuration descriptor
* @param speed : current device speed
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
static uint8_t *USBD_AUDIO_GetCfgDesc(uint16_t *length)
{
*length = (uint16_t)sizeof(USBD_AUDIO_CfgDesc);
return USBD_AUDIO_CfgDesc;
}
/**
* @brief USBD_AUDIO_DataIn
* handle data IN Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_AUDIO_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
return USB_Audio_Port_DataIn(pdev, epnum);
}
/**
* @brief USBD_AUDIO_EP0_RxReady
* handle EP0 Rx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_AUDIO_EP0_RxReady(USBD_HandleTypeDef *pdev)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if (haudio == NULL)
{
return (uint8_t)USBD_FAIL;
}
if (haudio->control.cmd == AUDIO_REQ_SET_CUR)
{
/* In this driver, to simplify code, only SET_CUR request is managed */
if (haudio->control.unit == AUDIO_OUT_STREAMING_CTRL)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->MuteCtl(haudio->control.data[0]);
haudio->control.cmd = 0U;
haudio->control.len = 0U;
}
}
return (uint8_t)USBD_OK;
}
/**
* @brief USBD_AUDIO_EP0_TxReady
* handle EP0 TRx Ready event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_AUDIO_EP0_TxReady(USBD_HandleTypeDef *pdev)
{
UNUSED(pdev);
/* Only OUT control data are processed */
return (uint8_t)USBD_OK;
}
/**
* @brief USBD_AUDIO_SOF
* handle SOF event
* @param pdev: device instance
* @retval status
*/
static uint8_t USBD_AUDIO_SOF(USBD_HandleTypeDef *pdev)
{
UNUSED(pdev);
return (uint8_t)USBD_OK;
}
/**
* @brief USBD_AUDIO_SOF
* handle SOF event
* @param pdev: device instance
* @retval status
*/
void USBD_AUDIO_Sync(USBD_HandleTypeDef *pdev, AUDIO_OffsetTypeDef offset)
{
USBD_AUDIO_HandleTypeDef *haudio;
uint32_t BufferSize = AUDIO_TOTAL_BUF_SIZE / 2U;
if (pdev->pClassData == NULL)
{
return;
}
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
haudio->offset = offset;
if (haudio->rd_enable == 1U)
{
haudio->rd_ptr += (uint16_t)BufferSize;
if (haudio->rd_ptr == AUDIO_TOTAL_BUF_SIZE)
{
/* roll back */
haudio->rd_ptr = 0U;
}
}
if (haudio->rd_ptr > haudio->wr_ptr)
{
if ((haudio->rd_ptr - haudio->wr_ptr) < AUDIO_OUT_PACKET)
{
BufferSize += 4U;
}
else
{
if ((haudio->rd_ptr - haudio->wr_ptr) > (AUDIO_TOTAL_BUF_SIZE - AUDIO_OUT_PACKET))
{
BufferSize -= 4U;
}
}
}
else
{
if ((haudio->wr_ptr - haudio->rd_ptr) < AUDIO_OUT_PACKET)
{
BufferSize -= 4U;
}
else
{
if ((haudio->wr_ptr - haudio->rd_ptr) > (AUDIO_TOTAL_BUF_SIZE - AUDIO_OUT_PACKET))
{
BufferSize += 4U;
}
}
}
if (haudio->offset == AUDIO_OFFSET_FULL)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->AudioCmd(&haudio->buffer[0],
BufferSize, AUDIO_CMD_PLAY);
haudio->offset = AUDIO_OFFSET_NONE;
}
}
/**
* @brief USBD_AUDIO_IsoINIncomplete
* handle data ISO IN Incomplete event
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_AUDIO_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
UNUSED(pdev);
UNUSED(epnum);
return (uint8_t)USBD_OK;
}
/**
* @brief USBD_AUDIO_IsoOutIncomplete
* handle data ISO OUT Incomplete event
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_AUDIO_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
UNUSED(pdev);
UNUSED(epnum);
return (uint8_t)USBD_OK;
}
/**
* @brief USBD_AUDIO_DataOut
* handle data OUT Stage
* @param pdev: device instance
* @param epnum: endpoint index
* @retval status
*/
static uint8_t USBD_AUDIO_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
{
uint16_t PacketSize;
USBD_AUDIO_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if (haudio == NULL)
{
return (uint8_t)USBD_FAIL;
}
if (epnum == AUDIO_OUT_EP)
{
/* Get received data packet length */
PacketSize = (uint16_t)USBD_LL_GetRxDataSize(pdev, epnum);
/* Packet received Callback */
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->PeriodicTC(&haudio->buffer[haudio->wr_ptr],
PacketSize, AUDIO_OUT_TC);
/* Increment the Buffer pointer or roll it back when all buffers are full */
haudio->wr_ptr += PacketSize;
if (haudio->wr_ptr == AUDIO_TOTAL_BUF_SIZE)
{
/* All buffers are full: roll back */
haudio->wr_ptr = 0U;
if (haudio->offset == AUDIO_OFFSET_UNKNOWN)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->AudioCmd(&haudio->buffer[0],
AUDIO_TOTAL_BUF_SIZE / 2U,
AUDIO_CMD_START);
haudio->offset = AUDIO_OFFSET_NONE;
}
}
if (haudio->rd_enable == 0U)
{
if (haudio->wr_ptr == (AUDIO_TOTAL_BUF_SIZE / 2U))
{
haudio->rd_enable = 1U;
}
}
/* Prepare Out endpoint to receive next audio packet */
(void)USBD_LL_PrepareReceive(pdev, AUDIO_OUT_EP,
&haudio->buffer[haudio->wr_ptr],
AUDIO_OUT_PACKET);
}
return (uint8_t)USBD_OK;
}
/**
* @brief AUDIO_Req_GetCurrent
* Handles the GET_CUR Audio control request.
* @param pdev: instance
* @param req: setup class request
* @retval status
*/
static void AUDIO_REQ_GetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if (haudio == NULL)
{
return;
}
(void)USBD_memset(haudio->control.data, 0, 64U);
/* Send the current mute state */
(void)USBD_CtlSendData(pdev, haudio->control.data, req->wLength);
}
/**
* @brief AUDIO_Req_SetCurrent
* Handles the SET_CUR Audio control request.
* @param pdev: instance
* @param req: setup class request
* @retval status
*/
static void AUDIO_REQ_SetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)
{
USBD_AUDIO_HandleTypeDef *haudio;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if (haudio == NULL)
{
return;
}
if (req->wLength != 0U)
{
/* Prepare the reception of the buffer over EP0 */
(void)USBD_CtlPrepareRx(pdev, haudio->control.data, req->wLength);
haudio->control.cmd = AUDIO_REQ_SET_CUR; /* Set the request value */
haudio->control.len = (uint8_t)req->wLength; /* Set the request data length */
haudio->control.unit = HIBYTE(req->wIndex); /* Set the request target unit */
}
}
/**
* @brief DeviceQualifierDescriptor
* return Device Qualifier descriptor
* @param length : pointer data length
* @retval pointer to descriptor buffer
*/
static uint8_t *USBD_AUDIO_GetDeviceQualifierDesc(uint16_t *length)
{
*length = (uint16_t)sizeof(USBD_AUDIO_DeviceQualifierDesc);
return USBD_AUDIO_DeviceQualifierDesc;
}
/**
* @brief USBD_AUDIO_RegisterInterface
* @param fops: Audio interface callback
* @retval status
*/
uint8_t USBD_AUDIO_RegisterInterface(USBD_HandleTypeDef *pdev,
USBD_AUDIO_ItfTypeDef *fops)
{
if (fops == NULL)
{
return (uint8_t)USBD_FAIL;
}
pdev->pUserData = fops;
return (uint8_t)USBD_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
usbd_audio.h
其内主要修改了 缓冲区大小,包含了接口头文件
/**
******************************************************************************
* @file usbd_audio.h
* @author MCD Application Team
* @brief header file for the usbd_audio.c file.
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2015 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USB_AUDIO_H
#define __USB_AUDIO_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "usbd_ioreq.h"
#include "USB_Audio_Port.h"
/** @addtogroup STM32_USB_DEVICE_LIBRARY
* @{
*/
/** @defgroup USBD_AUDIO
* @brief This file is the Header file for usbd_audio.c
* @{
*/
/** @defgroup USBD_AUDIO_Exported_Defines
* @{
*/
#ifndef USBD_AUDIO_FREQ
/* AUDIO Class Config */
#define USBD_AUDIO_FREQ 48000U
#endif /* USBD_AUDIO_FREQ */
#ifndef USBD_MAX_NUM_INTERFACES
#define USBD_MAX_NUM_INTERFACES 1U
#endif /* USBD_AUDIO_FREQ */
#ifndef AUDIO_HS_BINTERVAL
#define AUDIO_HS_BINTERVAL 0x01U
#endif /* AUDIO_HS_BINTERVAL */
#ifndef AUDIO_FS_BINTERVAL
#define AUDIO_FS_BINTERVAL 0x01U
#endif /* AUDIO_FS_BINTERVAL */
#define AUDIO_OUT_EP 0x01U
#define USB_AUDIO_CONFIG_DESC_SIZ 0x6DU
#define AUDIO_INTERFACE_DESC_SIZE 0x09U
#define USB_AUDIO_DESC_SIZ 0x09U
#define AUDIO_STANDARD_ENDPOINT_DESC_SIZE 0x09U
#define AUDIO_STREAMING_ENDPOINT_DESC_SIZE 0x07U
#define AUDIO_DESCRIPTOR_TYPE 0x21U
#define USB_DEVICE_CLASS_AUDIO 0x01U
#define AUDIO_SUBCLASS_AUDIOCONTROL 0x01U
#define AUDIO_SUBCLASS_AUDIOSTREAMING 0x02U
#define AUDIO_PROTOCOL_UNDEFINED 0x00U
#define AUDIO_STREAMING_GENERAL 0x01U
#define AUDIO_STREAMING_FORMAT_TYPE 0x02U
/* Audio Descriptor Types */
#define AUDIO_INTERFACE_DESCRIPTOR_TYPE 0x24U
#define AUDIO_ENDPOINT_DESCRIPTOR_TYPE 0x25U
/* Audio Control Interface Descriptor Subtypes */
#define AUDIO_CONTROL_HEADER 0x01U
#define AUDIO_CONTROL_INPUT_TERMINAL 0x02U
#define AUDIO_CONTROL_OUTPUT_TERMINAL 0x03U
#define AUDIO_CONTROL_FEATURE_UNIT 0x06U
#define AUDIO_INPUT_TERMINAL_DESC_SIZE 0x0CU
#define AUDIO_OUTPUT_TERMINAL_DESC_SIZE 0x09U
#define AUDIO_STREAMING_INTERFACE_DESC_SIZE 0x07U
#define AUDIO_CONTROL_MUTE 0x0001U
#define AUDIO_FORMAT_TYPE_I 0x01U
#define AUDIO_FORMAT_TYPE_III 0x03U
#define AUDIO_ENDPOINT_GENERAL 0x01U
#define AUDIO_REQ_GET_CUR 0x81U
#define AUDIO_REQ_SET_CUR 0x01U
#define AUDIO_OUT_STREAMING_CTRL 0x02U
#define AUDIO_OUT_TC 0x01U
#define AUDIO_IN_TC 0x02U
#define AUDIO_OUT_PACKET AUDIO_PORT_OUT_SIZE
#define AUDIO_DEFAULT_VOLUME 70U
/* Number of sub-packets in the audio transfer buffer. You can modify this value but always make sure
that it is an even number and higher than 3 */
#define AUDIO_OUT_PACKET_NUM 80U
/* Total size of the audio transfer buffer */
#define AUDIO_TOTAL_BUF_SIZE AUDIO_PORT_BUF_SIZE
/* Audio Commands enumeration */
typedef enum
{
AUDIO_CMD_START = 1,
AUDIO_CMD_PLAY,
AUDIO_CMD_STOP,
} AUDIO_CMD_TypeDef;
typedef enum
{
AUDIO_OFFSET_NONE = 0,
AUDIO_OFFSET_HALF,
AUDIO_OFFSET_FULL,
AUDIO_OFFSET_UNKNOWN,
} AUDIO_OffsetTypeDef;
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_TypesDefinitions
* @{
*/
typedef struct
{
uint8_t cmd;
uint8_t data[USB_MAX_EP0_SIZE];
uint8_t len;
uint8_t unit;
} USBD_AUDIO_ControlTypeDef;
typedef struct
{
uint32_t alt_setting;
uint8_t buffer[AUDIO_TOTAL_BUF_SIZE];
AUDIO_OffsetTypeDef offset;
uint8_t rd_enable;
uint16_t rd_ptr;
uint16_t wr_ptr;
USBD_AUDIO_ControlTypeDef control;
} USBD_AUDIO_HandleTypeDef;
typedef struct
{
int8_t (*Init)(uint32_t AudioFreq, uint32_t Volume, uint32_t options);
int8_t (*DeInit)(uint32_t options);
int8_t (*AudioCmd)(uint8_t *pbuf, uint32_t size, uint8_t cmd);
int8_t (*VolumeCtl)(uint8_t vol);
int8_t (*MuteCtl)(uint8_t cmd);
int8_t (*PeriodicTC)(uint8_t *pbuf, uint32_t size, uint8_t cmd);
int8_t (*GetState)(void);
} USBD_AUDIO_ItfTypeDef;
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBD_CORE_Exported_Variables
* @{
*/
extern USBD_ClassTypeDef USBD_AUDIO;
#define USBD_AUDIO_CLASS &USBD_AUDIO
/**
* @}
*/
/** @defgroup USB_CORE_Exported_Functions
* @{
*/
uint8_t USBD_AUDIO_RegisterInterface(USBD_HandleTypeDef *pdev,
USBD_AUDIO_ItfTypeDef *fops);
void USBD_AUDIO_Sync(USBD_HandleTypeDef *pdev, AUDIO_OffsetTypeDef offset);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __USB_AUDIO_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
实现部分
其内需要环形缓冲区,源码获取:https://blog.****.net/weixin_42892101/article/details/104886937
USB_Audio_Port.c
/**
* @file USB_Audio_Port.c
*
* @date 2021-06-01
*
* @author aron566
*
* @copyright Copyright (c) 2021 aron566 <aron566@163.com>.
*
* @brief USB音频类接口,对外提供音频更新及输出接口
*
* @details 1、开启对应FS中断,中断处理和初始化位于usbd_conf.c
* 2、16k采样,双声道,10ms出320点数据
* 3、1ms间隔发送,10ms发送5次,每次发送320/5 = 64点数据
* 4、接收来自MIC数据,10ms来一次每次双通道160点*2
* @version V1.0
*/
/** Includes -----------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
#include "USB_Audio_Port.h"
#include "main.h"
#include <arm_math.h>
#include "usbd_audio.h"
/** Use C compiler -----------------------------------------------------------*/
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Private typedef ----------------------------------------------------------*/
/** Private macros -----------------------------------------------------------*/
#define USB_RX_BUF_SIZE_MAX 1024 /**< 接收缓冲区设置1024*2Bytes*/
#define USB_PORT_AUDIO_OUT_PACKET AUDIO_PORT_OUT_SIZE /**< 一次发送大小字节数*/
#define USB_PORT_AUDIO_BUF_SIZE AUDIO_TOTAL_BUF_SIZE
#define USB_PORT_AUDIO_IN_EP AUDIO_PORT_IN_EP_DIR_ID
#define USB_PORT_AUDIO_OUT_EP AUDIO_PORT_OUT_EP_DIR_ID
/** Private constants --------------------------------------------------------*/
/** Public variables ---------------------------------------------------------*/
/** Private variables --------------------------------------------------------*/
/*音频缓冲区*/
static CQ_handleTypeDef USB_Audio_Data_Handle;
static int16_t USB_Audio_Receive_Buf[STEREO_FRAME_SIZE] = {0};
static uint16_t USB_Audio_Send_Buf[USB_RX_BUF_SIZE_MAX];
/** Private function prototypes ----------------------------------------------*/
/** Private user code --------------------------------------------------------*/
/** Private application code -------------------------------------------------*/
/*******************************************************************************
*
* Static code
*
********************************************************************************
*/
/**
******************************************************************
* @brief USB音频接口初始化
* @param [in]None.
* @return None.
* @author aron566
* @version V1.0
* @date 2021-06-02
******************************************************************
*/
static void USB_Audio_Port_Init(void)
{
/*初始化接收音频缓冲区*/
CQ_16_init(&USB_Audio_Data_Handle, USB_Audio_Send_Buf, USB_RX_BUF_SIZE_MAX);
}
/**
******************************************************************
* @brief 向USB缓冲区数据加入数据
* @param [in]Data 待加入数据.
* @param [in]Size 待加入数据长度Size个16Bit.
* @return None.
* @author aron566
* @version V1.0
* @date 2021-06-04
******************************************************************
*/
static inline void USB_Audio_Port_Put_Audio_Data(const int16_t *Data, uint32_t Size)
{
CQ_16putData(&USB_Audio_Data_Handle, (const uint16_t *)Data, Size);
}
/** Public application code --------------------------------------------------*/
/*******************************************************************************
*
* Public code
*
********************************************************************************
*/
/**
******************************************************************
* @brief USB缓冲区数据接收来自HOST
* @param [in]pdev device instance
* @param [in]epnum 端点号
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
uint8_t USB_Audio_Port_DataOut(void *xpdev, uint8_t epnum)
{
uint16_t PacketSize;
USBD_AUDIO_HandleTypeDef *haudio;
USBD_HandleTypeDef *pdev = (USBD_HandleTypeDef *)xpdev;
haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData;
if (haudio == NULL)
{
return (uint8_t)USBD_FAIL;
}
if (epnum == USB_PORT_AUDIO_OUT_EP)
{
/* Get received data packet length */
PacketSize = (uint16_t)USBD_LL_GetRxDataSize(pdev, epnum);
/* Packet received Callback */
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->PeriodicTC(&haudio->buffer[haudio->wr_ptr],
PacketSize, AUDIO_OUT_TC);
/* Increment the Buffer pointer or roll it back when all buffers are full */
haudio->wr_ptr += PacketSize;
if (haudio->wr_ptr == AUDIO_TOTAL_BUF_SIZE)
{
/* All buffers are full: roll back */
haudio->wr_ptr = 0U;
if (haudio->offset == AUDIO_OFFSET_UNKNOWN)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->AudioCmd(&haudio->buffer[0],
AUDIO_TOTAL_BUF_SIZE / 2U,
AUDIO_CMD_START);
haudio->offset = AUDIO_OFFSET_NONE;
}
}
if (haudio->rd_enable == 0U)
{
if (haudio->wr_ptr == (AUDIO_TOTAL_BUF_SIZE / 2U))
{
haudio->rd_enable = 1U;
}
}
/* Prepare Out endpoint to receive next audio packet */
(void)USBD_LL_PrepareReceive(pdev, USB_PORT_AUDIO_OUT_EP,
&haudio->buffer[haudio->wr_ptr],
AUDIO_OUT_PACKET);
}
return (uint8_t)USBD_OK;
}
/**
******************************************************************
* @brief USB缓冲区数据发送至HOST
* @param [in]pdev device instance
* @param [in]epnum 端点号
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
uint8_t USB_Audio_Port_DataIn(void *xpdev, uint8_t epnum)
{
USBD_HandleTypeDef *pdev = (USBD_HandleTypeDef *)xpdev;
USBD_AUDIO_HandleTypeDef *haudio = (USBD_AUDIO_HandleTypeDef*) pdev->pClassData;
USBD_LL_FlushEP(pdev, USB_PORT_AUDIO_IN_EP);
if(CQ_getLength(&USB_Audio_Data_Handle) < USB_PORT_AUDIO_OUT_PACKET/2)
{
return (uint8_t)USBD_BUSY;
}
CQ_16getData(&USB_Audio_Data_Handle, (uint16_t *)haudio->buffer, USB_PORT_AUDIO_OUT_PACKET/2);
return USBD_LL_Transmit(pdev, USB_PORT_AUDIO_IN_EP, haudio->buffer, USB_PORT_AUDIO_OUT_PACKET);
}
/**
******************************************************************
* @brief 反初始化音频输出端点
* @param [in]pdev
* @param [in]cfgidx
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
uint8_t USB_Audio_Port_EP_OUT_DeInit(void *xpdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
USBD_HandleTypeDef *pdev = (USBD_HandleTypeDef *)xpdev;
/* Open EP OUT */
(void)USBD_LL_CloseEP(pdev, USB_PORT_AUDIO_OUT_EP);
pdev->ep_out[USB_PORT_AUDIO_OUT_EP & 0xFU].is_used = 0U;
pdev->ep_out[USB_PORT_AUDIO_OUT_EP & 0xFU].bInterval = 0U;
/* DeInit physical Interface components */
if (pdev->pClassData != NULL)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->DeInit(0U);
(void)USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return (uint8_t)USBD_OK;
}
/**
******************************************************************
* @brief 反初始化音频输入端点
* @param [in]pdev
* @param [in]cfgidx
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
uint8_t USB_Audio_Port_EP_IN_DeInit(void *xpdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
USBD_HandleTypeDef *pdev = (USBD_HandleTypeDef *)xpdev;
/* Open EP OUT */
USBD_LL_CloseEP(pdev, USB_PORT_AUDIO_IN_EP);
/* DeInit physical Interface components */
if (pdev->pClassData != NULL)
{
((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->DeInit(0U);
(void)USBD_free(pdev->pClassData);
pdev->pClassData = NULL;
}
return (uint8_t)USBD_OK;
}
/**
******************************************************************
* @brief 初始化为音频输出端点
* @param [in]pdev
* @param [in]cfgidx
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
uint8_t USB_Audio_Port_EP_OUT_Init(void *xpdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
USBD_AUDIO_HandleTypeDef *haudio;
USBD_HandleTypeDef *pdev = (USBD_HandleTypeDef *)xpdev;
/* Allocate Audio structure */
haudio = USBD_malloc(sizeof(USBD_AUDIO_HandleTypeDef));
if (haudio == NULL)
{
pdev->pClassData = NULL;
return (uint8_t)USBD_EMEM;
}
pdev->pClassData = (void *)haudio;
if (pdev->dev_speed == USBD_SPEED_HIGH)
{
pdev->ep_out[USB_PORT_AUDIO_OUT_EP & 0xFU].bInterval = AUDIO_HS_BINTERVAL;
}
else /* LOW and FULL-speed endpoints */
{
pdev->ep_out[USB_PORT_AUDIO_OUT_EP & 0xFU].bInterval = AUDIO_FS_BINTERVAL;
}
/* Open EP OUT */
(void)USBD_LL_OpenEP(pdev, USB_PORT_AUDIO_OUT_EP, USBD_EP_TYPE_ISOC, USB_PORT_AUDIO_OUT_PACKET);
pdev->ep_out[USB_PORT_AUDIO_OUT_EP & 0xFU].is_used = 1U;
haudio->alt_setting = 0U;
haudio->offset = AUDIO_OFFSET_UNKNOWN;
haudio->wr_ptr = 0U;
haudio->rd_ptr = 0U;
haudio->rd_enable = 0U;
/* Initialize the Audio output Hardware layer */
if (((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->Init(USBD_AUDIO_FREQ,
AUDIO_DEFAULT_VOLUME,
0U) != 0U)
{
return (uint8_t)USBD_FAIL;
}
/* Prepare Out endpoint to receive 1st packet */
(void)USBD_LL_PrepareReceive(pdev, USB_PORT_AUDIO_OUT_EP, haudio->buffer,
AUDIO_OUT_PACKET);
return (uint8_t)USBD_OK;
}
/**
******************************************************************
* @brief 初始化为音频输入端点
* @param [in]pdev
* @param [in]cfgidx
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
uint8_t USB_Audio_Port_EP_IN_Init(void *xpdev, uint8_t cfgidx)
{
UNUSED(cfgidx);
USBD_AUDIO_HandleTypeDef *haudio;
USBD_HandleTypeDef *pdev = (USBD_HandleTypeDef *)xpdev;
/*USB接口初始化*/
USB_Audio_Port_Init();
/* Allocate Audio structure */
haudio = USBD_malloc(sizeof(USBD_AUDIO_HandleTypeDef));
if (haudio == NULL)
{
pdev->pClassData = NULL;
return (uint8_t)USBD_EMEM;
}
pdev->pClassData = (void *)haudio;
if (pdev->dev_speed == USBD_SPEED_HIGH)
{
pdev->ep_in[USB_PORT_AUDIO_IN_EP & 0xFU].bInterval = AUDIO_HS_BINTERVAL;
}
else /* LOW and FULL-speed endpoints */
{
pdev->ep_in[USB_PORT_AUDIO_IN_EP & 0xFU].bInterval = AUDIO_FS_BINTERVAL;
}
/* Open EP IN */
(void)USBD_LL_OpenEP(pdev, USB_PORT_AUDIO_IN_EP, USBD_EP_TYPE_ISOC, USB_PORT_AUDIO_OUT_PACKET);
pdev->ep_in[USB_PORT_AUDIO_IN_EP & 0xFU].is_used = 1U;
haudio->alt_setting = 0U;
haudio->offset = AUDIO_OFFSET_UNKNOWN;
haudio->wr_ptr = 0U;
haudio->rd_ptr = 0U;
haudio->rd_enable = 0U;
memset(haudio->buffer, 0, USB_PORT_AUDIO_BUF_SIZE);
USBD_LL_Transmit(pdev, USB_PORT_AUDIO_IN_EP, haudio->buffer, USB_PORT_AUDIO_OUT_PACKET);
return (uint8_t)USBD_OK;
}
/**
******************************************************************
* @brief 更新USB音频数据
* @param [in]pdev
* @param [in]cfgidx
* @return USBD_OK 正常.
* @author aron566
* @version V1.0
* @date 2021-06-01
******************************************************************
*/
void USB_Audio_Port_Put_Data(const int16_t *Left_Audio, const int16_t *Right_Audio)
{
/*更新USB音频数据*/
int index = 0, i = 0;
for(i = 0; i < STEREO_FRAME_SIZE;)
{
USB_Audio_Receive_Buf[i++] = Left_Audio[index++];/**< TO USB LEFT*/
USB_Audio_Receive_Buf[i++] = Right_Audio[index];/**< TO USB RIGHT*/
}
USB_Audio_Port_Put_Audio_Data(USB_Audio_Receive_Buf, STEREO_FRAME_SIZE);
}
#ifdef __cplusplus ///<end extern c
}
#endif
/******************************** End of file *********************************/
USB_Audio_Port.h
文件中主要定义了相关宏,用于配置USB 麦克风描述符,如通道数,一次发送包大小,采样率(CubeMX配置),最大缓冲区
/**
* @file USB_Audio_Port.h
*
* @date 2021-06-01
*
* @author aron566
*
* @brief
*
* @version V1.0
*/
#ifndef USB_AUDIO_PORT_H
#define USB_AUDIO_PORT_H
/** Includes -----------------------------------------------------------------*/
#include <stdint.h> /**< need definition of uint8_t */
#include <stddef.h> /**< need definition of NULL */
#include <stdbool.h>/**< need definition of BOOL */
#include <stdio.h> /**< if need printf */
#include <stdlib.h>
#include <string.h>
#include <limits.h> /**< need variable max value */
/** Exported macros-----------------------------------------------------------*/
#define AUDIO_PORT_CHANNEL_NUMS 2U /**< MIC音频通道数*/
#define MONO_CHANNEL_SEL 2U /**< 0使用L声道 1使用R声道 2配置MONO*/
#define AUDIO_PORT_USBD_AUDIO_FREQ 16000U /**< 设置音频采样率*/
/*音频类终端类型定义*/
#define AUDIO_PORT_INPUT_TERMINAL_ID_1 0x01
#define AUDIO_PORT_OUTPUT_TERMINAL_ID_3 0x03
#define AUDIO_PORT_INPUT_CTL_ID_2 0x02
#define AUDIO_PORT_SPEAKE_TERMINAL_TYPE_L 0x01U
#define AUDIO_PORT_SPEAKE_TERMINAL_TYPE_H 0x03U
#define AUDIO_PORT_STREAM_TERMINAL_TYPE_L 0x01U
#define AUDIO_PORT_STREAM_TERMINAL_TYPE_H 0x01U
#define AUDIO_PORT_MICRO_PHONE_TERMINAL_L 0x01U
#define AUDIO_PORT_MICRO_PHONE_TERMINAL_H 0x02U
#define AUDIO_PORT_IN_EP_DIR_ID 0x81 /**< (Direction=IN EndpointID=1)*/
#define AUDIO_PORT_OUT_EP_DIR_ID 0x01 /**< (Direction=OUT EndpointID=1)*/
/*立体声配置*/
#if AUDIO_PORT_CHANNEL_NUMS == 2
/*使用L+R声道*/
#define AUDIO_PORT_CHANNEL_CONFIG_L 0x03U
#define AUDIO_PORT_CHANNEL_CONFIG_H 0x00U
/*单声道配置*/
#elif AUDIO_PORT_CHANNEL_NUMS == 1
#if MONO_CHANNEL_SEL == 0
/*使用L声道*/
#define AUDIO_PORT_CHANNEL_CONFIG_L 0x01U
#define AUDIO_PORT_CHANNEL_CONFIG_H 0x00U
#elif MONO_CHANNEL_SEL == 1
/*使用R声道*/
#define AUDIO_PORT_CHANNEL_CONFIG_L 0x02U
#define AUDIO_PORT_CHANNEL_CONFIG_H 0x00U
#elif MONO_CHANNEL_SEL == 2
/*使用默认MONO声道*/
#define AUDIO_PORT_CHANNEL_CONFIG_L 0x00U
#define AUDIO_PORT_CHANNEL_CONFIG_H 0x00U
#endif
#endif
/*轮询时间间隔*/
#define AUDIO_PORT_FS_BINTERVAL 1U /**< 1ms一次轮询*/
/*音频传输大小设置*/
#define AUDIO_PORT_PACKET_SZE(frq) (uint8_t)(((frq * 2U * 2U)/(1000U/AUDIO_PORT_FS_BINTERVAL)) & 0xFFU), \
(uint8_t)((((frq * 2U * 2U)/(1000U/AUDIO_PORT_FS_BINTERVAL)) >> 8) & 0xFFU)
#define AUDIO_PORT_OUT_SIZE ((AUDIO_PORT_USBD_AUDIO_FREQ * 2U * 2U)/(1000U/AUDIO_PORT_FS_BINTERVAL)) /**< 音频发送大小Byte*/
#define AUDIO_PORT_BUF_SIZE AUDIO_PORT_OUT_SIZE*4 /**< 音频缓冲区大小 大于3的倍数*/
/** Private includes ---------------------------------------------------------*/
/** Use C compiler -----------------------------------------------------------*/
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Private defines ----------------------------------------------------------*/
/** Exported typedefines -----------------------------------------------------*/
/** Exported constants -------------------------------------------------------*/
/** Exported variables -------------------------------------------------------*/
/** Exported functions prototypes --------------------------------------------*/
/*向USB缓冲区数据加入数据*/
void USB_Audio_Port_Put_Data(const int16_t *Left_Audio, const int16_t *Right_Audio);
/*初始化音频输出端点*/
uint8_t USB_Audio_Port_EP_IN_Init(void *xpdev, uint8_t cfgidx);
/*初始化音频输入端点*/
uint8_t USB_Audio_Port_EP_OUT_Init(void *xpdev, uint8_t cfgidx);
/*反初始化音频输出端点*/
uint8_t USB_Audio_Port_EP_IN_DeInit(void *xpdev, uint8_t cfgidx);
/*反初始化音频输入端点*/
uint8_t USB_Audio_Port_EP_OUT_DeInit(void *xpdev, uint8_t cfgidx);
/*USB缓冲区数据发送至HOST*/
uint8_t USB_Audio_Port_DataIn(void *xpdev, uint8_t epnum);
/*USB缓冲区数据接收来自HOST*/
uint8_t USB_Audio_Port_DataOut(void *xpdev, uint8_t epnum);
#ifdef __cplusplus ///<end extern c
}
#endif
#endif
/******************************** End of file *********************************/
如何使用
1、用usb_audio.c和对应头文件替换你原先的文件
2、工程添加USB_Audio_Port.c
及USB_Audio_Port.h
,环形缓冲区
3、调用接口添加新音频到缓冲区即可USB_Audio_Port_Put_Data
参考引用
https://blog.****.net/xiaowanbiao123/article/details/112611264#comments_15318445
https://my.oschina.net/u/2007478/blog/1204300