mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
67 lines
4.4 KiB
Markdown
67 lines
4.4 KiB
Markdown
# Контракт бэкенда DMA-TX ИК (`IrDmaTxStm32`)
|
||
|
||
См. также: [IR_TX_MODES.md](IR_TX_MODES.md) — общая схема выбора `legacy ISR`, `buffered ISR` и `external backend`.
|
||
|
||
Платформа: **STM32G4**, Arduino STM32. Передача: **DMA memory → GPIO BSRR**, запрос от **TIM UPDATE** (частота `carrierFrec×2` из `IR_Encoder::beginClockOnly`).
|
||
|
||
### Число потоков (шаблон)
|
||
|
||
Класс: **`IrDmaTxStm32<MaxStreams>`**. Число слотов в `Config::streams[]` и внутреннем массиве задаётся **в коде**, без `-D` и без макроса до инклюда:
|
||
|
||
```cpp
|
||
constexpr size_t kStreams = 2;
|
||
static IrDmaTxStm32<kStreams> dma;
|
||
IrDmaTxStm32<kStreams>::Config cfg;
|
||
// IRQ: IrDmaTxStm32<kStreams>::instance()
|
||
```
|
||
|
||
По умолчанию: **`IrDmaTxStm32<>`** эквивалентно **`IrDmaTxStm32<irproto::kDefaultDmaTxMaxStreams>`** (`IR_config.h`, обычно 4). Реализация в заголовке (отдельного `.cpp` нет).
|
||
|
||
## Роль библиотеки
|
||
|
||
- Разбор пакета в RLE-пробеги: `IR_Encoder::buildGateRuns`.
|
||
- Генерация слов для BSRR (несущая/тишина по тикам), предзаполнение буфера и дозаполнение по прерываниям half/complete.
|
||
- Настройка канала DMA, DMAMUX, кольцевой режим, старт/стоп DMA и таймера, колбэки HAL.
|
||
- В `begin()` только `HAL_NVIC_EnableIRQ` для каналов DMA (без `SetPriority`).
|
||
|
||
## Роль прошивки (клиента)
|
||
|
||
### Буферы и размеры
|
||
|
||
На **каждый** поток в `StreamCfg` клиент передаёт:
|
||
|
||
| Поле | Смысл |
|
||
|------|--------|
|
||
| `dmaWords` | Указатель на массив `uint32_t` — слова для записи в BSRR. |
|
||
| `dmaWordCount` | Число **слов** (32-bit), **чётное**, ≥ 2. Половина — один «полубуфер» для HT/TC IRQ. |
|
||
| `gateRuns` | Массив `IR_Encoder::IR_TxGateRun` для выхода `buildGateRuns`. |
|
||
| `maxGateRuns` | Длина этого массива. Должен быть достаточен для самого длинного кадра. |
|
||
|
||
Память и выравнивание — ответственность клиента; типичные порядки: 4096 слов DMA, 1024 ранов (как в машинке).
|
||
|
||
### Таймер и DMA
|
||
|
||
- `HardwareTimer` / тот же TIM, что и `beginClockOnly`, без конкурирующего `attachInterrupt` на UPDATE.
|
||
- `instance`, `irq`, `dmamuxRequest` (например `DMA_REQUEST_TIM17_UP`) — из схемы платы; оба потока на одном TIM обычно используют **один** `TIMx_UP` в DMAMUX.
|
||
|
||
### Приоритеты NVIC
|
||
|
||
Не задаются в библиотеке. После `begin()` клиент выставляет preempt/sub для `DMA1_ChannelN` (и согласует с приёмом EXTI и др.), например общей функцией вроде `Car_applyInterruptPriorities()`.
|
||
|
||
### Прерывания DMA
|
||
|
||
Библиотека **не** объявляет `DMA1_ChannelN_IRQHandler`. В одном `.cpp` прошивки — единственное определение на канал, внутри:
|
||
|
||
`IrDmaTxStm32<N>::instance()->irqForStream(i)` (тот же **N**, что у объекта бэкенда) или `IrDmaTxStm32_onDmaHandle(hdma)`.
|
||
|
||
## Контракт `IR_Encoder::setExternalTxBackend`
|
||
|
||
Подключение: `setExternalTxBackend(startFn, busyFn, ctx)`.
|
||
|
||
- **`startFn(ctx, enc, packet, len)`** — должен вызвать `IrDmaTxStm32<N>::start(enc, packet, len)` (или обёртку). Возвращает успех старта DMA.
|
||
- **`busyFn(ctx)`** — пока возвращает «занято», новая отправка не стартует. У `IrDmaTxStm32<N>::busy()`: **true**, если **все** настроенные потоки в передаче (для двух передатчиков — оба активны); иначе можно запустить второй канал.
|
||
|
||
## Сбой `begin()`
|
||
|
||
При ошибке `HAL_DMA_Init` и т.п. `begin()` возвращает `false`, `instance()` не используется для IRQ до успешного `begin()`.
|