diff --git a/stm32/aioc-fw/Inc/tusb_config.h b/stm32/aioc-fw/Inc/tusb_config.h index 635d07d..f6058b1 100644 --- a/stm32/aioc-fw/Inc/tusb_config.h +++ b/stm32/aioc-fw/Inc/tusb_config.h @@ -45,7 +45,7 @@ #endif #ifndef MAX_EP_COUNT -#define MAX_EP_COUNT 6 +#define MAX_EP_COUNT 8 #endif //-------------------------------------------------------------------- @@ -113,6 +113,8 @@ #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 1 +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 1 #define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_IO_DESC_LEN #define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 @@ -121,9 +123,9 @@ #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX 1 #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EP_SZ_OUT + CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ 2*CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN + CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 2*CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX #define CFG_TUD_AUDIO_EP_SZ_IN (48) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channel #define CFG_TUD_AUDIO_EP_SZ_OUT (48) * CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE * CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX // 48 Samples (48 kHz) x 2 Bytes/Sample x 1 Channel diff --git a/stm32/aioc-fw/Src/usb_audio.c b/stm32/aioc-fw/Src/usb_audio.c index 467b8b0..bff85e8 100644 --- a/stm32/aioc-fw/Src/usb_audio.c +++ b/stm32/aioc-fw/Src/usb_audio.c @@ -1,5 +1,6 @@ #include "usb_audio.h" #include "tusb.h" +#include "stm32f3xx_hal.h" #ifndef AUDIO_SAMPLE_RATE #define AUDIO_SAMPLE_RATE 48000 @@ -267,6 +268,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * return false; // Yet not implemented } +#if 0 bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting) { (void) rhport; @@ -279,6 +281,7 @@ bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, u return true; } + bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting) { (void) rhport; @@ -294,16 +297,202 @@ bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uin return true; } +#endif + +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + (void) p_request; + + NVIC_EnableIRQ(TIM3_IRQn); + NVIC_EnableIRQ(ADC1_2_IRQn); + + return true; +} + bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) { (void) rhport; (void) p_request; - startVal = 0; + NVIC_DisableIRQ(TIM3_IRQn); + NVIC_DisableIRQ(ADC1_2_IRQn); return true; } +void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) +{ + /* Configure parameters for feedback endpoint */ + feedback_param->frequency.mclk_freq = 2 * HAL_RCC_GetPCLK1Freq(); + feedback_param->sample_freq = AUDIO_SAMPLE_RATE; + feedback_param->method = AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT; +} + +TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) +{ + static uint32_t prev_cycles = 0; + uint32_t this_cycles = TIM2->CNT; + + /* Calculate number of master clock cycles between now and last call */ + uint32_t diff_cycles = (uint32_t) (((uint64_t) this_cycles - prev_cycles) & 0xFFFFFFFFUL); + + /* Notify the USB audio feedback endpoint */ + tud_audio_feedback_update(0, diff_cycles); + + /* Prepare for next time */ + prev_cycles = this_cycles; +} + +void ADC1_2_IRQHandler (void) +{ + if (ADC2->ISR & ADC_ISR_EOS) { + ADC2->ISR = ADC_ISR_EOS; + uint16_t value = ADC2->DR; + int16_t a = ((int32_t) value - 32768) & 0xFFFFU; + tud_audio_write (&a, sizeof(value)); + + //uint16_t value = sine[startVal]; + //tud_audio_write (&value, sizeof(value)); + //startVal = startVal == (sizeof(sine)/sizeof(*sine)-1) ? 0 : startVal + 1; + + //uint16_t value = startVal++; + //tud_audio_write(&value, sizeof(value)); + } +} + +void TIM3_IRQHandler(void) +{ + if (TIM3->SR & TIM_SR_UIF) { + TIM3->SR = (uint32_t) ~TIM_SR_UIF; + + uint16_t items = tud_audio_available() / 2; + int16_t sample = 0x0000; + if (items > 0) { + /* Grab a sample from usb */ + tud_audio_read(&sample, sizeof(sample)); + } + + int16_t a = ((int32_t) sample + 32768) & 0xFFFFU; + + /* Load DAC holding register with sample */ + DAC1->DHR12L1 = a; + } +} + +static void GPIO_Init(void) +{ + __HAL_RCC_GPIOB_CLK_ENABLE(); + + GPIO_InitTypeDef ADCInGpio; + ADCInGpio.Pin = GPIO_PIN_2; + ADCInGpio.Mode = GPIO_MODE_ANALOG; + ADCInGpio.Pull = GPIO_NOPULL; + ADCInGpio.Speed = GPIO_SPEED_FREQ_LOW; + ADCInGpio.Alternate = 0; + HAL_GPIO_Init(GPIOB, &ADCInGpio); + + GPIO_InitTypeDef SamplerateGpio; + SamplerateGpio.Pin = GPIO_PIN_0; + SamplerateGpio.Mode = GPIO_MODE_AF_PP; + SamplerateGpio.Pull = GPIO_NOPULL; + SamplerateGpio.Speed = GPIO_SPEED_FREQ_HIGH; + SamplerateGpio.Alternate = GPIO_AF2_TIM3; + HAL_GPIO_Init(GPIOB, &SamplerateGpio); + + GPIO_InitTypeDef DACOutGpio; + DACOutGpio.Pin = GPIO_PIN_4; + DACOutGpio.Mode = GPIO_MODE_ANALOG; + DACOutGpio.Pull = GPIO_NOPULL; + DACOutGpio.Speed = GPIO_SPEED_FREQ_LOW; + DACOutGpio.Alternate = 0; + HAL_GPIO_Init(GPIOA, &DACOutGpio); +} + +static void Timer_Init(void) +{ + __HAL_RCC_TIM3_CLK_ENABLE(); + /* TODO: Use TIM6? */ + /* TIM3_TRGO triggers ADC2 */ + TIM3->CR1 = TIM_CLOCKDIVISION_DIV1 | TIM_COUNTERMODE_UP | TIM_AUTORELOAD_PRELOAD_ENABLE; + TIM3->CR2 = TIM_TRGO_UPDATE; + TIM3->PSC = 0; + TIM3->ARR = (2 * HAL_RCC_GetPCLK1Freq() / AUDIO_SAMPLE_RATE) - 1; + TIM3->EGR = TIM_EGR_UG; +#if 1 /* Output sample rate on compare channel 3 */ + TIM3->CCMR2 = TIM_OCMODE_PWM1 | TIM_CCMR2_OC3PE; + TIM3->CCER = (0 << TIM_CCER_CC3P_Pos) | TIM_CCER_CC3E; + TIM3->CCR3 = 500; +#endif + TIM3->DIER = TIM_DIER_UIE; + TIM3->CR1 |= TIM_CR1_CEN; + + + + __HAL_RCC_TIM2_CLK_ENABLE(); + + /* TIM2 generates a timebase for USB OUT feedback endpoint */ + TIM2->CR1 = TIM_CLOCKDIVISION_DIV1 | TIM_COUNTERMODE_UP | TIM_AUTORELOAD_PRELOAD_ENABLE; + TIM2->PSC = 0; + TIM2->ARR = 0xFFFFFFFFUL; + TIM2->EGR = TIM_EGR_UG; + TIM2->CR1 |= TIM_CR1_CEN; + +} + +static void ADC_Init(void) +{ + __HAL_RCC_ADC2_CLK_ENABLE(); + + ADC2->CR = 0x00 << ADC_CR_ADVREGEN_Pos; + ADC2->CR = 0x01 << ADC_CR_ADVREGEN_Pos; + + for (uint32_t i=0; i<200; i++) { + asm volatile ("nop"); + } + + /* Select AHB clock */ + ADC12_COMMON->CCR = (0x1 << ADC12_CCR_CKMODE_Pos) | (0x00 << ADC12_CCR_MULTI_Pos); + + ADC2->CR |= ADC_CR_ADCAL; + + while (ADC2->CR & ADC_CR_ADCAL) + ; + + ADC2->CR |= ADC_CR_ADEN; + + /* Wait for ADC to be ready */ + while (!(ADC2->ISR & ADC_ISR_ADRDY)) + ; + + /* External Trigger on TIM3_TRGO, left aligned data with 12 bit resolution */ + ADC2->CFGR = (0x01 << ADC_CFGR_EXTEN_Pos) | (0x04 << ADC_CFGR_EXTSEL_Pos) | (ADC_CFGR_ALIGN) | (0x00 << ADC_CFGR_RES_Pos); + + /* Maximum sample time of 601.5 cycles for channel 12. */ + ADC2->SMPR2 = 0x7 << ADC_SMPR2_SMP12_Pos; + + /* Sample only channel 12 in a regular sequence */ + ADC2->SQR1 = (12 << ADC_SQR1_SQ1_Pos) | (0 << ADC_SQR1_L_Pos); + + /* Enable Interrupt Request */ + ADC2->IER = ADC_IER_EOSIE; + + /* Start ADC */ + ADC2->CR |= ADC_CR_ADSTART; + + +} + +void DAC_Init(void) +{ + __HAL_RCC_DAC1_CLK_ENABLE(); + + /* TSEL1 == TIM3 trigger */ + __HAL_REMAPTRIGGER_ENABLE(HAL_REMAPTRIGGER_DAC1_TRIG); + + DAC->CR = (0x1 << DAC_CR_TSEL1_Pos) | DAC_CR_TEN1 | DAC_CR_EN1; +} + void USB_AudioInit(void) { sampFreq = AUDIO_SAMPLE_RATE; @@ -314,4 +503,9 @@ void USB_AudioInit(void) sampleFreqRng.subrange[0].bMax = AUDIO_SAMPLE_RATE; sampleFreqRng.subrange[0].bRes = 0; + GPIO_Init(); + Timer_Init(); + ADC_Init(); + DAC_Init(); + } diff --git a/stm32/aioc-fw/Src/usb_descriptors.h b/stm32/aioc-fw/Src/usb_descriptors.h index 8fd9cf4..29704a8 100644 --- a/stm32/aioc-fw/Src/usb_descriptors.h +++ b/stm32/aioc-fw/Src/usb_descriptors.h @@ -14,10 +14,10 @@ enum USB_DESCRIPTORS_ITF { /* Endpoints */ #define EPNUM_AUDIO_IN 0x81 #define EPNUM_AUDIO_OUT 0x02 -#define EPNUM_AUDIO_FB 0x83 -#define EPNUM_CDC_0_OUT 0x04 -#define EPNUM_CDC_0_IN 0x84 -#define EPNUM_CDC_0_NOTIF 0x85 +#define EPNUM_AUDIO_FB 0x82 +#define EPNUM_CDC_0_OUT 0x03 +#define EPNUM_CDC_0_IN 0x83 +#define EPNUM_CDC_0_NOTIF 0x84 /* Custom Audio Descriptor. * Courtesy of https://github.com/hathach/tinyusb/issues/1249#issuecomment-1148727765 */ @@ -101,7 +101,7 @@ enum USB_DESCRIPTORS_ITF { /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)+2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO_DESC_CS_AS_INT(AUDIO_CTRL_ID_MIC_OUTPUT_STREAM, AUDIO_CTRL_NONE, AUDIO_FORMAT_TYPE_I, AUDIO_DATA_FORMAT_TYPE_I_PCM, AUDIO_NUM_INCHANNELS, AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(AUDIO_CTRL_ID_MIC_OUTPUT_STREAM, AUDIO_CTRL_NONE, AUDIO_FORMAT_TYPE_I, AUDIO_DATA_FORMAT_TYPE_I_PCM, AUDIO_NUM_INCHANNELS, AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \