Skip to content

aulsz/embedded-explainer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

embedded-explainer

$ embedded-explainer timer_config.c --depth detailed

── timer_config.c  [detailed] ──
Detected: STM32 HAL  ·  ISR ×1  ·  Timer  ·  volatile ×1

## STM32F4 TIM2 — 1 kHz Interrupt Configuration

**Clock gating** — __HAL_RCC_TIM2_CLK_ENABLE() sets TIM2EN in RCC_APB1ENR,
connecting TIM2 to the bus matrix. Without this, writes to TIM2 registers do
nothing.

**Prescaler arithmetic** — Prescaler=83 divides the 84 MHz APB1 timer clock to
1 MHz. The hardware always adds 1, so PSC=83 means ÷84.

**Period and overflow** — Period=999 makes the counter overflow at 1 kHz
(1 MHz ÷ 1000). AutoReloadPreload double-buffers ARR so runtime changes take
effect cleanly at the next cycle boundary.

**ISR dispatch chain** — TIM2_IRQHandler → HAL_TIM_IRQHandler (clears UIF in
TIM2_SR) → HAL_TIM_PeriodElapsedCallback. Clearing UIF before the callback is
critical: if it is still set on ISR return, the CPU re-enters immediately.

**Race condition** — tick_count++ is a load-add-store sequence, not atomic.
Read it into a local variable in main before comparing.

Generic code explainers tell you what the code says. This one tells you what the hardware is doing.


What makes this different

Most LLMs explain HAL_TIM_Base_Init() as "initializes the timer base." That's the function name — not an explanation. embedded-explainer detects STM32 HAL calls, ISR handlers, DMA transfers, volatile shared variables, and memory-mapped register patterns, then builds a domain-aware prompt that produces explanations like:

"Prescaler=83 divides the 84 MHz APB1 timer clock to 1 MHz. The hardware always adds 1 to PSC, so writing 83 gives you a ÷84 divisor."

That's the explanation a senior firmware engineer gives a junior on their first week.


Install

pip install embedded-explainer

Or install from source:

git clone https://github.com/aulsz/embedded-explainer
cd embedded-explainer
pip install -e .

Set your API key:

export ANTHROPIC_API_KEY=sk-ant-...

No key? Try the built-in demo first (no key required):

embedded-explainer --demo

Usage

embedded-explainer [FILE] [OPTIONS]

Arguments:
  FILE  Path to a .c or .py file

Options:
  -d, --depth [quick|detailed|teach]
        quick    — 3-4 sentence summary
        detailed — section-by-section with hardware implications  [default]
        teach    — full walkthrough for a junior developer

  --stream / --no-stream   Stream tokens as they generate  [default: stream]
  --demo                   Run on bundled STM32 TIM2 example (no API key)
  --no-cache               Force a fresh API call, skip cache
  --clear-cache            Delete all cached responses and exit
  -h, --help               Show this message and exit
  --version                Show version and exit

Examples:

# Explain a file with default (detailed) depth
embedded-explainer src/motor_control.c

# Get a quick summary
embedded-explainer usart.c --depth quick

# Full junior-dev walkthrough
embedded-explainer dma_config.c --depth teach

# Run the built-in STM32 demo — no API key needed
embedded-explainer --demo --depth teach

# Force re-analysis (skip cache)
embedded-explainer isr.c --no-cache

Patterns detected

embedded-explainer scans the file before calling the API and injects targeted context for whatever it finds:

Pattern What gets injected
HAL_* calls STM32 HAL peripheral knowledge, clock gating requirements
*_IRQHandler / __attribute__((interrupt)) ISR dispatch chain, UIF clearing, re-entrancy
DMA_* / HAL_DMA_* Transfer direction, completion behavior, cache coherency
TIM_* / HAL_TIM_* Prescaler/ARR arithmetic, double-buffering
UART_* / USART_* Baud rate calculation, clock source
volatile variables Atomicity assessment, ISR/main shared-state risks
RTOS primitives ISR-safe API variants, priority inversion
Raw *(uint32_t*)0x4... Peripheral address range identification

Caching

Responses are cached in ~/.cache/embedded-explainer/ keyed by SHA-256(file_content + depth). Rerunning on the same file at the same depth is instant and costs no API tokens.

embedded-explainer --clear-cache   # wipe all cached responses
embedded-explainer file.c --no-cache  # force fresh call

Architecture

The preprocessing pipeline is what separates this from a generic "send to ChatGPT" script:

  1. Pattern detection (preprocess.py) — regex scan for HAL calls, ISR handlers, DMA patterns, volatile variables, RTOS primitives. Builds a CodeContext dataclass.
  2. Dynamic system prompt (prompts.py) — assembles a targeted system prompt from the detected context. Different peripherals inject different domain knowledge. A file with DMA gets cache coherency context. A file with ISRs gets interrupt dispatch chain context.
  3. Depth-aware user prompt — three prompt templates (quick, detailed, teach) that set different output format expectations.
  4. SHA-256 cache (cache.py) — keyed on file content + depth. Repeated analysis of unchanged files is free.
  5. Streaming CLI (cli.py) — Click-based interface with streaming output, colored headers, and pattern tag display.

Environment variables

Variable Default Description
ANTHROPIC_API_KEY Required (except --demo)
EXPLAINER_MODEL claude-3-5-haiku-20241022 Override the model

License

MIT

About

Explain embedded C code in plain English. Understands STM32 HAL, ISRs, DMA, and memory-mapped peripherals.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors