diff --git a/components/esp_driver_rmt/include/driver/rmt_encoder.h b/components/esp_driver_rmt/include/driver/rmt_encoder.h index d10e3a5737..a1fe60a8b5 100644 --- a/components/esp_driver_rmt/include/driver/rmt_encoder.h +++ b/components/esp_driver_rmt/include/driver/rmt_encoder.h @@ -26,6 +26,7 @@ typedef enum { RMT_ENCODING_RESET = 0, /*!< The encoding session is in reset state */ RMT_ENCODING_COMPLETE = (1 << 0), /*!< The encoding session is finished, the caller can continue with subsequent encoding */ RMT_ENCODING_MEM_FULL = (1 << 1), /*!< The encoding artifact memory is full, the caller should return from current encoding session */ + RMT_ENCODING_WITH_EOF = (1 << 2), /*!< The encoding session has inserted the EOF marker to the symbol stream */ } rmt_encode_state_t; /** @@ -169,6 +170,8 @@ esp_err_t rmt_bytes_encoder_update_config(rmt_encoder_handle_t bytes_encoder, co /** * @brief Create RMT copy encoder, which copies the given RMT symbols into RMT memory * + * @note When transmitting using a copy encoder, ensure that the input data is already formatted as `rmt_symbol_word_t`. + * * @param[in] config Copy encoder configuration * @param[out] ret_encoder Returned encoder handle * @return diff --git a/components/esp_driver_rmt/src/rmt_encoder_bytes.c b/components/esp_driver_rmt/src/rmt_encoder_bytes.c index 6b87186f69..5bf5e9acb3 100644 --- a/components/esp_driver_rmt/src/rmt_encoder_bytes.c +++ b/components/esp_driver_rmt/src/rmt_encoder_bytes.c @@ -42,7 +42,8 @@ static size_t rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t chan // how many symbols will be generated by the encoder size_t mem_want = (data_size - byte_index - 1) * 8 + (8 - bit_index); // how many symbols we can save for this round - size_t mem_have = tx_chan->mem_end - tx_chan->mem_off; + size_t symbol_off = tx_chan->mem_off_bytes / sizeof(rmt_symbol_word_t); + size_t mem_have = tx_chan->mem_end - symbol_off; // where to put the encoded symbols? DMA buffer or RMT HW memory rmt_symbol_word_t *mem_to_nc = NULL; if (channel->dma_chan) { @@ -57,7 +58,7 @@ static size_t rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t chan if (channel->dma_chan) { // mark the start descriptor - if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { + if (symbol_off < tx_chan->ping_pong_symbols) { desc0 = &tx_chan->dma_nodes_nc[0]; } else { desc0 = &tx_chan->dma_nodes_nc[1]; @@ -74,9 +75,9 @@ static size_t rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t chan } while ((len > 0) && (bit_index < 8)) { if (cur_byte & (1 << bit_index)) { - mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit1; + mem_to_nc[symbol_off++] = bytes_encoder->bit1; } else { - mem_to_nc[tx_chan->mem_off++] = bytes_encoder->bit0; + mem_to_nc[symbol_off++] = bytes_encoder->bit0; } len--; bit_index++; @@ -89,7 +90,7 @@ static size_t rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t chan if (channel->dma_chan) { // mark the end descriptor - if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { + if (symbol_off < tx_chan->ping_pong_symbols) { desc1 = &tx_chan->dma_nodes_nc[0]; } else { desc1 = &tx_chan->dma_nodes_nc[1]; @@ -119,12 +120,14 @@ static size_t rmt_encode_bytes(rmt_encoder_t *encoder, rmt_channel_handle_t chan } // reset offset pointer when exceeds maximum range - if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) { + if (symbol_off >= tx_chan->ping_pong_symbols * 2) { if (channel->dma_chan) { desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t); desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; } - tx_chan->mem_off = 0; + tx_chan->mem_off_bytes = 0; + } else { + tx_chan->mem_off_bytes = symbol_off * sizeof(rmt_symbol_word_t); } *ret_state = state; diff --git a/components/esp_driver_rmt/src/rmt_encoder_copy.c b/components/esp_driver_rmt/src/rmt_encoder_copy.c index 55bb42bdd8..8a9a2977c1 100644 --- a/components/esp_driver_rmt/src/rmt_encoder_copy.c +++ b/components/esp_driver_rmt/src/rmt_encoder_copy.c @@ -20,11 +20,11 @@ static esp_err_t rmt_copy_encoder_reset(rmt_encoder_t *encoder) } static size_t rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t channel, - const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) + const void *input_symbols, size_t data_size, rmt_encode_state_t *ret_state) { rmt_copy_encoder_t *copy_encoder = __containerof(encoder, rmt_copy_encoder_t, base); rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base); - rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)primary_data; + rmt_symbol_word_t *symbols = (rmt_symbol_word_t *)input_symbols; rmt_encode_state_t state = RMT_ENCODING_RESET; rmt_dma_descriptor_t *desc0 = NULL; rmt_dma_descriptor_t *desc1 = NULL; @@ -33,7 +33,8 @@ static size_t rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t chann // how many symbols will be copied by the encoder size_t mem_want = (data_size / 4 - symbol_index); // how many symbols we can save for this round - size_t mem_have = tx_chan->mem_end - tx_chan->mem_off; + size_t symbol_off = tx_chan->mem_off_bytes / sizeof(rmt_symbol_word_t); + size_t mem_have = tx_chan->mem_end - symbol_off; // where to put the encoded symbols? DMA buffer or RMT HW memory rmt_symbol_word_t *mem_to_nc = NULL; if (channel->dma_chan) { @@ -48,7 +49,7 @@ static size_t rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t chann if (channel->dma_chan) { // mark the start descriptor - if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { + if (symbol_off < tx_chan->ping_pong_symbols) { desc0 = &tx_chan->dma_nodes_nc[0]; } else { desc0 = &tx_chan->dma_nodes_nc[1]; @@ -57,13 +58,13 @@ static size_t rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t chann size_t len = encode_len; while (len > 0) { - mem_to_nc[tx_chan->mem_off++] = symbols[symbol_index++]; + mem_to_nc[symbol_off++] = symbols[symbol_index++]; len--; } if (channel->dma_chan) { // mark the end descriptor - if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { + if (symbol_off < tx_chan->ping_pong_symbols) { desc1 = &tx_chan->dma_nodes_nc[0]; } else { desc1 = &tx_chan->dma_nodes_nc[1]; @@ -91,12 +92,14 @@ static size_t rmt_encode_copy(rmt_encoder_t *encoder, rmt_channel_handle_t chann } // reset offset pointer when exceeds maximum range - if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) { + if (symbol_off >= tx_chan->ping_pong_symbols * 2) { if (channel->dma_chan) { desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t); desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; } - tx_chan->mem_off = 0; + tx_chan->mem_off_bytes = 0; + } else { + tx_chan->mem_off_bytes = symbol_off * sizeof(rmt_symbol_word_t); } *ret_state = state; diff --git a/components/esp_driver_rmt/src/rmt_encoder_simple.c b/components/esp_driver_rmt/src/rmt_encoder_simple.c index 6697ccb5a0..2a530739a0 100644 --- a/components/esp_driver_rmt/src/rmt_encoder_simple.c +++ b/components/esp_driver_rmt/src/rmt_encoder_simple.c @@ -37,6 +37,7 @@ static size_t rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t cha rmt_encode_state_t state = RMT_ENCODING_RESET; rmt_dma_descriptor_t *desc0 = NULL; rmt_dma_descriptor_t *desc1 = NULL; + size_t symbol_off = tx_chan->mem_off_bytes / sizeof(rmt_symbol_word_t); // where to put the encoded symbols? DMA buffer or RMT HW memory rmt_symbol_word_t *mem_to_nc = NULL; @@ -48,7 +49,7 @@ static size_t rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t cha if (channel->dma_chan) { // mark the start descriptor - if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { + if (symbol_off < tx_chan->ping_pong_symbols) { desc0 = &tx_chan->dma_nodes_nc[0]; } else { desc0 = &tx_chan->dma_nodes_nc[1]; @@ -69,11 +70,11 @@ static size_t rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t cha // when then called with a larger buffer. size_t encode_len = 0; //total amount of symbols written to rmt memory bool is_done = false; - while (tx_chan->mem_off < tx_chan->mem_end) { + while (symbol_off < tx_chan->mem_end) { if (simple_encoder->ovf_buf_parsed_pos < simple_encoder->ovf_buf_fill_len) { // Overflow buffer has data from the previous encoding call. Copy one entry // from that. - mem_to_nc[tx_chan->mem_off++] = simple_encoder->ovf_buf[simple_encoder->ovf_buf_parsed_pos++]; + mem_to_nc[symbol_off++] = simple_encoder->ovf_buf[simple_encoder->ovf_buf_parsed_pos++]; encode_len++; } else { // Overflow buffer is empty, so we don't need to empty that first. @@ -87,11 +88,11 @@ static size_t rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t cha // Try to have the callback write the data directly into RMT memory. size_t enc_size = simple_encoder->callback(data, data_size, simple_encoder->last_symbol_index, - tx_chan->mem_end - tx_chan->mem_off, - &mem_to_nc[tx_chan->mem_off], + tx_chan->mem_end - symbol_off, + &mem_to_nc[symbol_off], &is_done, simple_encoder->arg); encode_len += enc_size; - tx_chan->mem_off += enc_size; + symbol_off += enc_size; simple_encoder->last_symbol_index += enc_size; if (is_done) { break; // we're done, no more data to write to RMT memory. @@ -130,7 +131,7 @@ static size_t rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t cha if (channel->dma_chan) { // mark the end descriptor - if (tx_chan->mem_off < tx_chan->ping_pong_symbols) { + if (symbol_off < tx_chan->ping_pong_symbols) { desc1 = &tx_chan->dma_nodes_nc[0]; } else { desc1 = &tx_chan->dma_nodes_nc[1]; @@ -153,12 +154,14 @@ static size_t rmt_encode_simple(rmt_encoder_t *encoder, rmt_channel_handle_t cha } // reset offset pointer when exceeds maximum range - if (tx_chan->mem_off >= tx_chan->ping_pong_symbols * 2) { + if (symbol_off >= tx_chan->ping_pong_symbols * 2) { if (channel->dma_chan) { desc1->dw0.length = tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t); desc1->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; } - tx_chan->mem_off = 0; + tx_chan->mem_off_bytes = 0; + } else { + tx_chan->mem_off_bytes = symbol_off * sizeof(rmt_symbol_word_t); } *ret_state = state; diff --git a/components/esp_driver_rmt/src/rmt_private.h b/components/esp_driver_rmt/src/rmt_private.h index 011ef58462..d2bc9e83ba 100644 --- a/components/esp_driver_rmt/src/rmt_private.h +++ b/components/esp_driver_rmt/src/rmt_private.h @@ -183,6 +183,7 @@ typedef struct { struct { uint32_t eot_level : 1; // Set the output level for the "End Of Transmission" uint32_t encoding_done: 1; // Indicate whether the encoding has finished (not the encoding of transmission) + uint32_t need_eof_mark: 1; // Indicate whether need to insert an EOF mark (a special RMT symbol) } flags; } rmt_tx_trans_desc_t; @@ -191,7 +192,7 @@ struct rmt_tx_channel_t { rmt_channel_t base; // channel base class rmt_symbol_word_t *dma_mem_base; // base address of RMT channel DMA buffer rmt_symbol_word_t *dma_mem_base_nc; // base address of RMT channel DMA buffer, accessed in non-cached way - size_t mem_off; // runtime argument, indicating the next writing position in the RMT hardware memory + size_t mem_off_bytes; // runtime argument, indicating the next writing position in the RMT hardware memory, the offset unit is in bytes size_t mem_end; // runtime argument, indicating the end of current writing region size_t ping_pong_symbols; // ping-pong size (half of the RMT channel memory) size_t queue_size; // size of transaction queue diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index 663af7b38a..31be3b6e0b 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -589,39 +589,43 @@ esp_err_t rmt_tx_wait_all_done(rmt_channel_handle_t channel, int timeout_ms) return ESP_OK; } -static void rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan) +static size_t rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan, bool need_eof_marker) { rmt_channel_t *channel = &tx_chan->base; rmt_group_t *group = channel->group; int channel_id = channel->channel_id; - rmt_symbol_word_t *mem_to_nc = NULL; rmt_tx_trans_desc_t *cur_trans = tx_chan->cur_trans; rmt_dma_descriptor_t *desc_nc = NULL; - if (channel->dma_chan) { - mem_to_nc = tx_chan->dma_mem_base_nc; - } else { - mem_to_nc = channel->hw_mem_base; - } - // a RMT word whose duration is zero means a "stop" pattern - mem_to_nc[tx_chan->mem_off++] = (rmt_symbol_word_t) { - .duration0 = 0, - .level0 = cur_trans->flags.eot_level, - .duration1 = 0, - .level1 = cur_trans->flags.eot_level, - }; + if (need_eof_marker) { + rmt_symbol_word_t *mem_to_nc = NULL; + if (channel->dma_chan) { + mem_to_nc = tx_chan->dma_mem_base_nc; + } else { + mem_to_nc = channel->hw_mem_base; + } + size_t symbol_off = tx_chan->mem_off_bytes / sizeof(rmt_symbol_word_t); + // a RMT word whose duration is zero means a "stop" pattern + mem_to_nc[symbol_off] = (rmt_symbol_word_t) { + .duration0 = 0, + .level0 = cur_trans->flags.eot_level, + .duration1 = 0, + .level1 = cur_trans->flags.eot_level, + }; + tx_chan->mem_off_bytes += sizeof(rmt_symbol_word_t); + } size_t off = 0; if (channel->dma_chan) { - if (tx_chan->mem_off <= tx_chan->ping_pong_symbols) { + if (tx_chan->mem_off_bytes <= tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t)) { desc_nc = &tx_chan->dma_nodes_nc[0]; - off = tx_chan->mem_off; + off = tx_chan->mem_off_bytes; } else { desc_nc = &tx_chan->dma_nodes_nc[1]; - off = tx_chan->mem_off - tx_chan->ping_pong_symbols; + off = tx_chan->mem_off_bytes - tx_chan->ping_pong_symbols * sizeof(rmt_symbol_word_t); } desc_nc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; - desc_nc->dw0.length = off * sizeof(rmt_symbol_word_t); + desc_nc->dw0.length = off; // break down the DMA descriptor link desc_nc->next = NULL; } else { @@ -630,6 +634,8 @@ static void rmt_tx_mark_eof(rmt_tx_channel_t *tx_chan) rmt_ll_enable_interrupt(group->hal.regs, RMT_LL_EVENT_TX_THRES(channel_id), false); portEXIT_CRITICAL_ISR(&group->spinlock); } + + return need_eof_marker ? 1 : 0; } size_t rmt_encode_check_result(rmt_tx_channel_t *tx_chan, rmt_tx_trans_desc_t *t) @@ -639,12 +645,13 @@ size_t rmt_encode_check_result(rmt_tx_channel_t *tx_chan, rmt_tx_trans_desc_t *t size_t encoded_symbols = encoder->encode(encoder, &tx_chan->base, t->payload, t->payload_bytes, &encode_state); if (encode_state & RMT_ENCODING_COMPLETE) { - t->flags.encoding_done = true; + bool need_eof_mark = (encode_state & RMT_ENCODING_WITH_EOF) == 0; // inserting EOF symbol if there's extra space if (!(encode_state & RMT_ENCODING_MEM_FULL)) { - rmt_tx_mark_eof(tx_chan); - encoded_symbols += 1; + encoded_symbols += rmt_tx_mark_eof(tx_chan, need_eof_mark); } + t->flags.encoding_done = true; + t->flags.need_eof_mark = need_eof_mark; } // for loop transaction, the memory block should accommodate all encoded RMT symbols @@ -717,7 +724,7 @@ static void rmt_tx_do_transaction(rmt_tx_channel_t *tx_chan, rmt_tx_trans_desc_t // at the beginning of a new transaction, encoding memory offset should start from zero. // It will increase in the encode function e.g. `rmt_encode_copy()` - tx_chan->mem_off = 0; + tx_chan->mem_off_bytes = 0; // use the full memory block for the beginning encoding session tx_chan->mem_end = tx_chan->ping_pong_symbols * 2; // perform the encoding session, return the number of encoded symbols @@ -899,8 +906,7 @@ bool rmt_isr_handle_tx_threshold(rmt_tx_channel_t *tx_chan) size_t encoded_symbols = t->transmitted_symbol_num; // encoding finished, only need to send the EOF symbol if (t->flags.encoding_done) { - rmt_tx_mark_eof(tx_chan); - encoded_symbols += 1; + encoded_symbols += rmt_tx_mark_eof(tx_chan, t->flags.need_eof_mark); } else { encoded_symbols += rmt_encode_check_result(tx_chan, t); } @@ -1101,8 +1107,7 @@ static bool rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t rmt_tx_trans_desc_t *t = tx_chan->cur_trans; size_t encoded_symbols = t->transmitted_symbol_num; if (t->flags.encoding_done) { - rmt_tx_mark_eof(tx_chan); - encoded_symbols += 1; + encoded_symbols += rmt_tx_mark_eof(tx_chan, t->flags.need_eof_mark); } else { encoded_symbols += rmt_encode_check_result(tx_chan, t); }