forked from espressif/esp-idf
feat(rmt): allow the encoder to emit the EOF marker
This commit is contained in:
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user