mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2026-04-28 03:08:08 +00:00
dma fix priority and debug
This commit is contained in:
87
ref/IR_EDGE_TRACE_FORMAT.md
Normal file
87
ref/IR_EDGE_TRACE_FORMAT.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Формат журнала фронтов ИК (`IR_EDGE_TRACE`)
|
||||
|
||||
Включается в `IR_config.h`: раскомментируйте `#define IR_EDGE_TRACE`.
|
||||
Размер кольца задаётся `IR_EDGE_TRACE_CAPACITY` (по умолчанию 512 записей).
|
||||
Память: примерно `IR_EDGE_TRACE_CAPACITY × 6` байт на экземпляр `IR_DecoderRaw`.
|
||||
|
||||
## Назначение
|
||||
|
||||
В ISR на каждый аппаратный фронт на линии приёмника пишется запись: абсолютное время `micros()`, уровень линии после фронта, флаги. Это **отдельное** кольцо от `subBuffer`: при переполнении `subBuffer` фронты в журнале всё равно сохраняются, пока не заполнится это кольцо.
|
||||
|
||||
При **передаче ИК по DMA** на STM32 важно, чтобы **прерывание приёма (EXTI)** имело **более высокий приоритет NVIC**, чем DMA канала передачи — иначе метки времени и сам поток фронтов в логе искажаются. См. **[`IR_DMA_ISR_signal_analysis.md`](../IR_DMA_ISR_signal_analysis.md)** (раздел 2.1).
|
||||
|
||||
## Вывод в Serial
|
||||
|
||||
При включённом `IR_EDGE_TRACE` протокол **сам** сбрасывает накопленные фронты в конце каждого `IR_DecoderRaw::tick()` (и на ветке «subBuffer пуст»): в цикле вызывается `edgeTraceFlushChunk(Serial, 48)`, пока в кольце есть записи.
|
||||
|
||||
Вручную тот же смысл: `edgeTraceFlushChunk(Print &out, maxRec)` печатает **ровно одну строку** (если есть что выгрузить; при пустом кольце выход без печати):
|
||||
|
||||
1. Символ перевода строки `\n` (отделяет блок от предыдущего вывода).
|
||||
2. Литеральный префикс **`@IRF1v1:`** (удобно grep-ать; не используйте этот текст в других `Serial.print`, чтобы строки не сливались).
|
||||
3. **Нижний регистр hex** без пробелов: полезная нагрузка бинарного блока ниже.
|
||||
4. `\n` в конце.
|
||||
|
||||
Другой текст (например `IR raw:` из `IRDEBUG_SERIAL_PACK`) не содержит `@IRF1v1:`, поэтому визуально и по парсеру блоки разделимы.
|
||||
|
||||
Если авто-сброс в `tick()` отключён или нужен другой `Print`, вызывайте `edgeTraceFlushChunk` в цикле, пока возвращаемое значение > 0.
|
||||
|
||||
## Бинарная полезная нагрузка (до кодирования в hex)
|
||||
|
||||
Все многобайтовые целые — **little-endian**, порядок байт от младшего к старшему.
|
||||
|
||||
| Смещение | Размер | Поле |
|
||||
|----------|--------|------|
|
||||
| 0 | 1 | **meta** |
|
||||
| 1 | 2 | **count** — число записей в этой строке (`uint16_t`) |
|
||||
| 3 | `count × 6` | Массив записей |
|
||||
|
||||
### meta (байт)
|
||||
|
||||
| Бит | Значение |
|
||||
|-----|----------|
|
||||
| 0 | **overflow**: кольцо хотя бы раз переполнилось с момента последнего `edgeTraceClear()`; новые фронты терялись, пока не освободилось место. Сбрасывается только `edgeTraceClear()`. |
|
||||
| 1 | **truncated**: после этой выгрузки в буфере ещё есть записи (chunk урезан лимитом `maxRec` или внутренним максимумом 64). |
|
||||
|
||||
Биты 2–7 зарезервированы (0).
|
||||
|
||||
### Одна запись (6 байт)
|
||||
|
||||
| Смещение в записи | Размер | Поле |
|
||||
|-------------------|--------|------|
|
||||
| 0 | 4 | **t_us** — значение `micros()` на момент фронта (`uint32_t`). При переполнении `micros()` (~70 мин) разницы между соседними записями всё ещё корректны, если обрабатывать как unsigned. |
|
||||
| 4 | 1 | **level** — уровень входа приёмника после фронта: `0` = LOW, `1` = HIGH (как `port->IDR & mask` в ISR). |
|
||||
| 5 | 1 | **flags** |
|
||||
| | | бит 0 **SKIP_DECODE** (`IR_EDGE_TRACE_F_SKIP_DECODE`): фронт записан, но в `subBuffer` **не** попал, потому что был активен `isPairSending` (пара передаёт). Алгоритм декодирования этот фронт не видит. |
|
||||
|
||||
## Минимальный разбор (Python 3)
|
||||
|
||||
```python
|
||||
import binascii, re
|
||||
|
||||
def parse_irf1_line(line: str):
|
||||
m = re.search(r"@IRF1v1:([0-9a-f]+)\s*$", line.strip())
|
||||
if not m:
|
||||
return None
|
||||
raw = binascii.unhexlify(m.group(1))
|
||||
meta, cnt_lo, cnt_hi = raw[0], raw[1], raw[2]
|
||||
count = cnt_lo | (cnt_hi << 8)
|
||||
recs = []
|
||||
p = 3
|
||||
for _ in range(count):
|
||||
t = raw[p] | (raw[p+1]<<8) | (raw[p+2]<<16) | (raw[p+3]<<24)
|
||||
level, flags = raw[p+4], raw[p+5]
|
||||
recs.append((t, level, flags))
|
||||
p += 6
|
||||
return {
|
||||
"overflow": bool(meta & 1),
|
||||
"truncated": bool(meta & 2),
|
||||
"count": count,
|
||||
"records": recs,
|
||||
}
|
||||
```
|
||||
|
||||
## Рекомендации по съёму
|
||||
|
||||
- При очень плотном потоке фронтов кольцо всё же может переполниться до следующего `tick()` — увеличьте `IR_EDGE_TRACE_CAPACITY` или уменьшите нагрузку на ISR.
|
||||
- Для «чистого» лога отключите или сильно урежьте `IRDEBUG_SERIAL_PACK`, иначе объём Serial будет очень большим.
|
||||
- Для полного сброса состояния перед тестом: `edgeTraceClear()`.
|
||||
Reference in New Issue
Block a user