diff --git a/firmware/App/Inc/FreeRTOSConfig.h b/firmware/App/Inc/FreeRTOSConfig.h index f59a23f..e72164a 100644 --- a/firmware/App/Inc/FreeRTOSConfig.h +++ b/firmware/App/Inc/FreeRTOSConfig.h @@ -3,6 +3,7 @@ #define configCHECK_FOR_STACK_OVERFLOW 2 +#define configUSE_MALLOC_FAILED_HOOK 1 #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 diff --git a/firmware/App/Inc/health.h b/firmware/App/Inc/health.h new file mode 100644 index 0000000..b4f1dbf --- /dev/null +++ b/firmware/App/Inc/health.h @@ -0,0 +1,15 @@ +#ifndef HEALTH_H +#define HEALTH_H + +#include +#include + +void health_kick_watchdog(void); + +void health_init_watchdog(void); + +void health_update_led(float freq_hz, float rms_dbfs); + +void health_led_task(void *param); + +#endif // HEALTH_H diff --git a/firmware/App/Src/health.c b/firmware/App/Src/health.c new file mode 100644 index 0000000..34ff964 --- /dev/null +++ b/firmware/App/Src/health.c @@ -0,0 +1,68 @@ +#include "health.h" +#include +#include "FreeRTOS.h" +#include "stm32f1xx.h" +#include "task.h" + +// Default to "Heartbeat" mode (1 Hz) +static volatile uint32_t led_period_ms = 3000; + +void health_init_watchdog(void) { + IWDG->KR = 0x5555; + IWDG->PR = 0x04; // Prescaler /64 -> 625 Hz + IWDG->RLR = 1875; // ~3 seconds + IWDG->KR = 0xCCCC; + IWDG->KR = 0xAAAA; +} + +void health_kick_watchdog(void) { + IWDG->KR = 0xAAAA; +} + +void health_update_led(float freq_hz, float rms_dbfs) { + if (rms_dbfs < -35.0f) { + led_period_ms = 3000; + return; + } + + if (freq_hz < 100.0f) freq_hz = 100.0f; + if (freq_hz > 6000.0f) freq_hz = 6000.0f; + + // 100..8000 Hz -> 1..5 Hz blink (period 1000..200 ms) + float t = (log10f(freq_hz) - log10f(100.0f)) / + (log10f(6000.0f) - log10f(100.0f)); // 0..1 + float blink_hz = 1.0f + t * 20.0f; // 1..5 + uint32_t period = (uint32_t)(3000.0f / blink_hz); // 1000..200 ms + + if (period < 200) period = 50; + if (period > 3000) period = 3000; + led_period_ms = period; +} + +void health_led_task(void *param) { + (void)param; + + // 1) Включаем тактирование GPIOC и настраиваем PC13 как выход push-pull + // 2MHz + RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; + GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13); + GPIOC->CRH |= GPIO_CRH_MODE13_1; // 2 MHz output, push-pull (CNF=00) + + // LED off initially (Blue Pill LED is active-low) + GPIOC->ODR |= GPIO_ODR_ODR13; + + while (1) { + uint32_t period = led_period_ms; + uint32_t on_ms = 40; + if (on_ms > period / 2) on_ms = period / 2; + uint32_t off_ms = period - on_ms; + + // LED active-low: 0 = ON, 1 = OFF + GPIOC->BSRR = GPIO_BSRR_BR13; // ON + vTaskDelay(pdMS_TO_TICKS(on_ms)); // держим заметный импульс + GPIOC->BSRR = GPIO_BSRR_BS13; // OFF + vTaskDelay(pdMS_TO_TICKS(off_ms)); // пауза + + health_kick_watchdog(); + } +} diff --git a/firmware/App/Src/main.c b/firmware/App/Src/main.c index b91c013..a709c38 100644 --- a/firmware/App/Src/main.c +++ b/firmware/App/Src/main.c @@ -3,6 +3,7 @@ #include "FreeRTOS.h" #include "audio_adc.h" #include "audio_processor.h" // НОВОЕ +#include "health.h" #include "protocol.h" #include "queue.h" #include "stm32f1xx.h" @@ -18,6 +19,22 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { } } +void vApplicationMallocFailedHook(void) { + taskDISABLE_INTERRUPTS(); + while (1) { + GPIOC->ODR ^= GPIO_ODR_ODR13; + for (volatile int i = 0; i < 200000; i++) {} + } +} + +static void panic_blink_forever(uint32_t delay_ms) { + // PC13 уже сконфигурирован в main + while (1) { + GPIOC->ODR ^= GPIO_ODR_ODR13; + vTaskDelay(pdMS_TO_TICKS(delay_ms)); + } +} + // === Структуры данных === typedef struct { @@ -63,7 +80,7 @@ void audio_buffer_ready(audio_sample_t *buffer, uint32_t size) { buffer_counter++; // Мигаем LED - if (buffer_counter % 5 == 0) { GPIOC->ODR ^= GPIO_ODR_ODR13; } + /* if (buffer_counter % 5 == 0) { GPIOC->ODR ^= GPIO_ODR_ODR13; } */ // Копируем данные (ISR должен быть быстрым) memcpy(processing_buffer, buffer, size * sizeof(audio_sample_t)); @@ -89,47 +106,57 @@ void usb_device_task(void *param) { } } -// НОВОЕ: задача обработки 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)); + vTaskDelay(pdMS_TO_TICKS(50)); + health_kick_watchdog(); } } audio_metrics_t metrics; + TickType_t last_wake = xTaskGetTickCount(); + const TickType_t period = pdMS_TO_TICKS(100); // 10 Hz + while (1) { - // Ждём сигнала от ISR + // 1) Ждём хотя бы один новый буфер от ISR ulTaskNotifyTake(pdTRUE, portMAX_DELAY); - // Обработка 512 сэмплов + // 2) Выкидываем накопившиеся уведомления, чтобы не пытаться "догонять" + // прошлое + while (ulTaskNotifyTake(pdTRUE, 0) > 0) {} + + // 3) Обрабатываем самый свежий буфер (processing_buffer + // перезаписывается в ISR) 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); - } + health_update_led(metrics.peak_hz, metrics.rms_dbfs); + + 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(), + }; + (void)xQueueSend(audio_metrics_queue, &packet, 0); } + + health_kick_watchdog(); + + // ограничиваем частоту обработки + vTaskDelayUntil(&last_wake, period); } } void cdc_task(void *param) { (void)param; - // Buffer for the FR-1.4 packet (12 bytes) + // Buffer for packet (12 bytes) uint8_t tx_buffer[PACKET_TOTAL_SIZE]; while (1) { @@ -164,16 +191,6 @@ void cdc_task(void *param) { } } -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; @@ -215,9 +232,9 @@ void force_usb_reset(void) { int main(void) { SystemClock_Config(); - // LED + // LED GPIO (will be managed by health_led_task) RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; - GPIOC->CRH &= ~GPIO_CRH_CNF13; + GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13); GPIOC->CRH |= GPIO_CRH_MODE13_1; force_usb_reset(); @@ -225,18 +242,19 @@ int main(void) { // 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 + // Initialize watchdog BEFORE starting tasks + health_init_watchdog(); + + // FFT queue audio_metrics_queue = xQueueCreate(10, sizeof(audio_metrics_packet_t)); if (audio_metrics_queue == NULL) { while (1) { @@ -245,7 +263,7 @@ int main(void) { } } - // Задачи + // Create tasks xTaskCreate( usb_device_task, "usbd", @@ -254,10 +272,10 @@ int main(void) { 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(health_led_task, "health_led", 128, NULL, 1, NULL); + + xTaskCreate(audio_init_task, "audio_init", 128, NULL, 2, NULL); xTaskCreate( audio_process_task, "audio_proc", @@ -266,9 +284,14 @@ int main(void) { configMAX_PRIORITIES - 2, &audio_process_task_handle); + if (xTaskCreate(health_led_task, "health_led", 128, NULL, 1, NULL) != + pdPASS) { + panic_blink_forever(100); + } + vTaskStartScheduler(); - while (1); + while (1); // Should never reach here } // === USB Handlers === diff --git a/firmware/Makefile b/firmware/Makefile index cb5b94a..c97cd98 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -7,6 +7,7 @@ App/Src/main.c \ App/Src/audio_adc.c \ App/Src/audio_processor.c \ App/Src/protocol.c \ +App/Src/health.c \ App/Src/usb_descriptors.c \ App/Src/system_stm32f1xx.c \