mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-21 09:05:59 +08:00
279 lines
9.5 KiB
C
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;
|
|
}
|