forked from espressif/esp-idf
feat(rmt): check if the gpio number is reserved by others
This commit is contained in:
@@ -205,7 +205,6 @@ esp_err_t rmt_apply_carrier(rmt_channel_handle_t channel, const rmt_carrier_conf
|
|||||||
esp_err_t rmt_del_channel(rmt_channel_handle_t channel)
|
esp_err_t rmt_del_channel(rmt_channel_handle_t channel)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(channel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
gpio_reset_pin(channel->gpio_num);
|
|
||||||
return channel->del(channel);
|
return channel->del(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_private/gdma.h"
|
#include "esp_private/gdma.h"
|
||||||
|
#include "esp_private/esp_gpio_reserve.h"
|
||||||
#include "driver/rmt_common.h"
|
#include "driver/rmt_common.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@@ -146,6 +146,9 @@ static void rmt_rx_unregister_from_group(rmt_channel_t *channel, rmt_group_t *gr
|
|||||||
|
|
||||||
static esp_err_t rmt_rx_destroy(rmt_rx_channel_t *rx_channel)
|
static esp_err_t rmt_rx_destroy(rmt_rx_channel_t *rx_channel)
|
||||||
{
|
{
|
||||||
|
if (rx_channel->base.gpio_num >= 0) {
|
||||||
|
gpio_reset_pin(rx_channel->base.gpio_num);
|
||||||
|
}
|
||||||
if (rx_channel->base.intr) {
|
if (rx_channel->base.intr) {
|
||||||
ESP_RETURN_ON_ERROR(esp_intr_free(rx_channel->base.intr), TAG, "delete interrupt service failed");
|
ESP_RETURN_ON_ERROR(esp_intr_free(rx_channel->base.intr), TAG, "delete interrupt service failed");
|
||||||
}
|
}
|
||||||
@@ -177,21 +180,23 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_
|
|||||||
rmt_rx_channel_t *rx_channel = NULL;
|
rmt_rx_channel_t *rx_channel = NULL;
|
||||||
// Check if priority is valid
|
// Check if priority is valid
|
||||||
if (config->intr_priority) {
|
if (config->intr_priority) {
|
||||||
ESP_GOTO_ON_FALSE((config->intr_priority) > 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
ESP_RETURN_ON_FALSE((config->intr_priority) > 0, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||||
ESP_GOTO_ON_FALSE(1 << (config->intr_priority) & RMT_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, err, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & RMT_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||||
}
|
}
|
||||||
ESP_GOTO_ON_FALSE(config && ret_chan && config->resolution_hz, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(config && ret_chan && config->resolution_hz, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid GPIO number");
|
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, TAG, "invalid GPIO number %d", config->gpio_num);
|
||||||
ESP_GOTO_ON_FALSE((config->mem_block_symbols & 0x01) == 0 && config->mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL,
|
ESP_RETURN_ON_FALSE((config->mem_block_symbols & 0x01) == 0 && config->mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL,
|
||||||
ESP_ERR_INVALID_ARG, err, TAG, "mem_block_symbols must be even and at least %d", SOC_RMT_MEM_WORDS_PER_CHANNEL);
|
ESP_ERR_INVALID_ARG, TAG, "mem_block_symbols must be even and at least %d", SOC_RMT_MEM_WORDS_PER_CHANNEL);
|
||||||
#if !SOC_RMT_SUPPORT_DMA
|
#if !SOC_RMT_SUPPORT_DMA
|
||||||
ESP_GOTO_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "DMA not supported");
|
ESP_RETURN_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA not supported");
|
||||||
#endif // SOC_RMT_SUPPORT_DMA
|
#endif // SOC_RMT_SUPPORT_DMA
|
||||||
|
|
||||||
// malloc channel memory
|
// malloc channel memory
|
||||||
uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
|
uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
|
||||||
rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t), mem_caps);
|
rx_channel = heap_caps_calloc(1, sizeof(rmt_rx_channel_t), mem_caps);
|
||||||
ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel");
|
ESP_GOTO_ON_FALSE(rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for rx channel");
|
||||||
|
// gpio is not configured yet
|
||||||
|
rx_channel->base.gpio_num = -1;
|
||||||
// create DMA descriptor
|
// create DMA descriptor
|
||||||
size_t num_dma_nodes = 0;
|
size_t num_dma_nodes = 0;
|
||||||
if (config->flags.with_dma) {
|
if (config->flags.with_dma) {
|
||||||
@@ -266,16 +271,16 @@ esp_err_t rmt_new_rx_channel(const rmt_rx_channel_config_t *config, rmt_channel_
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// GPIO Matrix/MUX configuration
|
// GPIO Matrix/MUX configuration
|
||||||
rx_channel->base.gpio_num = config->gpio_num;
|
|
||||||
gpio_config_t gpio_conf = {
|
gpio_config_t gpio_conf = {
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
// also enable the input path is `io_loop_back` is on, this is useful for debug
|
// also enable the input path is `io_loop_back` is on, this is useful for debug
|
||||||
.mode = GPIO_MODE_INPUT | (config->flags.io_loop_back ? GPIO_MODE_OUTPUT : 0),
|
.mode = GPIO_MODE_INPUT | (config->flags.io_loop_back ? GPIO_MODE_OUTPUT : 0),
|
||||||
.pull_down_en = false,
|
.pull_down_en = false,
|
||||||
.pull_up_en = true,
|
.pull_up_en = true,
|
||||||
.pin_bit_mask = 1ULL << config->gpio_num,
|
.pin_bit_mask = BIT64(config->gpio_num),
|
||||||
};
|
};
|
||||||
ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config GPIO failed");
|
ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config GPIO failed");
|
||||||
|
rx_channel->base.gpio_num = config->gpio_num;
|
||||||
esp_rom_gpio_connect_in_signal(config->gpio_num,
|
esp_rom_gpio_connect_in_signal(config->gpio_num,
|
||||||
rmt_periph_signals.groups[group_id].channels[channel_id + RMT_RX_CHANNEL_OFFSET_IN_GROUP].rx_sig,
|
rmt_periph_signals.groups[group_id].channels[channel_id + RMT_RX_CHANNEL_OFFSET_IN_GROUP].rx_sig,
|
||||||
config->flags.invert_in);
|
config->flags.invert_in);
|
||||||
|
@@ -185,6 +185,10 @@ exit:
|
|||||||
|
|
||||||
static esp_err_t rmt_tx_destroy(rmt_tx_channel_t *tx_channel)
|
static esp_err_t rmt_tx_destroy(rmt_tx_channel_t *tx_channel)
|
||||||
{
|
{
|
||||||
|
if (tx_channel->base.gpio_num >= 0) {
|
||||||
|
gpio_reset_pin(tx_channel->base.gpio_num);
|
||||||
|
esp_gpio_revoke(BIT64(tx_channel->base.gpio_num));
|
||||||
|
}
|
||||||
if (tx_channel->base.intr) {
|
if (tx_channel->base.intr) {
|
||||||
ESP_RETURN_ON_ERROR(esp_intr_free(tx_channel->base.intr), TAG, "delete interrupt service failed");
|
ESP_RETURN_ON_ERROR(esp_intr_free(tx_channel->base.intr), TAG, "delete interrupt service failed");
|
||||||
}
|
}
|
||||||
@@ -227,24 +231,26 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
|
|||||||
ESP_RETURN_ON_FALSE((config->intr_priority) > 0, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
ESP_RETURN_ON_FALSE((config->intr_priority) > 0, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||||
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & RMT_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & RMT_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG, TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||||
}
|
}
|
||||||
ESP_GOTO_ON_FALSE(config && ret_chan && config->resolution_hz && config->trans_queue_depth, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(config && ret_chan && config->resolution_hz && config->trans_queue_depth, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_GOTO_ON_FALSE(GPIO_IS_VALID_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, err, TAG, "invalid GPIO number");
|
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_OUTPUT_GPIO(config->gpio_num), ESP_ERR_INVALID_ARG, TAG, "invalid GPIO number %d", config->gpio_num);
|
||||||
ESP_GOTO_ON_FALSE((config->mem_block_symbols & 0x01) == 0 && config->mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL,
|
ESP_RETURN_ON_FALSE((config->mem_block_symbols & 0x01) == 0 && config->mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL,
|
||||||
ESP_ERR_INVALID_ARG, err, TAG, "mem_block_symbols must be even and at least %d", SOC_RMT_MEM_WORDS_PER_CHANNEL);
|
ESP_ERR_INVALID_ARG, TAG, "mem_block_symbols must be even and at least %d", SOC_RMT_MEM_WORDS_PER_CHANNEL);
|
||||||
|
|
||||||
#if SOC_RMT_SUPPORT_DMA
|
#if SOC_RMT_SUPPORT_DMA
|
||||||
// we only support 2 nodes ping-pong, if the configured memory block size needs more than two DMA descriptors, should treat it as invalid
|
// we only support 2 nodes ping-pong, if the configured memory block size needs more than two DMA descriptors, should treat it as invalid
|
||||||
ESP_GOTO_ON_FALSE(config->mem_block_symbols <= RMT_DMA_DESC_BUF_MAX_SIZE * RMT_DMA_NODES_PING_PONG / sizeof(rmt_symbol_word_t),
|
ESP_RETURN_ON_FALSE(config->mem_block_symbols <= RMT_DMA_DESC_BUF_MAX_SIZE * RMT_DMA_NODES_PING_PONG / sizeof(rmt_symbol_word_t),
|
||||||
ESP_ERR_INVALID_ARG, err, TAG, "mem_block_symbols can't exceed %d",
|
ESP_ERR_INVALID_ARG, TAG, "mem_block_symbols can't exceed %d",
|
||||||
RMT_DMA_DESC_BUF_MAX_SIZE * RMT_DMA_NODES_PING_PONG / sizeof(rmt_symbol_word_t));
|
RMT_DMA_DESC_BUF_MAX_SIZE * RMT_DMA_NODES_PING_PONG / sizeof(rmt_symbol_word_t));
|
||||||
#else
|
#else
|
||||||
ESP_GOTO_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "DMA not supported");
|
ESP_RETURN_ON_FALSE(config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA not supported");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// malloc channel memory
|
// malloc channel memory
|
||||||
uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
|
uint32_t mem_caps = RMT_MEM_ALLOC_CAPS;
|
||||||
tx_channel = heap_caps_calloc(1, sizeof(rmt_tx_channel_t) + sizeof(rmt_tx_trans_desc_t) * config->trans_queue_depth, mem_caps);
|
tx_channel = heap_caps_calloc(1, sizeof(rmt_tx_channel_t) + sizeof(rmt_tx_trans_desc_t) * config->trans_queue_depth, mem_caps);
|
||||||
ESP_GOTO_ON_FALSE(tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for tx channel");
|
ESP_GOTO_ON_FALSE(tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for tx channel");
|
||||||
|
// GPIO configuration is not done yet
|
||||||
|
tx_channel->base.gpio_num = -1;
|
||||||
// create DMA descriptors
|
// create DMA descriptors
|
||||||
if (config->flags.with_dma) {
|
if (config->flags.with_dma) {
|
||||||
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
|
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
|
||||||
@@ -312,20 +318,26 @@ esp_err_t rmt_new_tx_channel(const rmt_tx_channel_config_t *config, rmt_channel_
|
|||||||
rmt_ll_tx_enable_wrap(hal->regs, channel_id, true);
|
rmt_ll_tx_enable_wrap(hal->regs, channel_id, true);
|
||||||
|
|
||||||
// GPIO Matrix/MUX configuration
|
// GPIO Matrix/MUX configuration
|
||||||
tx_channel->base.gpio_num = config->gpio_num;
|
|
||||||
gpio_config_t gpio_conf = {
|
gpio_config_t gpio_conf = {
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
.intr_type = GPIO_INTR_DISABLE,
|
||||||
// also enable the input path if `io_loop_back` is on, this is useful for bi-directional buses
|
// also enable the input path if `io_loop_back` is on, this is useful for bi-directional buses
|
||||||
.mode = (config->flags.io_od_mode ? GPIO_MODE_OUTPUT_OD : GPIO_MODE_OUTPUT) | (config->flags.io_loop_back ? GPIO_MODE_INPUT : 0),
|
.mode = (config->flags.io_od_mode ? GPIO_MODE_OUTPUT_OD : GPIO_MODE_OUTPUT) | (config->flags.io_loop_back ? GPIO_MODE_INPUT : 0),
|
||||||
.pull_down_en = false,
|
.pull_down_en = false,
|
||||||
.pull_up_en = true,
|
.pull_up_en = true,
|
||||||
.pin_bit_mask = 1ULL << config->gpio_num,
|
.pin_bit_mask = BIT64(config->gpio_num),
|
||||||
};
|
};
|
||||||
ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config GPIO failed");
|
ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config GPIO failed");
|
||||||
|
// reserve the GPIO output path, because we don't expect another peripheral to signal to the same GPIO
|
||||||
|
uint64_t old_gpio_rsv_mask = esp_gpio_reserve(BIT64(config->gpio_num));
|
||||||
|
// check if the GPIO is already used by others, RMT TX channel only uses the output path of the GPIO
|
||||||
|
if (old_gpio_rsv_mask & BIT64(config->gpio_num)) {
|
||||||
|
ESP_LOGW(TAG, "GPIO %d is not usable, maybe conflict with others", config->gpio_num);
|
||||||
|
}
|
||||||
esp_rom_gpio_connect_out_signal(config->gpio_num,
|
esp_rom_gpio_connect_out_signal(config->gpio_num,
|
||||||
rmt_periph_signals.groups[group_id].channels[channel_id + RMT_TX_CHANNEL_OFFSET_IN_GROUP].tx_sig,
|
rmt_periph_signals.groups[group_id].channels[channel_id + RMT_TX_CHANNEL_OFFSET_IN_GROUP].tx_sig,
|
||||||
config->flags.invert_out, false);
|
config->flags.invert_out, false);
|
||||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->gpio_num], PIN_FUNC_GPIO);
|
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->gpio_num], PIN_FUNC_GPIO);
|
||||||
|
tx_channel->base.gpio_num = config->gpio_num;
|
||||||
|
|
||||||
portMUX_INITIALIZE(&tx_channel->base.spinlock);
|
portMUX_INITIALIZE(&tx_channel->base.spinlock);
|
||||||
atomic_init(&tx_channel->base.fsm, RMT_FSM_INIT);
|
atomic_init(&tx_channel->base.fsm, RMT_FSM_INIT);
|
||||||
|
Reference in New Issue
Block a user