Basic audio output working

v1.1
Simon Kueppers 2022-10-31 14:07:12 +01:00
rodzic f5e1d8ca73
commit 0da0b9c46b
3 zmienionych plików z 205 dodań i 9 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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();
}

Wyświetl plik

@ -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) */ \