RMT receiving oddities
Posted: Sun May 11, 2025 1:07 pm
I'm implementing transmitters and receivers for the SENT (SAE J2716) protocol, a tick-based protocol (default tick length 3µs), which transmits a SYNC pulse (length 56 ticks), then 6 + 2 nibbles based pulses with different lengths (12 + nibble-value). Here's an example from my scope:
Sending this using RMT is straightforward and works very well.
Receiving though seems to be more complicated. Note that I do my decoding decoupled from the rx callback
and have the callback marked w/ IRAM_ATTR.
Here's portions from my code so you can see how I'm initializing RMT:
My concrete example (as seen on the scope) is using a 3µs tick time. SENT pulse lengths are always measured from falling edge to falling edge.
Here's the log output trying to receive 5 frames:
The problem: I can't seem to set the parameters correctly to receive SYNC pulses. SYNC pulses are supposed to have a length of 168µs, but when I try to configure it like that:
Then nothing works anymore and I'm just getting a loop full of:
Now: Limiting signal_range_max_ns to 100 * 1000 seems to work somewhat, at least I can see the data nibbles being correctly deciphered. But then I can't no longer read the 168µs SYNC pulse and instead I'm getting spurious symbols with length 0. If you see compare the log output, you'll see that I frequently get those "in the middle" of the correctly detected symbols. Since I can rule out the sender doing strange things, the receiver must be the problem.
What is happening here? Why is the signal_range_max_ns not allowing 175 and why am I getting 0 lengths (followed by symbols where the polarity is switched, e.g. level0 is HIGH and level1 is LOW whereas they're typically vice versa).
Sending this using RMT is straightforward and works very well.
Receiving though seems to be more complicated. Note that I do my decoding decoupled from the rx callback
and have the callback marked w/ IRAM_ATTR.
Here's portions from my code so you can see how I'm initializing RMT:
Code: Select all
void init() {
// Configure RMT RX channel
rmt_rx_channel_config_t rx_channel_config = {
.gpio_num = gpio_num_,
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 1'000'000, // 1 MHz, 1 tick = 1 µs
.mem_block_symbols = MemBlockBuffer,
};
ESP_ERROR_CHECK(rmt_new_rx_channel(&rx_channel_config, &rmt_channel_));
// Install RX done callback
rmt_rx_event_callbacks_t cbs = {
.on_recv_done = rxDoneCallback,
};
ESP_ERROR_CHECK(rmt_rx_register_event_callbacks(rmt_channel_, &cbs, this));
// Enable RMT RX channel
ESP_ERROR_CHECK(rmt_enable(rmt_channel_));
startReceive();
}
void startReceive() {
// Allocate buffer for received symbols
static rmt_symbol_word_t symbols[MemBlockBuffer]; // Maximum supported by hardware
// Configure RX parameters - adjust for our tick period
auto config = rmt_receive_config_t {
.signal_range_min_ns = 1 * 1000, // 1µs resolution
.signal_range_max_ns = 100 * 1000, // Max sync high pulse
};
ESP_ERROR_CHECK(rmt_receive(rmt_channel_, symbols, sizeof(symbols), &config));
}
Here's the log output trying to receive 5 frames:
Code: Select all
D (4692) rmt: new group(0) at 0x3fcb15a4, occupy=ffffff00
D (4694) intr_alloc: Connected src 40 to int 12 (cpu 0)
D (4694) rmt: group (0) clock resolution:80000000Hz
D (4694) rmt: new rx channel(0,0) at 0x3fcb14c0, gpio=1, res=1000000Hz, hw_mem_base=0x60016b00, ping_pong_size=72
Waiting for 5 SENT frames on GPIO 1 (tick period 3 µs)...
D (4696) TASK: SENTReceiver created.
D (4697) TASK: SENTReceiver resumed.
D (4697) TASK: SENTReceiver entering code.
D (4697) SENTReceiver: SENTReceiver task started
D (4698) SENTReceiver: [RAW] LOW 14 us -> HIGH 21 us
D (4698) SENTReceiver: [STAT] 0x0
D (4699) SENTReceiver: [RAW] LOW 15 us -> HIGH 24 us
D (4699) SENTReceiver: [DATA] 0x1
D (4699) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4700) SENTReceiver: [DATA] 0x2
D (4700) SENTReceiver: [RAW] LOW 15 us -> HIGH 30 us
D (4700) SENTReceiver: [DATA] 0x3
D (4701) SENTReceiver: [RAW] LOW 15 us -> HIGH 33 us
D (4701) SENTReceiver: [DATA] 0x4
D (4701) SENTReceiver: [RAW] LOW 15 us -> HIGH 36 us
D (4702) SENTReceiver: [DATA] 0x5
D (4702) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4703) SENTReceiver: [DATA] 0x6
D (4703) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4703) SENTReceiver: [CRC ] 0x2 (valid)
D (4704) SENTReceiver: [FRAME] Status:0x0 Data:[0x1,0x2,0x3,0x4,0x5,0x6] CRC:0x2 (valid)
Frame 1/5 received: [0x0] 0x1 0x2 0x3 0x4 0x5 0x6 [0x2 (valid)
D (4705) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
D (4705) SENTReceiver: Incomplete frame (0/8 nibbles) terminated by zero-duration pulse
D (4707) SENTReceiver: [RAW] LOW 14 us -> HIGH 21 us
D (4707) SENTReceiver: [STAT] 0x0
D (4708) SENTReceiver: [RAW] LOW 15 us -> HIGH 24 us
D (4708) SENTReceiver: [DATA] 0x1
D (4709) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4709) SENTReceiver: [DATA] 0x2
D (4709) SENTReceiver: [RAW] LOW 15 us -> HIGH 30 us
D (4710) SENTReceiver: [DATA] 0x3
D (4710) SENTReceiver: [RAW] LOW 15 us -> HIGH 33 us
D (4711) SENTReceiver: [DATA] 0x4
D (4711) SENTReceiver: [RAW] LOW 15 us -> HIGH 36 us
D (4712) SENTReceiver: [DATA] 0x5
D (4712) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4713) SENTReceiver: [DATA] 0x6
D (4713) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4713) SENTReceiver: [CRC ] 0x2 (valid)
D (4714) SENTReceiver: [FRAME] Status:0x0 Data:[0x1,0x2,0x3,0x4,0x5,0x6] CRC:0x2 (valid)
Frame 2/5 received: [0x0] 0x1 0x2 0x3 0x4 0x5 0x6 [0x2 (valid)
D (4715) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
D (4716) SENTReceiver: Incomplete frame (0/8 nibbles) terminated by zero-duration pulse
D (4717) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4717) SENTReceiver: [STAT] 0x6
D (4718) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4718) SENTReceiver: [DATA] 0x2
D (4719) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
D (4719) SENTReceiver: Incomplete frame (2/8 nibbles) terminated by zero-duration pulse
D (4720) SENTReceiver: [RAW] LOW 15 us -> HIGH 21 us
D (4721) SENTReceiver: [STAT] 0x0
D (4721) SENTReceiver: [RAW] LOW 14 us -> HIGH 25 us
D (4722) SENTReceiver: [DATA] 0x1
D (4722) SENTReceiver: [RAW] LOW 14 us -> HIGH 27 us
D (4723) SENTReceiver: [DATA] 0x2
D (4723) SENTReceiver: [RAW] LOW 15 us -> HIGH 30 us
D (4724) SENTReceiver: [DATA] 0x3
D (4724) SENTReceiver: [RAW] LOW 15 us -> HIGH 33 us
D (4724) SENTReceiver: [DATA] 0x4
D (4725) SENTReceiver: [RAW] LOW 15 us -> HIGH 36 us
D (4725) SENTReceiver: [DATA] 0x5
D (4726) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4726) SENTReceiver: [DATA] 0x6
D (4727) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4727) SENTReceiver: [CRC ] 0x2 (valid)
D (4728) SENTReceiver: [FRAME] Status:0x0 Data:[0x1,0x2,0x3,0x4,0x5,0x6] CRC:0x2 (valid)
Frame 3/5 received: [0x0] 0x1 0x2 0x3 0x4 0x5 0x6 [0x2 (valid)
D (4729) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
D (4729) SENTReceiver: Incomplete frame (0/8 nibbles) terminated by zero-duration pulse
D (4730) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4731) SENTReceiver: [STAT] 0x6
D (4731) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4732) SENTReceiver: [DATA] 0x2
D (4732) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
D (4733) SENTReceiver: Incomplete frame (2/8 nibbles) terminated by zero-duration pulse
D (4734) SENTReceiver: [RAW] LOW 14 us -> HIGH 21 us
D (4735) SENTReceiver: [STAT] 0x0
D (4735) SENTReceiver: [RAW] LOW 15 us -> HIGH 24 us
D (4735) SENTReceiver: [DATA] 0x1
D (4736) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4736) SENTReceiver: [DATA] 0x2
D (4737) SENTReceiver: [RAW] LOW 15 us -> HIGH 30 us
D (4737) SENTReceiver: [DATA] 0x3
D (4738) SENTReceiver: [RAW] LOW 15 us -> HIGH 33 us
D (4738) SENTReceiver: [DATA] 0x4
D (4738) SENTReceiver: [RAW] LOW 15 us -> HIGH 36 us
D (4739) SENTReceiver: [DATA] 0x5
D (4739) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4740) SENTReceiver: [DATA] 0x6
D (4740) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4741) SENTReceiver: [CRC ] 0x2 (valid)
D (4741) SENTReceiver: [FRAME] Status:0x0 Data:[0x1,0x2,0x3,0x4,0x5,0x6] CRC:0x2 (valid)
Frame 4/5 received: [0x0] 0x1 0x2 0x3 0x4 0x5 0x6 [0x2 (valid)
D (4742) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
D (4743) SENTReceiver: Incomplete frame (0/8 nibbles) terminated by zero-duration pulse
D (4745) SENTReceiver: [RAW] LOW 14 us -> HIGH 21 us
D (4745) SENTReceiver: [STAT] 0x0
D (4745) SENTReceiver: [RAW] LOW 15 us -> HIGH 24 us
D (4746) SENTReceiver: [DATA] 0x1
D (4746) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4747) SENTReceiver: [DATA] 0x2
D (4747) SENTReceiver: [RAW] LOW 15 us -> HIGH 30 us
D (4748) SENTReceiver: [DATA] 0x3
D (4748) SENTReceiver: [RAW] LOW 15 us -> HIGH 33 us
D (4749) SENTReceiver: [DATA] 0x4
D (4749) SENTReceiver: [RAW] LOW 15 us -> HIGH 36 us
D (4749) SENTReceiver: [DATA] 0x5
D (4750) SENTReceiver: [RAW] LOW 15 us -> HIGH 39 us
D (4750) SENTReceiver: [DATA] 0x6
D (4751) SENTReceiver: [RAW] LOW 15 us -> HIGH 27 us
D (4751) SENTReceiver: [CRC ] 0x2 (valid)
D (4752) SENTReceiver: [FRAME] Status:0x0 Data:[0x1,0x2,0x3,0x4,0x5,0x6] CRC:0x2 (valid)
Frame 5/5 received: [0x0] 0x1 0x2 0x3 0x4 0x5 0x6 [0x2 (valid)
D (4753) SENTReceiver: [RAW] LOW 15 us -> HIGH 0 us
Received 5 frames, dropped 0 symbols, 6 short frames
D (4754) TASK: SENTReceiver will cancel...
D (4754) SENTReceiver: Incomplete frame (0/8 nibbles) terminated by zero-duration pulse
D (4755) SENTReceiver: SENTReceiver task stopped
D (4755) TASK: SENTReceiver exited code regularly (cancel).
D (4756) TASK: SENTReceiver cancelled.
D (4756) rmt: del rx channel(0,0)
D (4757) rmt: del group(0)
D (4757) TASK: SENTReceiver ~Task
ESP32>
Code: Select all
auto config = rmt_receive_config_t {
.signal_range_min_ns = 1 * 1000, // 1µs resolution
.signal_range_max_ns = 175 * 1000, // Max sync high pulse
};
Code: Select all
E rmt: user buffer too small, received symbols truncated
What is happening here? Why is the signal_range_max_ns not allowing 175 and why am I getting 0 lengths (followed by symbols where the polarity is switched, e.g. level0 is HIGH and level1 is LOW whereas they're typically vice versa).