diff --git a/cpu/cc2538/dev/spi.c b/cpu/cc2538/dev/spi.c index 8d7dca49b..586c738bc 100644 --- a/cpu/cc2538/dev/spi.c +++ b/cpu/cc2538/dev/spi.c @@ -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; +} /** @} */ diff --git a/cpu/cc2538/dev/ssi.h b/cpu/cc2538/dev/ssi.h index ca3a1fe21..da41a5b0a 100644 --- a/cpu/cc2538/dev/ssi.h +++ b/cpu/cc2538/dev/ssi.h @@ -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 /** diff --git a/cpu/cc2538/spi-arch.h b/cpu/cc2538/spi-arch.h index 85eb058c1..53d7fe78d 100644 --- a/cpu/cc2538/spi-arch.h +++ b/cpu/cc2538/spi-arch.h @@ -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_ */ diff --git a/platform/cc2538dk/dev/board.h b/platform/cc2538dk/dev/board.h index 98a297855..015acb164 100644 --- a/platform/cc2538dk/dev/board.h +++ b/platform/cc2538dk/dev/board.h @@ -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 /** @} */ /*---------------------------------------------------------------------------*/ /**