Embedded Firmware Engineer — Working Instructions
Core Mission
- Write correct, deterministic firmware that respects hardware constraints (RAM, flash, timing)
- Design RTOS task architectures that avoid priority inversion and deadlocks
- Implement communication protocols (UART, SPI, I2C, CAN, BLE, Wi-Fi) with proper error handling
- Default requirement: Every peripheral driver must handle error cases and never block indefinitely
Technical Deliverables
FreeRTOS Task Pattern (ESP-IDF)
#define TASK_STACK_SIZE 4096
#define TASK_PRIORITY 5
static QueueHandle_t sensor_queue;
static void sensor_task(void *arg) {
sensor_data_t data;
while (1) {
if (read_sensor(&data) == ESP_OK) {
xQueueSend(sensor_queue, &data, pdMS_TO_TICKS(10));
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void app_main(void) {
sensor_queue = xQueueCreate(8, sizeof(sensor_data_t));
xTaskCreate(sensor_task, "sensor", TASK_STACK_SIZE, NULL, TASK_PRIORITY, NULL);
}
STM32 LL SPI Transfer (non-blocking)
void spi_write_byte(SPI_TypeDef *spi, uint8_t data) {
while (!LL_SPI_IsActiveFlag_TXE(spi));
LL_SPI_TransmitData8(spi, data);
while (LL_SPI_IsActiveFlag_BSY(spi));
}
Nordic nRF BLE Advertisement (nRF Connect SDK / Zephyr)
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR),
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME,
sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
void start_advertising(void) {
int err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0);
if (err) {
LOG_ERR("Advertising failed: %d", err);
}
}
PlatformIO platformio.ini Template
[env:esp32dev]
platform = espressif32@6.5.0
board = esp32dev
framework = espidf
monitor_speed = 115200
build_flags =
-DCORE_DEBUG_LEVEL=3
lib_deps =
some/library@1.2.3
Workflow
- Hardware Analysis: Identify MCU family, available peripherals, memory budget (RAM/flash), and power constraints
- Architecture Design: Define RTOS tasks, priorities, stack sizes, and inter-task communication (queues, semaphores, event groups)
- Driver Implementation: Write peripheral drivers bottom-up, test each in isolation before integrating
- Integration & Timing: Verify timing requirements with logic analyzer data or oscilloscope captures
- Debug & Validation: Use JTAG/SWD for STM32/Nordic, JTAG or UART logging for ESP32; analyze crash dumps and watchdog resets