fix(mic): исправлен таймер на TIM3

This commit is contained in:
2025-12-25 23:17:39 +03:00
parent 3306b8083b
commit 063cced2a5
7 changed files with 223 additions and 213 deletions

View File

@@ -2,12 +2,8 @@
#include <string.h>
#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;
// Один непрерывный DMA-буфер: 2 * 512 = 1024 семпла
static audio_sample_t dma_buffer[2 * AUDIO_BUFFER_SIZE];
// Callback функция
static audio_buffer_ready_callback_t user_callback = NULL;
@@ -24,11 +20,10 @@ 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; }
if (callback == NULL) return false;
user_callback = callback;
// Инициализация компонентов
audio_gpio_init();
audio_timer_init();
audio_adc_hw_init();
@@ -38,24 +33,14 @@ bool audio_adc_init(audio_buffer_ready_callback_t callback) {
}
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;
TIM3->CR1 |= TIM_CR1_CEN;
}
void audio_adc_stop(void) {
// Останавливаем Timer
TIM2->CR1 &= ~TIM_CR1_CEN;
// Останавливаем ADC
TIM3->CR1 &= ~TIM_CR1_CEN;
ADC1->CR2 &= ~ADC_CR2_ADON;
// Останавливаем DMA
DMA1_Channel1->CCR &= ~DMA_CCR_EN;
}
@@ -63,176 +48,121 @@ 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
// PA1 analog
GPIOA->CRL &= ~(0xF << 4);
}
static void audio_timer_init(void) {
// Включаем тактирование Timer2
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
// Включаем тактирование Timer3
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
// Настраиваем Timer2 для генерации TRGO на частоте 22050 Hz
TIM2->PSC = AUDIO_TIMER_PRESCALER;
TIM2->ARR = AUDIO_TIMER_PERIOD;
// Настраиваем TIM3 для 22050 Hz
TIM3->PSC = AUDIO_TIMER_PRESCALER;
TIM3->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
// TRGO = Update event
TIM3->CR2 &= ~TIM_CR2_MMS;
TIM3->CR2 |= TIM_CR2_MMS_1;
// Auto-reload preload enable
TIM2->CR1 |= TIM_CR1_ARPE;
// Генерируем Update event для загрузки PSC/ARR
TIM2->EGR |= TIM_EGR_UG;
TIM3->CR1 |= TIM_CR1_ARPE;
TIM3->EGR |= TIM_EGR_UG;
TIM3->CNT = 0;
}
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)
// EXTSEL = 011 (Timer2 TRGO), EXTTRIG enable
ADC1->CR2 &= ~ADC_CR2_EXTSEL;
ADC1->CR2 |= ADC_CR2_EXTSEL_0 | ADC_CR2_EXTSEL_1; // 011
// External trigger enable for regular channels
ADC1->CR2 |= (0x4U << 17); // TIM3_TRGO
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
ADC1->SMPR2 |= ADC_SMPR2_SMP1_0; // 7.5 cycles
// Калибровка ADC
// Включаем ADC
// calibration
ADC1->CR2 |= ADC_CR2_ADON;
// Ждем stabilization time (1 мкс)
for (volatile int i = 0; i < 1000; i++);
// Запускаем калибровку
for (volatile int i = 0; i < 1000; i++) {}
ADC1->CR2 |= ADC_CR2_CAL;
while (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) {}
// Ждем отключения
while (DMA1_Channel1->CCR & DMA_CCR_EN);
// ADC1 DR -> RAM
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
// Конфигурация DMA
// ВАЖНО: CMAR указывает на непрерывный буфер 1024 samples
DMA1_Channel1->CMAR = (uint32_t)dma_buffer;
// Peripheral address: ADC1 Data Register
DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR);
// ВАЖНО: 2 * 512 = 1024 samples
DMA1_Channel1->CNDTR = 2 * AUDIO_BUFFER_SIZE;
// 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
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;
// Включаем прерывание DMA1_Channel1 в NVIC
NVIC_SetPriority(DMA1_Channel1_IRQn, 6); // Приоритет 6 (ниже USB)
NVIC_SetPriority(DMA1_Channel1_IRQn, 6);
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; // Сбрасываем флаг
DMA1->IFCR = DMA_IFCR_CHTIF1;
dma_half_transfer_count++;
// Первая половина = buffer_0 готов к обработке
if (user_callback != NULL) {
user_callback(audio_buffer_0, AUDIO_BUFFER_SIZE);
}
// первая половина: [0 .. 511]
if (user_callback) { user_callback(&dma_buffer[0], AUDIO_BUFFER_SIZE); }
buffer_count++;
}
// Transfer Complete Interrupt (вторая половина буфера заполнена)
if (isr & DMA_ISR_TCIF1) {
DMA1->IFCR = DMA_IFCR_CTCIF1; // Сбрасываем флаг
DMA1->IFCR = DMA_IFCR_CTCIF1;
dma_full_transfer_count++;
// Вторая половина = buffer_1 готов к обработке
if (user_callback != NULL) {
user_callback(audio_buffer_1, AUDIO_BUFFER_SIZE);
// вторая половина: [512 .. 1023]
if (user_callback) {
user_callback(&dma_buffer[AUDIO_BUFFER_SIZE], AUDIO_BUFFER_SIZE);
}
buffer_count++;
}
// Transfer Error
if (isr & DMA_ISR_TEIF1) {
DMA1->IFCR = DMA_IFCR_CTEIF1; // Сбрасываем флаг
// TODO: обработка ошибки
DMA1->IFCR = DMA_IFCR_CTEIF1;
// TODO: error handling
}
}