Skip to content

Commit

Permalink
Merge branch 'bugfix/fix_openthread_spi_slave_transaction' into 'master'
Browse files Browse the repository at this point in the history
fix(openthread): fix openthread SPI tx timeout issue

See merge request espressif/esp-idf!27887
  • Loading branch information
chshu committed Dec 21, 2023
2 parents 8863d09 + d4d8607 commit f0d10c8
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 55 deletions.
1 change: 1 addition & 0 deletions components/openthread/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ menu "OpenThread"

config OPENTHREAD_RCP_SPI
bool "SPI RCP"
select GPIO_CTRL_FUNC_IN_IRAM
help
Select this to enable SPI connection to host.
endchoice
Expand Down
127 changes: 72 additions & 55 deletions components/openthread/src/port/esp_openthread_spi_slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
#include "esp_attr.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_heap_caps.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_task_queue.h"
#include "esp_openthread_types.h"
#include "esp_rom_sys.h"
#include <stdint.h>
#include <string.h>
#include "driver/gpio.h"
Expand All @@ -33,37 +33,38 @@
static const char *SPI_SLAVE_TAG = "spi_slave";

static void *s_context = NULL;
static uint8_t *s_prev_output_buf;
static uint16_t s_prev_output_len;
static uint8_t *s_prev_input_buf;
static uint16_t s_prev_input_len;
static uint8_t *s_output_buf;
static uint16_t s_output_len;
static uint8_t *s_input_buf;
static uint16_t s_input_len;
static bool s_request_transaction = false;

static esp_openthread_spi_slave_config_t s_spi_config;
static otPlatSpiSlaveTransactionProcessCallback s_process_callback = NULL;
static otPlatSpiSlaveTransactionCompleteCallback s_complete_callback = NULL;
static spi_slave_transaction_t s_spi_transaction;

typedef struct {
uint16_t output_buf_len;
uint16_t input_buf_len;
} pending_transaction_t;

static otPlatSpiSlaveTransactionProcessCallback s_process_callback = NULL;
static otPlatSpiSlaveTransactionCompleteCallback s_complete_callback = NULL;

static DRAM_ATTR esp_openthread_spi_slave_config_t *s_spi_config;
static DRAM_ATTR spi_slave_transaction_t *s_spi_transaction;
static DRAM_ATTR pending_transaction_t *s_pending_transaction;

static void IRAM_ATTR handle_spi_setup_done(spi_slave_transaction_t *trans)
{
if (s_request_transaction) {
gpio_set_level(s_spi_config.intr_pin, 0);
gpio_set_level(s_spi_config->intr_pin, 0);
}
}

static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans)
{
gpio_set_level(s_spi_config.intr_pin, 1);
pending_transaction_t *pending_transaction = (pending_transaction_t *)&(trans->user);
gpio_set_level(s_spi_config->intr_pin, 1);
pending_transaction_t *pending_transaction = (pending_transaction_t *)(trans->user);
trans->trans_len /= CHAR_BIT;

if (s_complete_callback &&
s_complete_callback(s_context, (uint8_t *)trans->tx_buffer, pending_transaction->output_buf_len,
s_complete_callback(s_context, (void*)trans->tx_buffer, pending_transaction->output_buf_len,
trans->rx_buffer, pending_transaction->input_buf_len, trans->trans_len)) {
esp_openthread_task_queue_post(s_process_callback, s_context);
}
Expand All @@ -72,33 +73,54 @@ static void IRAM_ATTR handle_spi_transaction_done(spi_slave_transaction_t *trans

esp_err_t esp_openthread_host_rcp_spi_init(const esp_openthread_platform_config_t *config)
{
s_spi_config = config->host_config.spi_slave_config;
s_spi_config = heap_caps_malloc(sizeof(esp_openthread_spi_slave_config_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_RETURN_ON_FALSE(s_spi_config != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG,
"failed to allocate memory for SPI transaction on internal heap");
memcpy(s_spi_config, &(config->host_config.spi_slave_config), sizeof(esp_openthread_spi_slave_config_t));
gpio_config_t io_conf = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = (1 << s_spi_config.intr_pin),
.pin_bit_mask = (1 << s_spi_config->intr_pin),
};
ESP_RETURN_ON_ERROR(gpio_config(&io_conf), OT_PLAT_LOG_TAG, "fail to configure SPI gpio");

gpio_set_pull_mode(s_spi_config.bus_config.mosi_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config.bus_config.sclk_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config.slave_config.spics_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config->bus_config.mosi_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config->bus_config.sclk_io_num, GPIO_PULLUP_ONLY);
gpio_set_pull_mode(s_spi_config->slave_config.spics_io_num, GPIO_PULLUP_ONLY);

s_spi_transaction = heap_caps_malloc(sizeof(spi_slave_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
s_pending_transaction = heap_caps_malloc(sizeof(pending_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
if (s_spi_transaction == NULL || s_pending_transaction == NULL) {
heap_caps_free(s_spi_config);
heap_caps_free(s_spi_transaction);
heap_caps_free(s_pending_transaction);
ESP_LOGE(OT_PLAT_LOG_TAG, "failed to allocate memory for SPI transaction on internal heap");
return ESP_ERR_NO_MEM;
}

s_spi_transaction->user = (void *)s_pending_transaction;

/* Initialize SPI slave interface */
s_spi_config.slave_config.post_setup_cb = handle_spi_setup_done;
s_spi_config.slave_config.post_trans_cb = handle_spi_transaction_done;
ESP_RETURN_ON_ERROR(spi_slave_initialize(s_spi_config.host_device, &s_spi_config.bus_config,
&s_spi_config.slave_config, SPI_DMA_CH_AUTO),
s_spi_config->slave_config.post_setup_cb = handle_spi_setup_done;
s_spi_config->slave_config.post_trans_cb = handle_spi_transaction_done;
ESP_RETURN_ON_ERROR(spi_slave_initialize(s_spi_config->host_device, &s_spi_config->bus_config,
&s_spi_config->slave_config, SPI_DMA_CH_AUTO),
OT_PLAT_LOG_TAG, "fail to initialize SPI slave");

return ESP_OK;
}

void esp_openthread_spi_slave_deinit(void)
{
spi_slave_free(s_spi_config.host_device);
s_spi_config.slave_config.post_setup_cb = NULL;
s_spi_config.slave_config.post_trans_cb = NULL;
spi_slave_free(s_spi_config->host_device);
s_spi_config->slave_config.post_setup_cb = NULL;
s_spi_config->slave_config.post_trans_cb = NULL;
heap_caps_free(s_spi_config);
heap_caps_free(s_spi_transaction);
heap_caps_free(s_pending_transaction);
s_spi_config = NULL;
s_spi_transaction = NULL;
s_pending_transaction = NULL;
return;
}

Expand All @@ -115,43 +137,38 @@ otError IRAM_ATTR otPlatSpiSlavePrepareTransaction(uint8_t *aOutputBuf, uint16_t
uint16_t aInputBufLen, bool aRequestTransactionFlag)
{
esp_err_t trans_state = ESP_OK;
pending_transaction_t *pending_transaction = NULL;
if (aOutputBuf == NULL) {
aOutputBuf = s_prev_output_buf;
aOutputBufLen = s_prev_output_len;
uint16_t trans_length = 0;

if (aOutputBuf != NULL) {
s_output_buf = aOutputBuf;
s_output_len = aOutputBufLen;
}
if (aInputBuf == NULL) {
aInputBuf = s_prev_input_buf;
aInputBufLen = s_prev_input_len;
if (aInputBuf != NULL) {
s_input_buf = aInputBuf;
s_input_len = aInputBufLen;
}
s_prev_output_buf = aOutputBuf;
s_prev_output_len = aOutputBufLen;
s_prev_input_buf = aInputBuf;
s_prev_input_len = aInputBufLen;

s_spi_transaction.length = aOutputBufLen > aInputBufLen ? aOutputBufLen : aInputBufLen;
s_spi_transaction.length *= CHAR_BIT;
s_spi_transaction.rx_buffer = aInputBuf;
s_spi_transaction.tx_buffer = aOutputBuf;

assert(sizeof(s_spi_transaction.user) >= sizeof(pending_transaction_t));
pending_transaction = (pending_transaction_t *)&(s_spi_transaction.user);
pending_transaction->input_buf_len = aInputBufLen;
pending_transaction->output_buf_len = aOutputBufLen;
s_spi_transaction.user = pending_transaction;
s_request_transaction = aRequestTransactionFlag;

if ((gpio_get_level(s_spi_config.slave_config.spics_io_num) == 0)) {
trans_length = s_output_len > s_input_len ? s_output_len : s_input_len;
trans_length *= CHAR_BIT;
if ((gpio_get_level(s_spi_config->slave_config.spics_io_num) == 0)) {
ESP_EARLY_LOGE(SPI_SLAVE_TAG, "SPI busy");
return OT_ERROR_BUSY;
}
s_spi_transaction->length = trans_length;
s_spi_transaction->rx_buffer = s_input_buf;
s_spi_transaction->tx_buffer = s_output_buf;

pending_transaction_t *pending_transaction = (pending_transaction_t *)s_spi_transaction->user;
pending_transaction->input_buf_len = s_input_len;
pending_transaction->output_buf_len = s_output_len;
s_request_transaction = aRequestTransactionFlag;

if (xPortCanYield()) {
spi_slave_queue_reset(s_spi_config.host_device);
trans_state = spi_slave_queue_trans(s_spi_config.host_device, &s_spi_transaction, 0);
spi_slave_queue_reset(s_spi_config->host_device);
trans_state = spi_slave_queue_trans(s_spi_config->host_device, s_spi_transaction, 0);
} else {
spi_slave_queue_reset_isr(s_spi_config.host_device);
trans_state = spi_slave_queue_trans_isr(s_spi_config.host_device, &s_spi_transaction);
spi_slave_queue_reset_isr(s_spi_config->host_device);
trans_state = spi_slave_queue_trans_isr(s_spi_config->host_device, s_spi_transaction);
}

if (trans_state == ESP_OK) {
Expand Down

0 comments on commit f0d10c8

Please sign in to comment.