Files

279 lines
9.5 KiB
C

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#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;
}