├── 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 |
--------------------------------------------------------------------------------