1.接管中断(未测试)。

This commit is contained in:
MacRsh
2023-07-16 01:13:17 +08:00
parent c7eb0e7905
commit d235fed2b4
2 changed files with 398 additions and 37 deletions

View File

@@ -11,16 +11,78 @@
#include "device/spi/spi.h"
#if (MR_CONF_PIN == MR_CONF_ENABLE)
#include "device/pin/pin.h"
#endif
#if (MR_CONF_SPI == MR_CONF_ENABLE)
static mr_err_t mr_take_spi_bus(mr_spi_device_t spi_device)
static mr_err_t mr_spi_bus_rx_fifo_init(mr_spi_bus_t spi_bus, mr_size_t rx_bufsz)
{
mr_uint8_t *buffer = MR_NULL;
if (spi_bus->rx_fifo.buffer)
{
mr_free(spi_bus->rx_fifo.buffer);
mr_fifo_init(&spi_bus->rx_fifo, MR_NULL, 0);
}
spi_bus->rx_bufsz = rx_bufsz;
if (spi_bus->rx_bufsz != 0)
{
buffer = mr_malloc(spi_bus->rx_bufsz);
if (buffer == MR_NULL)
{
return -MR_ERR_NO_MEMORY;
}
mr_fifo_init(&spi_bus->rx_fifo, buffer, spi_bus->rx_bufsz);
}
return MR_ERR_OK;
}
static mr_err_t mr_spi_bus_tx_fifo_init(mr_spi_bus_t spi_bus, mr_size_t tx_bufsz)
{
mr_uint8_t *buffer = MR_NULL;
if (spi_bus->tx_fifo.buffer)
{
mr_free(spi_bus->tx_fifo.buffer);
mr_fifo_init(&spi_bus->tx_fifo, MR_NULL, 0);
}
spi_bus->tx_bufsz = tx_bufsz;
if (spi_bus->tx_bufsz != 0)
{
buffer = mr_malloc(spi_bus->tx_bufsz);
if (buffer == MR_NULL)
{
return -MR_ERR_NO_MEMORY;
}
mr_fifo_init(&spi_bus->tx_fifo, buffer, spi_bus->tx_bufsz);
}
return MR_ERR_OK;
}
mr_inline mr_uint8_t mr_spi_bus_transfer(mr_spi_bus_t spi_bus, mr_uint8_t data)
{
spi_bus->ops->write(spi_bus, data);
return spi_bus->ops->read(spi_bus);
}
mr_inline mr_err_t mr_take_spi_bus(mr_spi_device_t spi_device)
{
mr_err_t ret = MR_ERR_OK;
MR_ASSERT(spi_device->bus != MR_NULL);
/* Without attach the bus */
if (spi_device->bus == MR_NULL)
{
return -MR_ERR_GENERIC;
}
/* Take the mutex lock of the spi-bus */
ret = mr_mutex_take(&spi_device->bus->lock, &spi_device->device.object);
@@ -49,18 +111,18 @@ static mr_err_t mr_take_spi_bus(mr_spi_device_t spi_device)
spi_device->bus->config = spi_device->config;
spi_device->bus->owner = spi_device;
}
/* Start the chip-select of the current spi-device */
spi_device->bus->ops->cs_ctrl(spi_device->bus, spi_device->bus->owner->cs_pin, MR_ENABLE);
return MR_ERR_OK;
}
static mr_err_t mr_release_spi_bus(mr_spi_device_t spi_device)
mr_inline mr_err_t mr_release_spi_bus(mr_spi_device_t spi_device)
{
mr_err_t ret = MR_ERR_OK;
MR_ASSERT(spi_device->bus != MR_NULL);
/* Without attach the bus */
if (spi_device->bus == MR_NULL)
{
return -MR_ERR_GENERIC;
}
/* Release the mutex lock of the spi-bus */
ret = mr_mutex_release(&spi_device->bus->lock, &spi_device->device.object);
@@ -69,17 +131,27 @@ static mr_err_t mr_release_spi_bus(mr_spi_device_t spi_device)
return ret;
}
/* Stop the chip-select of the current spi-device */
spi_device->bus->ops->cs_ctrl(spi_device->bus, spi_device->bus->owner->cs_pin, MR_DISABLE);
return MR_ERR_OK;
}
static mr_err_t mr_spi_bus_open(mr_device_t device)
{
mr_spi_bus_t spi_bus = (mr_spi_bus_t)device;
mr_err_t ret = MR_ERR_OK;
struct mr_spi_config default_config = MR_SPI_CONFIG_DEFAULT;
/* Allocate the fifo buffer */
ret = mr_spi_bus_rx_fifo_init(spi_bus, spi_bus->rx_bufsz);
if (ret != MR_ERR_OK)
{
return ret;
}
ret = mr_spi_bus_tx_fifo_init(spi_bus, spi_bus->tx_bufsz);
if (ret != MR_ERR_OK)
{
return ret;
}
/* Setting spi-bus to default config, if the baud-rate not set */
if (spi_bus->config.baud_rate == 0)
{
@@ -92,6 +164,21 @@ static mr_err_t mr_spi_bus_open(mr_device_t device)
static mr_err_t mr_spi_bus_close(mr_device_t device)
{
mr_spi_bus_t spi_bus = (mr_spi_bus_t)device;
mr_err_t ret = MR_ERR_OK;
/* Allocate the fifo buffer */
ret = mr_spi_bus_rx_fifo_init(spi_bus, 0);
if (ret != MR_ERR_OK)
{
return ret;
}
ret = mr_spi_bus_tx_fifo_init(spi_bus, 0);
if (ret != MR_ERR_OK)
{
return ret;
}
spi_bus->rx_bufsz = MR_CONF_SPI_RX_BUFSZ;
spi_bus->tx_bufsz = MR_CONF_SPI_TX_BUFSZ;
/* Setting spi-bus to close config */
spi_bus->config.baud_rate = 0;
@@ -99,6 +186,35 @@ static mr_err_t mr_spi_bus_close(mr_device_t device)
return spi_bus->ops->configure(spi_bus, &spi_bus->config);
}
static mr_err_t mr_spi_bus_ioctl(mr_device_t device, int cmd, void *args)
{
mr_spi_bus_t spi_bus = (mr_spi_bus_t)device;
switch (cmd & _MR_CTRL_FLAG_MASK)
{
case MR_CTRL_SET_RX_BUFSZ:
{
if (args)
{
return mr_spi_bus_rx_fifo_init(spi_bus, *((mr_size_t *)args));
}
return -MR_ERR_INVALID;
}
case MR_CTRL_SET_TX_BUFSZ:
{
if (args)
{
return mr_spi_bus_tx_fifo_init(spi_bus, *((mr_size_t *)args));
}
return -MR_ERR_INVALID;
}
default:
return -MR_ERR_UNSUPPORTED;
}
}
static mr_err_t mr_spi_device_open(mr_device_t device)
{
mr_spi_device_t spi_device = (mr_spi_device_t)device;
@@ -156,14 +272,10 @@ static mr_err_t mr_spi_device_ioctl(mr_device_t device, int cmd, void *args)
/* Find the spi-bus */
mr_device_t spi_bus = mr_device_find((char *)args);
if (spi_bus == MR_NULL)
if (spi_bus == MR_NULL || spi_bus->type != MR_DEVICE_TYPE_SPI_BUS)
{
return -MR_ERR_NOT_FOUND;
}
if (spi_bus->type != MR_DEVICE_TYPE_SPI_BUS)
{
return -MR_ERR_INVALID;
}
/* Open the spi-bus */
ret = mr_device_open(spi_bus, MR_OPEN_RDWR);
@@ -190,9 +302,9 @@ static mr_err_t mr_spi_device_ioctl(mr_device_t device, int cmd, void *args)
{
buffer = (mr_uint8_t *)((mr_transfer_t)args)->data;
for (size = 0; size < ((mr_transfer_t)args)->size; size++)
for (size = 0; size < ((mr_transfer_t)args)->size; size += sizeof(*buffer))
{
*buffer = spi_device->bus->ops->transfer(spi_device->bus, *buffer);
*buffer = mr_spi_bus_transfer(spi_device->bus, *buffer);
buffer++;
}
@@ -226,16 +338,38 @@ static mr_ssize_t mr_spi_device_read(mr_device_t device, mr_off_t pos, void *buf
return ret;
}
/* Send offset */
if (pos > 0)
if (spi_device->config.host_slave == MR_SPI_HOST)
{
spi_device->bus->ops->transfer(spi_device->bus, (mr_uint8_t)pos);
}
/* Start the chip-select of the current spi-device */
spi_device->bus->ops->cs_ctrl(spi_device->bus, spi_device->bus->owner->cs_pin, MR_ENABLE);
for (recv_size = 0; recv_size < size; recv_size += sizeof(recv_buffer))
/* Send position */
if (pos != 0)
{
mr_spi_bus_transfer(spi_device->bus, (mr_uint8_t)pos);
}
/* Host blocking read */
for (recv_size = 0; recv_size < size; recv_size += sizeof(*recv_buffer))
{
*recv_buffer = mr_spi_bus_transfer(spi_device->bus, 0u);
recv_buffer++;
}
/* Stop the chip-select of the current spi-device */
spi_device->bus->ops->cs_ctrl(spi_device->bus, spi_device->bus->owner->cs_pin, MR_DISABLE);
} else
{
*recv_buffer = spi_device->bus->ops->transfer(spi_device->bus, 0u);
recv_buffer++;
if (spi_device->bus->rx_bufsz == 0)
{
return -MR_ERR_UNSUPPORTED;
}
/* Slave non-blocking read */
for (recv_size = 0; recv_size < size;)
{
recv_size += mr_fifo_read(&spi_device->bus->rx_fifo, recv_buffer + recv_size, size - recv_size);
}
}
/* Release spi-bus */
@@ -249,7 +383,10 @@ static mr_ssize_t mr_spi_device_write(mr_device_t device, mr_off_t pos, const vo
mr_spi_device_t spi_device = (mr_spi_device_t)device;
mr_uint8_t *send_buffer = (mr_uint8_t *)buffer;
mr_err_t ret = MR_ERR_OK;
mr_spi_bus_t spi_bus = MR_NULL;
mr_size_t send_size = 0;
mr_uint8_t send_position = 0;
mr_size_t dma_size = 0;
/* Take spi-bus */
ret = mr_take_spi_bus(spi_device);
@@ -257,17 +394,87 @@ static mr_ssize_t mr_spi_device_write(mr_device_t device, mr_off_t pos, const vo
{
return ret;
}
spi_bus = spi_device->bus;
/* Send offset */
if (pos > 0)
if (spi_bus->tx_bufsz == 0 || (spi_device->device.open_flag & MR_OPEN_NONBLOCKING) == 0)
{
spi_device->bus->ops->transfer(spi_device->bus, (mr_uint8_t)pos);
}
if (spi_device->config.host_slave == MR_SPI_HOST)
{
/* Start the chip-select of the current device */
spi_bus->ops->cs_ctrl(spi_bus, spi_device->cs_pin, MR_ENABLE);
for (send_size = 0; send_size < size; send_size += sizeof(send_buffer))
/* Send position */
if (pos != 0)
{
mr_spi_bus_transfer(spi_bus, (mr_uint8_t)pos);
}
}
/* Blocking write */
for (send_size = 0; send_size < size; send_size += sizeof(*send_buffer))
{
mr_spi_bus_transfer(spi_bus, *send_buffer);
send_buffer++;
}
/* Stop the chip-select of the current device */
if (spi_device->config.host_slave == MR_SPI_HOST)
{
spi_bus->ops->cs_ctrl(spi_bus, spi_device->cs_pin, MR_DISABLE);
}
} else
{
spi_device->bus->ops->transfer(spi_device->bus, *send_buffer);
send_buffer++;
if (spi_device->config.host_slave == MR_SPI_HOST)
{
/* Send position */
if (pos != 0)
{
send_position = (mr_uint8_t)pos;
for (send_size = 0; send_size < sizeof(send_position);)
{
send_size += mr_fifo_write(&spi_bus->tx_fifo, &send_position, sizeof(send_position));
}
}
}
/* Count the number of send */
spi_device->tx_count += size;
if (mr_list_is_empty(&spi_device->tx_list))
{
mr_list_insert_before(&spi_bus->tx_list, &spi_device->tx_list);
}
/* Non-blocking write */
for (send_size = 0; send_size < size;)
{
/* If this is the first write, start sending */
if (mr_fifo_get_data_size(&spi_bus->tx_fifo) != 0)
{
send_size += mr_fifo_write(&spi_bus->tx_fifo, send_buffer + send_size, size - send_size);
} else
{
send_size += mr_fifo_write(&spi_bus->tx_fifo, send_buffer + send_size, size - send_size);
/* Start the chip-select of the current device */
if (spi_device->config.host_slave == MR_SPI_HOST)
{
spi_bus->ops->cs_ctrl(spi_bus, spi_device->cs_pin, MR_ENABLE);
}
if ((device->open_flag & MR_OPEN_DMA) == 0)
{
/* Interrupt write */
spi_bus->ops->start_tx(spi_bus);
} else
{
/* DMA write */
dma_size = mr_fifo_read(&spi_bus->tx_fifo,
spi_bus->tx_dma,
sizeof(spi_bus->tx_dma));
spi_bus->ops->start_dma_tx(spi_bus, spi_bus->tx_dma, dma_size);
}
}
}
}
/* Release spi-bus */
@@ -282,7 +489,12 @@ static mr_err_t _err_io_spi_configure(mr_spi_bus_t spi_bus, struct mr_spi_config
return -MR_ERR_IO;
}
static mr_uint8_t _err_io_spi_transfer(mr_spi_bus_t spi_bus, mr_uint8_t data)
static void _err_io_spi_write(mr_spi_bus_t spi_bus, mr_uint8_t data)
{
MR_ASSERT(0);
}
static mr_uint8_t _err_io_spi_read(mr_spi_bus_t spi_bus)
{
MR_ASSERT(0);
return 0;
@@ -293,13 +505,29 @@ static void _err_io_spi_cs_ctrl(mr_spi_bus_t spi_bus, mr_uint16_t cs_pin, mr_uin
MR_ASSERT(0);
}
static mr_uint8_t _err_io_spi_cs_read(mr_spi_bus_t spi_bus, mr_uint16_t cs_pin)
{
MR_ASSERT(0);
return 0;
}
static void _err_io_spi_start_tx(mr_spi_bus_t spi_bus)
{
MR_ASSERT(0);
}
static void _err_io_spi_stop_tx(mr_spi_bus_t spi_bus)
{
MR_ASSERT(0);
}
mr_err_t mr_spi_bus_add(mr_spi_bus_t spi_bus, const char *name, void *data, struct mr_spi_bus_ops *ops)
{
const static struct mr_device_ops device_ops =
{
mr_spi_bus_open,
mr_spi_bus_close,
MR_NULL,
mr_spi_bus_ioctl,
MR_NULL,
MR_NULL,
};
@@ -316,11 +544,20 @@ mr_err_t mr_spi_bus_add(mr_spi_bus_t spi_bus, const char *name, void *data, stru
spi_bus->config.baud_rate = 0;
spi_bus->owner = MR_NULL;
mr_mutex_init(&spi_bus->lock);
spi_bus->rx_bufsz = MR_CONF_SPI_RX_BUFSZ;
mr_fifo_init(&spi_bus->rx_fifo, MR_NULL, 0);
spi_bus->tx_bufsz = MR_CONF_SPI_TX_BUFSZ;
mr_fifo_init(&spi_bus->tx_fifo, MR_NULL, 0);
mr_list_init(&spi_bus->tx_list);
/* Set operations as protection-ops if ops is null */
ops->configure = ops->configure ? ops->configure : _err_io_spi_configure;
ops->transfer = ops->transfer ? ops->transfer : _err_io_spi_transfer;
ops->write = ops->write ? ops->write : _err_io_spi_write;
ops->read = ops->read ? ops->read : _err_io_spi_read;
ops->cs_ctrl = ops->cs_ctrl ? ops->cs_ctrl : _err_io_spi_cs_ctrl;
ops->cs_read = ops->cs_read ? ops->cs_read : _err_io_spi_cs_read;
ops->start_tx = ops->start_tx ? ops->start_tx : _err_io_spi_start_tx;
ops->stop_tx = ops->stop_tx ? ops->stop_tx : _err_io_spi_stop_tx;
spi_bus->ops = ops;
/* Add to the container */
@@ -353,6 +590,8 @@ mr_err_t mr_spi_device_add(mr_spi_device_t spi_device, const char *name, mr_uint
spi_device->config.baud_rate = 0;
spi_device->bus = MR_NULL;
spi_device->cs_pin = cs_pin;
mr_list_init(&spi_device->tx_list);
spi_device->tx_count = 0;
#if (MR_CONF_PIN == MR_CONF_ENABLE)
/* Configure pin */
@@ -366,7 +605,95 @@ mr_err_t mr_spi_device_add(mr_spi_device_t spi_device, const char *name, mr_uint
#endif /* MR_CONF_PIN */
/* Add to the container */
return mr_device_add(&spi_device->device, name, MR_OPEN_RDWR);
return mr_device_add(&spi_device->device, name, MR_OPEN_RDWR | MR_OPEN_NONBLOCKING);
}
void mr_spi_bus_isr(mr_spi_bus_t spi_bus, mr_uint32_t event)
{
mr_spi_device_t spi_device = MR_NULL;
mr_uint32_t length = 0;
mr_uint8_t data = 0;
mr_size_t dma_size = 0;
MR_ASSERT(spi_bus != MR_NULL);
switch (event & _MR_SPI_BUS_EVENT_MASK)
{
case MR_SPI_BUS_EVENT_RX_INT:
{
spi_device = spi_bus->owner;
/* The data not belong to this device */
if (spi_device->config.host_slave == MR_SPI_HOST ||
spi_bus->ops->cs_read(spi_bus, spi_device->cs_pin) != spi_device->config.cs_active)
{
break;
}
/* Read data into the fifo */
data = spi_bus->ops->read(spi_bus);
mr_fifo_write_force(&spi_bus->rx_fifo, &data, sizeof(data));
/* Invoke the rx-cb function */
if (spi_device->device.rx_cb != MR_NULL)
{
length = mr_fifo_get_data_size(&spi_bus->rx_fifo);
spi_device->device.rx_cb(&spi_device->device, &length);
}
break;
}
case MR_SPI_BUS_EVENT_TX_INT:
{
/* Check if the list is not empty */
if (!mr_list_is_empty(&spi_bus->tx_list))
{
spi_device = mr_container_of(spi_bus->tx_list.next, struct mr_spi_device, tx_list);
if (spi_device->tx_count == 0)
{
/* Remove from the list */
mr_list_remove(&spi_device->tx_list);
/* Stop the chip-select of the current device */
if (spi_device->config.host_slave == MR_SPI_HOST)
{
spi_bus->ops->cs_ctrl(spi_bus, spi_device->cs_pin, MR_DISABLE);
}
/* Invoke the tx-cb function */
if (spi_device->device.tx_cb != MR_NULL)
{
spi_device->device.rx_cb(&spi_device->device, &spi_device->tx_count);
}
/* Select next device if list not empty */
if (!mr_list_is_empty(&spi_bus->tx_list))
{
spi_device = mr_container_of(spi_bus->tx_list.next, struct mr_spi_device, tx_list);
/* Start the chip-select of the current device */
if (spi_device->config.host_slave == MR_SPI_HOST)
{
spi_bus->ops->cs_ctrl(spi_bus, spi_device->cs_pin, MR_ENABLE);
}
}
} else
{
/* Decrement tx count */
spi_device->tx_count--;
/* Write data from the fifo */
mr_fifo_read(&spi_bus->tx_fifo, &data, sizeof(data));
mr_spi_bus_transfer(spi_bus, data);
}
} else
{
/* Stop transmission */
spi_bus->ops->stop_tx(spi_bus);
}
break;
}
}
}
#endif /* MR_CONF_SPI */

View File

@@ -30,6 +30,15 @@
#define MR_SPI_CS_ACTIVE_HIGH 1
#define MR_SPI_CS_ACTIVE_NONE 2
#define MR_SPI_BUS_EVENT_RX_INT 0x10000000
#define MR_SPI_BUS_EVENT_TX_INT 0x20000000
#define MR_SPI_BUS_EVENT_RX_DMA 0x40000000
#define MR_SPI_BUS_EVENT_TX_DMA 0x80000000
#define _MR_SPI_BUS_EVENT_MASK 0xf0000000
#define _MR_SPI_BUS_STATE_IDLE 0x00
#define _MR_SPI_BUS_STATE_RUNNING 0x10
/* Default config for mr_spi_config structure */
#define MR_SPI_CONFIG_DEFAULT \
{ \
@@ -58,14 +67,27 @@ struct mr_spi_device
struct mr_spi_config config;
struct mr_spi_bus *bus;
mr_uint16_t cs_pin;
struct mr_list tx_list;
mr_size_t tx_count;
};
typedef struct mr_spi_device *mr_spi_device_t;
struct mr_spi_bus_ops
{
mr_err_t (*configure)(mr_spi_bus_t spi_bus, struct mr_spi_config *config);
mr_uint8_t (*transfer)(mr_spi_bus_t spi_bus, mr_uint8_t data);
void (*write)(mr_spi_bus_t spi_bus, mr_uint8_t data);
mr_uint8_t (*read)(mr_spi_bus_t spi_bus);
void (*cs_ctrl)(mr_spi_bus_t spi_bus, mr_uint16_t cs_pin, mr_uint8_t state);
/* Interrupt */
mr_uint8_t (*cs_read)(mr_spi_bus_t spi_bus, mr_uint16_t cs_pin);
void (*start_tx)(mr_spi_bus_t spi_bus);
void (*stop_tx)(mr_spi_bus_t spi_bus);
/* DMA */
void (*start_dma_tx)(mr_spi_bus_t spi_bus, mr_uint8_t *buffer, mr_size_t size);
void (*stop_dma_tx)(mr_spi_bus_t spi_bus);
};
struct mr_spi_bus
@@ -76,11 +98,23 @@ struct mr_spi_bus
struct mr_spi_device *owner;
struct mr_mutex lock;
/* Interrupt */
mr_size_t rx_bufsz;
struct mr_fifo rx_fifo;
mr_size_t tx_bufsz;
struct mr_fifo tx_fifo;
struct mr_list tx_list;
/* DMA */
mr_uint8_t rx_dma[MR_CONF_SERIAL_RX_DMA_BUFS];
mr_uint8_t tx_dma[MR_CONF_SERIAL_TX_DMA_BUFS];
const struct mr_spi_bus_ops *ops;
};
mr_err_t mr_spi_bus_add(mr_spi_bus_t spi_bus, const char *name, void *data, struct mr_spi_bus_ops *ops);
mr_err_t mr_spi_device_add(mr_spi_device_t spi_device, const char *name, mr_uint16_t cs_pin);
void mr_spi_bus_isr(mr_spi_bus_t spi_bus, mr_uint32_t event);
#endif /* MR_CONF_SPI */