mirror of https://github.com/ARMmbed/mbed-os.git
Modifications and bug fixes in SPI APIs' implementations.
parent
5d1b574d8b
commit
6fd1a45011
|
@ -68,6 +68,7 @@ enum spi_mode {
|
||||||
# define SPI_TIMEOUT 10000
|
# define SPI_TIMEOUT 10000
|
||||||
|
|
||||||
extern uint8_t g_sys_init;
|
extern uint8_t g_sys_init;
|
||||||
|
uint16_t dummy_fill_word = 0xFFFF;
|
||||||
|
|
||||||
#if DEVICE_SPI_ASYNCH
|
#if DEVICE_SPI_ASYNCH
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
|
@ -93,7 +94,7 @@ const uint32_t _sercom_handlers[SERCOM_INST_NUM] = {
|
||||||
MREPEAT(SERCOM_INST_NUM, _SERCOM_SPI_INTERRUPT_HANDLER_DECLR, ~)
|
MREPEAT(SERCOM_INST_NUM, _SERCOM_SPI_INTERRUPT_HANDLER_DECLR, ~)
|
||||||
};
|
};
|
||||||
uint32_t _sercom_callbacks[SERCOM_INST_NUM] = {0};
|
uint32_t _sercom_callbacks[SERCOM_INST_NUM] = {0};
|
||||||
#endif
|
#endif /* DEVICE_SPI_ASYNCH */
|
||||||
|
|
||||||
static inline bool spi_is_syncing(spi_t *obj)
|
static inline bool spi_is_syncing(spi_t *obj)
|
||||||
{
|
{
|
||||||
|
@ -172,13 +173,13 @@ static inline bool spi_write(spi_t *obj, uint16_t tx_data)
|
||||||
/* Check if the data register has been copied to the shift register */
|
/* Check if the data register has been copied to the shift register */
|
||||||
if (!spi_is_ready_to_write(obj)) {
|
if (!spi_is_ready_to_write(obj)) {
|
||||||
/* Data register has not been copied to the shift register, return */
|
/* Data register has not been copied to the shift register, return */
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the character to the DATA register */
|
/* Write the character to the DATA register */
|
||||||
_SPI(obj).DATA.reg = tx_data & SERCOM_SPI_DATA_MASK;
|
_SPI(obj).DATA.reg = tx_data & SERCOM_SPI_DATA_MASK;
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool spi_read(spi_t *obj, uint16_t *rx_data)
|
static inline bool spi_read(spi_t *obj, uint16_t *rx_data)
|
||||||
|
@ -189,7 +190,7 @@ static inline bool spi_read(spi_t *obj, uint16_t *rx_data)
|
||||||
/* Check if data is ready to be read */
|
/* Check if data is ready to be read */
|
||||||
if (!spi_is_ready_to_read(obj)) {
|
if (!spi_is_ready_to_read(obj)) {
|
||||||
/* No data has been received, return */
|
/* No data has been received, return */
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if data is overflown */
|
/* Check if data is overflown */
|
||||||
|
@ -205,7 +206,7 @@ static inline bool spi_read(spi_t *obj, uint16_t *rx_data)
|
||||||
*rx_data = (uint8_t)_SPI(obj).DATA.reg;
|
*rx_data = (uint8_t)_SPI(obj).DATA.reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,8 +235,8 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
|
||||||
g_sys_init = 1;
|
g_sys_init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Calculate SERCOM instance from pins
|
/* TODO: Calculate SERCOM instance from pins */
|
||||||
// TEMP: Giving our own value for testing
|
/* TEMP: Giving external SPI module value of SAMR21 for now */
|
||||||
pSPI_SERCOM(obj) = EXT1_SPI_MODULE;
|
pSPI_SERCOM(obj) = EXT1_SPI_MODULE;
|
||||||
|
|
||||||
/* Disable SPI */
|
/* Disable SPI */
|
||||||
|
@ -291,13 +292,10 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
|
||||||
_SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
|
_SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
|
||||||
pSPI_S(obj)->mode = SPI_MODE_MASTER;
|
pSPI_S(obj)->mode = SPI_MODE_MASTER;
|
||||||
|
|
||||||
// TODO: Do pin muxing here
|
/* TODO: Do pin muxing here */
|
||||||
struct system_pinmux_config pin_conf;
|
struct system_pinmux_config pin_conf;
|
||||||
system_pinmux_get_config_defaults(&pin_conf);
|
system_pinmux_get_config_defaults(&pin_conf);
|
||||||
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
|
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
|
||||||
//if(config->mode == SPI_MODE_SLAVE) {
|
|
||||||
//pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
|
|
||||||
//}
|
|
||||||
|
|
||||||
uint32_t pad_pinmuxes[] = {
|
uint32_t pad_pinmuxes[] = {
|
||||||
EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1,
|
EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1,
|
||||||
|
@ -324,7 +322,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
|
||||||
_SPI(obj).BAUD.reg = (uint8_t)baud;
|
_SPI(obj).BAUD.reg = (uint8_t)baud;
|
||||||
|
|
||||||
/* Set MUX setting */
|
/* Set MUX setting */
|
||||||
ctrla |= EXT1_SPI_SERCOM_MUX_SETTING; // TODO: Change this to appropriate Settings
|
ctrla |= EXT1_SPI_SERCOM_MUX_SETTING; /* TODO: Change this to appropriate Settings */
|
||||||
|
|
||||||
/* Set SPI character size */
|
/* Set SPI character size */
|
||||||
ctrlb |= SERCOM_SPI_CTRLB_CHSIZE(0);
|
ctrlb |= SERCOM_SPI_CTRLB_CHSIZE(0);
|
||||||
|
@ -397,6 +395,8 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
|
||||||
/* Already in SPI master mode */
|
/* Already in SPI master mode */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* TODO: Change MUX settings to appropriate value */
|
||||||
|
|
||||||
/* Set SPI Frame size - only 8-bit and 9-bit supported now */
|
/* Set SPI Frame size - only 8-bit and 9-bit supported now */
|
||||||
_SPI(obj).CTRLB.bit.CHSIZE = (bits > 8)? 1 : 0;
|
_SPI(obj).CTRLB.bit.CHSIZE = (bits > 8)? 1 : 0;
|
||||||
|
|
||||||
|
@ -612,18 +612,20 @@ static void _spi_write_async(spi_t *obj)
|
||||||
/* Do nothing if we are at the end of buffer */
|
/* Do nothing if we are at the end of buffer */
|
||||||
if (obj->tx_buff.pos < obj->tx_buff.length) {
|
if (obj->tx_buff.pos < obj->tx_buff.length) {
|
||||||
/* Write value will be at least 8-bits long */
|
/* Write value will be at least 8-bits long */
|
||||||
data_to_send = tx_buffer[obj->tx_buff.pos];
|
if (tx_buffer)
|
||||||
|
data_to_send = tx_buffer[obj->tx_buff.pos];
|
||||||
/* Increment 8-bit index */
|
/* Increment 8-bit index */
|
||||||
obj->tx_buff.pos++;
|
obj->tx_buff.pos++;
|
||||||
|
|
||||||
if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
|
if (_SPI(obj).CTRLB.bit.CHSIZE == 1) {
|
||||||
data_to_send |= (tx_buffer[obj->tx_buff.pos] << 8);
|
if (tx_buffer)
|
||||||
|
data_to_send |= (tx_buffer[obj->tx_buff.pos] << 8);
|
||||||
/* Increment 8-bit index */
|
/* Increment 8-bit index */
|
||||||
obj->tx_buff.pos++;
|
obj->tx_buff.pos++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Write a dummy packet */
|
/* Write a dummy packet */
|
||||||
data_to_send = ~0;
|
data_to_send = dummy_fill_word;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the data to send*/
|
/* Write the data to send*/
|
||||||
|
@ -631,7 +633,7 @@ static void _spi_write_async(spi_t *obj)
|
||||||
|
|
||||||
/* Check for error */
|
/* Check for error */
|
||||||
if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
|
if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
|
||||||
obj->spi.event != SPI_EVENT_ERROR;
|
obj->spi.event |= SPI_EVENT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +656,7 @@ static void _spi_read_async(spi_t *obj)
|
||||||
_SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
|
_SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF;
|
||||||
if (obj->spi.mask & SPI_EVENT_RX_OVERFLOW) {
|
if (obj->spi.mask & SPI_EVENT_RX_OVERFLOW) {
|
||||||
/* Set overflow error */
|
/* Set overflow error */
|
||||||
obj->spi.event != SPI_EVENT_RX_OVERFLOW;
|
obj->spi.event |= SPI_EVENT_RX_OVERFLOW;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -663,7 +665,7 @@ static void _spi_read_async(spi_t *obj)
|
||||||
uint16_t received_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK);
|
uint16_t received_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK);
|
||||||
|
|
||||||
/* Do nothing if we are at the end of buffer */
|
/* Do nothing if we are at the end of buffer */
|
||||||
if (obj->rx_buff.pos >= obj->rx_buff.length) {
|
if ((obj->rx_buff.pos >= obj->rx_buff.length) && rx_buffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,15 +683,35 @@ static void _spi_read_async(spi_t *obj)
|
||||||
|
|
||||||
/* Check for error */
|
/* Check for error */
|
||||||
if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
|
if ((_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_ERROR) && (obj->spi.mask & SPI_EVENT_ERROR)) {
|
||||||
obj->spi.event != SPI_EVENT_ERROR;
|
obj->spi.event |= SPI_EVENT_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \internal
|
||||||
|
* Clears all interrupt flags of SPI
|
||||||
|
*
|
||||||
|
* \param[in,out] module Pointer to SPI software instance struct
|
||||||
|
*/
|
||||||
|
static void _spi_clear_interrupts(spi_t *obj)
|
||||||
|
{
|
||||||
|
uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
|
||||||
|
|
||||||
|
/* Clear all interrupts */
|
||||||
|
_SPI(obj).INTENCLR.reg =
|
||||||
|
SERCOM_SPI_INTFLAG_DRE |
|
||||||
|
SERCOM_SPI_INTFLAG_TXC |
|
||||||
|
SERCOM_SPI_INTFLAG_RXC |
|
||||||
|
SERCOM_SPI_INTFLAG_ERROR;
|
||||||
|
NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
|
||||||
|
NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \internal
|
* \internal
|
||||||
* Starts transceive of buffers with a given length
|
* Starts transceive of buffers with a given length
|
||||||
*
|
*
|
||||||
* \param[in] obj Pointer to SPI software instance struct
|
* \param[in,out] obj Pointer to SPI software instance struct
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void _spi_transceive_buffer(spi_t *obj)
|
static void _spi_transceive_buffer(spi_t *obj)
|
||||||
|
@ -698,30 +720,45 @@ static void _spi_transceive_buffer(spi_t *obj)
|
||||||
MBED_ASSERT(obj);
|
MBED_ASSERT(obj);
|
||||||
void (*callback_func)(void);
|
void (*callback_func)(void);
|
||||||
|
|
||||||
|
|
||||||
uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
|
uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
|
||||||
|
|
||||||
uint16_t interrupt_status = _SPI(obj).INTFLAG.reg;
|
uint16_t interrupt_status = _SPI(obj).INTFLAG.reg;
|
||||||
interrupt_status &= _SPI(obj).INTENSET.reg;
|
interrupt_status &= _SPI(obj).INTENSET.reg;
|
||||||
|
|
||||||
if (interrupt_status & SERCOM_SPI_INTFLAG_DRE) {
|
if (interrupt_status & SERCOM_SPI_INTFLAG_DRE) {
|
||||||
|
/* Clear DRE interrupt */
|
||||||
|
_SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_DRE;
|
||||||
|
/* Write data */
|
||||||
_spi_write_async(obj);
|
_spi_write_async(obj);
|
||||||
|
/* Set TXC interrupt */
|
||||||
|
_SPI(obj).INTENSET.reg |= SERCOM_SPI_INTFLAG_TXC;
|
||||||
|
}
|
||||||
|
if (interrupt_status & SERCOM_SPI_INTFLAG_TXC) {
|
||||||
|
/* Clear TXC interrupt */
|
||||||
|
_SPI(obj).INTENCLR.reg = SERCOM_SPI_INTFLAG_TXC;
|
||||||
|
if ((obj->rx_buff.buffer) && (obj->rx_buff.pos < obj->rx_buff.length)) {
|
||||||
|
while (!spi_is_ready_to_read(obj));
|
||||||
|
_spi_read_async(obj);
|
||||||
|
if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->tx_buff.length < obj->rx_buff.length)) {
|
||||||
|
obj->tx_buff.length = obj->rx_buff.length;
|
||||||
|
obj->tx_buff.buffer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj->tx_buff.pos < obj->tx_buff.length) {
|
||||||
|
/* Set DRE interrupt */
|
||||||
|
_SPI(obj).INTENSET.reg |= SERCOM_SPI_INTFLAG_DRE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interrupt_status & SERCOM_SPI_INTFLAG_RXC) {
|
if (obj->spi.event & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW) || (interrupt_status & SERCOM_SPI_INTFLAG_ERROR)) {
|
||||||
_spi_read_async(obj);
|
/* Clear all interrupts */
|
||||||
}
|
_spi_clear_interrupts(obj);
|
||||||
|
|
||||||
if (obj->spi.event & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW)) {
|
if (interrupt_status & SERCOM_SPI_INTFLAG_ERROR) {
|
||||||
/* Disable all interrupts */
|
obj->spi.event = STATUS_ERR_BAD_DATA;
|
||||||
_SPI(obj).INTENCLR.reg =
|
}
|
||||||
SERCOM_SPI_INTFLAG_DRE |
|
|
||||||
SERCOM_SPI_INTFLAG_TXC |
|
|
||||||
SERCOM_SPI_INTFLAG_RXC |
|
|
||||||
SERCOM_SPI_INTFLAG_ERROR;
|
|
||||||
NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
|
|
||||||
|
|
||||||
/* Transfer complete, invoke the callback function */
|
/* Transfer interrupted, invoke the callback function */
|
||||||
if (obj->spi.event & SPI_EVENT_RX_OVERFLOW) {
|
if (obj->spi.event & SPI_EVENT_RX_OVERFLOW) {
|
||||||
obj->spi.status = STATUS_ERR_OVERFLOW;
|
obj->spi.status = STATUS_ERR_OVERFLOW;
|
||||||
} else {
|
} else {
|
||||||
|
@ -731,31 +768,22 @@ static void _spi_transceive_buffer(spi_t *obj)
|
||||||
if (callback_func && (obj->spi.mask & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW))) {
|
if (callback_func && (obj->spi.mask & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW))) {
|
||||||
callback_func();
|
callback_func();
|
||||||
}
|
}
|
||||||
obj->spi.status = STATUS_OK;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (interrupt_status & (SERCOM_SPI_INTFLAG_TXC | SERCOM_SPI_INTFLAG_RXC)) {
|
if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length) && (interrupt_status & SERCOM_SPI_INTFLAG_TXC)) {
|
||||||
if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length)) {
|
|
||||||
/* Clear all interrupts */
|
/* Clear all interrupts */
|
||||||
_SPI(obj).INTENCLR.reg =
|
_spi_clear_interrupts(obj);
|
||||||
SERCOM_SPI_INTFLAG_DRE |
|
|
||||||
SERCOM_SPI_INTFLAG_TXC |
|
|
||||||
SERCOM_SPI_INTFLAG_RXC |
|
|
||||||
SERCOM_SPI_INTFLAG_ERROR;
|
|
||||||
NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
|
|
||||||
NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
|
|
||||||
|
|
||||||
/* Transfer complete, invoke the callback function */
|
/* Transfer complete, invoke the callback function */
|
||||||
obj->spi.event |= SPI_EVENT_COMPLETE;
|
obj->spi.event = SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
|
||||||
|
obj->spi.status = STATUS_OK;
|
||||||
callback_func = _sercom_callbacks[sercom_index];
|
callback_func = _sercom_callbacks[sercom_index];
|
||||||
if (callback_func && (obj->spi.mask & SPI_EVENT_COMPLETE)) {
|
if (callback_func && (obj->spi.mask & SPI_EVENT_COMPLETE)) {
|
||||||
callback_func();
|
callback_func();
|
||||||
}
|
}
|
||||||
obj->spi.status = STATUS_OK;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
|
/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
|
||||||
|
@ -763,15 +791,16 @@ static void _spi_transceive_buffer(spi_t *obj)
|
||||||
* @param[in] obj The SPI object which holds the transfer information
|
* @param[in] obj The SPI object which holds the transfer information
|
||||||
* @param[in] tx The buffer to send
|
* @param[in] tx The buffer to send
|
||||||
* @param[in] tx_length The number of words to transmit
|
* @param[in] tx_length The number of words to transmit
|
||||||
* @param[in] rx The buffer to receive
|
* @param[out]rx The buffer to receive
|
||||||
* @param[in] rx_length The number of words to receive
|
* @param[in] rx_length The number of words to receive
|
||||||
* @param[in] bit_width The bit width of buffer words
|
* @param[in] bit_width The bit width of buffer words
|
||||||
* @param[in] event The logical OR of events to be registered
|
* @param[in] event The logical OR of events to be registered
|
||||||
* @param[in] handler SPI interrupt handler
|
* @param[in] handler SPI interrupt handler
|
||||||
* @param[in] hint A suggestion for how to use DMA with this transfer **< DMA currently not implemented >**
|
* @param[in] hint A suggestion for how to use DMA with this transfer **< DMA currently not implemented >**
|
||||||
*/
|
*/
|
||||||
void spi_master_transfer(spi_t *obj, void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
|
void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
|
||||||
{
|
{
|
||||||
|
uint16_t dummy_read;
|
||||||
/* Sanity check arguments */
|
/* Sanity check arguments */
|
||||||
MBED_ASSERT(obj);
|
MBED_ASSERT(obj);
|
||||||
|
|
||||||
|
@ -780,12 +809,29 @@ void spi_master_transfer(spi_t *obj, void *tx, size_t tx_length, void *rx, size_
|
||||||
obj->spi.tx_buffer = tx;
|
obj->spi.tx_buffer = tx;
|
||||||
obj->tx_buff.buffer = tx;
|
obj->tx_buff.buffer = tx;
|
||||||
obj->tx_buff.pos = 0;
|
obj->tx_buff.pos = 0;
|
||||||
obj->tx_buff.length = tx_length * (bit_width>>3);
|
if (tx) {
|
||||||
|
obj->tx_buff.length = tx_length * (bit_width>>3);
|
||||||
|
} else {
|
||||||
|
obj->tx_buff.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
obj->spi.rx_buffer = rx;
|
obj->spi.rx_buffer = rx;
|
||||||
obj->rx_buff.buffer = rx;
|
obj->rx_buff.buffer = rx;
|
||||||
obj->rx_buff.pos = 0;
|
obj->rx_buff.pos = 0;
|
||||||
obj->rx_buff.length = rx_length * (bit_width>>3);
|
if (rx) {
|
||||||
|
obj->rx_buff.length = rx_length * (bit_width>>3);
|
||||||
|
} else {
|
||||||
|
/* Disable RXEN */
|
||||||
|
spi_disable(obj);
|
||||||
|
_SPI(obj).CTRLB.bit.RXEN = 0;
|
||||||
|
spi_enable(obj);
|
||||||
|
obj->rx_buff.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear data buffer if there is anything pending to read */
|
||||||
|
while (spi_is_ready_to_read(obj)) {
|
||||||
|
dummy_read = _SPI(obj).DATA.reg;
|
||||||
|
}
|
||||||
|
|
||||||
_sercom_callbacks[sercom_index] = handler;
|
_sercom_callbacks[sercom_index] = handler;
|
||||||
obj->spi.mask = event;
|
obj->spi.mask = event;
|
||||||
|
@ -810,9 +856,6 @@ void spi_master_transfer(spi_t *obj, void *tx, size_t tx_length, void *rx, size_
|
||||||
if (tx) {
|
if (tx) {
|
||||||
irq_mask |= SERCOM_SPI_INTFLAG_DRE;
|
irq_mask |= SERCOM_SPI_INTFLAG_DRE;
|
||||||
}
|
}
|
||||||
if (rx) {
|
|
||||||
irq_mask |= SERCOM_SPI_INTFLAG_RXC;
|
|
||||||
}
|
|
||||||
if (event & SPI_EVENT_ERROR) {
|
if (event & SPI_EVENT_ERROR) {
|
||||||
irq_mask |= SERCOM_SPI_INTFLAG_ERROR;
|
irq_mask |= SERCOM_SPI_INTFLAG_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -836,39 +879,47 @@ uint32_t spi_irq_handler_asynch(spi_t *obj)
|
||||||
|
|
||||||
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
if (obj->spi.dma_usage == DMA_USAGE_NEVER) {
|
||||||
/* IRQ method */
|
/* IRQ method */
|
||||||
obj->spi.status = STATUS_BUSY;
|
if (obj->spi.event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
|
||||||
if ((obj->tx_buff.pos < obj->tx_buff.length) || (obj->rx_buff.pos < obj->rx_buff.length)) {
|
obj->spi.event |= SPI_EVENT_COMPLETE;
|
||||||
bytes_to_transfer = (obj->tx_buff.length > obj->rx_buff.length)? obj->tx_buff.length : obj->rx_buff.length;
|
transfer_event = obj->spi.event;
|
||||||
while (bytes_to_transfer) {
|
} else {
|
||||||
if (spi_is_ready_to_write(obj)) {
|
/* Data is still remaining to be transferred! */
|
||||||
_spi_write_async(obj);
|
obj->spi.status = STATUS_BUSY;
|
||||||
|
|
||||||
|
/* Read any pending data in RX buffer */
|
||||||
|
while (spi_is_ready_to_read(obj)) {
|
||||||
|
_spi_read_async(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (obj->tx_buff.pos < obj->tx_buff.length) {
|
||||||
|
/* Write data */
|
||||||
|
_spi_write_async(obj);
|
||||||
|
/* Read if any */
|
||||||
|
if ((obj->rx_buff.buffer) && (obj->rx_buff.pos < obj->rx_buff.length)) {
|
||||||
|
if (spi_is_ready_to_read(obj)) {
|
||||||
|
_spi_read_async(obj);
|
||||||
|
}
|
||||||
|
/* Extend TX buffer (with dummy) if there is more to receive */
|
||||||
|
if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->tx_buff.length < obj->rx_buff.length)) {
|
||||||
|
obj->tx_buff.length = obj->rx_buff.length;
|
||||||
|
obj->tx_buff.buffer = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (spi_is_ready_to_read(obj)) {
|
if (obj->spi.event & SPI_EVENT_ERROR) {
|
||||||
_spi_read_async(obj);
|
|
||||||
}
|
|
||||||
if (obj->spi.event & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW)) {
|
|
||||||
transfer_event = obj->spi.event;
|
transfer_event = obj->spi.event;
|
||||||
obj->spi.status = (obj->spi.event & SPI_EVENT_RX_OVERFLOW)? STATUS_ERR_OVERFLOW : STATUS_ERR_BAD_DATA;
|
obj->spi.status = STATUS_ERR_BAD_DATA;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bytes_to_transfer--;
|
}
|
||||||
|
if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length)) {
|
||||||
|
transfer_event = (SPI_EVENT_INTERNAL_TRANSFER_COMPLETE | SPI_EVENT_COMPLETE);
|
||||||
|
obj->spi.status = STATUS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bytes_to_transfer == 0) {
|
transfer_event &= (obj->spi.mask | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE);
|
||||||
transfer_event |= SPI_EVENT_COMPLETE;
|
/* Clear all interrupts */
|
||||||
/* Clear all interrupts */
|
_spi_clear_interrupts(obj);
|
||||||
_SPI(obj).INTENCLR.reg =
|
|
||||||
SERCOM_SPI_INTFLAG_DRE |
|
|
||||||
SERCOM_SPI_INTFLAG_TXC |
|
|
||||||
SERCOM_SPI_INTFLAG_RXC |
|
|
||||||
SERCOM_SPI_INTFLAG_ERROR;
|
|
||||||
NVIC_DisableIRQ(SERCOM0_IRQn + sercom_index);
|
|
||||||
NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)NULL);
|
|
||||||
obj->spi.status = STATUS_OK;
|
|
||||||
}
|
|
||||||
transfer_event &= obj->spi.mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return transfer_event;
|
return transfer_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,12 +929,8 @@ uint32_t spi_irq_handler_asynch(spi_t *obj)
|
||||||
*/
|
*/
|
||||||
uint8_t spi_active(spi_t *obj)
|
uint8_t spi_active(spi_t *obj)
|
||||||
{
|
{
|
||||||
if (obj->spi.status == STATUS_BUSY) {
|
/* Check if the SPI module is busy with a job */
|
||||||
/* Check if the SPI module is busy with a job */
|
return (obj->spi.status == STATUS_BUSY);
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Abort an SPI transfer
|
/** Abort an SPI transfer
|
||||||
|
@ -911,4 +958,4 @@ void spi_abort_asynch(spi_t *obj)
|
||||||
obj->spi.status = STATUS_ABORTED;
|
obj->spi.status = STATUS_ABORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif /* DEVICE_SPI_ASYNCH */
|
||||||
|
|
Loading…
Reference in New Issue