Refining implementation of SPI APIs

pull/1243/head
vimalrajr 2015-07-07 14:52:59 +05:30 committed by Karthik Purushothaman
parent 1c3039fc24
commit 17333d6c85
1 changed files with 28 additions and 110 deletions

View File

@ -29,13 +29,6 @@
#define SPI_SCLK_INDEX 2
#define SPI_SSEL_INDEX 3
/** Default pinmux. */
# define PINMUX_DEFAULT 0
/** Unused pinmux. */
# define PINMUX_UNUSED 0xFFFFFFFF
/** Temporary definitions END */
/**
* \brief SPI modes enum
*
@ -67,31 +60,6 @@ enum spi_mode {
extern uint8_t g_sys_init;
uint16_t dummy_fill_word = 0xFFFF;
#if DEVICE_SPI_ASYNCH
/* Global variables */
extern void *_sercom_instances[SERCOM_INST_NUM];
static void _spi_transceive_buffer(spi_t *obj);
/** \internal
* Generates a SERCOM interrupt handler function for a given SERCOM index.
*/
#define _SERCOM_SPI_INTERRUPT_HANDLER(n, unused) \
void SERCOM##n##_SPIHandler(void) \
{ \
_spi_transceive_buffer((spi_t *)_sercom_instances[n]); \
}
#define _SERCOM_SPI_INTERRUPT_HANDLER_DECLR(n, unused) \
(uint32_t)SERCOM##n##_SPIHandler,
/** Auto-generate a set of interrupt handlers for each SERCOM SPI in the device */
MREPEAT(SERCOM_INST_NUM, _SERCOM_SPI_INTERRUPT_HANDLER, ~)
const uint32_t _sercom_handlers[SERCOM_INST_NUM] = {
MREPEAT(SERCOM_INST_NUM, _SERCOM_SPI_INTERRUPT_HANDLER_DECLR, ~)
};
uint32_t _sercom_callbacks[SERCOM_INST_NUM] = {0};
#endif /* DEVICE_SPI_ASYNCH */
static inline bool spi_is_syncing(spi_t *obj)
{
@ -107,11 +75,6 @@ static inline void spi_enable(spi_t *obj)
/* Sanity check arguments */
MBED_ASSERT(obj);
#if DEVICE_SPI_ASYNCH
/* Enable interrupt */
NVIC_EnableIRQ(SERCOM0_IRQn + _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)));
#endif
/* Wait until the synchronization is complete */
while (spi_is_syncing(obj));
@ -124,10 +87,6 @@ static inline void spi_disable(spi_t *obj)
/* Sanity check arguments */
MBED_ASSERT(obj);
#if DEVICE_SPI_ASYNCH
/* Disable interrupt */
NVIC_DisableIRQ(SERCOM0_IRQn + _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)));
#endif
/* Wait until the synchronization is complete */
while (spi_is_syncing(obj));
@ -275,6 +234,10 @@ static uint32_t spi_find_mux_settings(spi_t *obj)
*/
void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
{
/* Sanity check arguments */
MBED_ASSERT(obj);
MBED_ASSERT(sclk != NC);
uint16_t baud = 0;
uint32_t ctrla = 0;
uint32_t ctrlb = 0;
@ -287,7 +250,7 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
/* Calculate SERCOM instance from pins */
uint32_t sercom_index = pinmap_find_sercom(mosi, miso, sclk, ssel);
pSPI_SERCOM(obj) = pinmap_peripheral_sercom(NC, sercom_index);
pSPI_SERCOM(obj) = (Sercom*)pinmap_peripheral_sercom(NC, sercom_index);
/* Disable SPI */
spi_disable(obj);
@ -330,14 +293,6 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
system_gclk_chan_enable(gclk_index);
sercom_set_gclk_generator(GCLK_GENERATOR_0, false);
#if DEVICE_SPI_ASYNCH
/* Save the object */
_sercom_instances[sercom_index] = obj;
/* Configure interrupt handler */
NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)_sercom_handlers[sercom_index]);
#endif
/* Set the SERCOM in SPI master mode */
_SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3);
pSPI_S(obj)->mode = SPI_MODE_MASTER;
@ -347,7 +302,6 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
system_pinmux_get_config_defaults(&pin_conf);
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
uint32_t mux_func;
pSPI_S(obj)->pins[SPI_MOSI_INDEX] = mosi;
pSPI_S(obj)->pins[SPI_MISO_INDEX] = miso;
pSPI_S(obj)->pins[SPI_SCLK_INDEX] = sclk;
@ -356,10 +310,9 @@ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel
for (uint8_t pad = 0; pad < 4; pad++) {
uint32_t current_pin = pSPI_S(obj)->pins[pad];
if (current_pin != NC) {
mux_func = pinmap_function_sercom(current_pin, sercom_index);
if (NC != mux_func) {
pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
if ((uint8_t)NC != pin_conf.mux_position) {
system_pinmux_pin_set_config(current_pin, &pin_conf);
pin_function(current_pin, mux_func);
}
}
}
@ -419,11 +372,13 @@ void spi_free(spi_t *obj)
void spi_format(spi_t *obj, int bits, int mode, int slave)
{
PinMode pull_mode;
/* Sanity check arguments */
MBED_ASSERT(obj);
/* Disable SPI */
spi_disable(obj);
uint32_t ctrla = _SPI(obj).CTRLA.reg;
uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj));
if (slave) {
/* Set the SERCOM in SPI mode */
@ -472,6 +427,8 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
void spi_frequency(spi_t *obj, int hz)
{
uint16_t baud = 0;
/* Sanity check arguments */
MBED_ASSERT(obj);
/* Disable SPI */
spi_disable(obj);
@ -751,6 +708,9 @@ static void _spi_read_async(spi_t *obj)
*/
static void _spi_clear_interrupts(spi_t *obj)
{
/* Sanity check arguments */
MBED_ASSERT(obj);
uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
/* Clear all interrupts */
@ -770,13 +730,10 @@ static void _spi_clear_interrupts(spi_t *obj)
* \param[in,out] obj Pointer to SPI software instance struct
*
*/
static void _spi_transceive_buffer(spi_t *obj)
static enum status_code _spi_transceive_buffer(spi_t *obj)
{
/* Sanity check arguments */
MBED_ASSERT(obj);
void (*callback_func)(void);
uint8_t sercom_index = _sercom_get_sercom_inst_index(obj->spi.spi);
uint16_t interrupt_status = _SPI(obj).INTFLAG.reg;
interrupt_status &= _SPI(obj).INTENSET.reg;
@ -820,11 +777,7 @@ static void _spi_transceive_buffer(spi_t *obj)
} else {
obj->spi.status = STATUS_ERR_BAD_DATA;
}
callback_func = _sercom_callbacks[sercom_index];
if (callback_func && (obj->spi.mask & (SPI_EVENT_ERROR | SPI_EVENT_RX_OVERFLOW))) {
callback_func();
}
return;
return obj->spi.status;
}
if ((obj->tx_buff.pos >= obj->tx_buff.length) && (obj->rx_buff.pos >= obj->rx_buff.length) && (interrupt_status & SERCOM_SPI_INTFLAG_TXC)) {
@ -834,12 +787,9 @@ static void _spi_transceive_buffer(spi_t *obj)
/* Transfer complete, invoke the callback function */
obj->spi.event = SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
obj->spi.status = STATUS_OK;
callback_func = _sercom_callbacks[sercom_index];
if (callback_func && (obj->spi.mask & SPI_EVENT_COMPLETE)) {
callback_func();
}
return;
}
return obj->spi.status;
}
/** Begin the SPI transfer. Buffer pointers and lengths are specified in tx_buff and rx_buff
@ -896,7 +846,6 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
dummy_read = _SPI(obj).DATA.reg;
}
_sercom_callbacks[sercom_index] = handler;
obj->spi.mask = event;
obj->spi.dma_usage = hint;
@ -907,7 +856,7 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
obj->spi.status = STATUS_BUSY;
/* Enable interrupt */
NVIC_SetVector((SERCOM0_IRQn + sercom_index), _sercom_handlers[sercom_index]);
NVIC_SetVector((SERCOM0_IRQn + sercom_index), handler);
NVIC_EnableIRQ(SERCOM0_IRQn + sercom_index);
/* Clear all interrupts */
@ -935,50 +884,16 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,
*/
uint32_t spi_irq_handler_asynch(spi_t *obj)
{
/* Sanity check arguments */
MBED_ASSERT(obj);
uint32_t transfer_event = 0;
/*if (obj->spi.dma_usage == DMA_USAGE_NEVER) {** TEMP: Commented as DMA is not implemented now */
/* IRQ method */
if (obj->spi.event & SPI_EVENT_INTERNAL_TRANSFER_COMPLETE) {
obj->spi.event |= SPI_EVENT_COMPLETE;
transfer_event = obj->spi.event;
} else {
/* Data is still remaining to be transferred! */
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 (obj->spi.event & SPI_EVENT_ERROR) {
transfer_event = obj->spi.event;
obj->spi.status = STATUS_ERR_BAD_DATA;
break;
}
}
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 (STATUS_BUSY != _spi_transceive_buffer(obj)) {
transfer_event = obj->spi.event & (obj->spi.mask | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE);
}
transfer_event &= (obj->spi.mask | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE);
/* Clear all interrupts */
_spi_clear_interrupts(obj);
/*}** TEMP: Commented as DMA is not implemented now */
return transfer_event;
}
@ -989,6 +904,9 @@ uint32_t spi_irq_handler_asynch(spi_t *obj)
*/
uint8_t spi_active(spi_t *obj)
{
/* Sanity check arguments */
MBED_ASSERT(obj);
/* Check if the SPI module is busy with a job */
return (obj->spi.status == STATUS_BUSY);
}