ormus-solutions/libreembed-claude-code/communication-buses

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Bus reference for I2C, SPI, UART, CAN, and USB: addressing, pull-up sizing, bus recovery, SPI mode card, DMA cache rules, ring buffers, CAN bit timing and error states, USB descriptors, and STM32 HAL code for each bus. Use when writing or reviewing a bus driver or diagnosing a misbehaving bus.

Install

npx vskill@latest install ormus-solutions/libreembed-claude-code/communication-buses

SKILL.md

Communication buses pattern library

Reference patterns for I2C, SPI, UART, CAN, and USB driver development. Use as a lookup when designing or reviewing drivers.

I2C reference

Address resolution
Address spaceBitsRange
7-bitbits 7..10x08–0x77 (0x00-0x07 and 0x78-0x7F reserved)
10-bitbits 9..00x000–0x3FF

Format on the wire (7-bit):

S | 7-bit addr | R/W | A | ... | P

The R/W bit is bit 0. Many HALs accept the address pre-shifted (address << 1); some accept it raw. Confirm against the HAL docs — common bug source.

Pull-up sizing

For VCC = 3.3V:

SpeedRecommended pull-up
Standard (100 kHz)4.7 kΩ
Fast (400 kHz)4.7 kΩ or 2.2 kΩ
Fast Plus (1 MHz)2.2 kΩ or 1 kΩ
High Speed (3.4 MHz)1 kΩ + external buffer

Bus capacitance matters. Wire capacitance ~ 1 pF/cm. Total bus capacitance (wire + slaves + master) should be < 400 pF for standard, < 200 pF for fast modes.

Clock stretching

Slave holds SCL low to gain processing time. Master must wait. STM32 hardware I2C handles this. Some software bit-bang implementations don't. If using bit-bang, sample SCL before assuming the master controls it.

Bus recovery

When SDA is stuck low (slave hung mid-transfer):

1. Configure SDA + SCL as GPIO (out of AF)
2. Pulse SCL low → high, 9-16 times
3. Check if SDA released (high)
4. If yes: generate STOP (SCL high, SDA low → high)
5. Restore SDA + SCL to AF
6. Re-init the I2C peripheral

SPI reference

Mode card
ModeCPOLCPHAIdle clockData captured on
000LowRising edge
101LowFalling edge
210HighFalling edge
311HighRising edge

Most sensors: mode 0 or 3. Always verify against datasheet — wrong mode silently corrupts every byte.

CS line patterns

Hardware NSS (single slave):

  • Peripheral toggles NSS automatically
  • Faster setup/hold timing
  • Limited to one slave

GPIO CS (multi-slave):

  • Software writes GPIO before/after transfer
  • More flexible
  • Setup time: typically need a few microseconds CS-low before SCK starts
  • Hold time: keep CS low until last bit clocked + a few extra cycles
DMA buffer alignment
MCU familyRequirement
Cortex-M0/M3/M4 (no cache)No alignment requirement beyond AHB bus
Cortex-M7 with cacheBuffer in non-cacheable region OR explicit cache maintenance
ESP32DMA-capable memory region only (check linker)

For Cortex-M7 cache maintenance:

c
// Before DMA write (CPU → peripheral):
SCB_CleanDCache_by_Addr((uint32_t*)tx_buf, len);
// Before DMA read (peripheral → CPU):
SCB_InvalidateDCache_by_Addr((uint32_t*)rx_buf, len);
Daisy chain

For multiple SPI slaves on one CS:

Master MOSI → Slave 1 MOSI
Slave 1 MISO → Slave 2 MOSI
Slave 2 MISO → Master MISO
Common CS to all slaves
Common SCK to all slaves

Transfer N×M bytes for N slaves with M-byte registers. Each slave shifts out its previous-cycle data while shifting in new data. Useful for sensor arrays.

UART reference

Frame format
Start bit | Data bits (5-9) | Parity (optional) | Stop bits (1 / 1.5 / 2)

Common configurations:

  • 8N1: 8 data, no parity, 1 stop — default for most modern UART
  • 7E1: 7 data, even parity, 1 stop — legacy serial
  • 8E2: 8 data, even parity, 2 stop — older industrial
Baud rate selection

Common rates: 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1500000, 2000000, 3000000

Above 921600, accuracy of the MCU's UART clock matters. STM32 USART_BRR can hit any baud rate; calculate the actual rate and verify it's within ±2% of nominal.

RX patterns
ThroughputPattern
< 1 kbpsPolled (rare, debug only)
1 kbps – 100 kbpsInterrupt RX + ring buffer
100 kbps – 1 MbpsDMA RX + IDLE line detection
> 1 MbpsDMA RX circular + IDLE line + flow control
Ring buffer pattern
c
typedef struct {
uint8_t buf[256];
volatile uint16_t head;
uint16_t tail;
} ringbuf_t;
// ISR
void USART2_IRQHandler(void) {
if (USART2->SR & USART_SR_RXNE) {
uint8_t byte = USART2->DR;
uint16_t next = (rb.head + 1) & 0xFF;
if (next != rb.tail) { // Not full
rb.buf[rb.head] = byte;
rb.head = next;
}
// else: overflow — log it
}
}
// Task
ssize_t ringbuf_read(uint8_t *out, size_t maxlen) {
size_t count = 0;
while (rb.tail != rb.head && count < maxlen) {
out[count++] = rb.buf[rb.tail];
rb.tail = (rb.tail + 1) & 0xFF;
}
return count;
}
Hardware flow control (RTS/CTS)

When the host can stall:

  • MCU asserts RTS = "I have buffer space, send me data"
  • MCU deasserts RTS = "stop, my buffer is full"
  • MCU checks CTS = "host has buffer space, I can transmit"

For STM32 USART:

  • USART_CR3_CTSE enables CTS
  • USART_CR3_RTSE enables RTS
  • Hardware handles both — no software signaling needed

CAN reference

Bit timing
Bit time = sync + propagation + phase1 + phase2
Sample point = (sync + propagation + phase1) / bit time

Recommended sample point: 75–87.5% of bit time. Higher sample point gives more margin for bus propagation delay but less margin for resync.

For 500 kbps on 42 MHz APB clock:

  • 42 MHz / 0.5 MHz = 84 time quanta — too many, use prescaler
  • Prescaler = 6 → 14 time quanta per bit
  • 1 sync + 6 prop + 5 phase1 + 2 phase2 → sample point at (1+6+5)/14 = 86% ✓
  • SJW = 2
Filter banks

For STM32 bxCAN:

  • 14 filter banks per CAN peripheral
  • Each bank: 16-bit list mode (4 IDs) OR 16-bit mask mode (2 ID/mask pairs) OR 32-bit list (2 IDs) OR 32-bit mask (1 ID/mask)

Configure for the IDs you actually consume. Other IDs dropped at the controller (no CPU work).

Error states
Active → Passive (TX error count > 127): sends recessive error frames only
Active → Bus-off (TX error count > 255): controller stops
Bus-off → Active (after 128 × 11 recessive bits): automatic recovery

Driver must detect bus-off and either wait for auto-recovery OR explicitly re-init. Auto-recovery is safer for production.

USB reference

Descriptor tree
Device descriptor
├─ Configuration descriptor (1+)
│ ├─ Interface descriptor (1+)
│ │ └─ Endpoint descriptor (0+)
│ └─ String descriptors (indexed)
└─ Vendor extensions (rare)

Total length in configuration descriptor must equal sum of all subordinate descriptor lengths. Off-by-one here causes enumeration to fail at the configuration-read step.

Endpoint types
  • Control (EP0) — required, bidirectional, 8/16/32/64 byte packets
  • Bulk — high throughput, no latency guarantee, packet size 8-512
  • Interrupt — low latency, periodic polling, packet size 8-1024
  • Isochronous — guaranteed bandwidth, no error recovery, packet size up to 1024
Common enumeration failures
SymptomLikely cause
Host doesn't see device at allD+ pullup not raised; VBUS detection wrong
Host sees device but fails enumerationDescriptor length mismatch; EP0 size wrong
Host enumerates but wrong driver loadsVID/PID conflict with existing driver
Enumerates fine but immediate disconnectPower request > bus can provide
Sometimes works, sometimes notVBUS noise; pullup raised before VBUS stable

Common mistakes catalog

"I2C bus is stuck"

A slave is holding SDA low. Use bus recovery (pulse SCL 9-16 times, then STOP). Common causes:

  • Power glitch on slave during transfer
  • Master reset mid-transfer
  • Slave with buggy firmware
"SPI reads all 0xFFs"

Slave isn't driving MISO. Check:

  • Slave VCC (at the chip, not the regulator)
  • Slave reset state
  • CS line actually going low during transfer
  • Correct SPI mode
  • Slave power-up time elapsed
"UART loses bytes under load"

RX overrun. Either:

  • Increase RX FIFO threshold to give software more time
  • Switch from interrupt to DMA RX
  • Add hardware flow control
"CAN bus shows messages but receiver doesn't see them"

Filter bank misconfigured. Check the filter bank's ID + mask vs. the actual message ID being broadcast.

"USB device works on one host, fails on another"

Descriptor issue. Some hosts are stricter than others. Run USB-IF compliance tool on the descriptors.

Code patterns (STM32 HAL)

Production communication bus patterns for embedded C. STM32 HAL and LL examples.

I2C Register Read/Write for MEMS Sensors

Generic register-addressed I2C sensor driver (BME280, MPU-6050, etc.):

c
#define I2C_TIMEOUT_MS 5U
HAL_StatusTypeDef sensor_write_reg(I2C_HandleTypeDef *hi2c,
uint8_t dev_addr, uint8_t reg, uint8_t val)
{
uint8_t buf[2] = { reg, val };
return HAL_I2C_Master_Transmit(hi2c, dev_addr << 1, buf, 2, I2C_TIMEOUT_MS);
}
HAL_StatusTypeDef sensor_read_reg(I2C_HandleTypeDef *hi2c,
uint8_t dev_addr, uint8_t reg,
uint8_t *out, uint16_t len)
{
HAL_StatusTypeDef s;
s = HAL_I2C_Master_Transmit(hi2c, dev_addr << 1, &reg, 1, I2C_TIMEOUT_MS);
if (s != HAL_OK) { return s; }
return HAL_I2C_Master_Receive(hi2c, (dev_addr << 1) | 1,
out, len, I2C_TIMEOUT_MS);
}
/* I2C bus recovery: toggle SCL 9 times to release stuck SDA */
void i2c_bus_recover(GPIO_TypeDef *scl_port, uint16_t scl_pin,
GPIO_TypeDef *sda_port, uint16_t sda_pin)
{
for (int i = 0; i < 9; i++) {
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_RESET);
HAL_Delay(1);
}
/* Generate STOP: SDA low→high while SCL high */
HAL_GPIO_WritePin(sda_port, sda_pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(scl_port, scl_pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(sda_port, sda_pin, GPIO_PIN_SET);
}
SPI DMA Transfer with Semaphore

Non-blocking SPI using DMA and FreeRTOS binary semaphore for completion notification:

c
static SemaphoreHandle_t s_spi_done;
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
if (hspi == &hspi1) {
BaseType_t woken = pdFALSE;
xSemaphoreGiveFromISR(s_spi_done, &woken);
portYIELD_FROM_ISR(woken);
}
}
void spi_dma_init(void)
{
s_spi_done = xSemaphoreCreateBinary();
}
bool spi_transfer(const uint8_t *tx, uint8_t *rx, uint16_t len)
{
spi_cs_assert();
HAL_SPI_TransmitReceive_DMA(&hspi1, (uint8_t *)tx, rx, len);
/* Block task until DMA complete (max 10ms) */
bool ok = xSemaphoreTake(s_spi_done, pdMS_TO_TICKS(10)) == pdTRUE;
spi_cs_deassert();
return ok;
}
UART DMA Circular Buffer with IDLE Detection

Most reliable pattern for variable-length UART frames at high baud:

c
#define DMA_RX_BUF 256U
static uint8_t s_dma_rx[DMA_RX_BUF];
static uint32_t s_rx_wr = 0U; /* Written by IDLE ISR */
static uint32_t s_rx_rd = 0U; /* Read by application */
void uart_dma_init(UART_HandleTypeDef *hu)
{
/* Start DMA receive in circular mode — never needs restart */
HAL_UARTEx_ReceiveToIdle_DMA(hu, s_dma_rx, DMA_RX_BUF);
__HAL_DMA_DISABLE_IT(hu->hdmarx, DMA_IT_HT); /* Disable half-transfer */
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *hu, uint16_t size)
{
/* size = write position in s_dma_rx (bytes from buffer start), not a */
/* count since the last callback. size == DMA_RX_BUF means it wrapped. */
s_rx_wr = size % DMA_RX_BUF;
}
uint16_t uart_available(void) {
return (s_rx_wr - s_rx_rd + DMA_RX_BUF) % DMA_RX_BUF;
}
uint8_t uart_read_byte(void) {
uint8_t c = s_dma_rx[s_rx_rd];
s_rx_rd = (s_rx_rd + 1U) % DMA_RX_BUF;
return c;
}
CAN Transmit and Receive

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/ormus-solutions/libreembed-claude-code/communication-buses/badge)](https://verified-skill.com/skills/ormus-solutions/libreembed-claude-code/communication-buses)

Something wrong with this skill or its page? Tell us.