feat(fw/health): добавлено моргание светодиода
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#define configCHECK_FOR_STACK_OVERFLOW 2
|
#define configCHECK_FOR_STACK_OVERFLOW 2
|
||||||
|
|
||||||
|
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||||
#define configUSE_PREEMPTION 1
|
#define configUSE_PREEMPTION 1
|
||||||
#define configUSE_IDLE_HOOK 0
|
#define configUSE_IDLE_HOOK 0
|
||||||
#define configUSE_TICK_HOOK 0
|
#define configUSE_TICK_HOOK 0
|
||||||
|
|||||||
15
firmware/App/Inc/health.h
Normal file
15
firmware/App/Inc/health.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef HEALTH_H
|
||||||
|
#define HEALTH_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
||||||
68
firmware/App/Src/health.c
Normal file
68
firmware/App/Src/health.c
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#include "health.h"
|
||||||
|
#include <math.h>
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "audio_adc.h"
|
#include "audio_adc.h"
|
||||||
#include "audio_processor.h" // НОВОЕ
|
#include "audio_processor.h" // НОВОЕ
|
||||||
|
#include "health.h"
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include "stm32f1xx.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 {
|
typedef struct {
|
||||||
@@ -63,7 +80,7 @@ void audio_buffer_ready(audio_sample_t *buffer, uint32_t size) {
|
|||||||
buffer_counter++;
|
buffer_counter++;
|
||||||
|
|
||||||
// Мигаем LED
|
// Мигаем LED
|
||||||
if (buffer_counter % 5 == 0) { GPIOC->ODR ^= GPIO_ODR_ODR13; }
|
/* if (buffer_counter % 5 == 0) { GPIOC->ODR ^= GPIO_ODR_ODR13; } */
|
||||||
|
|
||||||
// Копируем данные (ISR должен быть быстрым)
|
// Копируем данные (ISR должен быть быстрым)
|
||||||
memcpy(processing_buffer, buffer, size * sizeof(audio_sample_t));
|
memcpy(processing_buffer, buffer, size * sizeof(audio_sample_t));
|
||||||
@@ -89,31 +106,37 @@ void usb_device_task(void *param) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// НОВОЕ: задача обработки FFT
|
|
||||||
TaskHandle_t audio_process_task_handle = NULL;
|
TaskHandle_t audio_process_task_handle = NULL;
|
||||||
|
|
||||||
void audio_process_task(void *param) {
|
void audio_process_task(void *param) {
|
||||||
(void)param;
|
(void)param;
|
||||||
|
|
||||||
// Инициализация процессора
|
|
||||||
if (!audio_processor_init()) {
|
if (!audio_processor_init()) {
|
||||||
// Ошибка FFT init
|
|
||||||
while (1) {
|
while (1) {
|
||||||
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
GPIOC->ODR ^= GPIO_ODR_ODR13;
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
vTaskDelay(pdMS_TO_TICKS(50));
|
||||||
|
health_kick_watchdog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_metrics_t metrics;
|
audio_metrics_t metrics;
|
||||||
|
|
||||||
|
TickType_t last_wake = xTaskGetTickCount();
|
||||||
|
const TickType_t period = pdMS_TO_TICKS(100); // 10 Hz
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// Ждём сигнала от ISR
|
// 1) Ждём хотя бы один новый буфер от ISR
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
|
||||||
// Обработка 512 сэмплов
|
// 2) Выкидываем накопившиеся уведомления, чтобы не пытаться "догонять"
|
||||||
|
// прошлое
|
||||||
|
while (ulTaskNotifyTake(pdTRUE, 0) > 0) {}
|
||||||
|
|
||||||
|
// 3) Обрабатываем самый свежий буфер (processing_buffer
|
||||||
|
// перезаписывается в ISR)
|
||||||
if (audio_processor_process_512(processing_buffer, &metrics)) {
|
if (audio_processor_process_512(processing_buffer, &metrics)) {
|
||||||
// Отправляем только каждый 10-й (10 Hz)
|
health_update_led(metrics.peak_hz, metrics.rms_dbfs);
|
||||||
if (buffer_counter % 10 == 0) {
|
|
||||||
audio_metrics_packet_t packet = {
|
audio_metrics_packet_t packet = {
|
||||||
.rms_dbfs = metrics.rms_dbfs,
|
.rms_dbfs = metrics.rms_dbfs,
|
||||||
.peak_hz = metrics.peak_hz,
|
.peak_hz = metrics.peak_hz,
|
||||||
@@ -121,15 +144,19 @@ void audio_process_task(void *param) {
|
|||||||
.clipped = metrics.clipped,
|
.clipped = metrics.clipped,
|
||||||
.timestamp_ms = xTaskGetTickCount(),
|
.timestamp_ms = xTaskGetTickCount(),
|
||||||
};
|
};
|
||||||
xQueueSend(audio_metrics_queue, &packet, 0);
|
(void)xQueueSend(audio_metrics_queue, &packet, 0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
health_kick_watchdog();
|
||||||
|
|
||||||
|
// ограничиваем частоту обработки
|
||||||
|
vTaskDelayUntil(&last_wake, period);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cdc_task(void *param) {
|
void cdc_task(void *param) {
|
||||||
(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];
|
uint8_t tx_buffer[PACKET_TOTAL_SIZE];
|
||||||
|
|
||||||
while (1) {
|
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 audio_init_task(void *param) {
|
||||||
(void)param;
|
(void)param;
|
||||||
|
|
||||||
@@ -215,9 +232,9 @@ void force_usb_reset(void) {
|
|||||||
int main(void) {
|
int main(void) {
|
||||||
SystemClock_Config();
|
SystemClock_Config();
|
||||||
|
|
||||||
// LED
|
// LED GPIO (will be managed by health_led_task)
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
|
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
|
||||||
GPIOC->CRH &= ~GPIO_CRH_CNF13;
|
GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13);
|
||||||
GPIOC->CRH |= GPIO_CRH_MODE13_1;
|
GPIOC->CRH |= GPIO_CRH_MODE13_1;
|
||||||
|
|
||||||
force_usb_reset();
|
force_usb_reset();
|
||||||
@@ -225,18 +242,19 @@ int main(void) {
|
|||||||
// USB
|
// USB
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
|
||||||
|
|
||||||
NVIC_SetPriority(USB_HP_CAN1_TX_IRQn, 6);
|
NVIC_SetPriority(USB_HP_CAN1_TX_IRQn, 6);
|
||||||
NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 6);
|
NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn, 6);
|
||||||
NVIC_SetPriority(USBWakeUp_IRQn, 6);
|
NVIC_SetPriority(USBWakeUp_IRQn, 6);
|
||||||
|
|
||||||
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
|
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
|
||||||
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
||||||
NVIC_EnableIRQ(USBWakeUp_IRQn);
|
NVIC_EnableIRQ(USBWakeUp_IRQn);
|
||||||
|
|
||||||
tusb_init();
|
tusb_init();
|
||||||
|
|
||||||
// НОВОЕ: очередь для метрик FFT
|
// Initialize watchdog BEFORE starting tasks
|
||||||
|
health_init_watchdog();
|
||||||
|
|
||||||
|
// FFT queue
|
||||||
audio_metrics_queue = xQueueCreate(10, sizeof(audio_metrics_packet_t));
|
audio_metrics_queue = xQueueCreate(10, sizeof(audio_metrics_packet_t));
|
||||||
if (audio_metrics_queue == NULL) {
|
if (audio_metrics_queue == NULL) {
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -245,7 +263,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Задачи
|
// Create tasks
|
||||||
xTaskCreate(
|
xTaskCreate(
|
||||||
usb_device_task,
|
usb_device_task,
|
||||||
"usbd",
|
"usbd",
|
||||||
@@ -254,10 +272,10 @@ int main(void) {
|
|||||||
configMAX_PRIORITIES - 1,
|
configMAX_PRIORITIES - 1,
|
||||||
NULL);
|
NULL);
|
||||||
xTaskCreate(cdc_task, "cdc", 320, 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);
|
|
||||||
|
|
||||||
// НОВОЕ: задача обработки FFT (высокий приоритет, большой стек для FFT)
|
xTaskCreate(health_led_task, "health_led", 128, NULL, 1, NULL);
|
||||||
|
|
||||||
|
xTaskCreate(audio_init_task, "audio_init", 128, NULL, 2, NULL);
|
||||||
xTaskCreate(
|
xTaskCreate(
|
||||||
audio_process_task,
|
audio_process_task,
|
||||||
"audio_proc",
|
"audio_proc",
|
||||||
@@ -266,9 +284,14 @@ int main(void) {
|
|||||||
configMAX_PRIORITIES - 2,
|
configMAX_PRIORITIES - 2,
|
||||||
&audio_process_task_handle);
|
&audio_process_task_handle);
|
||||||
|
|
||||||
|
if (xTaskCreate(health_led_task, "health_led", 128, NULL, 1, NULL) !=
|
||||||
|
pdPASS) {
|
||||||
|
panic_blink_forever(100);
|
||||||
|
}
|
||||||
|
|
||||||
vTaskStartScheduler();
|
vTaskStartScheduler();
|
||||||
|
|
||||||
while (1);
|
while (1); // Should never reach here
|
||||||
}
|
}
|
||||||
|
|
||||||
// === USB Handlers ===
|
// === USB Handlers ===
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ App/Src/main.c \
|
|||||||
App/Src/audio_adc.c \
|
App/Src/audio_adc.c \
|
||||||
App/Src/audio_processor.c \
|
App/Src/audio_processor.c \
|
||||||
App/Src/protocol.c \
|
App/Src/protocol.c \
|
||||||
|
App/Src/health.c \
|
||||||
App/Src/usb_descriptors.c \
|
App/Src/usb_descriptors.c \
|
||||||
App/Src/system_stm32f1xx.c \
|
App/Src/system_stm32f1xx.c \
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user