mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(rmt_tx): allow to switch gpio in tx channal
This commit is contained in:
@@ -88,12 +88,10 @@ typedef enum {
|
||||
} rmt_channel_direction_t;
|
||||
|
||||
typedef enum {
|
||||
RMT_FSM_INIT_WAIT,
|
||||
RMT_FSM_INIT,
|
||||
RMT_FSM_ENABLE_WAIT,
|
||||
RMT_FSM_ENABLE,
|
||||
RMT_FSM_RUN_WAIT,
|
||||
RMT_FSM_RUN,
|
||||
RMT_FSM_WAIT,
|
||||
} rmt_fsm_t;
|
||||
|
||||
enum {
|
||||
|
||||
@@ -408,7 +408,7 @@ esp_err_t rmt_receive(rmt_channel_handle_t channel, void *buffer, size_t buffer_
|
||||
|
||||
// check if we're in a proper state to start the receiver
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_ENABLE;
|
||||
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT),
|
||||
ESP_RETURN_ON_FALSE_ISR(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT),
|
||||
ESP_ERR_INVALID_STATE, TAG, "channel not in enable state");
|
||||
|
||||
// fill in the transaction descriptor
|
||||
@@ -502,7 +502,7 @@ static esp_err_t rmt_rx_enable(rmt_channel_handle_t channel)
|
||||
{
|
||||
// can only enable the channel when it's in "init" state
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_INIT;
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_ENABLE_WAIT),
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT),
|
||||
ESP_ERR_INVALID_STATE, TAG, "channel not in init state");
|
||||
|
||||
rmt_group_t *group = channel->group;
|
||||
@@ -538,11 +538,11 @@ static esp_err_t rmt_rx_disable(rmt_channel_handle_t channel)
|
||||
// can disable the channel when it's in `enable` or `run` state
|
||||
bool valid_state = false;
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_ENABLE;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_INIT_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
valid_state = true;
|
||||
}
|
||||
expected_fsm = RMT_FSM_RUN;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_INIT_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
valid_state = true;
|
||||
}
|
||||
ESP_RETURN_ON_FALSE(valid_state, ESP_ERR_INVALID_STATE, TAG, "channel not in enable or run state");
|
||||
|
||||
@@ -579,7 +579,7 @@ esp_err_t rmt_transmit(rmt_channel_handle_t channel, rmt_encoder_t *encoder, con
|
||||
|
||||
// check if we need to start one pending transaction
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_ENABLE;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
// check if we need to start one transaction
|
||||
if (xQueueReceive(tx_chan->trans_queues[RMT_TX_QUEUE_PROGRESS], &t, 0) == pdTRUE) {
|
||||
atomic_store(&channel->fsm, RMT_FSM_RUN);
|
||||
@@ -764,7 +764,7 @@ static esp_err_t rmt_tx_enable(rmt_channel_handle_t channel)
|
||||
{
|
||||
// can enable the channel when it's in "init" state
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_INIT;
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_ENABLE_WAIT),
|
||||
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT),
|
||||
ESP_ERR_INVALID_STATE, TAG, "channel not in init state");
|
||||
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
|
||||
|
||||
@@ -792,7 +792,7 @@ static esp_err_t rmt_tx_enable(rmt_channel_handle_t channel)
|
||||
// check if we need to start one pending transaction
|
||||
rmt_tx_trans_desc_t *t = NULL;
|
||||
expected_fsm = RMT_FSM_ENABLE;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
if (xQueueReceive(tx_chan->trans_queues[RMT_TX_QUEUE_PROGRESS], &t, 0) == pdTRUE) {
|
||||
// sanity check
|
||||
assert(t);
|
||||
@@ -816,11 +816,11 @@ static esp_err_t rmt_tx_disable(rmt_channel_handle_t channel)
|
||||
// can disable the channel when it's in `enable` or `run` state
|
||||
bool valid_state = false;
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_ENABLE;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_INIT_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
valid_state = true;
|
||||
}
|
||||
expected_fsm = RMT_FSM_RUN;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_INIT_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
valid_state = true;
|
||||
// disable the hardware
|
||||
portENTER_CRITICAL(&channel->spinlock);
|
||||
@@ -939,7 +939,7 @@ static bool IRAM_ATTR rmt_isr_handle_tx_done(rmt_tx_channel_t *tx_chan)
|
||||
bool need_yield = false;
|
||||
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_RUN;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_ENABLE_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
trans_desc = tx_chan->cur_trans;
|
||||
// move current finished transaction to the complete queue
|
||||
xQueueSendFromISR(tx_chan->trans_queues[RMT_TX_QUEUE_COMPLETE], &trans_desc, &awoken);
|
||||
@@ -963,7 +963,7 @@ static bool IRAM_ATTR rmt_isr_handle_tx_done(rmt_tx_channel_t *tx_chan)
|
||||
|
||||
// let's try start the next pending transaction
|
||||
expected_fsm = RMT_FSM_ENABLE;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
if (xQueueReceiveFromISR(tx_chan->trans_queues[RMT_TX_QUEUE_PROGRESS], &trans_desc, &awoken) == pdTRUE) {
|
||||
// sanity check
|
||||
assert(trans_desc);
|
||||
@@ -1017,7 +1017,7 @@ static bool IRAM_ATTR rmt_isr_handle_tx_loop_end(rmt_tx_channel_t *tx_chan)
|
||||
|
||||
// loop transaction finished
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_RUN;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_ENABLE_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
// move current finished transaction to the complete queue
|
||||
xQueueSendFromISR(tx_chan->trans_queues[RMT_TX_QUEUE_COMPLETE], &trans_desc, &awoken);
|
||||
if (awoken == pdTRUE) {
|
||||
@@ -1040,7 +1040,7 @@ static bool IRAM_ATTR rmt_isr_handle_tx_loop_end(rmt_tx_channel_t *tx_chan)
|
||||
|
||||
// let's try start the next pending transaction
|
||||
expected_fsm = RMT_FSM_ENABLE;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_RUN_WAIT)) {
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
if (xQueueReceiveFromISR(tx_chan->trans_queues[RMT_TX_QUEUE_PROGRESS], &trans_desc, &awoken) == pdTRUE) {
|
||||
// sanity check
|
||||
assert(trans_desc);
|
||||
@@ -1134,3 +1134,45 @@ static bool IRAM_ATTR rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_eve
|
||||
return false;
|
||||
}
|
||||
#endif // SOC_RMT_SUPPORT_DMA
|
||||
|
||||
esp_err_t rmt_tx_switch_gpio(rmt_channel_handle_t channel, gpio_num_t gpio_num, bool invert_out)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(channel && channel->direction == RMT_CHANNEL_DIRECTION_TX, ESP_ERR_INVALID_ARG, TAG, "invalid channel");
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "invalid GPIO number %d", gpio_num);
|
||||
|
||||
// only can switch the GPIO when it's in INIT state
|
||||
rmt_fsm_t expected_fsm = RMT_FSM_INIT;
|
||||
if (atomic_compare_exchange_strong(&channel->fsm, &expected_fsm, RMT_FSM_WAIT)) {
|
||||
|
||||
rmt_tx_channel_t *tx_chan = __containerof(channel, rmt_tx_channel_t, base);
|
||||
rmt_group_t *group = channel->group;
|
||||
int group_id = group->group_id;
|
||||
int channel_id = channel->channel_id;
|
||||
|
||||
// Disable the old GPIO
|
||||
if (tx_chan->base.gpio_num >= 0) {
|
||||
gpio_output_disable(tx_chan->base.gpio_num);
|
||||
esp_gpio_revoke(BIT64(tx_chan->base.gpio_num));
|
||||
}
|
||||
|
||||
// Reserve the new GPIO
|
||||
uint64_t old_gpio_rsv_mask = esp_gpio_reserve(BIT64(gpio_num));
|
||||
if (old_gpio_rsv_mask & BIT64(gpio_num)) {
|
||||
ESP_LOGW(TAG, "GPIO %d is not usable, maybe conflict with others", gpio_num);
|
||||
}
|
||||
|
||||
// Configure the new GPIO
|
||||
gpio_func_sel(gpio_num, PIN_FUNC_GPIO);
|
||||
esp_rom_gpio_connect_out_signal(gpio_num,
|
||||
rmt_periph_signals.groups[group_id].channels[channel_id + RMT_TX_CHANNEL_OFFSET_IN_GROUP].tx_sig,
|
||||
invert_out, false);
|
||||
tx_chan->base.gpio_num = gpio_num;
|
||||
|
||||
// finally we return to the INIT state
|
||||
atomic_store(&channel->fsm, RMT_FSM_INIT);
|
||||
ESP_LOGD(TAG, "switch tx channel(%d,%d) gpio to %d", group_id, channel_id, gpio_num);
|
||||
} else {
|
||||
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "channel is not in init state");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user