From f6f9f93a9dd736ed6ee0c281b5f5eb4bc47ca36c Mon Sep 17 00:00:00 2001 From: kooho <2229179028@qq.com> Date: Wed, 2 May 2018 15:27:41 +0800 Subject: [PATCH] driver(i2c, rmt):Add intr_flag setting to ESP_INTR_FLAG_IRAM support when enable psram. --- components/driver/i2c.c | 87 +++++++++++++++++++++++++- components/driver/include/driver/i2c.h | 10 +++ components/driver/include/driver/rmt.h | 2 + components/driver/rmt.c | 30 +++++++++ 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/components/driver/i2c.c b/components/driver/i2c.c index 26ef67370..1d904fdcb 100644 --- a/components/driver/i2c.c +++ b/components/driver/i2c.c @@ -66,6 +66,7 @@ static DRAM_ATTR i2c_dev_t* const I2C[I2C_NUM_MAX] = { &I2C0, &I2C1 }; #define I2C_GPIO_PULLUP_ERR_STR "this i2c pin does not support internal pull-up" #define I2C_ACK_TYPE_ERR_STR "i2c ack type error" #define I2C_DATA_LEN_ERR_STR "i2c data read length error" +#define I2C_PSRAM_BUFFER_WARN_STR "Using buffer allocated from psram" #define I2C_FIFO_FULL_THRESH_VAL (28) #define I2C_FIFO_EMPTY_THRESH_VAL (5) #define I2C_IO_INIT_LEVEL (1) @@ -124,6 +125,11 @@ typedef struct { i2c_cmd_desc_t cmd_link; /*!< I2C command link */ QueueHandle_t cmd_evt_queue; /*!< I2C command event queue */ +#if CONFIG_SPIRAM_USE_MALLOC + uint8_t* evt_queue_storage; /*!< The buffer that will hold the items in the queue */ + int intr_alloc_flags; /*!< Used to allocate the interrupt */ + StaticQueue_t evt_queue_buffer; /*!< The buffer that will hold the queue structure*/ +#endif xSemaphoreHandle cmd_mux; /*!< semaphore to lock command process */ size_t tx_fifo_remain; /*!< tx fifo remain length, for master mode */ size_t rx_fifo_remain; /*!< rx fifo remain length, for master mode */ @@ -156,7 +162,16 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ ESP_ERR_INVALID_ARG); uint32_t intr_mask = 0; if (p_i2c_obj[i2c_num] == NULL) { + +#if !CONFIG_SPIRAM_USE_MALLOC p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t)); +#else + if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) { + p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t)); + } else { + p_i2c_obj[i2c_num] = (i2c_obj_t*) heap_caps_calloc(1, sizeof(i2c_obj_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + } +#endif if (p_i2c_obj[i2c_num] == NULL) { ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR); return ESP_FAIL; @@ -168,6 +183,9 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ p_i2c->rx_cnt = 0; p_i2c->status = I2C_STATUS_IDLE; +#if CONFIG_SPIRAM_USE_MALLOC + p_i2c->intr_alloc_flags = intr_alloc_flags; +#endif p_i2c->rx_fifo_remain = I2C_FIFO_LEN; p_i2c->tx_fifo_remain = I2C_FIFO_LEN; @@ -205,7 +223,21 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ } else { //semaphore to sync sending process, because we only have 32 bytes for hardware fifo. p_i2c->cmd_mux = xSemaphoreCreateMutex(); +#if !CONFIG_SPIRAM_USE_MALLOC p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t)); +#else + if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) { + p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t)); + } else { + p_i2c->evt_queue_storage = (uint8_t *)heap_caps_calloc(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if( p_i2c->evt_queue_storage == NULL ) { + ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR); + goto err; + } + memset(&p_i2c->evt_queue_buffer, 0, sizeof(StaticQueue_t)); + p_i2c->cmd_evt_queue = xQueueCreateStatic(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t), p_i2c->evt_queue_storage, &p_i2c->evt_queue_buffer); + } +#endif if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt_queue == NULL) { ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR); goto err; @@ -262,6 +294,12 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_ if (p_i2c_obj[i2c_num]->slv_tx_mux) { vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_tx_mux); } +#if CONFIG_SPIRAM_USE_MALLOC + if (p_i2c_obj[i2c_num]->evt_queue_storage) { + free(p_i2c_obj[i2c_num]->evt_queue_storage); + p_i2c_obj[i2c_num]->evt_queue_storage = NULL; + } +#endif } free(p_i2c_obj[i2c_num]); p_i2c_obj[i2c_num] = NULL; @@ -324,6 +362,12 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num) p_i2c->tx_ring_buf = NULL; p_i2c->tx_buf_length = 0; } +#if CONFIG_SPIRAM_USE_MALLOC + if (p_i2c_obj[i2c_num]->evt_queue_storage) { + free(p_i2c_obj[i2c_num]->evt_queue_storage); + p_i2c_obj[i2c_num]->evt_queue_storage = NULL; + } +#endif free(p_i2c_obj[i2c_num]); p_i2c_obj[i2c_num] = NULL; @@ -839,7 +883,11 @@ esp_err_t i2c_set_pin(i2c_port_t i2c_num, int sda_io_num, int scl_io_num, gpio_p i2c_cmd_handle_t i2c_cmd_link_create() { +#if !CONFIG_SPIRAM_USE_MALLOC i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) calloc(1, sizeof(i2c_cmd_desc_t)); +#else + i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) heap_caps_calloc(1, sizeof(i2c_cmd_desc_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#endif return (i2c_cmd_handle_t) cmd_desc; } @@ -865,7 +913,11 @@ static esp_err_t i2c_cmd_link_append(i2c_cmd_handle_t cmd_handle, i2c_cmd_t* cmd { i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) cmd_handle; if (cmd_desc->head == NULL) { - cmd_desc->head = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t)); +#if !CONFIG_SPIRAM_USE_MALLOC + cmd_desc->head = (i2c_cmd_link_t*) calloc(1, sizeof(i2c_cmd_link_t)); +#else + cmd_desc->head = (i2c_cmd_link_t*) heap_caps_calloc(1, sizeof(i2c_cmd_link_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#endif if (cmd_desc->head == NULL) { ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR); goto err; @@ -873,7 +925,11 @@ static esp_err_t i2c_cmd_link_append(i2c_cmd_handle_t cmd_handle, i2c_cmd_t* cmd cmd_desc->cur = cmd_desc->head; cmd_desc->free = cmd_desc->head; } else { - cmd_desc->cur->next = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t)); +#if !CONFIG_SPIRAM_USE_MALLOC + cmd_desc->cur->next = (i2c_cmd_link_t*) calloc(1, sizeof(i2c_cmd_link_t)); +#else + cmd_desc->cur->next = (i2c_cmd_link_t*) heap_caps_calloc(1, sizeof(i2c_cmd_link_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); +#endif if (cmd_desc->cur->next == NULL) { ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR); goto err; @@ -1128,6 +1184,23 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num) return; } +#if CONFIG_SPIRAM_USE_MALLOC +//Check whether read or write buffer in cmd_link is internal. +static bool is_cmd_link_buffer_internal(i2c_cmd_link_t *link) +{ + i2c_cmd_link_t* cmd_link = link; + while(cmd_link != NULL) { + if (cmd_link->cmd.op_code == I2C_CMD_WRITE || cmd_link->cmd.op_code == I2C_CMD_READ) { + if( cmd_link->cmd.data != NULL && !esp_ptr_internal(cmd_link->cmd.data)) { + return false; + } + } + cmd_link = cmd_link->next; + } + return true; +} +#endif + esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait) { I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG); @@ -1135,6 +1208,16 @@ esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, I2C_CHECK(p_i2c_obj[i2c_num]->mode == I2C_MODE_MASTER, I2C_MASTER_MODE_ERR_STR, ESP_ERR_INVALID_STATE); I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG); +#if CONFIG_SPIRAM_USE_MALLOC + //If the i2c read or write buffer is not in internal RAM, we will return ESP_FAIL + //to avoid the ISR handler function crashing when the cache is disabled. + if( (p_i2c_obj[i2c_num]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) { + if( !is_cmd_link_buffer_internal(((i2c_cmd_desc_t*)cmd_handle)->head) ) { + ESP_LOGE(I2C_TAG, I2C_PSRAM_BUFFER_WARN_STR); + return ESP_ERR_INVALID_ARG; + } + } +#endif // Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus. static uint8_t clear_bus_cnt = 0; esp_err_t ret = ESP_FAIL; diff --git a/components/driver/include/driver/i2c.h b/components/driver/include/driver/i2c.h index b7aceb7b1..0f892db5e 100644 --- a/components/driver/include/driver/i2c.h +++ b/components/driver/include/driver/i2c.h @@ -113,6 +113,10 @@ typedef void* i2c_cmd_handle_t; /*!< I2C command handle */ * Only slave mode will use this value, driver will ignore this value in master mode. * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * @note + * In master mode, if the cache is likely to be disabled(such as write flash) and the slave is time-sensitive, + * `ESP_INTR_FLAG_IRAM` is suggested to be used. In this case, please use the memory allocated from internal RAM in i2c read and write function, + * because we can not access the psram(if psram is enabled) in interrupt handle function when cache is disabled. * * @return * - ESP_OK Success @@ -272,6 +276,8 @@ esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool * * @param cmd_handle I2C cmd link * @param data data to send + * @note + * If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM. * @param data_len data length * @param ack_en enable ack check for master * @@ -289,6 +295,8 @@ esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t da * * @param cmd_handle I2C cmd link * @param data pointer accept the data byte + * @note + * If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM. * @param ack ack value for read command * * @return @@ -305,6 +313,8 @@ esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_a * * @param cmd_handle I2C cmd link * @param data data buffer to accept the data from bus + * @note + * If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM. * @param data_len read data length * @param ack ack value for read command * diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index 13d97b91c..a1bcbe819 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -632,6 +632,7 @@ esp_err_t rmt_fill_tx_items(rmt_channel_t channel, const rmt_item32_t* item, uin * @param rx_buf_size Size of RMT RX ringbuffer. Can be 0 if the RX ringbuffer is not used. * * @param intr_alloc_flags Flags for the RMT driver interrupt handler. Pass 0 for default flags. See esp_intr_alloc.h for details. + * If ESP_INTR_FLAG_IRAM is used, please do not use the memory allocated from psram when calling rmt_write_items. * * @return * - ESP_ERR_INVALID_STATE Driver is already installed, call rmt_driver_uninstall first. @@ -660,6 +661,7 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel); * @param channel RMT channel (0 - 7) * * @param rmt_item head point of RMT items array. + * If ESP_INTR_FLAG_IRAM is used, please do not use the memory allocated from psram when calling rmt_write_items. * * @param item_num RMT data item number. * diff --git a/components/driver/rmt.c b/components/driver/rmt.c index 84d7a81db..ca0dc6a28 100644 --- a/components/driver/rmt.c +++ b/components/driver/rmt.c @@ -45,6 +45,7 @@ #define RMT_CLK_DIV_ERROR_STR "RMT CLK DIV ERR" #define RMT_DRIVER_ERROR_STR "RMT DRIVER ERR" #define RMT_DRIVER_LENGTH_ERROR_STR "RMT PARAM LEN ERROR" +#define RMT_PSRAM_BUFFER_WARN_STR "Using buffer allocated from psram" static const char* RMT_TAG = "rmt"; static uint8_t s_rmt_driver_channels; // Bitmask (bits 0-7) of installed drivers' channels @@ -70,6 +71,10 @@ typedef struct { rmt_channel_t channel; const rmt_item32_t* tx_data; xSemaphoreHandle tx_sem; +#if CONFIG_SPIRAM_USE_MALLOC + int intr_alloc_flags; + StaticSemaphore_t tx_sem_buffer; +#endif RingbufHandle_t tx_buf; RingbufHandle_t rx_buf; } rmt_obj_t; @@ -690,7 +695,15 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr return ESP_ERR_INVALID_STATE; } +#if !CONFIG_SPIRAM_USE_MALLOC p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t)); +#else + if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) { + p_rmt_obj[channel] = (rmt_obj_t*) malloc(sizeof(rmt_obj_t)); + } else { + p_rmt_obj[channel] = (rmt_obj_t*) heap_caps_calloc(1, sizeof(rmt_obj_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + } +#endif if(p_rmt_obj[channel] == NULL) { ESP_LOGE(RMT_TAG, "RMT driver malloc error"); @@ -706,7 +719,16 @@ esp_err_t rmt_driver_install(rmt_channel_t channel, size_t rx_buf_size, int intr p_rmt_obj[channel]->wait_done = false; if(p_rmt_obj[channel]->tx_sem == NULL) { +#if !CONFIG_SPIRAM_USE_MALLOC p_rmt_obj[channel]->tx_sem = xSemaphoreCreateBinary(); +#else + p_rmt_obj[channel]->intr_alloc_flags = intr_alloc_flags; + if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) { + p_rmt_obj[channel]->tx_sem = xSemaphoreCreateBinary(); + } else { + p_rmt_obj[channel]->tx_sem = xSemaphoreCreateBinaryStatic(&p_rmt_obj[channel]->tx_sem_buffer); + } +#endif xSemaphoreGive(p_rmt_obj[channel]->tx_sem); } if(p_rmt_obj[channel]->rx_buf == NULL && rx_buf_size > 0) { @@ -736,6 +758,14 @@ esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t* rmt_item, i RMT_CHECK(p_rmt_obj[channel] != NULL, RMT_DRIVER_ERROR_STR, ESP_FAIL); RMT_CHECK(rmt_item != NULL, RMT_ADDR_ERROR_STR, ESP_FAIL); RMT_CHECK(item_num > 0, RMT_DRIVER_LENGTH_ERROR_STR, ESP_ERR_INVALID_ARG); +#if CONFIG_SPIRAM_USE_MALLOC + if( p_rmt_obj[channel]->intr_alloc_flags & ESP_INTR_FLAG_IRAM ) { + if( !esp_ptr_internal(rmt_item) ) { + ESP_LOGE(RMT_TAG, RMT_PSRAM_BUFFER_WARN_STR); + return ESP_ERR_INVALID_ARG; + } + } +#endif rmt_obj_t* p_rmt = p_rmt_obj[channel]; int block_num = RMT.conf_ch[channel].conf0.mem_size; int item_block_len = block_num * RMT_MEM_ITEM_NUM;