diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-04-11 22:53:00 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2019-04-11 22:56:43 +0200 |
commit | 0ba699511c136e0215fd2f75e2800be920221497 (patch) | |
tree | 93ada6042e058a9d0dcf074246b6c58fb282cdf7 /src/glutt-o-logique/audio_in.c | |
parent | 7c7cd71c56808610be6af41dbeb09637026414bb (diff) | |
download | glutte-o-matic-0ba699511c136e0215fd2f75e2800be920221497.tar.gz glutte-o-matic-0ba699511c136e0215fd2f75e2800be920221497.tar.bz2 glutte-o-matic-0ba699511c136e0215fd2f75e2800be920221497.zip |
Rework tone detector
- Send buffer pointers from ISR to userspace
- Use ADC interrupt to fetch data, not TIM6
- Increase size of buffer and do double-buffering
- Implement DTMF detectors
- Compare relative results instead of using absolute thresholds
- Add an IIR averaging filter on the results
Diffstat (limited to 'src/glutt-o-logique/audio_in.c')
-rw-r--r-- | src/glutt-o-logique/audio_in.c | 118 |
1 files changed, 75 insertions, 43 deletions
diff --git a/src/glutt-o-logique/audio_in.c b/src/glutt-o-logique/audio_in.c index 743c79b..a820b5f 100644 --- a/src/glutt-o-logique/audio_in.c +++ b/src/glutt-o-logique/audio_in.c @@ -26,61 +26,74 @@ #include "stm32f4xx_gpio.h" #include "stm32f4xx_adc.h" +#include "GPIO/usart.h" #include "Core/common.h" #include "Audio/audio_in.h" #include "queue.h" // APB1 prescaler = 4, see bsp/system_stm32f4xx.c #define APB1_FREQ (168000000ul / 4) -#define ADC2_SAMPLE_FREQ 16000 -#define ADC2_CHANNEL_AUDIO ADC_Channel_14 +#define ADC2_CHANNEL_AUDIO ADC_Channel_9 // see doc/pio.txt for allocation #define PINS_ADC2 /* PB1 on ADC2 IN9 */ (GPIO_Pin_1) -#warning "TODO: initialise ADC2 and use it for NF input" - -// The TIM6 ISR reads from ADC2 and writes into this buffer -static int16_t adc2_values[AUDIO_IN_BUF_LEN]; +// The TIM6 ISR reads from ADC2 and writes into these double buffers +static int16_t adc2_values[2][AUDIO_IN_BUF_LEN]; +static int adc2_current_buffer = 0; // which buffer is being written into static int adc2_values_end = 0; +static int32_t adc2_lost_samples = 0; -// ADC2 data from interrupt to userspace goes through the queue +// ADC2 data from interrupt to userspace. The queue contains the buffer index static QueueHandle_t adc2_values_queue; /* ISR for Timer6 and DAC1&2 underrun */ -void TIM6_DAC_IRQHandler(void) +void TIM6_DAC_IRQHandler(void); + +void TIM6_DAC_IRQHandler() { if (TIM_GetITStatus(TIM6, TIM_IT_Update)) { - if (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == SET) { - uint16_t value = ADC_GetConversionValue(ADC2); - /* input range: 0 to 65535 - * output range: -32768 to 32767 */ - adc2_values[adc2_values_end++] = (int32_t)value - 32768; - if (adc2_values_end == AUDIO_IN_BUF_LEN) { - int success = xQueueSendToBackFromISR( - adc2_values_queue, - adc2_values, - NULL); - - adc2_values_end = 0; - - if (success == pdFALSE) { - trigger_fault(FAULT_SOURCE_ADC2); - } - } - } - else { -#warning "handle fault" - } - ADC_SoftwareStartConv(ADC2); - TIM_ClearITPendingBit(TIM6, TIM_IT_Update); } + else { + usart_debug("%x\r\n", TIM6->SR); + trigger_fault(FAULT_SOURCE_TIM6_ISR); + } +} + +void ADC_IRQHandler(void); +void ADC_IRQHandler() +{ + if (ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC) == SET) { + uint16_t value = ADC_GetConversionValue(ADC2); + + ADC_ClearITPendingBit(ADC2, ADC_IT_EOC); + + /* input range: 0 to 2^12 + * output range: -32768 to 32767 */ + adc2_values[adc2_current_buffer][adc2_values_end++] = (int32_t)value - (1 << 11); + if (adc2_values_end == AUDIO_IN_BUF_LEN) { + int success = xQueueSendToBackFromISR( + adc2_values_queue, + &adc2_current_buffer, + NULL); + + adc2_values_end = 0; + adc2_current_buffer = (adc2_current_buffer + 1) % 2; + + if (success == pdFALSE) { + adc2_lost_samples += AUDIO_IN_BUF_LEN; + } + } + } + else { + adc2_lost_samples++; + } } // Timer6 is used for ADC2 sampling -static void enable_timer6(void) +static void enable_timer6() { /* TIM6 Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); @@ -88,26 +101,27 @@ static void enable_timer6(void) /* Time base configuration */ TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); - TIM_TimeBaseStructure.TIM_Period = (int)(APB1_FREQ/ADC2_SAMPLE_FREQ); - TIM_TimeBaseStructure.TIM_Prescaler = 0; - TIM_TimeBaseStructure.TIM_ClockDivision = 0; + TIM_TimeBaseStructure.TIM_Period = (int)(APB1_FREQ/AUDIO_IN_RATE); + TIM_TimeBaseStructure.TIM_Prescaler = 1; + TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn; - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); + NVIC_SetPriority(TIM6_DAC_IRQn, 5); - TIM_Cmd(TIM6, ENABLE); - ADC_SoftwareStartConv(ADC2); TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); + ADC_SoftwareStartConv(ADC2); + TIM_Cmd(TIM6, ENABLE); } -void audio_in_initialize(int rate) +void audio_in_initialize() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); @@ -131,18 +145,36 @@ void audio_in_initialize(int rate) ADC_InitStruct.ADC_NbrOfConversion = 1; ADC_Init(ADC2, &ADC_InitStruct); + ADC_RegularChannelConfig(ADC2, ADC2_CHANNEL_AUDIO, /*rank*/ 1, ADC_SampleTime_15Cycles); + ADC_ClearITPendingBit(ADC2, ADC_IT_EOC); + ADC_ITConfig(ADC2, ADC_IT_EOC, ENABLE); + + NVIC_InitTypeDef NVIC_InitStructure; + NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn; + NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 7; + NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; + NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; + NVIC_Init(&NVIC_InitStructure); + NVIC_SetPriority(ADC_IRQn, 7); + ADC_Cmd(ADC2, ENABLE); - adc2_values_queue = xQueueCreate(4, AUDIO_IN_BUF_LEN); + + adc2_values_queue = xQueueCreate(4, sizeof(adc2_current_buffer)); if (adc2_values_queue == 0) { - while(1); /* fatal error */ + trigger_fault(FAULT_SOURCE_ADC2_QUEUE); } enable_timer6(); } -void audio_in_get_buffer(int16_t *buffer /*of length AUDIO_IN_BUF_LEN*/ ) +int32_t audio_in_get_buffer(int16_t **buffer /*of length AUDIO_IN_BUF_LEN*/ ) { - while (!xQueueReceive(adc2_values_queue, buffer, portMAX_DELAY)) {} + int buf_ix = 0; + while (!xQueueReceive(adc2_values_queue, &buf_ix, portMAX_DELAY)) {} + + *buffer = adc2_values[buf_ix]; + + return adc2_lost_samples; } |