#include "audio_adc.h" #include #include "stm32f1xx.h" // Двойные буферы для DMA static audio_sample_t audio_buffer_0[AUDIO_BUFFER_SIZE] = {0}; static audio_sample_t audio_buffer_1[AUDIO_BUFFER_SIZE] = {0}; // Указатель на активный буфер для обработки static volatile uint8_t active_buffer_index = 0; // 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) { // Запускаем DMA DMA1_Channel1->CCR |= DMA_CCR_EN; // Запускаем ADC ADC1->CR2 |= ADC_CR2_ADON; // Запускаем Timer2, начинаем генерировать TRGO события TIM2->CR1 |= TIM_CR1_CEN; } void audio_adc_stop(void) { // Останавливаем Timer TIM2->CR1 &= ~TIM_CR1_CEN; // Останавливаем ADC ADC1->CR2 &= ~ADC_CR2_ADON; // Останавливаем DMA DMA1_Channel1->CCR &= ~DMA_CCR_EN; } uint32_t audio_adc_get_buffer_count(void) { return buffer_count; } // Private Functions static void audio_gpio_init(void) { // Включаем тактирование GPIOA RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // PA1 как Analog Input (CNF=00, MODE=00) GPIOA->CRL &= ~(GPIO_CRL_CNF1 | GPIO_CRL_MODE1); // По умолчанию уже 0000, но явно устанавливаем GPIOA->CRL &= ~(0xF << 4); // Биты [7:4] для Pin 1 } static void audio_timer_init(void) { // Включаем тактирование Timer2 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Настраиваем Timer2 для генерации TRGO на частоте 22050 Hz TIM2->PSC = AUDIO_TIMER_PRESCALER; TIM2->ARR = AUDIO_TIMER_PERIOD; // Master Mode Selection: Update event as TRGO // MMS[2:0] = 010 (Update) TIM2->CR2 &= ~TIM_CR2_MMS; TIM2->CR2 |= TIM_CR2_MMS_1; // 010 // Auto-reload preload enable TIM2->CR1 |= TIM_CR1_ARPE; // Генерируем Update event для загрузки PSC/ARR TIM2->EGR |= TIM_EGR_UG; } static void audio_adc_hw_init(void) { // Включаем тактирование ADC1 RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; // ADC Clock = PCLK2 / 6 = 72MHz / 6 = 12MHz (макс 14MHz для STM32F1) RCC->CFGR &= ~RCC_CFGR_ADCPRE; RCC->CFGR |= RCC_CFGR_ADCPRE_DIV6; // Сброс ADC1 ADC1->CR2 = 0; ADC1->CR1 = 0; // Конфигурация ADC1 // Scan mode disabled (один канал) ADC1->CR1 &= ~ADC_CR1_SCAN; // Continuous mode disabled (будет триггериться Timer2) ADC1->CR2 &= ~ADC_CR2_CONT; // External trigger: Timer2 TRGO // EXTSEL[2:0] = 011 (Timer2 TRGO для ADC1) ADC1->CR2 &= ~ADC_CR2_EXTSEL; ADC1->CR2 |= ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_1; // 011 // External trigger enable for regular channels ADC1->CR2 |= ADC_CR2_EXTTRIG; // 5. DMA mode enable ADC1->CR2 |= ADC_CR2_DMA; // Data alignment: right aligned ADC1->CR2 &= ~ADC_CR2_ALIGN; // Настройка канала // Regular sequence length = 1 (только один канал) ADC1->SQR1 &= ~ADC_SQR1_L; // First conversion in regular sequence: Channel 1 (PA1) ADC1->SQR3 &= ~ADC_SQR3_SQ1; ADC1->SQR3 |= (AUDIO_ADC_CHANNEL << ADC_SQR3_SQ1_Pos); // Sample time для Channel 1: 7.5 cycles (минимум для 12MHz ADC) // SMPR2[5:3] для CH1 = 001 (7.5 cycles) ADC1->SMPR2 &= ~ADC_SMPR2_SMP1; ADC1->SMPR2 |= ADC_SMPR2_SMP1_0; // 001 // Калибровка ADC // Включаем ADC ADC1->CR2 |= ADC_CR2_ADON; // Ждем stabilization time (1 мкс) for (volatile int i = 0; i < 1000; i++); // Запускаем калибровку ADC1->CR2 |= ADC_CR2_CAL; // Ждем завершения калибровки while (ADC1->CR2 & ADC_CR2_CAL); // Выключаем ADC (для запуска использовать audio_adc_start) ADC1->CR2 &= ~ADC_CR2_ADON; } static void audio_dma_init(void) { // Включаем тактирование DMA1 RCC->AHBENR |= RCC_AHBENR_DMA1EN; // Отключаем DMA1 Channel1 перед конфигурацией DMA1_Channel1->CCR &= ~DMA_CCR_EN; // Ждем отключения while (DMA1_Channel1->CCR & DMA_CCR_EN); // Конфигурация DMA // Peripheral address: ADC1 Data Register DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR); // Memory address: начинаем с buffer_0 DMA1_Channel1->CMAR = (uint32_t)audio_buffer_0; // Number of data to transfer: размер обоих буферов (для circular mode) DMA1_Channel1->CNDTR = AUDIO_BUFFER_SIZE * 2; // Конфигураци uint32_t ccr = 0; ccr |= DMA_CCR_MINC; // Memory increment mode ccr |= DMA_CCR_CIRC; // Circular mode ccr |= DMA_CCR_HTIE; // Half transfer interrupt enable ccr |= DMA_CCR_TCIE; // Transfer complete interrupt enable ccr |= DMA_CCR_PL_1; // Priority level: High (10) // Data size: 16-bit (MSIZE и PSIZE = 01) ccr |= DMA_CCR_MSIZE_0; // Memory size: 16-bit ccr |= DMA_CCR_PSIZE_0; // Peripheral size: 16-bit DMA1_Channel1->CCR = ccr; // Включаем прерывание DMA1_Channel1 в NVIC NVIC_SetPriority(DMA1_Channel1_IRQn, 6); // Приоритет 6 (ниже USB) NVIC_EnableIRQ(DMA1_Channel1_IRQn); } // DMA Interrupt Handler void DMA1_Channel1_IRQHandler(void) { uint32_t isr = DMA1->ISR; // Half Transfer Interrupt (первая половина буфера заполнена) if (isr & DMA_ISR_HTIF1) { DMA1->IFCR = DMA_IFCR_CHTIF1; // Сбрасываем флаг dma_half_transfer_count++; // Первая половина = buffer_0 готов к обработке if (user_callback != NULL) { user_callback(audio_buffer_0, AUDIO_BUFFER_SIZE); } buffer_count++; } // Transfer Complete Interrupt (вторая половина буфера заполнена) if (isr & DMA_ISR_TCIF1) { DMA1->IFCR = DMA_IFCR_CTCIF1; // Сбрасываем флаг dma_full_transfer_count++; // Вторая половина = buffer_1 готов к обработке if (user_callback != NULL) { user_callback(audio_buffer_1, AUDIO_BUFFER_SIZE); } buffer_count++; } // Transfer Error if (isr & DMA_ISR_TEIF1) { DMA1->IFCR = DMA_IFCR_CTEIF1; // Сбрасываем флаг // TODO: обработка ошибки } }