#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
\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
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
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
} 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
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
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
\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
{\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
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
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
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
* 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
*\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
*\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
*\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
#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
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;
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");
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) {
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;