287 lines
7.5 KiB
C
287 lines
7.5 KiB
C
#include <stdio.h>
|
||
#include <string.h>
|
||
#include "FreeRTOS.h"
|
||
#include "audio_adc.h"
|
||
#include "audio_processor.h" // НОВОЕ
|
||
#include "protocol.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++);
|
||
}
|
||
}
|
||
|
||
// === Структуры данных ===
|
||
|
||
typedef struct {
|
||
float rms_dbfs;
|
||
float peak_hz;
|
||
float peak_mag;
|
||
uint8_t clipped;
|
||
uint32_t timestamp_ms;
|
||
} 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,
|
||
.timestamp_ms = xTaskGetTickCount(),
|
||
};
|
||
xQueueSend(audio_metrics_queue, &packet, 0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void cdc_task(void *param) {
|
||
(void)param;
|
||
// Buffer for the FR-1.4 packet (12 bytes)
|
||
uint8_t tx_buffer[PACKET_TOTAL_SIZE];
|
||
|
||
while (1) {
|
||
// Check if USB is connected
|
||
if (tud_cdc_connected()) {
|
||
audio_metrics_packet_t packet;
|
||
|
||
// Wait for data from DSP task
|
||
if (xQueueReceive(
|
||
audio_metrics_queue,
|
||
&packet,
|
||
pdMS_TO_TICKS(10)) == pdPASS) {
|
||
// Pack data according to FR-1.4 spec
|
||
protocol_pack_v1(
|
||
tx_buffer,
|
||
packet.timestamp_ms,
|
||
packet.rms_dbfs,
|
||
packet.peak_hz);
|
||
|
||
// Write to USB CDC
|
||
// Check available space just in case
|
||
if (tud_cdc_write_available() >= sizeof(tx_buffer)) {
|
||
tud_cdc_write(tx_buffer, sizeof(tx_buffer));
|
||
tud_cdc_write_flush();
|
||
}
|
||
}
|
||
} else {
|
||
// Flush queue if USB not connected to prevent stalling DSP task
|
||
// or just sleep longer.
|
||
vTaskDelay(pdMS_TO_TICKS(100));
|
||
}
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|