mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-09-18 19:13:58 +00:00
perf(tx): заполнение DMA-буфера по ранам вместо пословного автомата
IrTxBsrrWave::fill: пауза (gate=0) — один цикл записи resetWord, несущая — копия шаблона периода (powerN слов setWord + остальные resetWord); состояние переносится через границы порций как у nextWord(). На 12 МГц предзаполнение 4096 слов перед стартом DMA и ISR-дозаполнение половин (2048 слов каждые ~8.9 мс кадра — было ~88% CPU) укорачиваются в разы: старт несущей после вызова send 15.7 → ~5 мс (с построением ранов). Эквивалентность проверена на хосте: 17856 случаев (len 1..31, multiply 2..8, powerN 1..multiply/2, порции 2048/случайные/по 1 слову), 0 расхождений на 719 млн слов. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeA1K5dBUKrnoXVwyoVjzq
This commit is contained in:
@ -65,13 +65,63 @@ public:
|
||||
return out;
|
||||
}
|
||||
|
||||
// Заполнение по ранам, а не по словам: тот же поток слов, что даёт nextWord() (состояние
|
||||
// runIndex_/ticksLeftInRun_/slotInPeriod_ переносится через границы порций), но пауза (gate=0)
|
||||
// пишется одним циклом записи, а несущая — копией готового шаблона периода. На 12 МГц это
|
||||
// ~1 мс на 4096 слов вместо ~16 (пословный автомат) — и в предзаполнении перед стартом DMA,
|
||||
// и в ISR-дозаполнении половин буфера во время передачи.
|
||||
IR_TX_BSRR_WAVE_HOT void fill(uint32_t* dst, uint16_t count) {
|
||||
if (dst == nullptr || count == 0) {
|
||||
return;
|
||||
}
|
||||
do {
|
||||
*dst++ = nextWord();
|
||||
} while (--count != 0);
|
||||
while (count != 0) {
|
||||
if (runIndex_ >= runCount) {
|
||||
do { *dst++ = resetWord; } while (--count != 0);
|
||||
return;
|
||||
}
|
||||
const bool gate = runs[runIndex_].gate;
|
||||
uint16_t n = ticksLeftInRun_; // слов до конца текущего рана
|
||||
if (n == 0) n = 1; // ран нулевой длины: nextWord() выдаёт одно слово и переходит дальше
|
||||
if (n > count) n = count;
|
||||
if (!gate) {
|
||||
slotInPeriod_ = 0;
|
||||
uint16_t k = n;
|
||||
do { *dst++ = resetWord; } while (--k != 0);
|
||||
} else {
|
||||
uint16_t k = n;
|
||||
// добить текущий период до слота 0 (если ран начался посреди периода на границе порции)
|
||||
while (k != 0 && slotInPeriod_ != 0) {
|
||||
*dst++ = (slotInPeriod_ < powerN_) ? setWord : resetWord;
|
||||
if (++slotInPeriod_ >= multiply_) slotInPeriod_ = 0;
|
||||
k--;
|
||||
}
|
||||
// целые периоды: powerN_ слов setWord, остальные resetWord
|
||||
while (k >= multiply_) {
|
||||
uint16_t i = 0;
|
||||
for (; i < powerN_; ++i) *dst++ = setWord;
|
||||
for (; i < multiply_; ++i) *dst++ = resetWord;
|
||||
k = (uint16_t)(k - multiply_);
|
||||
}
|
||||
// хвост неполного периода
|
||||
while (k != 0) {
|
||||
*dst++ = (slotInPeriod_ < powerN_) ? setWord : resetWord;
|
||||
if (++slotInPeriod_ >= multiply_) slotInPeriod_ = 0;
|
||||
k--;
|
||||
}
|
||||
}
|
||||
count = (uint16_t)(count - n);
|
||||
if (ticksLeftInRun_ > n) {
|
||||
ticksLeftInRun_ = (uint16_t)(ticksLeftInRun_ - n);
|
||||
} else {
|
||||
ticksLeftInRun_ = 0;
|
||||
}
|
||||
if (ticksLeftInRun_ == 0) {
|
||||
runIndex_++;
|
||||
if (runIndex_ < runCount) {
|
||||
ticksLeftInRun_ = runs[runIndex_].lenTicks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user