169 lines
4.2 KiB
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
|
|
}
|
|
}
|