Files
sound-analyze/firmware/App/Src/audio_adc.c

169 lines
4.2 KiB
C

#include "audio_adc.h"
#include <string.h>
#include "stm32f1xx.h"
// Один непрерывный DMA-буфер: 2 * 512 = 1024 семпла
static audio_sample_t dma_buffer[2 * AUDIO_BUFFER_SIZE];
// Callback функция
static audio_buffer_ready_callback_t user_callback = NULL;
// Статистика (для отладки)
static volatile uint32_t buffer_count = 0;
static volatile uint32_t dma_half_transfer_count = 0;
static volatile uint32_t dma_full_transfer_count = 0;
// Private Function Prototypes
static void audio_gpio_init(void);
static void audio_timer_init(void);
static void audio_adc_hw_init(void);
static void audio_dma_init(void);
bool audio_adc_init(audio_buffer_ready_callback_t callback) {
if (callback == NULL) return false;
user_callback = callback;
audio_gpio_init();
audio_timer_init();
audio_adc_hw_init();
audio_dma_init();
return true;
}
void audio_adc_start(void) {
DMA1_Channel1->CCR |= DMA_CCR_EN;
ADC1->CR2 |= ADC_CR2_ADON;
TIM3->CR1 |= TIM_CR1_CEN;
}
void audio_adc_stop(void) {
TIM3->CR1 &= ~TIM_CR1_CEN;
ADC1->CR2 &= ~ADC_CR2_ADON;
DMA1_Channel1->CCR &= ~DMA_CCR_EN;
}
uint32_t audio_adc_get_buffer_count(void) {
return buffer_count;
}
static void audio_gpio_init(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// PA1 analog
GPIOA->CRL &= ~(0xF << 4);
}
static void audio_timer_init(void) {
// Включаем тактирование Timer3
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// Настраиваем TIM3 для 22050 Hz
TIM3->PSC = AUDIO_TIMER_PRESCALER;
TIM3->ARR = AUDIO_TIMER_PERIOD;
// TRGO = Update event
TIM3->CR2 &= ~TIM_CR2_MMS;
TIM3->CR2 |= TIM_CR2_MMS_1;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->EGR |= TIM_EGR_UG;
TIM3->CNT = 0;
}
static void audio_adc_hw_init(void) {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
RCC->CFGR &= ~RCC_CFGR_ADCPRE;
RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6;
ADC1->CR2 = 0;
ADC1->CR1 = 0;
ADC1->CR1 &= ~ADC_CR1_SCAN;
ADC1->CR2 &= ~ADC_CR2_CONT;
// EXTSEL = 011 (Timer2 TRGO), EXTTRIG enable
ADC1->CR2 &= ~ADC_CR2_EXTSEL;
ADC1->CR2 |= (0x4U << 17); // TIM3_TRGO
ADC1->CR2 |= ADC_CR2_EXTTRIG;
ADC1->CR2 |= ADC_CR2_DMA;
ADC1->CR2 &= ~ADC_CR2_ALIGN;
ADC1->SQR1 &= ~ADC_SQR1_L;
ADC1->SQR3 &= ~ADC_SQR3_SQ1;
ADC1->SQR3 |= (AUDIO_ADC_CHANNEL << ADC_SQR3_SQ1_Pos);
ADC1->SMPR2 &= ~ADC_SMPR2_SMP1;
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0; // 7.5 cycles
// calibration
ADC1->CR2 |= ADC_CR2_ADON;
for (volatile int i = 0; i < 1000; i++) {}
ADC1->CR2 |= ADC_CR2_CAL;
while (ADC1->CR2 & ADC_CR2_CAL) {}
ADC1->CR2 &= ~ADC_CR2_ADON;
}
static void audio_dma_init(void) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1_Channel1->CCR &= ~DMA_CCR_EN;
while (DMA1_Channel1->CCR & DMA_CCR_EN) {}
// ADC1 DR -> RAM
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
// ВАЖНО: CMAR указывает на непрерывный буфер 1024 samples
DMA1_Channel1->CMAR = (uint32_t)dma_buffer;
// ВАЖНО: 2 * 512 = 1024 samples
DMA1_Channel1->CNDTR = 2 * AUDIO_BUFFER_SIZE;
uint32_t ccr = 0;
ccr |= DMA_CCR_MINC;
ccr |= DMA_CCR_CIRC;
ccr |= DMA_CCR_HTIE;
ccr |= DMA_CCR_TCIE;
ccr |= DMA_CCR_PL_1; // high
ccr |= DMA_CCR_MSIZE_0; // 16-bit
ccr |= DMA_CCR_PSIZE_0; // 16-bit
DMA1_Channel1->CCR = ccr;
NVIC_SetPriority(DMA1_Channel1_IRQn, 6);
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
void DMA1_Channel1_IRQHandler(void) {
uint32_t isr = DMA1->ISR;
if (isr & DMA_ISR_HTIF1) {
DMA1->IFCR = DMA_IFCR_CHTIF1;
dma_half_transfer_count++;
// первая половина: [0 .. 511]
if (user_callback) { user_callback(&dma_buffer[0], AUDIO_BUFFER_SIZE); }
buffer_count++;
}
if (isr & DMA_ISR_TCIF1) {
DMA1->IFCR = DMA_IFCR_CTCIF1;
dma_full_transfer_count++;
// вторая половина: [512 .. 1023]
if (user_callback) {
user_callback(&dma_buffer[AUDIO_BUFFER_SIZE], AUDIO_BUFFER_SIZE);
}
buffer_count++;
}
if (isr & DMA_ISR_TEIF1) {
DMA1->IFCR = DMA_IFCR_CTEIF1;
// TODO: error handling
}
}