4.2 KiB
Контракт бэкенда DMA-TX ИК (IrDmaTxStm32)
Платформа: STM32G4, Arduino STM32. Передача: DMA memory → GPIO BSRR, запрос от TIM UPDATE (частота carrierFrec×2 из IR_Encoder::beginClockOnly).
Число потоков (шаблон)
Класс: IrDmaTxStm32<MaxStreams>. Число слотов в Config::streams[] и внутреннем массиве задаётся в коде, без -D и без макроса до инклюда:
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().