78/uart-uhci

0.2.2

Latest
uploaded 19 hours ago
UART UHCI DMA Controller for ESP32

readme

# uart-uhci

A UART DMA receive controller component for ESP32, built on UHCI + GDMA. It uses a preallocated buffer pool together with the GDMA owner mechanism to provide continuous reception, and supports starting/stopping DMA on demand so the system can release its PM lock and enter low-power modes.

## Features

- **UHCI + GDMA**: bridges UART with GDMA through the UHCI controller for DMA-based reception.
- **Buffer pool**: preallocates multiple DMA buffers; a callback is invoked whenever a buffer is filled or the UART line goes idle.
- **Idle EOF**: uses UHCI's idle EOF mode to terminate the current DMA transfer when the UART line becomes idle.
- **Owner mechanism**: the GDMA descriptor owner field is used to track buffer ownership. After the user processes a buffer, calling `ReturnBuffer` hands it back to the DMA, which keeps consuming the rest of the pool automatically.
- **Overflow recovery**: when every buffer is held by the CPU, the DMA pauses and `OverflowCallback` is fired. Once all buffers have been returned, the component flushes the UART RX FIFO, re-mounts the buffers and resumes reception.
- **PM lock**: a PM lock is held during `StartReceive` and `Transmit` (when `CONFIG_PM_ENABLE` is on) and released by `StopReceive` and at the end of `Transmit`, which plays well with light sleep.
- **Transmit**: TX is done with synchronous UART FIFO writes, so no extra GDMA channel is needed for sending.

## Requirements

- ESP-IDF >= 5.5.2
- Component dependencies: `esp_pm`, `esp_mm`, `esp_driver_uart`

## Configuration

```c
// Buffer pool configuration
BufferPoolConfig rx_pool;
rx_pool.buffer_count = 4;   // At least 2; 4 or more is recommended
rx_pool.buffer_size  = 256; // Bytes per buffer

// Top-level configuration
UartUhci::Config config = {};
config.uart_port      = UART_NUM_1;
config.dma_burst_size = 16;  // Or 0 to use the default
config.rx_pool        = rx_pool;
```

## Basic usage

1. **Create and initialize**

```cpp
UartUhci uhci;
UartUhci::Config config = {};
config.uart_port      = UART_NUM_1;
config.dma_burst_size = 16;
config.rx_pool        = { .buffer_count = 4, .buffer_size = 256 };

esp_err_t err = uhci.Init(config);
```

2. **Register callbacks (must happen before `StartReceive`)**

```cpp
// Invoked whenever a buffer is completed (ISR context, return quickly)
bool on_rx(const UartUhci::RxEventData& data, void* user_data) {
    // Process the data via data.buffer->data and data.recv_size.
    // The buffer MUST be returned to the pool when you are done with it:
    uhci.ReturnBuffer(data.buffer);
    return false; // Return true to request a yield
}
uhci.SetRxCallback(on_rx, nullptr);

// Optional: invoked when DMA pauses because the buffer pool is exhausted (ISR context)
bool on_overflow(void* user_data) {
    // Return outstanding buffers as quickly as possible, or simply record the event
    return false; // Return true to request a yield
}
uhci.SetOverflowCallback(on_overflow, nullptr);
```

3. **Start / stop reception**

```cpp
uhci.StartReceive();  // Starts DMA reception and acquires the PM lock
// ...
uhci.StopReceive();   // Stops DMA and releases the PM lock
```

4. **Transmit data**

```cpp
uint8_t msg[] = "hello";
uhci.Transmit(msg, sizeof(msg) - 1);
```

5. **Status queries**

```cpp
bool running   = uhci.IsReceiving();           // Whether reception is active
bool overflow  = uhci.HasOverflow();           // Whether an overflow is currently latched (does not clear)
bool was_over  = uhci.CheckAndClearOverflow(); // Reads and clears the overflow flag
```

6. **Deinitialize**

```cpp
uhci.Deinit();
```

## Notes

- **Pool size**: `buffer_count` must be at least 2. A small pool makes overflow easy to hit when the consumer is slightly slow (all buffers are held by the CPU and the DMA pauses).
- **Callback context**: both `RxCallback` and `OverflowCallback` run inside an ISR, so avoid blocking or heavy logic and return the buffer via `ReturnBuffer` as soon as possible.
- **Always return buffers**: every buffer delivered via `RxCallback` must be released with `ReturnBuffer(buffer)`, otherwise the pool will eventually be exhausted and the DMA will stop.
- **Overflow recovery**: after an overflow, once every buffer has been returned, the component flushes the UART RX FIFO and re-mounts the DMA buffers automatically; no extra call is required.
- **UART setup**: the baud rate, pin assignment, and other UART parameters must be configured beforehand through `uart_driver_install` or the equivalent driver API. This component only handles UHCI/GDMA reception and writes TX data into an already configured UART.

## License

Apache-2.0

Links

Supports all targets

License: Apache-2.0

To add this component to your project, run:

idf.py add-dependency "78/uart-uhci^0.2.2"

download archive

Stats

  • Archive size
    Archive size ~ 13.01 KB
  • Downloaded in total
    Downloaded in total 174.4k times
  • Weekly Downloads Weekly Downloads (All Versions)
  • Downloaded this version
    This version: 0 times

Badge

78/uart-uhci version: 0.2.2
|