]> granicus.if.org Git - esp-idf/commitdiff
driver(i2c, rmt):Add intr_flag setting to ESP_INTR_FLAG_IRAM support when enable...
authorkooho <2229179028@qq.com>
Wed, 2 May 2018 07:27:41 +0000 (15:27 +0800)
committerkooho <2229179028@qq.com>
Mon, 21 May 2018 01:37:56 +0000 (09:37 +0800)
components/driver/i2c.c
components/driver/include/driver/i2c.h
components/driver/include/driver/rmt.h
components/driver/rmt.c

index 26ef67370bb86a65422d070dcb79c3c9881f6d2c..1d904fdcb7e50c89ca72defacaf8303eaa719db9 100644 (file)
@@ -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"\r
 #define I2C_ACK_TYPE_ERR_STR           "i2c ack type error"\r
 #define I2C_DATA_LEN_ERR_STR           "i2c data read length error"\r
+#define I2C_PSRAM_BUFFER_WARN_STR      "Using buffer allocated from psram"\r
 #define I2C_FIFO_FULL_THRESH_VAL       (28)\r
 #define I2C_FIFO_EMPTY_THRESH_VAL      (5)\r
 #define I2C_IO_INIT_LEVEL              (1)\r
@@ -124,6 +125,11 @@ typedef struct {
 \r
     i2c_cmd_desc_t cmd_link;         /*!< I2C command link */\r
     QueueHandle_t cmd_evt_queue;     /*!< I2C command event queue */\r
+#if CONFIG_SPIRAM_USE_MALLOC\r
+    uint8_t* evt_queue_storage;      /*!< The buffer that will hold the items in the queue */\r
+    int intr_alloc_flags;            /*!< Used to allocate the interrupt */\r
+    StaticQueue_t evt_queue_buffer;  /*!< The buffer that will hold the queue structure*/\r
+#endif\r
     xSemaphoreHandle cmd_mux;        /*!< semaphore to lock command process */\r
     size_t tx_fifo_remain;           /*!< tx fifo remain length, for master mode */\r
     size_t rx_fifo_remain;           /*!< rx fifo remain length, for master mode */\r
@@ -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);\r
     uint32_t intr_mask = 0;\r
     if (p_i2c_obj[i2c_num] == NULL) {\r
+\r
+#if !CONFIG_SPIRAM_USE_MALLOC\r
         p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t));\r
+#else\r
+        if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) {\r
+            p_i2c_obj[i2c_num] = (i2c_obj_t*) calloc(1, sizeof(i2c_obj_t));\r
+        } else {\r
+            p_i2c_obj[i2c_num] = (i2c_obj_t*) heap_caps_calloc(1, sizeof(i2c_obj_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);\r
+        }\r
+#endif\r
         if (p_i2c_obj[i2c_num] == NULL) {\r
             ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR);\r
             return ESP_FAIL;\r
@@ -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;\r
         p_i2c->status = I2C_STATUS_IDLE;\r
 \r
+#if CONFIG_SPIRAM_USE_MALLOC\r
+        p_i2c->intr_alloc_flags = intr_alloc_flags;\r
+#endif\r
         p_i2c->rx_fifo_remain = I2C_FIFO_LEN;\r
         p_i2c->tx_fifo_remain = I2C_FIFO_LEN;\r
 \r
@@ -205,7 +223,21 @@ esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t slv_rx_
         } else {\r
             //semaphore to sync sending process, because we only have 32 bytes for hardware fifo.\r
             p_i2c->cmd_mux = xSemaphoreCreateMutex();\r
+#if !CONFIG_SPIRAM_USE_MALLOC\r
             p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));\r
+#else\r
+            if( !(intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) {\r
+                p_i2c->cmd_evt_queue = xQueueCreate(I2C_EVT_QUEUE_LEN, sizeof(i2c_cmd_evt_t));\r
+            } else {\r
+                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);\r
+                if( p_i2c->evt_queue_storage == NULL ) {\r
+                    ESP_LOGE(I2C_TAG, I2C_DRIVER_MALLOC_ERR_STR);\r
+                    goto err;\r
+                }\r
+                memset(&p_i2c->evt_queue_buffer, 0, sizeof(StaticQueue_t));\r
+                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);\r
+            }\r
+#endif\r
             if (p_i2c->cmd_mux == NULL || p_i2c->cmd_evt_queue == NULL) {\r
                 ESP_LOGE(I2C_TAG, I2C_SEM_ERR_STR);\r
                 goto err;\r
@@ -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) {\r
             vSemaphoreDelete(p_i2c_obj[i2c_num]->slv_tx_mux);\r
         }\r
+#if CONFIG_SPIRAM_USE_MALLOC\r
+        if (p_i2c_obj[i2c_num]->evt_queue_storage) {\r
+            free(p_i2c_obj[i2c_num]->evt_queue_storage);\r
+            p_i2c_obj[i2c_num]->evt_queue_storage = NULL;\r
+        }\r
+#endif\r
     }\r
     free(p_i2c_obj[i2c_num]);\r
     p_i2c_obj[i2c_num] = NULL;\r
@@ -324,6 +362,12 @@ esp_err_t i2c_driver_delete(i2c_port_t i2c_num)
         p_i2c->tx_ring_buf = NULL;\r
         p_i2c->tx_buf_length = 0;\r
     }\r
+#if CONFIG_SPIRAM_USE_MALLOC\r
+    if (p_i2c_obj[i2c_num]->evt_queue_storage) {\r
+        free(p_i2c_obj[i2c_num]->evt_queue_storage);\r
+        p_i2c_obj[i2c_num]->evt_queue_storage = NULL;\r
+    }\r
+#endif\r
 \r
     free(p_i2c_obj[i2c_num]);\r
     p_i2c_obj[i2c_num] = NULL;\r
@@ -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
 \r
 i2c_cmd_handle_t i2c_cmd_link_create()\r
 {\r
+#if !CONFIG_SPIRAM_USE_MALLOC\r
     i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) calloc(1, sizeof(i2c_cmd_desc_t));\r
+#else\r
+    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);\r
+#endif\r
     return (i2c_cmd_handle_t) cmd_desc;\r
 }\r
 \r
@@ -865,7 +913,11 @@ static esp_err_t i2c_cmd_link_append(i2c_cmd_handle_t cmd_handle, i2c_cmd_t* cmd
 {\r
     i2c_cmd_desc_t* cmd_desc = (i2c_cmd_desc_t*) cmd_handle;\r
     if (cmd_desc->head == NULL) {\r
-        cmd_desc->head = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t));\r
+#if !CONFIG_SPIRAM_USE_MALLOC\r
+        cmd_desc->head = (i2c_cmd_link_t*) calloc(1, sizeof(i2c_cmd_link_t));\r
+#else\r
+        cmd_desc->head = (i2c_cmd_link_t*) heap_caps_calloc(1, sizeof(i2c_cmd_link_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);\r
+#endif\r
         if (cmd_desc->head == NULL) {\r
             ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR);\r
             goto err;\r
@@ -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;\r
         cmd_desc->free = cmd_desc->head;\r
     } else {\r
-        cmd_desc->cur->next = (i2c_cmd_link_t*) malloc(sizeof(i2c_cmd_link_t));\r
+#if !CONFIG_SPIRAM_USE_MALLOC\r
+        cmd_desc->cur->next = (i2c_cmd_link_t*) calloc(1, sizeof(i2c_cmd_link_t));\r
+#else\r
+        cmd_desc->cur->next = (i2c_cmd_link_t*) heap_caps_calloc(1, sizeof(i2c_cmd_link_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);\r
+#endif\r
         if (cmd_desc->cur->next == NULL) {\r
             ESP_LOGE(I2C_TAG, I2C_CMD_MALLOC_ERR_STR);\r
             goto err;\r
@@ -1128,6 +1184,23 @@ static void IRAM_ATTR i2c_master_cmd_begin_static(i2c_port_t i2c_num)
     return;\r
 }\r
 \r
+#if CONFIG_SPIRAM_USE_MALLOC\r
+//Check whether read or write buffer in cmd_link is internal.\r
+static bool is_cmd_link_buffer_internal(i2c_cmd_link_t *link)\r
+{\r
+    i2c_cmd_link_t* cmd_link = link;\r
+    while(cmd_link != NULL)  {\r
+        if (cmd_link->cmd.op_code == I2C_CMD_WRITE || cmd_link->cmd.op_code == I2C_CMD_READ) {\r
+            if( cmd_link->cmd.data != NULL && !esp_ptr_internal(cmd_link->cmd.data)) {\r
+                return false;\r
+            }\r
+        }\r
+        cmd_link = cmd_link->next;\r
+    }\r
+    return true;\r
+}\r
+#endif\r
+\r
 esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait)\r
 {\r
     I2C_CHECK(( i2c_num < I2C_NUM_MAX ), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);\r
@@ -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);\r
     I2C_CHECK(cmd_handle != NULL, I2C_CMD_LINK_INIT_ERR_STR, ESP_ERR_INVALID_ARG);\r
 \r
+#if CONFIG_SPIRAM_USE_MALLOC\r
+    //If the i2c read or write buffer is not in internal RAM, we will return ESP_FAIL\r
+    //to avoid the ISR handler function crashing when the cache is disabled.\r
+    if( (p_i2c_obj[i2c_num]->intr_alloc_flags & ESP_INTR_FLAG_IRAM) ) {\r
+        if( !is_cmd_link_buffer_internal(((i2c_cmd_desc_t*)cmd_handle)->head) ) {\r
+            ESP_LOGE(I2C_TAG, I2C_PSRAM_BUFFER_WARN_STR);\r
+            return ESP_ERR_INVALID_ARG;\r
+        }\r
+    }\r
+#endif\r
     // Sometimes when the FSM get stuck, the ACK_ERR interrupt will occur endlessly until we reset the FSM and clear bus.\r
     static uint8_t clear_bus_cnt = 0;\r
     esp_err_t ret = ESP_FAIL;\r
index b7aceb7b131771c25b92023ab484d63422e59c6b..0f892db5e7e17257dc7432c8fca9c1eb83324f0d 100644 (file)
@@ -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.\r
  * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred)\r
  *            ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info.\r
+ *        @note\r
+ *        In master mode, if the cache is likely to be disabled(such as write flash) and the slave is time-sensitive,\r
+ *        `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,\r
+ *        because we can not access the psram(if psram is enabled) in interrupt handle function when cache is disabled.\r
  *\r
  * @return\r
  *     - ESP_OK   Success\r
@@ -272,6 +276,8 @@ esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool
  *\r
  * @param cmd_handle I2C cmd link\r
  * @param data data to send\r
+ *        @note\r
+ *        If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM.\r
  * @param data_len data length\r
  * @param ack_en enable ack check for master\r
  *\r
@@ -289,6 +295,8 @@ esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, uint8_t* data, size_t da
  *\r
  * @param cmd_handle I2C cmd link\r
  * @param data pointer accept the data byte\r
+ *        @note\r
+ *        If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM.\r
  * @param ack ack value for read command\r
  *\r
  * @return\r
@@ -305,6 +313,8 @@ esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t* data, i2c_a
  *\r
  * @param cmd_handle I2C cmd link\r
  * @param data data buffer to accept the data from bus\r
+ *        @note\r
+ *        If the psram is enabled and intr_flag is `ESP_INTR_FLAG_IRAM`, please use the memory allocated from internal RAM.\r
  * @param data_len read data length\r
  * @param ack ack value for read command\r
  *\r
index 13d97b91cd1f1c39f32234ad3fe4f019d2873581..a1bcbe8195247cae9ca4b5daa38a06bdc90f3916 100644 (file)
@@ -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.
  *
index 84d7a81db1a03c6d6d2c51d5a73eb41ff32ec46c..ca0dc6a28c5031bc1c714cfe47f83042716801c6 100644 (file)
@@ -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;