Merge pull request #598 from lab11/spi-flush2

[SPI + CC2538] Update the SPI driver for CC2538
This commit is contained in:
George Oikonomou 2014-04-16 22:42:53 +01:00
commit db754a57d7
5 changed files with 117 additions and 60 deletions

View File

@ -82,10 +82,11 @@ void spi_init(void);
} while(0)
/* Flush the SPI read register */
#ifndef SPI_FLUSH
#define SPI_FLUSH() \
do { \
SPI_RXBUF; \
} while(0);
#endif
#endif /* SPI_H_ */

View File

@ -48,23 +48,6 @@
#define SPI_MOSI_PIN_MASK GPIO_PIN_MASK(SPI_MOSI_PIN)
#define SPI_MISO_PORT_BASE GPIO_PORT_TO_BASE(SPI_MISO_PORT)
#define SPI_MISO_PIN_MASK GPIO_PIN_MASK(SPI_MISO_PIN)
#define SPI_SEL_PORT_BASE GPIO_PORT_TO_BASE(SPI_SEL_PORT)
#define SPI_SEL_PIN_MASK GPIO_PIN_MASK(SPI_SEL_PIN)
/* Default: Motorola mode 3 with 8-bit data words */
#ifndef SPI_CONF_PHASE
#define SPI_CONF_PHASE SSI_CR0_SPH
#endif
#ifndef SPI_CONF_POLARITY
#define SPI_CONF_POLARITY SSI_CR0_SPO
#endif
#ifndef SPI_CONF_DATA_SIZE
#define SPI_CONF_DATA_SIZE 8
#endif
#if SPI_CONF_DATA_SIZE < 4 || SPI_CONF_DATA_SIZE > 16
#error SPI_CONF_DATA_SIZE must be set between 4 and 16 inclusive.
#endif
/**
* \brief Initialize the SPI bus.
@ -73,12 +56,11 @@
* SPI_CLK_PORT SPI_CLK_PIN
* SPI_MOSI_PORT SPI_MOSI_PIN
* SPI_MISO_PORT SPI_MISO_PIN
* SPI_SEL_PORT SPI_SEL_PIN
*
* This sets the mode to Motorola SPI with the following format options:
* SPI_CONF_PHASE: 0 or SSI_CR0_SPH
* SPI_CONF_POLARITY: 0 or SSI_CR0_SPO
* SPI_CONF_DATA_SIZE: 4 to 16 bits
* Clock phase: 1; data captured on second (rising) edge
* Clock polarity: 1; clock is high when idle
* Data size: 8 bits
*/
void
spi_init(void)
@ -95,31 +77,42 @@ spi_init(void)
ioc_set_sel(SPI_CLK_PORT, SPI_CLK_PIN, IOC_PXX_SEL_SSI0_CLKOUT);
ioc_set_sel(SPI_MOSI_PORT, SPI_MOSI_PIN, IOC_PXX_SEL_SSI0_TXD);
REG(IOC_SSIRXD_SSI0) = (SPI_MISO_PORT * 8) + SPI_MISO_PIN;
ioc_set_sel(SPI_SEL_PORT, SPI_SEL_PIN, IOC_PXX_SEL_SSI0_FSSOUT);
/* Put all the SSI gpios into peripheral mode */
GPIO_PERIPHERAL_CONTROL(SPI_CLK_PORT_BASE, SPI_CLK_PIN_MASK);
GPIO_PERIPHERAL_CONTROL(SPI_MOSI_PORT_BASE, SPI_MOSI_PIN_MASK);
GPIO_PERIPHERAL_CONTROL(SPI_MISO_PORT_BASE, SPI_MISO_PIN_MASK);
GPIO_PERIPHERAL_CONTROL(SPI_SEL_PORT_BASE, SPI_SEL_PIN_MASK);
/* Disable any pull ups or the like */
ioc_set_over(SPI_CLK_PORT, SPI_CLK_PIN, IOC_OVERRIDE_DIS);
ioc_set_over(SPI_MOSI_PORT, SPI_MOSI_PIN, IOC_OVERRIDE_DIS);
ioc_set_over(SPI_MISO_PORT, SPI_MISO_PIN, IOC_OVERRIDE_DIS);
ioc_set_over(SPI_SEL_PORT, SPI_SEL_PIN, IOC_OVERRIDE_DIS);
/* Configure the clock */
REG(SSI0_BASE + SSI_CPSR) = 2;
/* Put the ssi in Motorola SPI mode using the provided format options */
REG(SSI0_BASE + SSI_CR0) = SPI_CONF_PHASE | SPI_CONF_POLARITY | (SPI_CONF_DATA_SIZE - 1);
/* Configure the default SPI options.
* mode: Motorola frame format
* clock: High when idle
* data: Valid on rising edges of the clock
* bits: 8 byte data
*/
REG(SSI0_BASE + SSI_CR0) = SSI_CR0_SPH | SSI_CR0_SPO | (0x07);
/* Enable the SSI */
REG(SSI0_BASE + SSI_CR1) |= SSI_CR1_SSE;
}
/*---------------------------------------------------------------------------*/
void
spi_cs_init(uint8_t port, uint8_t pin)
{
GPIO_SOFTWARE_CONTROL(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin));
ioc_set_over(port, pin, IOC_OVERRIDE_DIS);
GPIO_SET_OUTPUT(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin));
GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin));
}
/*---------------------------------------------------------------------------*/
void
spi_enable(void)
{
/* Enable the clock for the SSI peripheral */
@ -132,4 +125,16 @@ spi_disable(void)
/* Gate the clock for the SSI peripheral */
REG(SYS_CTRL_RCGCSSI) &= ~1;
}
/*---------------------------------------------------------------------------*/
void spi_set_mode(uint32_t frame_format, uint32_t clock_polarity, uint32_t clock_phase, uint32_t data_size)
{
/* Disable the SSI peripheral to configure it */
REG(SSI0_BASE + SSI_CR1) = 0;
/* Configure the SSI options */
REG(SSI0_BASE + SSI_CR0) = clock_phase | clock_polarity | frame_format | (data_size - 1);
/* Re-enable the SSI */
REG(SSI0_BASE + SSI_CR1) |= SSI_CR1_SSE;
}
/** @} */

View File

@ -74,98 +74,106 @@
*/
#define SSI_CR0_SCR_M 0x0000FF00 /**< Serial clock rate mask */
#define SSI_CR0_SCR_S 8 /**< Serial clock rate shift */
#define SSI_CR0_SPH 0x00000080 /**< Serial clock phase (H) */
#define SSI_CR0_SPH_M 0x00000080 /**< Serial clock phase (H) mask */
#define SSI_CR0_SPH_S 7 /**< Serial clock phase (H) shift */
#define SSI_CR0_SPO 0x00000040 /**< Serial clock phase (O) */
#define SSI_CR0_SPO_M 0x00000040 /**< Serial clock phase (O) mask */
#define SSI_CR0_SPO_S 6 /**< Serial clock phase (O) shift */
#define SSI_CR0_FRF_M 0x00000030 /**< Frame format select mask */
#define SSI_CR0_FRF_S 4 /**< Frame format select shift */
#define SSI_CR0_DSS_M 0x0000000F /**< Data size select mask */
#define SSI_CR0_DSS_S 0 /**< Data size select shift */
#define SSI_CR1_SOD 0x00000008 /**< Slave mode output disable */
#define SSI_CR1_SOD_M 0x00000008 /**< Slave mode output disable mask */
#define SSI_CR1_SOD_S 3 /**< Slave mode output disable shift */
#define SSI_CR1_MS 0x00000004 /**< Master and slave select */
#define SSI_CR1_MS_M 0x00000004 /**< Master and slave select mask */
#define SSI_CR1_MS_S 2 /**< Master and slave select shift */
#define SSI_CR1_SSE 0x00000002 /**< Synchronous serial port enable */
#define SSI_CR1_SSE_M 0x00000002 /**< Synchronous serial port enable mask */
#define SSI_CR1_SSE_S 1 /**< Synchronous serial port enable shift */
#define SSI_CR1_LBM 0x00000001 /**< Loop-back mode */
#define SSI_CR1_LBM_M 0x00000001 /**< Loop-back mode mask */
#define SSI_CR1_LBM_S 0 /**< Loop-back mode shift */
#define SSI_DR_DATA_M 0x0000FFFF /**< FIFO data mask */
#define SSI_DR_DATA_S 0 /**< FIFO data shift */
#define SSI_SR_BSY 0x00000010 /**< Busy bit */
#define SSI_SR_BSY_M 0x00000010 /**< Busy bit mask */
#define SSI_SR_BSY_S 4 /**< Busy bit shift */
#define SSI_SR_RFF 0x00000008 /**< Receive FIFO full */
#define SSI_SR_RFF_M 0x00000008 /**< Receive FIFO full mask */
#define SSI_SR_RFF_S 3 /**< Receive FIFO full shift */
#define SSI_SR_RNE 0x00000004 /**< Receive FIFO not empty */
#define SSI_SR_RNE_M 0x00000004 /**< Receive FIFO not empty mask */
#define SSI_SR_RNE_S 2 /**< Receive FIFO not empty shift */
#define SSI_SR_TNF 0x00000002 /**< Transmit FIFO not full */
#define SSI_SR_TNF_M 0x00000002 /**< Transmit FIFO not full mask */
#define SSI_SR_TNF_S 1 /**< Transmit FIFO not full shift */
#define SSI_SR_TFE 0x00000001 /**< Transmit FIFO empty */
#define SSI_SR_TFE_M 0x00000001 /**< Transmit FIFO empty mask */
#define SSI_SR_TFE_S 0 /**< Transmit FIFO empty shift */
#define SSI_CPSR_CPSDVSR_M 0x000000FF /**< Clock prescale divisor mask */
#define SSI_CPSR_CPSDVSR_S 0 /**< Clock prescale divisor shift */
#define SSI_IM_TXIM 0x00000008 /**< Transmit FIFO interrupt mask */
#define SSI_IM_TXIM_M 0x00000008 /**< Transmit FIFO interrupt mask mask */
#define SSI_IM_TXIM_S 3 /**< Transmit FIFO interrupt mask shift */
#define SSI_IM_RXIM 0x00000004 /**< Receive FIFO interrupt mask */
#define SSI_IM_RXIM_M 0x00000004 /**< Receive FIFO interrupt mask mask */
#define SSI_IM_RXIM_S 2 /**< Receive FIFO interrupt mask shift */
#define SSI_IM_RTIM 0x00000002 /**< Receive time-out interrupt mask */
#define SSI_IM_RTIM_M 0x00000002 /**< Receive time-out interrupt mask mask */
#define SSI_IM_RTIM_S 1 /**< Receive time-out interrupt mask shift */
#define SSI_IM_RORIM 0x00000001 /**< Receive overrun interrupt mask */
#define SSI_IM_RORIM_M 0x00000001 /**< Receive overrun interrupt mask mask */
#define SSI_IM_RORIM_S 0 /**< Receive overrun interrupt mask shift */
#define SSI_RIS_TXRIS 0x00000008 /**< SSITXINTR raw state */
#define SSI_RIS_TXRIS_M 0x00000008 /**< SSITXINTR raw state mask */
#define SSI_RIS_TXRIS_S 3 /**< SSITXINTR raw state shift */
#define SSI_RIS_RXRIS 0x00000004 /**< SSIRXINTR raw state */
#define SSI_RIS_RXRIS_M 0x00000004 /**< SSIRXINTR raw state mask */
#define SSI_RIS_RXRIS_S 2 /**< SSIRXINTR raw state shift */
#define SSI_RIS_RTRIS 0x00000002 /**< SSIRTINTR raw state */
#define SSI_RIS_RTRIS_M 0x00000002 /**< SSIRTINTR raw state mask */
#define SSI_RIS_RTRIS_S 1 /**< SSIRTINTR raw state shift */
#define SSI_RIS_RORRIS 0x00000001 /**< SSIRORINTR raw state */
#define SSI_RIS_RORRIS_M 0x00000001 /**< SSIRORINTR raw state mask */
#define SSI_RIS_RORRIS_S 0 /**< SSIRORINTR raw state shift */
#define SSI_MIS_TXMIS 0x00000008 /**< SSITXINTR masked state */
#define SSI_MIS_TXMIS_M 0x00000008 /**< SSITXINTR masked state mask */
#define SSI_MIS_TXMIS_S 3 /**< SSITXINTR masked state shift */
#define SSI_MIS_RXMIS 0x00000004 /**< SSIRXINTR masked state */
#define SSI_MIS_RXMIS_M 0x00000004 /**< SSIRXINTR masked state mask */
#define SSI_MIS_RXMIS_S 2 /**< SSIRXINTR masked state shift */
#define SSI_MIS_RTMIS 0x00000002 /**< SSIRTINTR masked state */
#define SSI_MIS_RTMIS_M 0x00000002 /**< SSIRTINTR masked state mask */
#define SSI_MIS_RTMIS_S 1 /**< SSIRTINTR masked state shift */
#define SSI_MIS_RORMIS 0x00000001 /**< SSIRORINTR masked state */
#define SSI_MIS_RORMIS_M 0x00000001 /**< SSIRORINTR masked state mask */
#define SSI_MIS_RORMIS_S 0 /**< SSIRORINTR masked state shift */
#define SSI_ICR_RTIC 0x00000002 /**< Receive time-out interrupt clear */
#define SSI_ICR_RTIC_M 0x00000002 /**< Receive time-out interrupt clear mask */
#define SSI_ICR_RTIC_S 1 /**< Receive time-out interrupt clear shift */
#define SSI_ICR_RORIC 0x00000001 /**< Receive overrun interrupt clear */
#define SSI_ICR_RORIC_M 0x00000001 /**< Receive overrun interrupt clear mask */
#define SSI_ICR_RORIC_S 0 /**< Receive overrun interrupt clear shift */
#define SSI_DMACTL_TXDMAE 0x00000002 /**< Transmit DMA enable */
#define SSI_DMACTL_TXDMAE_M 0x00000002 /**< Transmit DMA enable mask */
#define SSI_DMACTL_TXDMAE_S 1 /**< Transmit DMA enable shift */
#define SSI_DMACTL_RXDMAE 0x00000001 /**< Receive DMA enable */
#define SSI_DMACTL_RXDMAE_M 0x00000001 /**< Receive DMA enable mask */
#define SSI_DMACTL_RXDMAE_S 0 /**< Receive DMA enable shift */
#define SSI_CC_CS_M 0x00000007 /**< Baud and system clock source mask */
#define SSI_CC_CS_S 0 /**< Baud and system clock source shift */
/** @} */
/*---------------------------------------------------------------------------*/
/** \name SSI Register Values
* @{
*/
#define SSI_CR0_SPH 0x00000080 /**< Serial clock phase (H) */
#define SSI_CR0_SPO 0x00000040 /**< Serial clock phase (O) */
#define SSI_CR0_FRF_MOTOROLA 0x00000000 /**< Motorola frame format */
#define SSI_CR0_FRF_TI 0x00000010 /**< Texas Instruments frame format */
#define SSI_CR0_FRF_MICROWIRE 0x00000020 /**< National Microwire frame format */
#define SSI_CR1_SOD 0x00000008 /**< Slave mode output disable */
#define SSI_CR1_MS 0x00000004 /**< Master and slave select */
#define SSI_CR1_SSE 0x00000002 /**< Synchronous serial port enable */
#define SSI_CR1_LBM 0x00000001 /**< Loop-back mode */
#define SSI_SR_BSY 0x00000010 /**< Busy bit */
#define SSI_SR_RFF 0x00000008 /**< Receive FIFO full */
#define SSI_SR_RNE 0x00000004 /**< Receive FIFO not empty */
#define SSI_SR_TNF 0x00000002 /**< Transmit FIFO not full */
#define SSI_SR_TFE 0x00000001 /**< Transmit FIFO empty */
#define SSI_IM_TXIM 0x00000008 /**< Transmit FIFO interrupt mask */
#define SSI_IM_RXIM 0x00000004 /**< Receive FIFO interrupt mask */
#define SSI_IM_RTIM 0x00000002 /**< Receive time-out interrupt mask */
#define SSI_IM_RORIM 0x00000001 /**< Receive overrun interrupt mask */
#define SSI_RIS_TXRIS 0x00000008 /**< SSITXINTR raw state */
#define SSI_RIS_RXRIS 0x00000004 /**< SSIRXINTR raw state */
#define SSI_RIS_RTRIS 0x00000002 /**< SSIRTINTR raw state */
#define SSI_RIS_RORRIS 0x00000001 /**< SSIRORINTR raw state */
#define SSI_MIS_TXMIS 0x00000008 /**< SSITXINTR masked state */
#define SSI_MIS_RXMIS 0x00000004 /**< SSIRXINTR masked state */
#define SSI_MIS_RTMIS 0x00000002 /**< SSIRTINTR masked state */
#define SSI_MIS_RORMIS 0x00000001 /**< SSIRORINTR masked state */
#define SSI_ICR_RTIC 0x00000002 /**< Receive time-out interrupt clear */
#define SSI_ICR_RORIC 0x00000001 /**< Receive overrun interrupt clear */
#define SSI_DMACTL_TXDMAE 0x00000002 /**< Transmit DMA enable */
#define SSI_DMACTL_RXDMAE 0x00000001 /**< Receive DMA enable */
/** @} */
#endif
/**

View File

@ -41,27 +41,51 @@
#ifndef SPI_ARCH_H_
#define SPI_ARCH_H_
#include "contiki.h"
#include "dev/ssi.h"
#define SPI_WAITFORTxREADY() do { \
while(!(REG(SSI0_BASE + SSI_SR) & SSI_SR_TNF)); \
} while (0)
} while(0)
#define SPI_TXBUF REG(SSI0_BASE + SSI_DR)
#define SPI_RXBUF REG(SSI0_BASE + SSI_DR)
#define SPI_WAITFOREOTx() do { \
while(REG(SSI0_BASE + SSI_SR) & SSI_SR_BSY); \
} while (0)
} while(0)
#define SPI_WAITFOREORx() do { \
while(!(REG(SSI0_BASE + SSI_SR) & SSI_SR_RNE)); \
} while (0)
} while(0)
#ifdef SPI_FLUSH
#error "You must include spi-arch.h before spi.h for the CC2538."
#endif
#define SPI_FLUSH() do { \
SPI_WAITFOREORx(); \
while (REG(SSI0_BASE + SSI_SR) & SSI_SR_RNE) { \
SPI_RXBUF; \
} \
} while(0)
#define SPI_CS_CLR(port, pin) do { \
GPIO_CLR_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \
} while(0)
#define SPI_CS_SET(port, pin) do { \
GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \
} while(0)
/*---------------------------------------------------------------------------*/
/** \name Arch-specific SPI functions
* @{
*/
/**
* \brief Configure a GPIO to be the chip select pin
*/
void spi_cs_init(uint8_t port, uint8_t pin);
/** \brief Enables the SPI peripheral
*/
void spi_enable(void);
@ -71,6 +95,27 @@ void spi_enable(void);
*/
void spi_disable(void);
/**
* \brief Configure the SPI data and clock polarity and the data size.
*
* This function configures the SSI peripheral to use a particular SPI
* configuration that a slave device requires. It should always be called
* before using the SPI bus as another driver could have changed the settings.
*
* See section 19.4.4 in the CC2538 user guide for more information.
*
* \param frame_format Set the SSI frame format. Use SSI_CR0_FRF_MOTOROLA,
* SSI_CR0_FRF_TI, or SSI_CR0_FRF_MICROWIRE.
* \param clock_polarity In Motorola mode, set whether the clock is high or low
* when idle. Use SSI_CR0_SPO or 0.
* \param clock_phase In Motorola mode, select whether data is valid on the
* first or second edge of the clock. Use SSI_CR0_SPH or 0.
* \param data_size The number of bits in each "byte" of data. Must be
* between 4 and 16, inclusive.
*/
void spi_set_mode(uint32_t frame_format, uint32_t clock_polarity,
uint32_t clock_phase, uint32_t data_size);
/** @} */
#endif /* SPI_ARCH_H_ */

View File

@ -193,8 +193,6 @@
#define SPI_MOSI_PIN 4
#define SPI_MISO_PORT GPIO_A_NUM
#define SPI_MISO_PIN 5
#define SPI_SEL_PORT GPIO_B_NUM
#define SPI_SEL_PIN 5
/** @} */
/*---------------------------------------------------------------------------*/
/**