espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13k stars 7.12k forks source link

RMT - rmt_ll_tx_stop missing from esp32 port (IDFGH-12543) #13548

Open florentbr opened 3 months ago

florentbr commented 3 months ago

Is your feature request related to a problem?

The RMT function rmt_ll_tx_stop is present in the ESP32-S2/S3/C3/C6/H2/P4 port but missing in the ESP32 port.

This function is quite useful to stop a transmission.

Describe the solution you'd like.

Changing the channel memory ownership has no effect. However, I found that setting RMT_MEM_SIZE_CHn = 0 can stop the transmission right away:

__attribute__((always_inline))
static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
{
    const uint32_t cache = dev->conf_ch[channel].conf0.val;
    dev->conf_ch[channel].conf0.mem_size = 0;
    dev->conf_ch[channel].conf0.val = cache;
}

Could you include it in the ESP32 port ? Unless there's side-effects I'm not aware of ?

Describe alternatives you've considered.

No response

Additional context.

No response

suda-morris commented 3 months ago

Hi @florentbr

As you already found, the ESP32 RMT doesn't provide a way to stop the transmission asynchronously. Thus in our driver, we use a trick: https://github.com/espressif/esp-idf/blob/master/components/esp_driver_rmt/src/rmt_tx.c#L827-L832

This way, the hardware can also stop the transmission, but not immediately.

Set the memory block size to 0 may force the hardware into an unknown state IMHO, I need to confirm this workaround with the Espressif digital team.

florentbr commented 3 months ago

Set the memory block size to 0 may force the hardware into an unknown state IMHO, I need to confirm this workaround with the Espressif digital team.

I use this trick with an ESP32-D0WD-V3 to stop the transmission with a synchronized interrupt on a long symbol. The FSM seems to recover just fine since I send a new symbol right away.

This way, the hardware can also stop the transmission, but not immediately.

Writing a 0 symbol is not a option for me since it has to wait for the previous symbol to end. It makes the output signal drifting away from an input synchronisation.

suda-morris commented 3 months ago

@florentbr Your workaround can work on esp32 as long as you don't enable the wrap mode, rmt_ll_tx_enable_wrap.

florentbr commented 3 months ago

@florentbr Your workaround can work on esp32 as long as you don't enable the wrap mode, rmt_ll_tx_enable_wrap.

Or as long as you disable it before clearing RMT_MEM_SIZE_CHn:


 __attribute__((always_inline))
static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel)
{
    const uint32_t apb_conf = dev->apb_conf.val;
    const uint32_t conf0 = dev->conf_ch[channel].conf0.val;

    dev->apb_conf.val = apb_conf & ~RMT_MEM_TX_WRAP_EN;
    dev->conf_ch[channel].conf0.val = conf0 & ~RMT_MEM_SIZE_CH0;
    dev->apb_conf.val = apb_conf;
    dev->conf_ch[channel].conf0.val = conf0;
}

The wrap mode covers all the channels, so I don't know what would happen if another channel were to end just before restoring the wrap mode. I would still consider it better than pool waiting for the end event.