fix(mic): исправлен таймер на TIM3
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,35 +2,48 @@
|
||||
#include <string.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "audio_adc.h"
|
||||
#include "queue.h"
|
||||
#include "stm32f1xx.h"
|
||||
#include "task.h"
|
||||
#include "tusb.h"
|
||||
|
||||
// System Clock Configuration
|
||||
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
|
||||
(void)xTask;
|
||||
(void)pcTaskName;
|
||||
// Мигаем LED очень быстро при переполнении стека
|
||||
while (1) {
|
||||
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
||||
for (volatile int i = 0; i < 50000; i++);
|
||||
}
|
||||
}
|
||||
|
||||
// === Структура данных для очереди ===
|
||||
|
||||
typedef struct {
|
||||
uint16_t min_val;
|
||||
uint16_t max_val;
|
||||
uint16_t avg_val;
|
||||
uint32_t buffer_num;
|
||||
} audio_stats_packet_t;
|
||||
|
||||
static QueueHandle_t audio_stats_queue = NULL;
|
||||
|
||||
// === System Clock ===
|
||||
|
||||
void SystemClock_Config(void) {
|
||||
// Настройка на 72 MHz через HSE + PLL
|
||||
|
||||
// 1. Включаем HSE (внешний кварц 8 МГц)
|
||||
RCC->CR |= RCC_CR_HSEON;
|
||||
while (!(RCC->CR & RCC_CR_HSERDY));
|
||||
|
||||
// 2. Настраиваем Flash: 2 цикла ожидания для 72 MHz
|
||||
FLASH->ACR = FLASH_ACR_LATENCY_2;
|
||||
|
||||
// 3. Настраиваем PLL: 8 MHz * 9 = 72 MHz
|
||||
RCC->CFGR &= ~RCC_CFGR_PLLMULL;
|
||||
RCC->CFGR |= RCC_CFGR_PLLMULL9;
|
||||
RCC->CFGR |= RCC_CFGR_PLLSRC; // Источник PLL = HSE
|
||||
RCC->CFGR |= RCC_CFGR_PLLSRC;
|
||||
RCC->CFGR &= ~RCC_CFGR_USBPRE;
|
||||
|
||||
// 4. USB делитель: 72 MHz / 1.5 = 48 MHz
|
||||
RCC->CFGR &= ~RCC_CFGR_USBPRE; // USBPRE = 0 (делитель 1.5)
|
||||
|
||||
// 5. Включаем PLL
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
while (!(RCC->CR & RCC_CR_PLLRDY));
|
||||
|
||||
// 6. Переключаем системную частоту на PLL
|
||||
RCC->CFGR &= ~RCC_CFGR_SW;
|
||||
RCC->CFGR |= RCC_CFGR_SW_PLL;
|
||||
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
|
||||
@@ -38,19 +51,15 @@ void SystemClock_Config(void) {
|
||||
SystemCoreClock = 72000000;
|
||||
}
|
||||
|
||||
// Audio Processing Callback
|
||||
|
||||
// Буфер для отправки статистики через USB
|
||||
static char usb_tx_buffer[128];
|
||||
static volatile uint32_t total_samples = 0;
|
||||
// === Audio Callback ===
|
||||
|
||||
void audio_buffer_ready(audio_sample_t *buffer, uint32_t size) {
|
||||
// Эта функция вызывается из прерывания DMA
|
||||
// Не делать тяжелых операций здесь
|
||||
static uint32_t buffer_counter = 0;
|
||||
buffer_counter++;
|
||||
|
||||
total_samples += size;
|
||||
// Мигаем LED при каждом вызове
|
||||
if (buffer_counter % 5 == 0) { GPIOC->ODR ^= GPIO_ODR_ODR13; }
|
||||
|
||||
// мин/макс значения
|
||||
uint16_t min_val = 4095;
|
||||
uint16_t max_val = 0;
|
||||
uint32_t sum = 0;
|
||||
@@ -62,27 +71,23 @@ void audio_buffer_ready(audio_sample_t *buffer, uint32_t size) {
|
||||
sum += val;
|
||||
}
|
||||
|
||||
uint16_t avg = sum / size;
|
||||
if (buffer_counter % 10 == 0) {
|
||||
audio_stats_packet_t packet = {
|
||||
.min_val = min_val,
|
||||
.max_val = max_val,
|
||||
.avg_val = (uint16_t)(max_val - min_val),
|
||||
.buffer_num = buffer_counter};
|
||||
|
||||
// Каждые 2 секунды отправляем статистику: каждый 100-й буфер
|
||||
static uint32_t report_counter = 0;
|
||||
report_counter++;
|
||||
|
||||
if (report_counter >= 100) {
|
||||
report_counter = 0;
|
||||
|
||||
snprintf(
|
||||
usb_tx_buffer,
|
||||
sizeof(usb_tx_buffer),
|
||||
"ADC Stats - Min: %4u, Max: %4u, Avg: %4u, Total samples: %lu\r\n",
|
||||
min_val,
|
||||
max_val,
|
||||
avg,
|
||||
total_samples);
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xQueueSendFromISR(
|
||||
audio_stats_queue,
|
||||
&packet,
|
||||
&xHigherPriorityTaskWoken);
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
|
||||
// FreeRTOS Tasks
|
||||
// === Tasks ===
|
||||
|
||||
void usb_device_task(void *param) {
|
||||
(void)param;
|
||||
@@ -94,44 +99,115 @@ void usb_device_task(void *param) {
|
||||
|
||||
void cdc_task(void *param) {
|
||||
(void)param;
|
||||
char tx_buffer[256];
|
||||
uint32_t heartbeat_counter = 0;
|
||||
uint32_t last_buffer_count = 0;
|
||||
|
||||
while (1) {
|
||||
if (tud_cdc_connected()) {
|
||||
// Отправка статистики если есть данные
|
||||
if (usb_tx_buffer[0] != '\0') {
|
||||
size_t len = strlen(usb_tx_buffer);
|
||||
if (tud_cdc_write_available() >= len) {
|
||||
tud_cdc_write(usb_tx_buffer, len);
|
||||
tud_cdc_write_flush();
|
||||
usb_tx_buffer[0] = '\0'; // Очищаем буфер
|
||||
}
|
||||
heartbeat_counter++;
|
||||
|
||||
// Heartbeat + ДИАГНОСТИКА регистров каждые 100 циклов
|
||||
if (heartbeat_counter % 100 == 0 && tud_cdc_connected()) {
|
||||
uint32_t current_buffer_count = audio_adc_get_buffer_count();
|
||||
|
||||
int len = snprintf(
|
||||
tx_buffer,
|
||||
sizeof(tx_buffer),
|
||||
"HB:%lu Q:%u BC:%lu | "
|
||||
"TIM3_CR1:%lX TIM3_CNT:%lu | "
|
||||
"ADC1_CR2:%lX ADC1_SR:%lX | "
|
||||
"DMA_CCR:%lX DMA_CNDTR:%lu\r\n",
|
||||
heartbeat_counter,
|
||||
(unsigned)uxQueueMessagesWaiting(audio_stats_queue),
|
||||
current_buffer_count,
|
||||
TIM3->CR1,
|
||||
TIM3->CNT,
|
||||
ADC1->CR2,
|
||||
ADC1->SR,
|
||||
DMA1_Channel1->CCR,
|
||||
DMA1_Channel1->CNDTR);
|
||||
|
||||
if (tud_cdc_write_available() >= len) {
|
||||
tud_cdc_write(tx_buffer, len);
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
|
||||
// Echo для тестирования
|
||||
if (tud_cdc_available()) {
|
||||
uint8_t buf[64];
|
||||
uint32_t count = tud_cdc_read(buf, sizeof(buf));
|
||||
tud_cdc_write(buf, count);
|
||||
last_buffer_count = current_buffer_count;
|
||||
}
|
||||
|
||||
// Остальной код без изменений
|
||||
audio_stats_packet_t packet;
|
||||
if (xQueueReceive(audio_stats_queue, &packet, pdMS_TO_TICKS(10)) ==
|
||||
pdPASS) {
|
||||
int len = snprintf(
|
||||
tx_buffer,
|
||||
sizeof(tx_buffer),
|
||||
"Buf:%lu Min:%u Max:%u Avg:%u\r\n",
|
||||
packet.buffer_num,
|
||||
packet.min_val,
|
||||
packet.max_val,
|
||||
packet.avg_val);
|
||||
|
||||
if (tud_cdc_connected() && len > 0 &&
|
||||
tud_cdc_write_available() >= len) {
|
||||
tud_cdc_write(tx_buffer, len);
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// Echo
|
||||
if (tud_cdc_available()) {
|
||||
uint8_t buf[64];
|
||||
uint32_t count = tud_cdc_read(buf, sizeof(buf));
|
||||
if (tud_cdc_connected() && count > 0) {
|
||||
tud_cdc_write(buf, count);
|
||||
tud_cdc_write_flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void led_task(void *param) {
|
||||
(void)param;
|
||||
|
||||
while (1) {
|
||||
GPIOC->BSRR = GPIO_BSRR_BR13; // LED ON
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
GPIOC->BSRR = GPIO_BSRR_BS13; // LED OFF
|
||||
vTaskDelay(pdMS_TO_TICKS(900));
|
||||
GPIOC->BSRR = GPIO_BSRR_BR13;
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
GPIOC->BSRR = GPIO_BSRR_BS13;
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
}
|
||||
|
||||
// USB Reset
|
||||
// === Задача инициализации аудио ===
|
||||
void audio_init_task(void *param) {
|
||||
(void)param;
|
||||
|
||||
// Индикация старта инициализации (мигнем 3 раза быстро)
|
||||
for (int i = 0; i < 3; i++) {
|
||||
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
if (!audio_adc_init(audio_buffer_ready)) {
|
||||
// Ошибка: мигаем очень быстро
|
||||
while (1) {
|
||||
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
||||
vTaskDelay(pdMS_TO_TICKS(50));
|
||||
}
|
||||
}
|
||||
|
||||
// Запускаем ADC после старта FreeRTOS
|
||||
audio_adc_start();
|
||||
|
||||
// Индикация успешного запуска (мигнем 5 раз медленно)
|
||||
for (int i = 0; i < 5; i++) {
|
||||
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// === USB Reset ===
|
||||
|
||||
void force_usb_reset(void) {
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
||||
@@ -143,19 +219,19 @@ void force_usb_reset(void) {
|
||||
GPIOA->CRH |= GPIO_CRH_CNF12_0;
|
||||
}
|
||||
|
||||
// Main
|
||||
// === Main ===
|
||||
|
||||
int main(void) {
|
||||
SystemClock_Config();
|
||||
|
||||
// Настройка LED (PC13)
|
||||
// LED
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
|
||||
GPIOC->CRH &= ~GPIO_CRH_CNF13;
|
||||
GPIOC->CRH |= GPIO_CRH_MODE13_1;
|
||||
|
||||
force_usb_reset();
|
||||
|
||||
// Включаем USB
|
||||
// USB
|
||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||
|
||||
@@ -169,21 +245,16 @@ int main(void) {
|
||||
|
||||
tusb_init();
|
||||
|
||||
// Инициализация Audio ADC
|
||||
if (!audio_adc_init(audio_buffer_ready)) {
|
||||
// Ошибка инициализации - быстро мигаем LED
|
||||
// Очередь создаем ДО старта планировщика
|
||||
audio_stats_queue = xQueueCreate(10, sizeof(audio_stats_packet_t));
|
||||
if (audio_stats_queue == NULL) {
|
||||
while (1) {
|
||||
GPIOC->BSRR = GPIO_BSRR_BR13;
|
||||
for (volatile int i = 0; i < 100000; i++);
|
||||
GPIOC->BSRR = GPIO_BSRR_BS13;
|
||||
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
||||
for (volatile int i = 0; i < 100000; i++);
|
||||
}
|
||||
}
|
||||
|
||||
// Запускаем захват аудио
|
||||
audio_adc_start();
|
||||
|
||||
// Создаем задачи FreeRTOS
|
||||
// Задачи
|
||||
xTaskCreate(
|
||||
usb_device_task,
|
||||
"usbd",
|
||||
@@ -191,15 +262,16 @@ int main(void) {
|
||||
NULL,
|
||||
configMAX_PRIORITIES - 1,
|
||||
NULL);
|
||||
xTaskCreate(cdc_task, "cdc", 256, NULL, configMAX_PRIORITIES - 2, NULL);
|
||||
xTaskCreate(cdc_task, "cdc", 320, NULL, configMAX_PRIORITIES - 2, NULL);
|
||||
xTaskCreate(led_task, "led", 128, NULL, 1, NULL);
|
||||
xTaskCreate(audio_init_task, "audio_init", 128, NULL, 2, NULL);
|
||||
|
||||
vTaskStartScheduler();
|
||||
|
||||
while (1);
|
||||
}
|
||||
|
||||
// USB Interrupt Handlers
|
||||
// === USB Handlers ===
|
||||
|
||||
void USB_HP_CAN1_TX_IRQHandler(void) {
|
||||
tud_int_handler(0);
|
||||
|
||||
Reference in New Issue
Block a user