RMT Sync Manager Workarounds/Alternatives

LukeMet
Posts: 4
Joined: Tue Jul 30, 2024 10:44 am

RMT Sync Manager Workarounds/Alternatives

Postby LukeMet » Sun Nov 17, 2024 8:47 pm

Hi there :) Been banging my head against the wall for quite some time with the RMT peripheral!

I'm trying to generate 8 signals, grouped into 4 pairs of 2 signals.

Each signal pair should work as follows:
  • Channel 1: Start pulse, then data protocol
  • Channel 2: Start pulse, then nothing
NB! The Start pulses of each signal pair need to be synchronised. The four pairs are independent, and loop at a given frequency.

I'm not at my oscilloscope right now, but here's what I'm aiming for for each pair:
SignalDiagram.jpg
SignalDiagram.jpg (242.85 KiB) Viewed 720 times

My problem lies in synchronising the pairs, as I have found the following hardware limitations:
Board | No. RMT TX Ch. | Sync Manager Supported?
ESP32 | 8 |NO
ESP32-S3 | 4 |YES
ESP32-C3 | 2 |YES

ESP32 has enough RMT channels, but no Sync Manager is not supported on it. I thought perhaps I could get around it by using 2x ESP32-S3s, generating 2x2 signals each, but I could only install one Sync Manager before producing an error: "rmt_new_sync_manager(383): no free sync manager in the group". So it seems as though I will need to look beyond the RMT Sync Manager.

I thought of using " rmt_tx_event_callbacks_t::on_trans_done" to trigger some callback that would handle Channel 2, but I am running my signals in looping mode, and the on_trans_done event is only triggered when I stop transmitting the signal (rmt_disable()), not at the end of each signal loop, as I had hoped. So no luck there.

I then tried using interrupts, hoping to read a rising edge on Channel 1, set a GPIO on Channel2, vTaskDelay() for the pulse width, reset the GPIO on Channel 2, delay for the remainder of the signal. But again I had no luck there, as the smallest delay I could generate was 1ms (would need around 1us resolution). I tried configuring CONFIG_FREERTOS_HZ to the required value of 1000000 Hz (1MHz = 1us tick), but it would constantly reset to 100Hz in sdkconfig (I could however set it to 1000 Hz - still not fast enough at 1ms tick).

Is this interrupt approach a viable approach? Is CONFIG_FREERTOS_HZ the correct variable to be modifying in order to increase the tick rate? Is it possible to configure a 1MHz tick?

More generally, does anyone else have any ideas on how else to generate and synchronise the signal pairs? Would really appreciate any help, thanks in advance! Happy to share code if needed :)
Last edited by LukeMet on Tue Nov 19, 2024 7:21 am, edited 1 time in total.

ESP_Sprite
Posts: 9764
Joined: Thu Nov 26, 2015 4:08 am

Re: RMT Synch Manager Workarounds/Alternatives

Postby ESP_Sprite » Mon Nov 18, 2024 2:25 am

Perhaps it's easier to use a different peripheral? The ESP32 can put its I2S module in parallel mode, and the ESP32S3 has the LCD peripheral; both can output 8 bit in parallel. Would those be options?

boarchuz
Posts: 606
Joined: Tue Aug 21, 2018 5:28 am

Re: RMT Synch Manager Workarounds/Alternatives

Postby boarchuz » Mon Nov 18, 2024 2:37 am

Are you using the high level RMT driver?

I would try commenting out this line:
https://github.com/espressif/esp-idf/bl ... _tx.c#L767
So that each channel is setup and ready to transmit, just waiting on that START bit, and then rmt_ll_tx_start‎ both channels in quick succession (with a little assembly you could even make the store instructions to each reg successive).

LukeMet
Posts: 4
Joined: Tue Jul 30, 2024 10:44 am

Re: RMT Sync Manager Workarounds/Alternatives

Postby LukeMet » Mon Nov 18, 2024 4:41 pm

Thanks for the suggestions! That approach looks promising, as commenting out rmt_ll_tx_start(hal->regs, channel_id); seemed to disable the transmission when I first ran it on an ESP32-S3. However, I changed target to an ESP32 (need 8x Tx), and suddenly this didn't work, the channels transmitted regardless.

I went deeper and modified rmt_ll_tx_start within hal/rmt_ll.h, setting conf1.tx_start = 0:

Code: Select all

static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel)
{
    dev->conf_ch[channel].conf1.tx_start = 0; //EDIT - default 1
}
This didn't work either, somehow the channels are still transmitting. I've now set it back to 1. Only when I comment out rmt_tx_do_transaction(), does it prevent transmission inside rmt_transmit(). But I think disabling it this far back would remove the timing advantage you described above. Maybe you can see what else I need to do inside there?

If I can get that to work, this is the function I wrote to control the transmission start myself:
I modified rmt_tx.c as you described, and wrote my own function within it, which I can hopefully call in main:

Code: Select all

static void IRAM_ATTR rmt_tx_start(rmt_channel_handle_t channel)
{   
    rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);

    rmt_channel_t *tx_channel = &tx_chan->base;
    rmt_group_t *group = tx_channel->group;
    rmt_hal_context_t *hal = &group->hal;
    int channel_id = tx_channel->channel_id;

    rmt_ll_tx_start(hal->regs, channel_id);
    
    /*
    // alt. replicate rmt_ll_tx_start:
    rmt_dev_t *dev = hal->regs;
    uint32_t channel_int = channel_id;
    dev->conf_ch[channel_int].conf1.tx_start = 1;
    */
}
I just hacked it together quickly, so it's only for one channel (want to expand to a channel pair) and the variable names are quite poor. But perhaps you can see whether the logic is reasonable/some modifications you'd make? NB! I'm using v5.1.5 as I need to include Arduino as a component and an Arduino library for later functions in my project! But right now, I'm only using IDF v5.1.5 :)

Who is online

Users browsing this forum: No registered users and 37 guests