#include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/event_groups.h" #include "freertos/stream_buffer.h" #include "ringbuf.h" #include "esp8266/spi_struct.h" #include "esp8266/gpio_struct.h" #include "esp_system.h" #include "esp_log.h" #include "driver/gpio.h" #include "driver/spi.h" #include "driver/hspi_logic_layer.h" static const char *TAG = "hspi_logic"; #define SPI_CHECK(a, str, ret_val) \ do { \ if (!(a)) { \ ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ return (ret_val); \ } \ } while(0) typedef struct { gpio_num_t trigger_pin; uint8_t trigger_level; bool is_sending; bool is_blocking_recv; uint32_t sending_len; uint32_t recving_len; StreamBufferHandle_t* tx_buffer; StreamBufferHandle_t* rx_buffer; SemaphoreHandle_t semphor; spi_event_callback_t event_cb; } spi_logic_device_t; static spi_logic_device_t * spi_logic_device; static void IRAM_ATTR hspi_slave_event_callback(int event, void *arg) { int x; BaseType_t xHigherPriorityTaskWoken; uint32_t status; uint32_t trans_done; uint32_t data[16]; spi_trans_t trans; uint16_t cmd = 0; bool trigger_flag = false; switch (event) { case SPI_TRANS_DONE_EVENT: { gpio_set_level(spi_logic_device->trigger_pin, !spi_logic_device->trigger_level); trans_done = *(uint32_t *)arg; if (trans_done & SPI_SLV_RD_BUF_DONE) { if (spi_logic_device->sending_len == 0) { spi_logic_device->is_sending = false; spi_logic_device->sending_len = xStreamBufferBytesAvailable(spi_logic_device->tx_buffer); if (spi_logic_device->sending_len > 0) { spi_slave_set_status(HSPI_HOST, (uint32_t*)&spi_logic_device->sending_len); spi_logic_device->is_sending = true; trigger_flag = true; } } else { memset(&trans, 0x0, sizeof(trans)); trans.cmd = &cmd; trans.addr = NULL; trans.bits.val = 0; // In Slave mode, spi cmd must be longer than 3 bits and shorter than 16 bits trans.bits.cmd = 8 * 1; // In Slave mode, spi addr must be longer than 1 bits and shorter than 32 bits trans.bits.addr = 8 * 1; trans.bits.mosi = 0; trans.miso = data; trans.bits.miso = xStreamBufferReceiveFromISR(spi_logic_device->tx_buffer, data, 64, &xHigherPriorityTaskWoken); if (trans.bits.miso != 0) { spi_logic_device->sending_len -= trans.bits.miso; trans.bits.miso <<= 3; spi_trans(HSPI_HOST, &trans); trigger_flag = true;; } } } if (trans_done & SPI_SLV_WR_BUF_DONE) { uint32_t len = spi_logic_device->recving_len; if (len > 64) { len = 64; } if (len > 0) { for (x = 0; x < 16; x++) { data[x] = SPI1.data_buf[x]; } xStreamBufferSendFromISR(spi_logic_device->rx_buffer, (void *) data, len, &xHigherPriorityTaskWoken); spi_logic_device->recving_len -= len; } else { ets_printf("remained %d\r\n", len); } if (xStreamBufferSpacesAvailable(spi_logic_device->rx_buffer) >= 64) { trigger_flag = true; } else { spi_logic_device->is_blocking_recv = true; } } if (trans_done & SPI_SLV_WR_STA_DONE) { spi_slave_get_status(HSPI_HOST, &status); spi_logic_device->recving_len = status; uint32_t tx_size = xStreamBufferBytesAvailable(spi_logic_device->tx_buffer); if (spi_logic_device->recving_len > 0) { trigger_flag = true; } else if (tx_size > 0) { if (spi_logic_device->is_sending == false) { spi_slave_set_status(HSPI_HOST, &tx_size); } trigger_flag = true; } } if (trans_done & SPI_SLV_RD_STA_DONE) { memset(&trans, 0x0, sizeof(trans)); trans.cmd = &cmd; trans.addr = NULL; trans.bits.val = 0; // In Slave mode, spi cmd must be longer than 3 bits and shorter than 16 bits trans.bits.cmd = 8 * 1; // In Slave mode, spi addr must be longer than 1 bits and shorter than 32 bits trans.bits.addr = 8 * 1; trans.bits.mosi = 0; trans.miso = data; trans.bits.miso = xStreamBufferReceiveFromISR(spi_logic_device->tx_buffer, data, 64, &xHigherPriorityTaskWoken); if (trans.bits.miso != 0) { spi_logic_device->sending_len -= trans.bits.miso; trans.bits.miso <<= 3; spi_trans(HSPI_HOST, &trans); trigger_flag = true; } } if (trigger_flag) { gpio_set_level(spi_logic_device->trigger_pin, spi_logic_device->trigger_level); } if (spi_logic_device->event_cb) { spi_logic_device->event_cb(event, arg); } if (xHigherPriorityTaskWoken == pdTRUE) { taskYIELD(); } } break; case SPI_DEINIT_EVENT: { } break; } } uint32_t hspi_slave_logic_read_data(uint8_t*data, uint32_t len, TickType_t xTicksToWait) { uint32_t ret = 0; ret = xStreamBufferReceive(spi_logic_device->rx_buffer, data, len, xTicksToWait); if (spi_logic_device->is_blocking_recv) { if (xStreamBufferBytesAvailable(spi_logic_device->rx_buffer) > 64) { gpio_set_level(spi_logic_device->trigger_pin, spi_logic_device->trigger_level); spi_logic_device->is_blocking_recv = false; } } return ret; } uint32_t hspi_slave_logic_write_data(uint8_t*data, uint32_t len, TickType_t xTicksToWait) { uint32_t ret = 0; uint32_t avail_spaces = 0; if (!spi_logic_device->is_sending) { portENTER_CRITICAL(); avail_spaces = xStreamBufferSpacesAvailable(spi_logic_device->tx_buffer); if (avail_spaces > len) { avail_spaces = len; } ret = xStreamBufferSend(spi_logic_device->tx_buffer, data, avail_spaces, xTicksToWait); // spi_logic_device->sending_len = xStreamBufferBytesAvailable(spi_logic_device->tx_buffer); spi_slave_set_status(HSPI_HOST, (uint32_t*)&spi_logic_device->sending_len); spi_logic_device->is_sending = true; gpio_set_level(spi_logic_device->trigger_pin, spi_logic_device->trigger_level); portEXIT_CRITICAL(); } if (ret < len) { ret += xStreamBufferSend(spi_logic_device->tx_buffer, data + ret, len - ret, xTicksToWait); } return ret; } esp_err_t hspi_slave_logic_device_create(gpio_num_t trigger_pin, uint32_t trigger_level,uint32_t tx_buffer_size, uint32_t rx_buffer_size) { SPI_CHECK(GPIO_IS_VALID_GPIO(trigger_pin), "gpio num error", ESP_ERR_INVALID_ARG); SPI_CHECK(tx_buffer_size != 0, "tx buffer error", ESP_ERR_INVALID_ARG); SPI_CHECK(rx_buffer_size != 0, "rx buffer error", ESP_ERR_INVALID_ARG); gpio_config_t io_conf; if (spi_logic_device) { hspi_slave_logic_device_delete(); } spi_logic_device = (spi_logic_device_t*)malloc(sizeof(spi_logic_device_t)); assert(spi_logic_device); memset(spi_logic_device, 0x0, sizeof(spi_logic_device_t)); spi_logic_device->tx_buffer = xStreamBufferCreate(tx_buffer_size,1); if (!spi_logic_device->tx_buffer) { free(spi_logic_device); spi_logic_device = NULL; return ESP_ERR_NO_MEM; } spi_logic_device->rx_buffer = xStreamBufferCreate(rx_buffer_size,1); if (!spi_logic_device->rx_buffer) { vStreamBufferDelete(spi_logic_device->tx_buffer); spi_logic_device->tx_buffer = NULL; free(spi_logic_device); spi_logic_device = NULL; return ESP_ERR_NO_MEM; } spi_logic_device->trigger_pin = trigger_pin; spi_logic_device->trigger_level = (trigger_level==1)?1:0; memset(&io_conf, 0x0, sizeof(io_conf)); io_conf.intr_type = GPIO_INTR_DISABLE; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pin_bit_mask = (1ULL << trigger_pin); io_conf.pull_down_en = 0; io_conf.pull_up_en = 0; gpio_config(&io_conf); gpio_set_level(trigger_pin, !spi_logic_device->trigger_level); spi_get_event_callback(HSPI_HOST, &spi_logic_device->event_cb); spi_event_callback_t event_cb = hspi_slave_event_callback; spi_set_event_callback(HSPI_HOST, &event_cb); return ESP_OK; } esp_err_t hspi_slave_logic_device_delete(void) { if (spi_logic_device == NULL) { return ESP_ERR_INVALID_STATE; } vStreamBufferDelete(spi_logic_device->tx_buffer); spi_logic_device->tx_buffer = NULL; vStreamBufferDelete(spi_logic_device->rx_buffer); spi_logic_device->rx_buffer = NULL; free(spi_logic_device); spi_logic_device = NULL; return ESP_OK; }