├── README.md ├── USB_MIC.ioc ├── usbd_audio.h ├── main.c └── usbd_audio.c /README.md: -------------------------------------------------------------------------------- 1 | # STM32F4_USB_MIC 2 | A simple USB microphone with ADC oversampling using the STM32F407 MCU and MAX9814 microphone module 3 | More details on https://hackaday.io/project/181868-stm32f4-usb-microphone 4 | -------------------------------------------------------------------------------- /USB_MIC.ioc: -------------------------------------------------------------------------------- 1 | #MicroXplorer Configuration settings - do not modify 2 | ADC1.Channel-2\#ChannelRegularConversion=ADC_CHANNEL_8 3 | ADC1.DMAContinuousRequests=ENABLE 4 | ADC1.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T8_TRGO 5 | ADC1.IPParameters=Rank-2\#ChannelRegularConversion,master,Channel-2\#ChannelRegularConversion,SamplingTime-2\#ChannelRegularConversion,NbrOfConversionFlag,InjNumberOfConversion,ExternalTrigConv,DMAContinuousRequests 6 | ADC1.InjNumberOfConversion=0 7 | ADC1.NbrOfConversionFlag=1 8 | ADC1.Rank-2\#ChannelRegularConversion=1 9 | ADC1.SamplingTime-2\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES 10 | ADC1.master=1 11 | Dma.ADC1.0.Direction=DMA_PERIPH_TO_MEMORY 12 | Dma.ADC1.0.FIFOMode=DMA_FIFOMODE_DISABLE 13 | Dma.ADC1.0.Instance=DMA2_Stream0 14 | Dma.ADC1.0.MemDataAlignment=DMA_MDATAALIGN_HALFWORD 15 | Dma.ADC1.0.MemInc=DMA_MINC_ENABLE 16 | Dma.ADC1.0.Mode=DMA_CIRCULAR 17 | Dma.ADC1.0.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD 18 | Dma.ADC1.0.PeriphInc=DMA_PINC_DISABLE 19 | Dma.ADC1.0.Priority=DMA_PRIORITY_LOW 20 | Dma.ADC1.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode 21 | Dma.Request0=ADC1 22 | Dma.RequestsNb=1 23 | File.Version=6 24 | GPIO.groupedBy=Group By Peripherals 25 | KeepUserPlacement=false 26 | Mcu.Family=STM32F4 27 | Mcu.IP0=ADC1 28 | Mcu.IP1=DMA 29 | Mcu.IP2=NVIC 30 | Mcu.IP3=RCC 31 | Mcu.IP4=SYS 32 | Mcu.IP5=TIM8 33 | Mcu.IP6=USB_DEVICE 34 | Mcu.IP7=USB_OTG_FS 35 | Mcu.IPNb=8 36 | Mcu.Name=STM32F407V(E-G)Tx 37 | Mcu.Package=LQFP100 38 | Mcu.Pin0=PH0-OSC_IN 39 | Mcu.Pin1=PH1-OSC_OUT 40 | Mcu.Pin2=PB0 41 | Mcu.Pin3=PB1 42 | Mcu.Pin4=PA11 43 | Mcu.Pin5=PA12 44 | Mcu.Pin6=VP_SYS_VS_Systick 45 | Mcu.Pin7=VP_TIM8_VS_ClockSourceINT 46 | Mcu.Pin8=VP_USB_DEVICE_VS_USB_DEVICE_AUDIO_FS 47 | Mcu.PinsNb=9 48 | Mcu.ThirdPartyNb=0 49 | Mcu.UserConstants= 50 | Mcu.UserName=STM32F407VGTx 51 | MxCube.Version=5.6.1 52 | MxDb.Version=DB.5.0.60 53 | NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false 54 | NVIC.DMA2_Stream0_IRQn=true\:0\:0\:false\:false\:true\:false\:true 55 | NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false 56 | NVIC.ForceEnableDMAVector=true 57 | NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false 58 | NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false 59 | NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false 60 | NVIC.OTG_FS_IRQn=true\:0\:0\:false\:false\:true\:false\:true 61 | NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false 62 | NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 63 | NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false 64 | NVIC.SysTick_IRQn=true\:0\:0\:false\:false\:true\:false\:true 65 | NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false 66 | PA11.Mode=Device_Only 67 | PA11.Signal=USB_OTG_FS_DM 68 | PA12.Mode=Device_Only 69 | PA12.Signal=USB_OTG_FS_DP 70 | PB0.Locked=true 71 | PB0.Signal=ADCx_IN8 72 | PB1.GPIOParameters=PinState 73 | PB1.Locked=true 74 | PB1.PinState=GPIO_PIN_SET 75 | PB1.Signal=GPIO_Output 76 | PH0-OSC_IN.Mode=HSE-External-Oscillator 77 | PH0-OSC_IN.Signal=RCC_OSC_IN 78 | PH1-OSC_OUT.Mode=HSE-External-Oscillator 79 | PH1-OSC_OUT.Signal=RCC_OSC_OUT 80 | PinOutPanel.RotationAngle=0 81 | ProjectManager.AskForMigrate=true 82 | ProjectManager.BackupPrevious=false 83 | ProjectManager.CompilerOptimize=6 84 | ProjectManager.ComputerToolchain=false 85 | ProjectManager.CoupleFile=false 86 | ProjectManager.CustomerFirmwarePackage= 87 | ProjectManager.DefaultFWLocation=true 88 | ProjectManager.DeletePrevious=true 89 | ProjectManager.DeviceId=STM32F407VGTx 90 | ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.25.2 91 | ProjectManager.FreePins=false 92 | ProjectManager.HalAssertFull=false 93 | ProjectManager.HeapSize=0x4000 94 | ProjectManager.KeepUserCode=true 95 | ProjectManager.LastFirmware=true 96 | ProjectManager.LibraryCopy=0 97 | ProjectManager.MainLocation=Src 98 | ProjectManager.NoMain=false 99 | ProjectManager.PreviousToolchain= 100 | ProjectManager.ProjectBuild=false 101 | ProjectManager.ProjectFileName=USB_MIC.ioc 102 | ProjectManager.ProjectName=USB_MIC 103 | ProjectManager.StackSize=0x2000 104 | ProjectManager.TargetToolchain=MDK-ARM V5.27 105 | ProjectManager.ToolChainLocation= 106 | ProjectManager.UnderRoot=false 107 | ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-SystemClock_Config-RCC-false-HAL-false,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false,6-MX_TIM8_Init-TIM8-false-HAL-true 108 | RCC.48MHZClocksFreq_Value=48000000 109 | RCC.AHBFreq_Value=96000000 110 | RCC.APB1CLKDivider=RCC_HCLK_DIV4 111 | RCC.APB1Freq_Value=24000000 112 | RCC.APB1TimFreq_Value=48000000 113 | RCC.APB2CLKDivider=RCC_HCLK_DIV2 114 | RCC.APB2Freq_Value=48000000 115 | RCC.APB2TimFreq_Value=96000000 116 | RCC.CortexFreq_Value=96000000 117 | RCC.EthernetFreq_Value=96000000 118 | RCC.FCLKCortexFreq_Value=96000000 119 | RCC.FamilyName=M 120 | RCC.HCLKFreq_Value=96000000 121 | RCC.HSE_VALUE=8000000 122 | RCC.HSI_VALUE=16000000 123 | RCC.I2SClocksFreq_Value=49142857.14285714 124 | RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLI2SN,PLLI2SR,PLLM,PLLN,PLLQCLKFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S 125 | RCC.LSE_VALUE=32768 126 | RCC.LSI_VALUE=32000 127 | RCC.MCO2PinFreq_Value=96000000 128 | RCC.PLLCLKFreq_Value=96000000 129 | RCC.PLLI2SN=172 130 | RCC.PLLI2SR=7 131 | RCC.PLLM=4 132 | RCC.PLLN=96 133 | RCC.PLLQCLKFreq_Value=48000000 134 | RCC.RTCFreq_Value=32000 135 | RCC.RTCHSEDivFreq_Value=4000000 136 | RCC.SYSCLKFreq_VALUE=96000000 137 | RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK 138 | RCC.VCOI2SOutputFreq_Value=344000000 139 | RCC.VCOInputFreq_Value=2000000 140 | RCC.VCOOutputFreq_Value=192000000 141 | RCC.VcooutputI2S=49142857.14285714 142 | SH.ADCx_IN8.0=ADC1_IN8,IN8 143 | SH.ADCx_IN8.ConfNb=1 144 | TIM8.IPParameters=Period,TIM_MasterOutputTrigger 145 | TIM8.Period=124 146 | TIM8.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE 147 | USB_DEVICE.CLASS_NAME_FS=AUDIO 148 | USB_DEVICE.IPParameters=VirtualMode-AUDIO_FS,VirtualModeFS,CLASS_NAME_FS,USBD_AUDIO_FREQ-AUDIO_FS,VID-AUDIO_FS 149 | USB_DEVICE.USBD_AUDIO_FREQ-AUDIO_FS=48000 150 | USB_DEVICE.VID-AUDIO_FS=1159 151 | USB_DEVICE.VirtualMode-AUDIO_FS=Audio 152 | USB_DEVICE.VirtualModeFS=Audio_FS 153 | USB_OTG_FS.IPParameters=VirtualMode 154 | USB_OTG_FS.VirtualMode=Device_Only 155 | VP_SYS_VS_Systick.Mode=SysTick 156 | VP_SYS_VS_Systick.Signal=SYS_VS_Systick 157 | VP_TIM8_VS_ClockSourceINT.Mode=Internal 158 | VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT 159 | VP_USB_DEVICE_VS_USB_DEVICE_AUDIO_FS.Mode=AUDIO_FS 160 | VP_USB_DEVICE_VS_USB_DEVICE_AUDIO_FS.Signal=USB_DEVICE_VS_USB_DEVICE_AUDIO_FS 161 | board=custom 162 | -------------------------------------------------------------------------------- /usbd_audio.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file usbd_audio.h 4 | * @author MCD Application Team 5 | * @brief header file for the usbd_audio.c file. 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2015 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under Ultimate Liberty license 13 | * SLA0044, the "License"; You may not use this file except in compliance with 14 | * the License. You may obtain a copy of the License at: 15 | * www.st.com/SLA0044 16 | * 17 | ****************************************************************************** 18 | */ 19 | 20 | /* Define to prevent recursive inclusion -------------------------------------*/ 21 | #ifndef __USB_AUDIO_H 22 | #define __USB_AUDIO_H 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /* Includes ------------------------------------------------------------------*/ 29 | #include "usbd_ioreq.h" 30 | 31 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 32 | * @{ 33 | */ 34 | 35 | /** @defgroup USBD_AUDIO 36 | * @brief This file is the Header file for usbd_audio.c 37 | * @{ 38 | */ 39 | 40 | 41 | /** @defgroup USBD_AUDIO_Exported_Defines 42 | * @{ 43 | */ 44 | #ifndef USBD_AUDIO_FREQ 45 | /* AUDIO Class Config */ 46 | #define USBD_AUDIO_FREQ 48000U 47 | #endif /* USBD_AUDIO_FREQ */ 48 | 49 | #ifndef USBD_MAX_NUM_INTERFACES 50 | #define USBD_MAX_NUM_INTERFACES 1U 51 | #endif /* USBD_AUDIO_FREQ */ 52 | 53 | #ifndef AUDIO_HS_BINTERVAL 54 | #define AUDIO_HS_BINTERVAL 0x01U 55 | #endif /* AUDIO_HS_BINTERVAL */ 56 | 57 | #ifndef AUDIO_FS_BINTERVAL 58 | #define AUDIO_FS_BINTERVAL 0x01U 59 | #endif /* AUDIO_FS_BINTERVAL */ 60 | 61 | #define AUDIO_IN_EP 0x81U // [EDITED] 62 | #define AUDIO_OUT_EP 0x01U 63 | #define USB_AUDIO_CONFIG_DESC_SIZ 100U // [EDITED] 64 | #define AUDIO_INTERFACE_DESC_SIZE 0x09U 65 | #define USB_AUDIO_DESC_SIZ 0x09U 66 | #define AUDIO_STANDARD_ENDPOINT_DESC_SIZE 0x09U 67 | #define AUDIO_STREAMING_ENDPOINT_DESC_SIZE 0x07U 68 | 69 | #define AUDIO_DESCRIPTOR_TYPE 0x21U 70 | #define USB_DEVICE_CLASS_AUDIO 0x01U 71 | #define AUDIO_SUBCLASS_AUDIOCONTROL 0x01U 72 | #define AUDIO_SUBCLASS_AUDIOSTREAMING 0x02U 73 | #define AUDIO_PROTOCOL_UNDEFINED 0x00U 74 | #define AUDIO_STREAMING_GENERAL 0x01U 75 | #define AUDIO_STREAMING_FORMAT_TYPE 0x02U 76 | 77 | /* Audio Descriptor Types */ 78 | #define AUDIO_INTERFACE_DESCRIPTOR_TYPE 0x24U 79 | #define AUDIO_ENDPOINT_DESCRIPTOR_TYPE 0x25U 80 | 81 | /* Audio Control Interface Descriptor Subtypes */ 82 | #define AUDIO_CONTROL_HEADER 0x01U 83 | #define AUDIO_CONTROL_INPUT_TERMINAL 0x02U 84 | #define AUDIO_CONTROL_OUTPUT_TERMINAL 0x03U 85 | #define AUDIO_CONTROL_FEATURE_UNIT 0x06U 86 | 87 | #define AUDIO_INPUT_TERMINAL_DESC_SIZE 0x0CU 88 | #define AUDIO_OUTPUT_TERMINAL_DESC_SIZE 0x09U 89 | #define AUDIO_STREAMING_INTERFACE_DESC_SIZE 0x07U 90 | 91 | #define AUDIO_CONTROL_MUTE 0x0001U 92 | 93 | #define AUDIO_FORMAT_TYPE_I 0x01U 94 | #define AUDIO_FORMAT_TYPE_III 0x03U 95 | 96 | #define AUDIO_ENDPOINT_GENERAL 0x01U 97 | 98 | #define AUDIO_REQ_GET_CUR 0x81U 99 | #define AUDIO_REQ_SET_CUR 0x01U 100 | 101 | #define AUDIO_OUT_STREAMING_CTRL 0x02U 102 | 103 | #define AUDIO_OUT_TC 0x01U 104 | #define AUDIO_IN_TC 0x02U 105 | 106 | 107 | #define AUDIO_OUT_PACKET (uint16_t)(((USBD_AUDIO_FREQ * 2U * 2U) / 1000U)) 108 | #define AUDIO_IN_PACKET (uint16_t)(((USBD_AUDIO_FREQ * 1U * 2U) / 1000U)) 109 | #define AUDIO_DEFAULT_VOLUME 70U 110 | 111 | /* Number of sub-packets in the audio transfer buffer. You can modify this value but always make sure 112 | that it is an even number and higher than 3 */ 113 | #define AUDIO_OUT_PACKET_NUM 80U 114 | /* Total size of the audio transfer buffer */ 115 | #define AUDIO_TOTAL_BUF_SIZE ((uint16_t)(AUDIO_OUT_PACKET * AUDIO_OUT_PACKET_NUM)) 116 | 117 | /* Audio Commands enumeration */ 118 | typedef enum 119 | { 120 | AUDIO_CMD_START = 1, 121 | AUDIO_CMD_PLAY, 122 | AUDIO_CMD_STOP, 123 | } AUDIO_CMD_TypeDef; 124 | 125 | 126 | typedef enum 127 | { 128 | AUDIO_OFFSET_NONE = 0, 129 | AUDIO_OFFSET_HALF, 130 | AUDIO_OFFSET_FULL, 131 | AUDIO_OFFSET_UNKNOWN, 132 | } AUDIO_OffsetTypeDef; 133 | /** 134 | * @} 135 | */ 136 | 137 | 138 | /** @defgroup USBD_CORE_Exported_TypesDefinitions 139 | * @{ 140 | */ 141 | typedef struct 142 | { 143 | uint8_t cmd; 144 | uint8_t data[USB_MAX_EP0_SIZE]; 145 | uint8_t len; 146 | uint8_t unit; 147 | } USBD_AUDIO_ControlTypeDef; 148 | 149 | 150 | typedef struct 151 | { 152 | uint32_t alt_setting; 153 | /* speaker */ 154 | uint8_t buffer[AUDIO_TOTAL_BUF_SIZE]; 155 | AUDIO_OffsetTypeDef offset; 156 | uint8_t rd_enable; 157 | uint16_t rd_ptr; 158 | uint16_t wr_ptr; 159 | /* mic */ 160 | int16_t in_buffer[AUDIO_IN_PACKET]; 161 | uint8_t in_buffer_half; 162 | /* control */ 163 | USBD_AUDIO_ControlTypeDef control; 164 | } USBD_AUDIO_HandleTypeDef; 165 | 166 | 167 | typedef struct 168 | { 169 | int8_t (*Init)(uint32_t AudioFreq, uint32_t Volume, uint32_t options); 170 | int8_t (*DeInit)(uint32_t options); 171 | int8_t (*AudioCmd)(uint8_t *pbuf, uint32_t size, uint8_t cmd); 172 | int8_t (*VolumeCtl)(uint8_t vol); 173 | int8_t (*MuteCtl)(uint8_t cmd); 174 | int8_t (*PeriodicTC)(uint8_t *pbuf, uint32_t size, uint8_t cmd); 175 | int8_t (*GetState)(void); 176 | } USBD_AUDIO_ItfTypeDef; 177 | /** 178 | * @} 179 | */ 180 | 181 | 182 | 183 | /** @defgroup USBD_CORE_Exported_Macros 184 | * @{ 185 | */ 186 | 187 | /** 188 | * @} 189 | */ 190 | 191 | /** @defgroup USBD_CORE_Exported_Variables 192 | * @{ 193 | */ 194 | 195 | extern USBD_ClassTypeDef USBD_AUDIO; 196 | #define USBD_AUDIO_CLASS &USBD_AUDIO 197 | /** 198 | * @} 199 | */ 200 | 201 | /** @defgroup USB_CORE_Exported_Functions 202 | * @{ 203 | */ 204 | uint8_t USBD_AUDIO_RegisterInterface(USBD_HandleTypeDef *pdev, 205 | USBD_AUDIO_ItfTypeDef *fops); 206 | 207 | void USBD_AUDIO_Sync(USBD_HandleTypeDef *pdev, AUDIO_OffsetTypeDef offset); 208 | /** 209 | * @} 210 | */ 211 | 212 | #ifdef __cplusplus 213 | } 214 | #endif 215 | 216 | #endif /* __USB_AUDIO_H */ 217 | /** 218 | * @} 219 | */ 220 | 221 | /** 222 | * @} 223 | */ 224 | 225 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 226 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* USER CODE BEGIN Header */ 2 | /** 3 | ****************************************************************************** 4 | * @file : main.c 5 | * @brief : Main program body 6 | ****************************************************************************** 7 | * @attention 8 | * 9 | *

© Copyright (c) 2021 STMicroelectronics. 10 | * All rights reserved.

11 | * 12 | * This software component is licensed by ST under Ultimate Liberty license 13 | * SLA0044, the "License"; You may not use this file except in compliance with 14 | * the License. You may obtain a copy of the License at: 15 | * www.st.com/SLA0044 16 | * 17 | ****************************************************************************** 18 | */ 19 | /* USER CODE END Header */ 20 | 21 | /* Includes ------------------------------------------------------------------*/ 22 | #include "main.h" 23 | #include "usb_device.h" 24 | #include "usbd_audio_if.h" 25 | 26 | /* Private includes ----------------------------------------------------------*/ 27 | /* USER CODE BEGIN Includes */ 28 | 29 | /* USER CODE END Includes */ 30 | 31 | /* Private typedef -----------------------------------------------------------*/ 32 | /* USER CODE BEGIN PTD */ 33 | 34 | /* USER CODE END PTD */ 35 | 36 | /* Private define ------------------------------------------------------------*/ 37 | /* USER CODE BEGIN PD */ 38 | #define OSA_BUF_SIZE 16 /* ADC oversampling buffer. Make sure to state the correct 39 | shift and offset amount in HAL_ADC_ConvCpltCallback() and 40 | adjust the sampling frequency accordingly */ 41 | extern USBD_HandleTypeDef hUsbDeviceFS; 42 | int16_t adc_buffer[OSA_BUF_SIZE * AUDIO_IN_PACKET / 2] = {0}; 43 | /* USER CODE END PD */ 44 | 45 | /* Private macro -------------------------------------------------------------*/ 46 | /* USER CODE BEGIN PM */ 47 | 48 | /* USER CODE END PM */ 49 | 50 | /* Private variables ---------------------------------------------------------*/ 51 | ADC_HandleTypeDef hadc1; 52 | DMA_HandleTypeDef hdma_adc1; 53 | 54 | TIM_HandleTypeDef htim8; 55 | 56 | /* USER CODE BEGIN PV */ 57 | 58 | /* USER CODE END PV */ 59 | 60 | /* Private function prototypes -----------------------------------------------*/ 61 | void SystemClock_Config(void); 62 | static void MX_GPIO_Init(void); 63 | static void MX_DMA_Init(void); 64 | static void MX_ADC1_Init(void); 65 | static void MX_TIM8_Init(void); 66 | /* USER CODE BEGIN PFP */ 67 | 68 | /* USER CODE END PFP */ 69 | 70 | /* Private user code ---------------------------------------------------------*/ 71 | /* USER CODE BEGIN 0 */ 72 | void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { 73 | USBD_AUDIO_HandleTypeDef *haudio = hUsbDeviceFS.pClassData; 74 | int16_t *buf_part = haudio->in_buffer + (AUDIO_IN_PACKET / 2) * haudio->in_buffer_half; // USB mic buffer access 75 | 76 | /* Oversample for +2 bits */ 77 | for (uint16_t i = 0; i < (AUDIO_IN_PACKET / 2); i++) { 78 | int32_t avg_value = 0; 79 | for (uint16_t j = 0; j < OSA_BUF_SIZE; j++) { 80 | avg_value += adc_buffer[OSA_BUF_SIZE * i + j]; 81 | } 82 | // bit shift for signed variables is undefined behaviour 83 | // Don't forget the mic amp offset: 0-1706, 1-3413, 2-6826 84 | buf_part[i] = (avg_value / 4) - 6826; 85 | } 86 | } 87 | 88 | void ADC_to_MIC(void) 89 | { 90 | HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, OSA_BUF_SIZE * (AUDIO_IN_PACKET / 2)); // Start ADC transfer into oversampling buffer 91 | } 92 | /* USER CODE END 0 */ 93 | 94 | /** 95 | * @brief The application entry point. 96 | * @retval int 97 | */ 98 | int main(void) 99 | { 100 | /* USER CODE BEGIN 1 */ 101 | 102 | /* USER CODE END 1 */ 103 | 104 | /* MCU Configuration--------------------------------------------------------*/ 105 | 106 | /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 107 | HAL_Init(); 108 | 109 | /* USER CODE BEGIN Init */ 110 | 111 | /* USER CODE END Init */ 112 | 113 | /* Configure the system clock */ 114 | SystemClock_Config(); 115 | 116 | /* USER CODE BEGIN SysInit */ 117 | 118 | /* USER CODE END SysInit */ 119 | 120 | /* Initialize all configured peripherals */ 121 | MX_GPIO_Init(); 122 | MX_DMA_Init(); 123 | MX_ADC1_Init(); 124 | MX_USB_DEVICE_Init(); 125 | MX_TIM8_Init(); 126 | /* USER CODE BEGIN 2 */ 127 | HAL_TIM_Base_Start(&htim8); 128 | /* USER CODE END 2 */ 129 | 130 | /* Infinite loop */ 131 | /* USER CODE BEGIN WHILE */ 132 | while (1) 133 | { 134 | /* USER CODE END WHILE */ 135 | 136 | /* USER CODE BEGIN 3 */ 137 | } 138 | /* USER CODE END 3 */ 139 | } 140 | 141 | /** 142 | * @brief System Clock Configuration 143 | * @retval None 144 | */ 145 | void SystemClock_Config(void) 146 | { 147 | RCC_OscInitTypeDef RCC_OscInitStruct = {0}; 148 | RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; 149 | 150 | /** Configure the main internal regulator output voltage 151 | */ 152 | __HAL_RCC_PWR_CLK_ENABLE(); 153 | __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); 154 | /** Initializes the CPU, AHB and APB busses clocks 155 | */ 156 | RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; 157 | RCC_OscInitStruct.HSEState = RCC_HSE_ON; 158 | RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; 159 | RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; 160 | RCC_OscInitStruct.PLL.PLLM = 4; 161 | RCC_OscInitStruct.PLL.PLLN = 96; 162 | RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; 163 | RCC_OscInitStruct.PLL.PLLQ = 4; 164 | if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) 165 | { 166 | Error_Handler(); 167 | } 168 | /** Initializes the CPU, AHB and APB busses clocks 169 | */ 170 | RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK 171 | |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; 172 | RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; 173 | RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; 174 | RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; 175 | RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; 176 | 177 | if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK) 178 | { 179 | Error_Handler(); 180 | } 181 | } 182 | 183 | /** 184 | * @brief ADC1 Initialization Function 185 | * @param None 186 | * @retval None 187 | */ 188 | static void MX_ADC1_Init(void) 189 | { 190 | 191 | /* USER CODE BEGIN ADC1_Init 0 */ 192 | 193 | /* USER CODE END ADC1_Init 0 */ 194 | 195 | ADC_ChannelConfTypeDef sConfig = {0}; 196 | 197 | /* USER CODE BEGIN ADC1_Init 1 */ 198 | 199 | /* USER CODE END ADC1_Init 1 */ 200 | /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) 201 | */ 202 | hadc1.Instance = ADC1; 203 | hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; 204 | hadc1.Init.Resolution = ADC_RESOLUTION_12B; 205 | hadc1.Init.ScanConvMode = DISABLE; 206 | hadc1.Init.ContinuousConvMode = DISABLE; 207 | hadc1.Init.DiscontinuousConvMode = DISABLE; 208 | hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; 209 | hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO; 210 | hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; 211 | hadc1.Init.NbrOfConversion = 1; 212 | hadc1.Init.DMAContinuousRequests = ENABLE; 213 | hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; 214 | if (HAL_ADC_Init(&hadc1) != HAL_OK) 215 | { 216 | Error_Handler(); 217 | } 218 | /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. 219 | */ 220 | sConfig.Channel = ADC_CHANNEL_8; 221 | sConfig.Rank = 1; 222 | sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; 223 | if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) 224 | { 225 | Error_Handler(); 226 | } 227 | /* USER CODE BEGIN ADC1_Init 2 */ 228 | 229 | /* USER CODE END ADC1_Init 2 */ 230 | 231 | } 232 | 233 | /** 234 | * @brief TIM8 Initialization Function 235 | * @param None 236 | * @retval None 237 | */ 238 | static void MX_TIM8_Init(void) 239 | { 240 | 241 | /* USER CODE BEGIN TIM8_Init 0 */ 242 | 243 | /* USER CODE END TIM8_Init 0 */ 244 | 245 | TIM_ClockConfigTypeDef sClockSourceConfig = {0}; 246 | TIM_MasterConfigTypeDef sMasterConfig = {0}; 247 | 248 | /* USER CODE BEGIN TIM8_Init 1 */ 249 | 250 | /* USER CODE END TIM8_Init 1 */ 251 | htim8.Instance = TIM8; 252 | htim8.Init.Prescaler = 0; 253 | htim8.Init.CounterMode = TIM_COUNTERMODE_UP; 254 | htim8.Init.Period = 124; 255 | htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 256 | htim8.Init.RepetitionCounter = 0; 257 | htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; 258 | if (HAL_TIM_Base_Init(&htim8) != HAL_OK) 259 | { 260 | Error_Handler(); 261 | } 262 | sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; 263 | if (HAL_TIM_ConfigClockSource(&htim8, &sClockSourceConfig) != HAL_OK) 264 | { 265 | Error_Handler(); 266 | } 267 | sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; 268 | sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; 269 | if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK) 270 | { 271 | Error_Handler(); 272 | } 273 | /* USER CODE BEGIN TIM8_Init 2 */ 274 | 275 | /* USER CODE END TIM8_Init 2 */ 276 | 277 | } 278 | 279 | /** 280 | * Enable DMA controller clock 281 | */ 282 | static void MX_DMA_Init(void) 283 | { 284 | 285 | /* DMA controller clock enable */ 286 | __HAL_RCC_DMA2_CLK_ENABLE(); 287 | 288 | /* DMA interrupt init */ 289 | /* DMA2_Stream0_IRQn interrupt configuration */ 290 | HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); 291 | HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); 292 | 293 | } 294 | 295 | /** 296 | * @brief GPIO Initialization Function 297 | * @param None 298 | * @retval None 299 | */ 300 | static void MX_GPIO_Init(void) 301 | { 302 | GPIO_InitTypeDef GPIO_InitStruct = {0}; 303 | 304 | /* GPIO Ports Clock Enable */ 305 | __HAL_RCC_GPIOH_CLK_ENABLE(); 306 | __HAL_RCC_GPIOB_CLK_ENABLE(); 307 | __HAL_RCC_GPIOA_CLK_ENABLE(); 308 | 309 | /*Configure GPIO pin Output Level */ 310 | HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); 311 | 312 | /*Configure GPIO pin : PB1 */ 313 | GPIO_InitStruct.Pin = GPIO_PIN_1; 314 | GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 315 | GPIO_InitStruct.Pull = GPIO_NOPULL; 316 | GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; 317 | HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 318 | 319 | } 320 | 321 | /* USER CODE BEGIN 4 */ 322 | 323 | /* USER CODE END 4 */ 324 | 325 | /** 326 | * @brief This function is executed in case of error occurrence. 327 | * @retval None 328 | */ 329 | void Error_Handler(void) 330 | { 331 | /* USER CODE BEGIN Error_Handler_Debug */ 332 | /* User can add his own implementation to report the HAL error return state */ 333 | 334 | /* USER CODE END Error_Handler_Debug */ 335 | } 336 | 337 | #ifdef USE_FULL_ASSERT 338 | /** 339 | * @brief Reports the name of the source file and the source line number 340 | * where the assert_param error has occurred. 341 | * @param file: pointer to the source file name 342 | * @param line: assert_param error line source number 343 | * @retval None 344 | */ 345 | void assert_failed(uint8_t *file, uint32_t line) 346 | { 347 | /* USER CODE BEGIN 6 */ 348 | /* User can add his own implementation to report the file name and line number, 349 | tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ 350 | /* USER CODE END 6 */ 351 | } 352 | #endif /* USE_FULL_ASSERT */ 353 | 354 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 355 | -------------------------------------------------------------------------------- /usbd_audio.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file usbd_audio.c 4 | * @author MCD Application Team 5 | * @brief This file provides the Audio core functions. 6 | * 7 | * @verbatim 8 | * 9 | * =================================================================== 10 | * AUDIO Class Description 11 | * =================================================================== 12 | * This driver manages the Audio Class 1.0 following the "USB Device Class Definition for 13 | * Audio Devices V1.0 Mar 18, 98". 14 | * This driver implements the following aspects of the specification: 15 | * - Device descriptor management 16 | * - Configuration descriptor management 17 | * - Standard AC Interface Descriptor management 18 | * - 1 Audio Streaming Interface (with single channel, PCM, Stereo mode) 19 | * - 1 Audio Streaming Endpoint 20 | * - 1 Audio Terminal Input (1 channel) 21 | * - Audio Class-Specific AC Interfaces 22 | * - Audio Class-Specific AS Interfaces 23 | * - AudioControl Requests: only SET_CUR and GET_CUR requests are supported (for Mute) 24 | * - Audio Feature Unit (limited to Mute control) 25 | * - Audio Synchronization type: Asynchronous 26 | * - Single fixed audio sampling rate (configurable in usbd_conf.h file) 27 | * The current audio class version supports the following audio features: 28 | * - Pulse Coded Modulation (PCM) format 29 | * - sampling rate: 48KHz. 30 | * - Bit resolution: 16 31 | * - Number of channels: 2 32 | * - No volume control 33 | * - Mute/Unmute capability 34 | * - Asynchronous Endpoints 35 | * 36 | * @note In HS mode and when the DMA is used, all variables and data structures 37 | * dealing with the DMA during the transaction process should be 32-bit aligned. 38 | * 39 | * 40 | * @endverbatim 41 | * 42 | ****************************************************************************** 43 | * @attention 44 | * 45 | *

© Copyright (c) 2015 STMicroelectronics. 46 | * All rights reserved.

47 | * 48 | * This software component is licensed by ST under Ultimate Liberty license 49 | * SLA0044, the "License"; You may not use this file except in compliance with 50 | * the License. You may obtain a copy of the License at: 51 | * www.st.com/SLA0044 52 | * 53 | ****************************************************************************** 54 | */ 55 | 56 | /* BSPDependencies 57 | - "stm32xxxxx_{eval}{discovery}.c" 58 | - "stm32xxxxx_{eval}{discovery}_io.c" 59 | - "stm32xxxxx_{eval}{discovery}_audio.c" 60 | EndBSPDependencies */ 61 | 62 | /* Includes ------------------------------------------------------------------*/ 63 | #include "usbd_audio.h" 64 | #include "usbd_ctlreq.h" 65 | #include "main.h" 66 | 67 | 68 | /** @addtogroup STM32_USB_DEVICE_LIBRARY 69 | * @{ 70 | */ 71 | 72 | 73 | /** @defgroup USBD_AUDIO 74 | * @brief usbd core module 75 | * @{ 76 | */ 77 | 78 | /** @defgroup USBD_AUDIO_Private_TypesDefinitions 79 | * @{ 80 | */ 81 | /** 82 | * @} 83 | */ 84 | 85 | 86 | /** @defgroup USBD_AUDIO_Private_Defines 87 | * @{ 88 | */ 89 | /** 90 | * @} 91 | */ 92 | 93 | 94 | /** @defgroup USBD_AUDIO_Private_Macros 95 | * @{ 96 | */ 97 | #define AUDIO_SAMPLE_FREQ(frq) (uint8_t)(frq), (uint8_t)((frq >> 8)), (uint8_t)((frq >> 16)) 98 | 99 | #define AUDIO_PACKET_SZE(frq) (uint8_t)(((frq * 2U * 2U)/1000U) & 0xFFU), \ 100 | (uint8_t)((((frq * 2U * 2U)/1000U) >> 8) & 0xFFU) 101 | #define MIC_PACKET_SZE(frq) (uint8_t)(((frq * 1U * 2U)/1000U) & 0xFFU), \ 102 | (uint8_t)((((frq * 1U * 2U)/1000U) >> 8) & 0xFFU) 103 | void ADC_to_MIC(void); 104 | /** 105 | * @} 106 | */ 107 | 108 | 109 | /** @defgroup USBD_AUDIO_Private_FunctionPrototypes 110 | * @{ 111 | */ 112 | static uint8_t USBD_AUDIO_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx); 113 | static uint8_t USBD_AUDIO_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx); 114 | 115 | static uint8_t USBD_AUDIO_Setup(USBD_HandleTypeDef *pdev, 116 | USBD_SetupReqTypedef *req); 117 | 118 | static uint8_t *USBD_AUDIO_GetCfgDesc(uint16_t *length); 119 | static uint8_t *USBD_AUDIO_GetDeviceQualifierDesc(uint16_t *length); 120 | static uint8_t USBD_AUDIO_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum); 121 | static uint8_t USBD_AUDIO_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum); 122 | static uint8_t USBD_AUDIO_EP0_RxReady(USBD_HandleTypeDef *pdev); 123 | static uint8_t USBD_AUDIO_EP0_TxReady(USBD_HandleTypeDef *pdev); 124 | static uint8_t USBD_AUDIO_SOF(USBD_HandleTypeDef *pdev); 125 | 126 | static uint8_t USBD_AUDIO_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); 127 | static uint8_t USBD_AUDIO_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum); 128 | static void AUDIO_REQ_GetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 129 | static void AUDIO_REQ_SetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req); 130 | 131 | /** 132 | * @} 133 | */ 134 | 135 | /** @defgroup USBD_AUDIO_Private_Variables 136 | * @{ 137 | */ 138 | 139 | USBD_ClassTypeDef USBD_AUDIO = 140 | { 141 | USBD_AUDIO_Init, 142 | USBD_AUDIO_DeInit, 143 | USBD_AUDIO_Setup, 144 | USBD_AUDIO_EP0_TxReady, 145 | USBD_AUDIO_EP0_RxReady, 146 | USBD_AUDIO_DataIn, 147 | USBD_AUDIO_DataOut, 148 | USBD_AUDIO_SOF, 149 | USBD_AUDIO_IsoINIncomplete, 150 | USBD_AUDIO_IsoOutIncomplete, 151 | USBD_AUDIO_GetCfgDesc, 152 | USBD_AUDIO_GetCfgDesc, 153 | USBD_AUDIO_GetCfgDesc, 154 | USBD_AUDIO_GetDeviceQualifierDesc, 155 | }; 156 | 157 | /* USB AUDIO device Configuration Descriptor */ 158 | __ALIGN_BEGIN static uint8_t USBD_AUDIO_CfgDesc[USB_AUDIO_CONFIG_DESC_SIZ] __ALIGN_END = 159 | { 160 | /* Configuration Descriptor */ 161 | 0x09, /* bLength */ 162 | USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType */ 163 | LOBYTE(USB_AUDIO_CONFIG_DESC_SIZ), /* wTotalLength 100 bytes*/ 164 | HIBYTE(USB_AUDIO_CONFIG_DESC_SIZ), 165 | 0x02, /* bNumInterfaces */ 166 | 0x01, /* bConfigurationValue */ 167 | 0x00, /* iConfiguration */ 168 | 0xC0, /* bmAttributes BUS Powred*/ 169 | 0x32, /* bMaxPower = 100 mA*/ 170 | /* 09 byte*/ 171 | 172 | /* Standard interface descriptor */ 173 | AUDIO_INTERFACE_DESC_SIZE, /* bLength */ 174 | USB_DESC_TYPE_INTERFACE, /* bDescriptorType */ 175 | 0x00, /* bInterfaceNumber */ 176 | 0x00, /* bAlternateSetting */ 177 | 0x00, /* bNumEndpoints */ 178 | USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ 179 | AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */ 180 | AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ 181 | 0x00, /* iInterface */ 182 | /* 09 byte*/ 183 | 184 | /* Class-specific AC Interface Descriptor */ 185 | AUDIO_INTERFACE_DESC_SIZE, /* bLength */ 186 | AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 187 | AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */ 188 | 0x00, /* 1.00 */ /* bcdADC */ 189 | 0x01, 190 | 0x1E, /* [EDITED] wTotalLength = 30*/ 191 | 0x00, 192 | 0x01, /* bInCollection */ 193 | 0x01, /* baInterfaceNr */ 194 | /* 09 byte*/ 195 | 196 | /* Mic Input Terminal Descriptor */ 197 | AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */ 198 | AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 199 | AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */ 200 | 0x01, /* bTerminalID */ 201 | 0x01, /* wTerminalType = 0x0201 = Microphone */ 202 | 0x02, 203 | 0x00, /* bAssocTerminal - No Associated Terminal */ 204 | 0x01, /* bNrChannels = 1 */ 205 | 0x00, /* wChannelConfig = 0x0000 = Mono */ 206 | 0x00, 207 | 0x00, /* iChannelNames */ 208 | 0x00, /* iTerminal */ 209 | /* 12 byte*/ 210 | 211 | /* Mic Output Terminal Descriptor */ 212 | 0x09, /* bLength */ 213 | AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 214 | AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */ 215 | 0x02, /* bTerminalID */ 216 | 0x01, /* wTerminalType = 0x0101 = USB_STREAMING */ 217 | 0x01, 218 | 0x00, /* bAssocTerminal */ 219 | 0x01, /* bSourceID */ 220 | 0x00, /* iTerminal */ 221 | /* 09 byte*/ 222 | 223 | /* Mic Standard AS Interface Descriptor - Audio Streaming Zero Bandwith */ 224 | /* Interface 1, Alternate Setting 0 */ 225 | AUDIO_INTERFACE_DESC_SIZE, /* bLength */ 226 | USB_DESC_TYPE_INTERFACE, /* bDescriptorType */ 227 | 0x01, /* bInterfaceNumber */ 228 | 0x00, /* bAlternateSetting */ 229 | 0x00, /* bNumEndpoints */ 230 | USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ 231 | AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ 232 | AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ 233 | 0x00, /* iInterface */ 234 | /* 09 byte*/ 235 | 236 | /* Mic Standard AS Interface Descriptor - Audio Streaming Operational */ 237 | /* Interface 1, Alternate Setting 1 */ 238 | AUDIO_INTERFACE_DESC_SIZE, /* bLength */ 239 | USB_DESC_TYPE_INTERFACE, /* bDescriptorType */ 240 | 0x01, /* bInterfaceNumber */ 241 | 0x01, /* bAlternateSetting */ 242 | 0x01, /* bNumEndpoints */ 243 | USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */ 244 | AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */ 245 | AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */ 246 | 0x00, /* iInterface */ 247 | /* 09 byte*/ 248 | 249 | /* Mic Audio Streaming Interface Descriptor */ 250 | AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */ 251 | AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */ 252 | AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */ 253 | 0x02, /* bTerminalLink */ 254 | 0x01, /* bDelay */ 255 | 0x01, /* wFormatTag AUDIO_FORMAT_PCM 0x0001 */ 256 | 0x00, 257 | /* 07 byte*/ 258 | 259 | /* Mic Audio Type I Format Interface Descriptor */ 260 | 0x0B, /* bLength */ 261 | AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType 0x24 */ 262 | AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype 0x02 */ 263 | AUDIO_FORMAT_TYPE_I, /* bFormatType */ 264 | 0x01, /* bNrChannels */ 265 | 0x02, /* bSubFrameSize : 2 Bytes per frame (16bits) */ 266 | 16, /* bBitResolution (16-bits per sample) */ 267 | 0x01, /* bSamFreqType only one frequency supported */ 268 | AUDIO_SAMPLE_FREQ(USBD_AUDIO_FREQ), /* Audio sampling frequency coded on 3 bytes */ 269 | /* 11 byte*/ 270 | 271 | /* Endpoint 1 - Standard Descriptor */ 272 | AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength 0x09 */ 273 | USB_DESC_TYPE_ENDPOINT, /* bDescriptorType 0x05 */ 274 | AUDIO_IN_EP, /* bEndpointAddress: IN endpoint 1 */ 275 | USBD_EP_TYPE_ISOC, /* bmAttributes */ 276 | MIC_PACKET_SZE(USBD_AUDIO_FREQ), /* wMaxPacketSize in Bytes (Freq(Samples)*1(Mono)*2(HalfWord)) */ 277 | AUDIO_FS_BINTERVAL, /* bInterval 0x01 */ 278 | 0x00, /* bRefresh */ 279 | 0x00, /* bSynchAddress */ 280 | /* 09 byte*/ 281 | 282 | /* Endpoint - Audio Streaming Descriptor*/ 283 | AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength 0x07 */ 284 | AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType 0x25 */ 285 | AUDIO_ENDPOINT_GENERAL, /* bDescriptor 0x01 */ 286 | 0x00, /* bmAttributes */ 287 | 0x00, /* bLockDelayUnits */ 288 | 0x00, /* wLockDelay */ 289 | 0x00, 290 | /* 07 byte*/ 291 | } ; 292 | 293 | /* USB Standard Device Descriptor */ 294 | __ALIGN_BEGIN static uint8_t USBD_AUDIO_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END = 295 | { 296 | USB_LEN_DEV_QUALIFIER_DESC, 297 | USB_DESC_TYPE_DEVICE_QUALIFIER, 298 | 0x00, 299 | 0x02, 300 | 0x00, 301 | 0x00, 302 | 0x00, 303 | 0x40, 304 | 0x01, 305 | 0x00, 306 | }; 307 | 308 | /** 309 | * @} 310 | */ 311 | 312 | /** @defgroup USBD_AUDIO_Private_Functions 313 | * @{ 314 | */ 315 | 316 | /** 317 | * @brief USBD_AUDIO_Init 318 | * Initialize the AUDIO interface 319 | * @param pdev: device instance 320 | * @param cfgidx: Configuration index 321 | * @retval status 322 | */ 323 | static uint8_t USBD_AUDIO_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx) 324 | { 325 | UNUSED(cfgidx); 326 | USBD_AUDIO_HandleTypeDef *haudio; 327 | 328 | /* Allocate Audio structure */ 329 | haudio = USBD_malloc(sizeof(USBD_AUDIO_HandleTypeDef)); 330 | 331 | if (haudio == NULL) 332 | { 333 | pdev->pClassData = NULL; 334 | return (uint8_t)USBD_EMEM; 335 | } 336 | 337 | pdev->pClassData = (void *)haudio; 338 | 339 | /* Open EP IN (mic) */ 340 | USBD_LL_OpenEP (pdev, AUDIO_IN_EP, USBD_EP_TYPE_ISOC, AUDIO_IN_PACKET); 341 | pdev->ep_in[AUDIO_IN_EP & 0xFU].is_used = 1U; 342 | 343 | /* Make a dummy transmission */ 344 | USBD_LL_FlushEP (pdev, AUDIO_IN_EP); 345 | USBD_LL_Transmit (pdev, AUDIO_IN_EP, 346 | (uint8_t*)&haudio->in_buffer[AUDIO_IN_PACKET * !!haudio->in_buffer_half], AUDIO_IN_PACKET); 347 | 348 | return (uint8_t)USBD_OK; 349 | } 350 | 351 | /** 352 | * @brief USBD_AUDIO_Init 353 | * DeInitialize the AUDIO layer 354 | * @param pdev: device instance 355 | * @param cfgidx: Configuration index 356 | * @retval status 357 | */ 358 | static uint8_t USBD_AUDIO_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx) 359 | { 360 | UNUSED(cfgidx); 361 | 362 | /* Open EP OUT */ 363 | (void)USBD_LL_CloseEP(pdev, AUDIO_OUT_EP); 364 | pdev->ep_out[AUDIO_OUT_EP & 0xFU].is_used = 0U; 365 | pdev->ep_out[AUDIO_OUT_EP & 0xFU].bInterval = 0U; 366 | 367 | /* DeInit physical Interface components */ 368 | if (pdev->pClassData != NULL) 369 | { 370 | ((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->DeInit(0U); 371 | (void)USBD_free(pdev->pClassData); 372 | pdev->pClassData = NULL; 373 | } 374 | 375 | return (uint8_t)USBD_OK; 376 | } 377 | 378 | /** 379 | * @brief USBD_AUDIO_Setup 380 | * Handle the AUDIO specific requests 381 | * @param pdev: instance 382 | * @param req: usb requests 383 | * @retval status 384 | */ 385 | static uint8_t USBD_AUDIO_Setup(USBD_HandleTypeDef *pdev, 386 | USBD_SetupReqTypedef *req) 387 | { 388 | USBD_AUDIO_HandleTypeDef *haudio; 389 | uint16_t len; 390 | uint8_t *pbuf; 391 | uint16_t status_info = 0U; 392 | USBD_StatusTypeDef ret = USBD_OK; 393 | 394 | haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData; 395 | 396 | switch (req->bmRequest & USB_REQ_TYPE_MASK) 397 | { 398 | case USB_REQ_TYPE_CLASS: 399 | switch (req->bRequest) 400 | { 401 | case AUDIO_REQ_GET_CUR: 402 | AUDIO_REQ_GetCurrent(pdev, req); 403 | break; 404 | 405 | case AUDIO_REQ_SET_CUR: 406 | AUDIO_REQ_SetCurrent(pdev, req); 407 | break; 408 | 409 | default: 410 | USBD_CtlError(pdev, req); 411 | ret = USBD_FAIL; 412 | break; 413 | } 414 | break; 415 | 416 | case USB_REQ_TYPE_STANDARD: 417 | switch (req->bRequest) 418 | { 419 | case USB_REQ_GET_STATUS: 420 | if (pdev->dev_state == USBD_STATE_CONFIGURED) 421 | { 422 | (void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U); 423 | } 424 | else 425 | { 426 | USBD_CtlError(pdev, req); 427 | ret = USBD_FAIL; 428 | } 429 | break; 430 | 431 | case USB_REQ_GET_DESCRIPTOR: 432 | if ((req->wValue >> 8) == AUDIO_DESCRIPTOR_TYPE) 433 | { 434 | pbuf = USBD_AUDIO_CfgDesc + 18; 435 | len = MIN(USB_AUDIO_DESC_SIZ, req->wLength); 436 | 437 | (void)USBD_CtlSendData(pdev, pbuf, len); 438 | } 439 | break; 440 | 441 | case USB_REQ_GET_INTERFACE: 442 | if (pdev->dev_state == USBD_STATE_CONFIGURED) 443 | { 444 | (void)USBD_CtlSendData(pdev, (uint8_t *)&haudio->alt_setting, 1U); 445 | } 446 | else 447 | { 448 | USBD_CtlError(pdev, req); 449 | ret = USBD_FAIL; 450 | } 451 | break; 452 | 453 | case USB_REQ_SET_INTERFACE: 454 | if (pdev->dev_state == USBD_STATE_CONFIGURED) 455 | { 456 | if ((uint8_t)(req->wValue) <= USBD_MAX_NUM_INTERFACES) 457 | { 458 | haudio->alt_setting = (uint8_t)(req->wValue); 459 | } 460 | else 461 | { 462 | /* Call the error management function (command will be nacked */ 463 | USBD_CtlError(pdev, req); 464 | ret = USBD_FAIL; 465 | } 466 | } 467 | else 468 | { 469 | USBD_CtlError(pdev, req); 470 | ret = USBD_FAIL; 471 | } 472 | break; 473 | 474 | case USB_REQ_CLEAR_FEATURE: 475 | break; 476 | 477 | default: 478 | USBD_CtlError(pdev, req); 479 | ret = USBD_FAIL; 480 | break; 481 | } 482 | break; 483 | default: 484 | USBD_CtlError(pdev, req); 485 | ret = USBD_FAIL; 486 | break; 487 | } 488 | 489 | return (uint8_t)ret; 490 | } 491 | 492 | 493 | /** 494 | * @brief USBD_AUDIO_GetCfgDesc 495 | * return configuration descriptor 496 | * @param speed : current device speed 497 | * @param length : pointer data length 498 | * @retval pointer to descriptor buffer 499 | */ 500 | static uint8_t *USBD_AUDIO_GetCfgDesc(uint16_t *length) 501 | { 502 | *length = (uint16_t)sizeof(USBD_AUDIO_CfgDesc); 503 | 504 | return USBD_AUDIO_CfgDesc; 505 | } 506 | 507 | /** 508 | * @brief USBD_AUDIO_DataIn 509 | * handle data IN Stage 510 | * @param pdev: device instance 511 | * @param epnum: endpoint index 512 | * @retval status 513 | */ 514 | static uint8_t USBD_AUDIO_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum) 515 | { 516 | USBD_AUDIO_HandleTypeDef *haudio; 517 | uint8_t retval = USBD_OK; 518 | 519 | haudio = (USBD_AUDIO_HandleTypeDef*) pdev->pClassData; 520 | 521 | if (epnum == (AUDIO_IN_EP & 0x7F)) 522 | { 523 | haudio->in_buffer_half = !haudio->in_buffer_half; // also serves as init to 1 or 0 524 | uint16_t prev = (AUDIO_IN_PACKET / 2) * !haudio->in_buffer_half; // invert in_buffer_half again to get the previous value 525 | // the double inversion serves to get rid of possible malloc 526 | // artifacts in in_buffer_half, not initialized at the start 527 | 528 | ADC_to_MIC(); 529 | 530 | USBD_LL_FlushEP (pdev, AUDIO_IN_EP); 531 | USBD_LL_Transmit (pdev, AUDIO_IN_EP, (uint8_t*)(haudio->in_buffer + prev), AUDIO_IN_PACKET); 532 | } 533 | 534 | return (uint8_t)USBD_OK; 535 | } 536 | 537 | /** 538 | * @brief USBD_AUDIO_EP0_RxReady 539 | * handle EP0 Rx Ready event 540 | * @param pdev: device instance 541 | * @retval status 542 | */ 543 | static uint8_t USBD_AUDIO_EP0_RxReady(USBD_HandleTypeDef *pdev) 544 | { 545 | USBD_AUDIO_HandleTypeDef *haudio; 546 | haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData; 547 | 548 | if (haudio->control.cmd == AUDIO_REQ_SET_CUR) 549 | { 550 | /* In this driver, to simplify code, only SET_CUR request is managed */ 551 | 552 | if (haudio->control.unit == AUDIO_OUT_STREAMING_CTRL) 553 | { 554 | ((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->MuteCtl(haudio->control.data[0]); 555 | haudio->control.cmd = 0U; 556 | haudio->control.len = 0U; 557 | } 558 | } 559 | 560 | return (uint8_t)USBD_OK; 561 | } 562 | /** 563 | * @brief USBD_AUDIO_EP0_TxReady 564 | * handle EP0 TRx Ready event 565 | * @param pdev: device instance 566 | * @retval status 567 | */ 568 | static uint8_t USBD_AUDIO_EP0_TxReady(USBD_HandleTypeDef *pdev) 569 | { 570 | UNUSED(pdev); 571 | 572 | /* Only OUT control data are processed */ 573 | return (uint8_t)USBD_OK; 574 | } 575 | /** 576 | * @brief USBD_AUDIO_SOF 577 | * handle SOF event 578 | * @param pdev: device instance 579 | * @retval status 580 | */ 581 | static uint8_t USBD_AUDIO_SOF(USBD_HandleTypeDef *pdev) 582 | { 583 | UNUSED(pdev); 584 | 585 | return (uint8_t)USBD_OK; 586 | } 587 | 588 | /** 589 | * @brief USBD_AUDIO_SOF 590 | * handle SOF event 591 | * @param pdev: device instance 592 | * @retval status 593 | */ 594 | void USBD_AUDIO_Sync(USBD_HandleTypeDef *pdev, AUDIO_OffsetTypeDef offset) 595 | { 596 | USBD_AUDIO_HandleTypeDef *haudio; 597 | uint32_t BufferSize = AUDIO_TOTAL_BUF_SIZE / 2U; 598 | 599 | if (pdev->pClassData == NULL) 600 | { 601 | return; 602 | } 603 | 604 | haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData; 605 | 606 | haudio->offset = offset; 607 | 608 | if (haudio->rd_enable == 1U) 609 | { 610 | haudio->rd_ptr += (uint16_t)BufferSize; 611 | 612 | if (haudio->rd_ptr == AUDIO_TOTAL_BUF_SIZE) 613 | { 614 | /* roll back */ 615 | haudio->rd_ptr = 0U; 616 | } 617 | } 618 | 619 | if (haudio->rd_ptr > haudio->wr_ptr) 620 | { 621 | if ((haudio->rd_ptr - haudio->wr_ptr) < AUDIO_OUT_PACKET) 622 | { 623 | BufferSize += 4U; 624 | } 625 | else 626 | { 627 | if ((haudio->rd_ptr - haudio->wr_ptr) > (AUDIO_TOTAL_BUF_SIZE - AUDIO_OUT_PACKET)) 628 | { 629 | BufferSize -= 4U; 630 | } 631 | } 632 | } 633 | else 634 | { 635 | if ((haudio->wr_ptr - haudio->rd_ptr) < AUDIO_OUT_PACKET) 636 | { 637 | BufferSize -= 4U; 638 | } 639 | else 640 | { 641 | if ((haudio->wr_ptr - haudio->rd_ptr) > (AUDIO_TOTAL_BUF_SIZE - AUDIO_OUT_PACKET)) 642 | { 643 | BufferSize += 4U; 644 | } 645 | } 646 | } 647 | 648 | if (haudio->offset == AUDIO_OFFSET_FULL) 649 | { 650 | ((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->AudioCmd(&haudio->buffer[0], 651 | BufferSize, AUDIO_CMD_PLAY); 652 | haudio->offset = AUDIO_OFFSET_NONE; 653 | } 654 | } 655 | 656 | /** 657 | * @brief USBD_AUDIO_IsoINIncomplete 658 | * handle data ISO IN Incomplete event 659 | * @param pdev: device instance 660 | * @param epnum: endpoint index 661 | * @retval status 662 | */ 663 | static uint8_t USBD_AUDIO_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) 664 | { 665 | UNUSED(pdev); 666 | UNUSED(epnum); 667 | 668 | return (uint8_t)USBD_OK; 669 | } 670 | /** 671 | * @brief USBD_AUDIO_IsoOutIncomplete 672 | * handle data ISO OUT Incomplete event 673 | * @param pdev: device instance 674 | * @param epnum: endpoint index 675 | * @retval status 676 | */ 677 | static uint8_t USBD_AUDIO_IsoOutIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) 678 | { 679 | UNUSED(pdev); 680 | UNUSED(epnum); 681 | 682 | return (uint8_t)USBD_OK; 683 | } 684 | /** 685 | * @brief USBD_AUDIO_DataOut 686 | * handle data OUT Stage 687 | * @param pdev: device instance 688 | * @param epnum: endpoint index 689 | * @retval status 690 | */ 691 | static uint8_t USBD_AUDIO_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum) 692 | { 693 | uint16_t PacketSize; 694 | USBD_AUDIO_HandleTypeDef *haudio; 695 | 696 | haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData; 697 | 698 | if (epnum == AUDIO_OUT_EP) 699 | { 700 | /* Get received data packet length */ 701 | PacketSize = (uint16_t)USBD_LL_GetRxDataSize(pdev, epnum); 702 | 703 | /* Packet received Callback */ 704 | ((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->PeriodicTC(&haudio->buffer[haudio->wr_ptr], 705 | PacketSize, AUDIO_OUT_TC); 706 | 707 | /* Increment the Buffer pointer or roll it back when all buffers are full */ 708 | haudio->wr_ptr += PacketSize; 709 | 710 | if (haudio->wr_ptr == AUDIO_TOTAL_BUF_SIZE) 711 | { 712 | /* All buffers are full: roll back */ 713 | haudio->wr_ptr = 0U; 714 | 715 | if (haudio->offset == AUDIO_OFFSET_UNKNOWN) 716 | { 717 | ((USBD_AUDIO_ItfTypeDef *)pdev->pUserData)->AudioCmd(&haudio->buffer[0], 718 | AUDIO_TOTAL_BUF_SIZE / 2U, 719 | AUDIO_CMD_START); 720 | haudio->offset = AUDIO_OFFSET_NONE; 721 | } 722 | } 723 | 724 | if (haudio->rd_enable == 0U) 725 | { 726 | if (haudio->wr_ptr == (AUDIO_TOTAL_BUF_SIZE / 2U)) 727 | { 728 | haudio->rd_enable = 1U; 729 | } 730 | } 731 | 732 | /* Prepare Out endpoint to receive next audio packet */ 733 | (void)USBD_LL_PrepareReceive(pdev, AUDIO_OUT_EP, 734 | &haudio->buffer[haudio->wr_ptr], 735 | AUDIO_OUT_PACKET); 736 | } 737 | 738 | return (uint8_t)USBD_OK; 739 | } 740 | 741 | /** 742 | * @brief AUDIO_Req_GetCurrent 743 | * Handles the GET_CUR Audio control request. 744 | * @param pdev: instance 745 | * @param req: setup class request 746 | * @retval status 747 | */ 748 | static void AUDIO_REQ_GetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) 749 | { 750 | USBD_AUDIO_HandleTypeDef *haudio; 751 | haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData; 752 | 753 | (void)USBD_memset(haudio->control.data, 0, 64U); 754 | 755 | /* Send the current mute state */ 756 | (void)USBD_CtlSendData(pdev, haudio->control.data, req->wLength); 757 | } 758 | 759 | /** 760 | * @brief AUDIO_Req_SetCurrent 761 | * Handles the SET_CUR Audio control request. 762 | * @param pdev: instance 763 | * @param req: setup class request 764 | * @retval status 765 | */ 766 | static void AUDIO_REQ_SetCurrent(USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req) 767 | { 768 | USBD_AUDIO_HandleTypeDef *haudio; 769 | haudio = (USBD_AUDIO_HandleTypeDef *)pdev->pClassData; 770 | 771 | if (req->wLength != 0U) 772 | { 773 | /* Prepare the reception of the buffer over EP0 */ 774 | (void)USBD_CtlPrepareRx(pdev, haudio->control.data, req->wLength); 775 | 776 | haudio->control.cmd = AUDIO_REQ_SET_CUR; /* Set the request value */ 777 | haudio->control.len = (uint8_t)req->wLength; /* Set the request data length */ 778 | haudio->control.unit = HIBYTE(req->wIndex); /* Set the request target unit */ 779 | } 780 | } 781 | 782 | 783 | /** 784 | * @brief DeviceQualifierDescriptor 785 | * return Device Qualifier descriptor 786 | * @param length : pointer data length 787 | * @retval pointer to descriptor buffer 788 | */ 789 | static uint8_t *USBD_AUDIO_GetDeviceQualifierDesc(uint16_t *length) 790 | { 791 | *length = (uint16_t)sizeof(USBD_AUDIO_DeviceQualifierDesc); 792 | 793 | return USBD_AUDIO_DeviceQualifierDesc; 794 | } 795 | 796 | /** 797 | * @brief USBD_AUDIO_RegisterInterface 798 | * @param fops: Audio interface callback 799 | * @retval status 800 | */ 801 | uint8_t USBD_AUDIO_RegisterInterface(USBD_HandleTypeDef *pdev, 802 | USBD_AUDIO_ItfTypeDef *fops) 803 | { 804 | if (fops == NULL) 805 | { 806 | return (uint8_t)USBD_FAIL; 807 | } 808 | 809 | pdev->pUserData = fops; 810 | 811 | return (uint8_t)USBD_OK; 812 | } 813 | /** 814 | * @} 815 | */ 816 | 817 | 818 | /** 819 | * @} 820 | */ 821 | 822 | 823 | /** 824 | * @} 825 | */ 826 | 827 | /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 828 | --------------------------------------------------------------------------------