kopia lustrzana https://github.com/skuep/AIOC
Basic audio output working
rodzic
f5e1d8ca73
commit
0da0b9c46b
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
|
|
@ -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) */ \
|
||||
|
|
Ładowanie…
Reference in New Issue