diff --git a/tests/platform/gimmi_ridimmi.c b/tests/platform/gimmi_ridimmi.c new file mode 100644 index 00000000..b1782199 --- /dev/null +++ b/tests/platform/gimmi_ridimmi.c @@ -0,0 +1,210 @@ +/*************************************************************************** + * Copyright (C) 2020 by Federico Amedeo Izzo IU2NUO, * + * Niccolò Izzo IU2KIN, * + * Frederik Saraci IU2NRO, * + * Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Uncomment this directive to sample audio coming from RTX stage instead of the + * one from microphone. + */ +// #define SAMPLE_RTX_AUDIO + +static const size_t numSamples = 45*1024; // 80kB + +void recordMic(uint16_t *buffer) +{ + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; + RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; + __DSB(); + + /* + * TIM2 for conversion triggering via TIM2_TRGO, that is counter reload. + * AP1 frequency is 42MHz but timer runs at 84MHz, configure for 8kHz interrupt rate. + */ + TIM2->PSC = 83; /* Tick rate 1MHz */ + TIM2->ARR = 124; /* Overflow rate 8kHz */ + TIM2->CNT = 0; + TIM2->EGR = TIM_EGR_UG; + TIM2->CR2 = TIM_CR2_MMS_1; + TIM2->CR1 = TIM_CR1_CEN; + + /* DMA2 Stream 0 configuration: + * - channel 0: ADC1 + * - low priority + * - half-word transfer, both memory and peripheral + * - increment memory + * - peripheral-to-memory transfer + * - no interrupts + */ + DMA2_Stream0->PAR = ((uint32_t) &(ADC1->DR)); + DMA2_Stream0->M0AR = ((uint32_t) buffer); + DMA2_Stream0->NDTR = numSamples; + DMA2_Stream0->CR = DMA_SxCR_MSIZE_0 /* Memory size: 16 bit */ + | DMA_SxCR_PSIZE_0 /* Peripheral size: 16 bit */ + | DMA_SxCR_PL_0 /* Medium priority */ + | DMA_SxCR_MINC /* Increment memory */ + | DMA_SxCR_EN; + + /* + * ADC clock is APB2 frequency divided by 8, giving 10.5MHz. + * A conversion takes 12 cycles. + */ + ADC->CCR |= ADC_CCR_ADCPRE; + ADC1->SMPR2 = ADC_SMPR2_SMP0 + | ADC_SMPR2_SMP1 + | ADC_SMPR2_SMP3 + | ADC_SMPR2_SMP8; + + ADC1->SQR1 = 0; /* One channel to be converted */ + + #ifdef SAMPLE_RTX_AUDIO + ADC1->SQR3 = 13; /* CH13, audio from RTX on PC13 */ + #else + ADC1->SQR3 = 3; /* CH3, vox level on PA3 */ + #endif + + /* + * No overrun interrupt, 12-bit resolution, no analog watchdog, no + * discontinuous mode, enable scan mode, no end of conversion interrupts, + * enable continuous conversion (free-running). + */ + ADC1->CR1 |= ADC_CR1_DISCEN; + ADC1->CR2 |= ADC_CR2_EXTEN_0 /* Trigger on rising edge */ + | ADC_CR2_EXTSEL_1 + | ADC_CR2_EXTSEL_2 /* 0b0110 TIM2_TRGO trig. source */ + | ADC_CR2_DDS /* Enable DMA data transfer */ + | ADC_CR2_DMA + | ADC_CR2_ALIGN + | ADC_CR2_ADON; /* Enable ADC */ +} + +void playbackSpk(uint16_t *buffer) +{ + /* + * Enable peripherals + */ + RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN + | RCC_APB1ENR_TIM7EN; + __DSB(); + + /* + * PWM for tone generator time base: 328kHz + */ + TIM3->ARR = 0xFF; + TIM3->PSC = 0; + TIM3->CCMR2 = TIM_CCMR2_OC3M_2 + | TIM_CCMR2_OC3M_1 + | TIM_CCMR2_OC3PE; + TIM3->CR1 |= TIM_CR1_ARPE; + + TIM3->CCER |= TIM_CCER_CC3E; + TIM3->CR1 |= TIM_CR1_CEN; + + /* + * Timebase for 48kHz sample rate + */ + TIM7->CNT = 0; + TIM7->PSC = 0; + TIM7->ARR = 1749;//(84000000/48000) - 1; + TIM7->EGR = TIM_EGR_UG; + TIM7->DIER = TIM_DIER_UDE; + TIM7->CR1 = TIM_CR1_CEN; + + /* + * DMA stream for sample transfer + */ + DMA1_Stream2->NDTR = numSamples; + DMA1_Stream2->PAR = ((uint32_t) &(TIM3->CCR3)); + DMA1_Stream2->M0AR = ((uint32_t) buffer); + DMA1_Stream2->CR = DMA_SxCR_CHSEL_0 /* Channel 1 */ + | DMA_SxCR_PL /* Very high priority */ + | DMA_SxCR_MSIZE_0 + | DMA_SxCR_PSIZE_0 + | DMA_SxCR_MINC /* Increment source pointer */ + | DMA_SxCR_CIRC /* Circular mode */ + | DMA_SxCR_DIR_0 /* Memory to peripheral */ + | DMA_SxCR_EN; /* Start transfer */ + + + /* Turn on audio amplifier and unmute speaker */ + gpio_setMode(AUDIO_AMP_EN, OUTPUT); + gpio_setMode(SPK_MUTE, OUTPUT); + + gpio_setPin(AUDIO_AMP_EN); + delayMs(10); + gpio_clearPin(SPK_MUTE); +} + +int main() +{ +// platform_init(); + + uint16_t *sampleBuf = ((uint16_t *) malloc(numSamples * sizeof(uint16_t))); + + gpio_setMode(GREEN_LED, OUTPUT); + gpio_setMode(RED_LED, OUTPUT); + gpio_setMode(MIC_PWR, OUTPUT); + gpio_setPin(MIC_PWR); + + #ifdef SAMPLE_RTX_AUDIO + gpio_setMode(GPIOC, 13, INPUT_ANALOG); + #else + gpio_setMode(AIN_MIC, INPUT_ANALOG); + #endif + + /* Enable pull-up resistor on PA3 (AIN_MIC) + GPIOA->PUPDR |= 1 << 6; */ + + /* AF2 is TIM3 channel 3 */ + gpio_setMode(BEEP_OUT, ALTERNATE); + gpio_setAlternateFunction(BEEP_OUT, 2); + + delayMs(3000); + + recordMic(sampleBuf); + + while((DMA2_Stream0->CR & DMA_SxCR_EN) == 1) + { + gpio_togglePin(GREEN_LED); + delayMs(250); + } + + gpio_clearPin(GREEN_LED); + gpio_setPin(RED_LED); + + delayMs(2000); + + playbackSpk(sampleBuf); + + while(1) ; + + return 0; +}