aboutsummaryrefslogtreecommitdiffstats
path: root/src/glutt-o-logique/audio_in.c
diff options
context:
space:
mode:
authorMatthias P. Braendli <matthias.braendli@mpb.li>2019-04-11 22:53:00 +0200
committerMatthias P. Braendli <matthias.braendli@mpb.li>2019-04-11 22:56:43 +0200
commit0ba699511c136e0215fd2f75e2800be920221497 (patch)
tree93ada6042e058a9d0dcf074246b6c58fb282cdf7 /src/glutt-o-logique/audio_in.c
parent7c7cd71c56808610be6af41dbeb09637026414bb (diff)
downloadglutte-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.c118
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;
}