Page 1 of 1

Remote peripheral ignores rmt_tx_stop command

Posted: Wed Dec 13, 2017 5:22 pm
by clarkster
I am trying to get the remote peripheral to stop sending pulses if I issue a new command to it. The reason I need to do this is because I am need to control a stepper motor based on an unstable signal. The signal may at first cause the stepper to move 100 steps clockwise, then shortly after that it may supersede that instruction with a command to move 10 steps counter-clockwise. This could often occur before the remote peripheral
has finished sending the 100 pulses as ordered by the previous command. So far I have been unable to stop the remote peripheral from sending pulses once it has started.

Today I simply tried to issue a stop command one second after starting a long series of pulses. As far as I can tell, the stop command does not work. In order to demonstrate this, here is a portion of the rmt_example_nec_task from the rmt_nec_tx_rx example project. The code below contains the only modifications to the example project.

Code: Select all

// Portion of rmt_example_nec_task
	//To send data according to the waveform items.
        ESP_LOGI(NEC_TAG, "Before rmt_write_items");
        rmt_write_items(channel, item, item_num, false);
        ESP_LOGI(NEC_TAG, "After rmt_write_items");
        
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        rmt_tx_stop(channel);                  // should stop, but it doesn't
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        rmt_tx_start(channel, true);        // if it stopped, should restart 
        						  // and send 100 more NEC waveforms
        
        //Wait until sending is done.
        rmt_wait_tx_done(channel, portMAX_DELAY);
        //before we free the data, make sure sending is already done.
        free(item);
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
The changes to the example are simple:

1. Change the rmt_write_items wait_tx_done flag from true to false
2. Add code after the rmt_write_items command to delay 1 second, stop transmission, delay 1 second, and then restart transmission at the beginning. This step does not work at all.

Am I misusing the stop command? Or have I found something that needs to be fixed?

Can anyone give me any advise how to accommodate my use case?

Re: Remote peripheral ignores rmt_tx_stop command

Posted: Thu Dec 14, 2017 9:56 am
by Bobbleballs
Is the looparound or continuous sending mode enabled?
I found that if you have the RMT_REG_TX_CONTI_MODE bit enabled that it would start sending even if RMT_TX_START_CHn was not.
Maybe you need to disable that as well?

Re: Remote peripheral ignores rmt_tx_stop command

Posted: Thu Dec 14, 2017 4:36 pm
by clarkster
Bobbleballs,

I've checked the example code and I've also checked rmt.c to make sure the example isn't calling any functions that set that register. So, yes, I'm sure the example isn't setting RMT_REG_TX_CONTI_MODE either directly or using the API.

Have you had success using the stop command if this register is not set? If so, would you mind sharing a example of this?

I wish Espressif would give us some guidance on this. I may be wrong, but it sure appears to me that the stop command is totally broken.

Re: Remote peripheral ignores rmt_tx_stop command

Posted: Thu Dec 14, 2017 5:10 pm
by clarkster
Bobbleballs

Right after replying to you, I thought of something. I was correct, I did not have RMT_REG_TX_CONTI_MODE set, but it just occurred to me that the example did cause the RMT_MEM_TX_WRAP_EN bit to be set.

So I modified my example to add
RMT.apb_conf.mem_tx_wrap_en = false;
immediately before the stop command and.....it worked!

THANK YOU!

Those two bits seem to do pretty much the same thing. Looking at the TRM, I see that RMT_REG_TX_CONTI_MODE is set on a channel by channel basis whereas RMT_MEM_TX_WRAP_EN is set for the entire remote peripheral. This does not sound good. This means whenever you use the API rmt_write_items function and rmt_item contains more memory than will fit in the memory, then RMT_MEM_TX_WRAP_EN is set for the entire remote peripheral. I'll have to test this but I am afraid it will make it difficult to use multiple channels of the remote peripheral, some with needing wrapping and others not needing wrapping.

I also notice the rmt_set_tx_wrap_em command takes a channel parameter, but the channel parameter is unused because there is nothing to do with it....it sets the RMT_MEM_TX_WRAP_EN bit but there is not one of those per channel.

I wonder if the API could be rewritten to use the RMT_REG_TX_CONTI_MODE on a per channel basis rather than use the RMT_MEM_TX_WRAP_EN bit which affects the entire peripheral. I will experiment with this too.

Re: Remote peripheral ignores rmt_tx_stop command

Posted: Mon Feb 05, 2018 9:38 pm
by clarkster
I found how to stop the remote peripheral from transmitting.

First of all, don't waste time trying the rmt_tx_stop function. That does nothing....at least it doesn't stop transmission.

Secondly, don't waste time trying to reset the tx_start bit of the Conf1 register. The rmt_tx_stop function does this and it doesn't work either.

The only way that I have been able to stop transmissions is to set the period portion of the rmt_item structure to zero. But the problem is the rmt is in the process of reading the memory and there is no way to know where it is reading it at. So you can't set just a single memory location to zero.

The solution is to reset all the memory in the memory buffer, like this:

Code: Select all

for (int i = 0; i < 64; i++) {
	RMTMEM.chan[(int) channel].data32[i].val = 0;
}     


This sets both period and duration values in the rmt_item structure to zero. This causes the rmt to stop transmitting as soon as it reads the next memory location.

If you are using more than one memory buffer per channel, you will need to change the count (64) in the for loop to the correct number of bytes in your buffer.

Re: Remote peripheral ignores rmt_tx_stop command

Posted: Mon Feb 05, 2018 9:56 pm
by Bobbleballs
Hi sorry for the lack of reply.
Yes this is what I found also. However I know when I want to stop sending as I am sending packets of data. So when I need the data to end I set the last part of the data to 0 which will cause the rmt to stop sending when it hits the blank space.
This actually ended up working really well for me and I got my application working pretty much perfectly.
One thing I found was that the processor isn't fast enough to deal with 8 channels of rmt at once. So it struggles to handle all 8 interrupts to fill the next data. However I found that 4 channels simultaneously works quite well. So I multiplexed the rmt channels so that only 4 were working at the same time using semaphores. When one channel reaches the data end it releases a semaphore to allow the next channel to start.
Glad you got your stuff sorted.

Re: Remote peripheral ignores rmt_tx_stop command

Posted: Mon Feb 05, 2018 10:06 pm
by clarkster
I am sure disappointed to hear that the ESP32 cannot handle all rmts working at once.