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

332 lines
9.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "audio_adc.h"
#include "audio_processor.h" // НОВОЕ
#include "queue.h"
#include "stm32f1xx.h"
#include "task.h"
#include "tusb.h"
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
(void)xTask;
(void)pcTaskName;
while (1) {
GPIOC->ODR ^= GPIO_ODR_ODR13;
for (volatile int i = 0; i < 50000; i++);
}
}
// === Структуры данных ===
// НОВОЕ: пакет с результатами FFT
typedef struct {
float rms_dbfs;
float peak_hz;
float peak_mag;
uint8_t clipped;
uint32_t buffer_num;
} audio_metrics_packet_t;
static QueueHandle_t audio_metrics_queue = NULL;
static volatile uint32_t buffer_counter = 0;
// === System Clock ===
void SystemClock_Config(void) {
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY));
FLASH->ACR = FLASH_ACR_LATENCY_2;
RCC->CFGR &= ~RCC_CFGR_PLLMULL;
RCC->CFGR |= RCC_CFGR_PLLMULL9;
RCC->CFGR |= RCC_CFGR_PLLSRC;
RCC->CFGR &= ~RCC_CFGR_USBPRE;
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY));
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
SystemCoreClock = 72000000;
}
// === Audio Callback (НОВОЕ: копируем в очередь для обработки) ===
// Буфер для копирования из ISR
static audio_sample_t processing_buffer[AUDIO_BUFFER_SIZE];
void audio_buffer_ready(audio_sample_t *buffer, uint32_t size) {
buffer_counter++;
// Мигаем LED
if (buffer_counter % 5 == 0) { GPIOC->ODR ^= GPIO_ODR_ODR13; }
// Копируем данные (ISR должен быть быстрым)
memcpy(processing_buffer, buffer, size * sizeof(audio_sample_t));
// Сигналим задаче обработки через notification
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
extern TaskHandle_t audio_process_task_handle;
if (audio_process_task_handle != NULL) {
vTaskNotifyGiveFromISR(
audio_process_task_handle,
&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
// === Tasks ===
void usb_device_task(void *param) {
(void)param;
while (1) {
tud_task();
vTaskDelay(pdMS_TO_TICKS(1));
}
}
// НОВОЕ: задача обработки FFT
TaskHandle_t audio_process_task_handle = NULL;
void audio_process_task(void *param) {
(void)param;
// Инициализация процессора
if (!audio_processor_init()) {
// Ошибка FFT init
while (1) {
GPIOC->ODR ^= GPIO_ODR_ODR13;
vTaskDelay(pdMS_TO_TICKS(100));
}
}
audio_metrics_t metrics;
while (1) {
// Ждём сигнала от ISR
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Обработка 512 сэмплов
if (audio_processor_process_512(processing_buffer, &metrics)) {
// Отправляем только каждый 10-й (10 Hz)
if (buffer_counter % 10 == 0) {
audio_metrics_packet_t packet = {
.rms_dbfs = metrics.rms_dbfs,
.peak_hz = metrics.peak_hz,
.peak_mag = metrics.peak_mag,
.clipped = metrics.clipped,
.buffer_num = buffer_counter};
xQueueSend(audio_metrics_queue, &packet, 0);
}
}
}
}
void cdc_task(void *param) {
(void)param;
char tx_buffer[256];
uint32_t heartbeat_counter = 0;
while (1) {
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\r\n",
heartbeat_counter,
(unsigned)uxQueueMessagesWaiting(audio_metrics_queue),
current_buffer_count);
if (len > 0 && tud_cdc_write_available() >= (uint32_t)len) {
tud_cdc_write(tx_buffer, (uint32_t)len);
tud_cdc_write_flush();
}
}
// Метрики FFT
audio_metrics_packet_t packet;
if (xQueueReceive(audio_metrics_queue, &packet, pdMS_TO_TICKS(10)) ==
pdPASS) {
// fixed-point:
// RMS: dBFS * 10 (один знак после запятой)
int32_t rms_x10 = (int32_t)(packet.rms_dbfs * 10.0f);
int32_t rms_int = rms_x10 / 10;
int32_t rms_frac = rms_x10 % 10;
if (rms_frac < 0) rms_frac = -rms_frac;
// Freq: Hz * 10 (один знак после запятой)
int32_t freq_x10 = (int32_t)(packet.peak_hz * 10.0f);
int32_t freq_int = freq_x10 / 10;
int32_t freq_frac = freq_x10 % 10;
if (freq_frac < 0) freq_frac = -freq_frac;
// Mag: *1000 (три знака после запятой)
int32_t mag_x1000 = (int32_t)(packet.peak_mag * 1000.0f);
int32_t mag_int = mag_x1000 / 1000;
int32_t mag_frac = mag_x1000 % 1000;
if (mag_frac < 0) mag_frac = -mag_frac;
int len = snprintf(
tx_buffer,
sizeof(tx_buffer),
"Buf:%lu RMS:%ld.%01ld dBFS Freq:%ld.%01ld Hz Mag:%ld.%03ld "
"Clip:%u\r\n",
packet.buffer_num,
(long)rms_int,
(long)rms_frac,
(long)freq_int,
(long)freq_frac,
(long)mag_int,
(long)mag_frac,
(unsigned)packet.clipped);
if (len > 0 && tud_cdc_connected() &&
tud_cdc_write_available() >= (uint32_t)len) {
tud_cdc_write(tx_buffer, (uint32_t)len);
tud_cdc_write_flush();
}
}
// 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;
vTaskDelay(pdMS_TO_TICKS(500));
GPIOC->BSRR = GPIO_BSRR_BS13;
vTaskDelay(pdMS_TO_TICKS(500));
}
}
void audio_init_task(void *param) {
(void)param;
// Индикация старта
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));
}
}
audio_adc_start();
for (int i = 0; i < 5; i++) {
GPIOC->ODR ^= GPIO_ODR_ODR13;
vTaskDelay(pdMS_TO_TICKS(200));
}
vTaskDelete(NULL);
}
void force_usb_reset(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
GPIOA->CRH &= ~GPIO_CRH_CNF12;
GPIOA->CRH |= GPIO_CRH_MODE12_1;
GPIOA->BSRR = GPIO_BSRR_BR12;
for (volatile int i = 0; i < 500000; i++) __NOP();
GPIOA->CRH &= ~GPIO_CRH_MODE12;
GPIOA->CRH |= GPIO_CRH_CNF12_0;
}
// === Main ===
int main(void) {
SystemClock_Config();
// LED
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
GPIOC->CRH &= ~GPIO_CRH_CNF13;
GPIOC->CRH |= GPIO_CRH_MODE13_1;
force_usb_reset();
// USB
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
NVIC_SetPriority(USB_HP_CAN1_TX_IRQn, 6);
NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 6);
NVIC_SetPriority(USBWakeUp_IRQn, 6);
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_EnableIRQ(USBWakeUp_IRQn);
tusb_init();
// НОВОЕ: очередь для метрик FFT
audio_metrics_queue = xQueueCreate(10, sizeof(audio_metrics_packet_t));
if (audio_metrics_queue == NULL) {
while (1) {
GPIOC->ODR ^= GPIO_ODR_ODR13;
for (volatile int i = 0; i < 100000; i++);
}
}
// Задачи
xTaskCreate(
usb_device_task,
"usbd",
256,
NULL,
configMAX_PRIORITIES - 1,
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);
// НОВОЕ: задача обработки FFT (высокий приоритет, большой стек для FFT)
xTaskCreate(
audio_process_task,
"audio_proc",
512,
NULL,
configMAX_PRIORITIES - 2,
&audio_process_task_handle);
vTaskStartScheduler();
while (1);
}
// === USB Handlers ===
void USB_HP_CAN1_TX_IRQHandler(void) {
tud_int_handler(0);
}
void USB_LP_CAN1_RX0_IRQHandler(void) {
tud_int_handler(0);
}
void USBWakeUp_IRQHandler(void) {
tud_int_handler(0);
}