brainstorming
brainstorming
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or planning anything new, in software or out of it (a talk, a business, a renovation).
embedded-stm32Best practices for embedded C/C++ development on STM32 microcontrollers using the HAL, covering peripherals, DMA, interrupts, memory constraints, and hardware-focused testing. Use when writing STM32 HAL code, configuring peripherals generated by STM32CubeMX, working with interrupts or DMA, debugging with SWD/JTAG, managing memory-constrained firmware, or wr…
Independent GitHub snapshot · Automated classification · Original documentation governs
This skill covers firmware development for STM32 microcontrollers using the STM32 HAL, including project structure, peripheral and interrupt handling, memory and timing constraints, and testing strategies for hardware-focused code.
.ioc file; generate the HAL initialization code.USER CODE BEGIN/END blocks; put application logic in separate files.HAL_*_Init() calls in main()/MX_*_Init() and avoid ad hoc reconfiguration elsewhere in the code.HAL_*_Callback functions, EXTI/DMA/timer IRQ handlers) short; set flags or push to a queue and defer real work to the main loop or an RTOS task.Core/Src/main.c, Drivers/) from hand-written application code so regenerating with CubeMX doesn't clobber custom logic — only edit inside /* USER CODE BEGIN */ ... /* USER CODE END */ markers in generated files.motor_driver.h with motor_set_speed()) so application logic can be unit-tested on a host build without real peripherals.SYSCLK, HCLK, PCLK1/PCLK2 and their max rates), pin mappings, peripheral ownership, and interrupt priority assignments in a single reference (README or header comments) — this is the first thing a debugging session needs.HAL_*_Init()/HAL_*_MspInit() calls or ad hoc register writes across multiple files.HAL_OK, HAL_ERROR, HAL_BUSY, HAL_TIMEOUT) and handle timeout/error cases explicitly — a silently ignored HAL_TIMEOUT from HAL_UART_Transmit is a classic source of "it works on my desk" bugs.HAL_UART_Transmit, HAL_I2C_Master_Receive without _IT/_DMA suffix) out of time-critical paths like control loops or ISRs.volatile only for memory shared with an ISR or memory-mapped hardware registers; volatile is not a substitute for a proper memory barrier or critical section when data is shared between contexts./* USER CODE BEGIN Includes */
#include "main.h"
#include <string.h>
#define RX_BUF_SIZE 128
static uint8_t rx_buf[RX_BUF_SIZE];
static volatile uint8_t rx_ready = 0;
static volatile uint16_t rx_len = 0;
extern UART_HandleTypeDef huart2;
extern DMA_HandleTypeDef hdma_usart2_rx;
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
void app_uart_start_receive(void)
{
/* Enable idle-line interrupt so a packet of unknown length completes
* the transfer without waiting for the buffer to fill. */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
if (HAL_UART_Receive_DMA(&huart2, rx_buf, RX_BUF_SIZE) != HAL_OK) {
Error_Handler();
}
}
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
void USART2_IRQHandler(void)
{
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) {
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
HAL_UART_DMAStop(&huart2);
rx_len = RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart2_rx);
rx_ready = 1; /* Deferred: main loop processes the packet. */
/* Re-arm for the next packet. */
HAL_UART_Receive_DMA(&huart2, rx_buf, RX_BUF_SIZE);
return;
}
HAL_UART_IRQHandler(&huart2);
}
/* USER CODE END 4 */
/* Main loop excerpt: heavy work deferred out of the ISR. */
void app_main_loop(void)
{
if (rx_ready) {
rx_ready = 0;
uint16_t len = rx_len;
/* Copy out or parse rx_buf[0..len) here. Do NOT touch rx_buf
* again until this point, since DMA may already be refilling it. */
(void)len;
}
}
__disable_irq()/__enable_irq(), or taskENTER_CRITICAL() under an RTOS), atomics, or lock-free queues — never assume a multi-byte read/write is atomic.malloc/new) inside interrupt handlers; allocation is neither deterministic nor guaranteed reentrant-safe.NVIC_SetPriority) — a mis-prioritized interrupt can starve time-critical peripherals or violate FreeRTOS's configMAX_SYSCALL_INTERRUPT_PRIORITY constraint.uxTaskGetStackHighWaterMark() under FreeRTOS) — stack overflow on embedded targets typically corrupts silently.const so the linker places them in flash instead of consuming scarce RAM.uint8_t, int32_t, uint32_t) for anything hardware-facing (register values, protocol fields, buffer sizes) instead of int/long, whose width isn't guaranteed.assert() or a custom configASSERT-style macro) for impossible hardware states in debug builds, compiled out in release builds if code size is tight.HardFault_Handler, etc.) useful: capture the reset reason (RCC->CSR), relevant fault status registers (SCB->CFSR, SCB->HFSR), and firmware build version/hash so a field crash is diagnosable after the fact.USER CODE blocks, so the next regeneration silently deletes the changes.