Merge pull request #1042 from uknoblic/cc2538_spi

CC2538: added support for SSI1
This commit is contained in:
Benoît Thébaudeau 2015-05-18 20:36:45 +02:00
commit b8ff3251e1
6 changed files with 487 additions and 173 deletions

View File

@ -57,36 +57,36 @@ extern unsigned char spi_busy;
void spi_init(void);
/* Write one character to SPI */
#define SPI_WRITE(data) \
do { \
SPI_WAITFORTx_BEFORE(); \
SPI_TXBUF = data; \
SPI_WAITFOREOTx(); \
#define SPI_WRITE(data) \
do { \
SPI_WAITFORTx_BEFORE(); \
SPI_TXBUF = data; \
SPI_WAITFOREOTx(); \
} while(0)
/* Write one character to SPI - will not wait for end
useful for multiple writes with wait after final */
#define SPI_WRITE_FAST(data) \
do { \
SPI_WAITFORTx_BEFORE(); \
SPI_TXBUF = data; \
SPI_WAITFORTx_AFTER(); \
#define SPI_WRITE_FAST(data) \
do { \
SPI_WAITFORTx_BEFORE(); \
SPI_TXBUF = data; \
SPI_WAITFORTx_AFTER(); \
} while(0)
/* Read one character from SPI */
#define SPI_READ(data) \
do { \
SPI_TXBUF = 0; \
SPI_WAITFOREORx(); \
data = SPI_RXBUF; \
#define SPI_READ(data) \
do { \
SPI_TXBUF = 0; \
SPI_WAITFOREORx(); \
data = SPI_RXBUF; \
} while(0)
/* Flush the SPI read register */
#ifndef SPI_FLUSH
#define SPI_FLUSH() \
do { \
SPI_RXBUF; \
} while(0);
do { \
SPI_RXBUF; \
} while(0)
#endif
#endif /* SPI_H_ */

View File

@ -129,12 +129,18 @@
#define CC_CONCAT2(s1, s2) s1##s2
/**
* A C preprocessing macro for concatenating to
* strings.
* A C preprocessing macro for concatenating two preprocessor tokens.
*
* We need use two macros (CC_CONCAT and CC_CONCAT2) in order to allow
* concatenation of two \#defined macros.
*/
#define CC_CONCAT(s1, s2) CC_CONCAT2(s1, s2)
#define CC_CONCAT_EXT_2(s1, s2) CC_CONCAT2(s1, s2)
/**
* A C preprocessing macro for concatenating three preprocessor tokens.
*/
#define CC_CONCAT3(s1, s2, s3) s1##s2##s3
#define CC_CONCAT_EXT_3(s1, s2, s3) CC_CONCAT3(s1, s2, s3)
#endif /* CC_H_ */

View File

@ -1,5 +1,9 @@
/*
* Copyright (c) 2013, University of Michigan.
*
* Copyright (c) 2015, Weptech elektronik GmbH
* Author: Ulf Knoblich, ulf.knoblich@weptech.de
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -41,102 +45,281 @@
#include "dev/spi.h"
#include "dev/ssi.h"
#include "dev/gpio.h"
/*---------------------------------------------------------------------------*/
/* Check port / pin settings for SPI0 and provide default values for spi_cfg */
#ifndef SPI0_CLK_PORT
#define SPI0_CLK_PORT (-1)
#endif
#ifndef SPI0_CLK_PIN
#define SPI0_CLK_PIN (-1)
#endif
#if SPI0_CLK_PORT >= 0 && SPI0_CLK_PIN < 0 || \
SPI0_CLK_PORT < 0 && SPI0_CLK_PIN >= 0
#error Both SPI0_CLK_PORT and SPI0_CLK_PIN must be valid or invalid
#endif
#define SPI_CLK_PORT_BASE GPIO_PORT_TO_BASE(SPI_CLK_PORT)
#define SPI_CLK_PIN_MASK GPIO_PIN_MASK(SPI_CLK_PIN)
#define SPI_MOSI_PORT_BASE GPIO_PORT_TO_BASE(SPI_MOSI_PORT)
#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)
#ifndef SPI0_TX_PORT
#define SPI0_TX_PORT (-1)
#endif
#ifndef SPI0_TX_PIN
#define SPI0_TX_PIN (-1)
#endif
#if SPI0_TX_PORT >= 0 && SPI0_TX_PIN < 0 || \
SPI0_TX_PORT < 0 && SPI0_TX_PIN >= 0
#error Both SPI0_TX_PORT and SPI0_TX_PIN must be valid or invalid
#endif
/**
* \brief Initialize the SPI bus.
*
* This SPI init() function uses the following defines to set the pins:
* SPI_CLK_PORT SPI_CLK_PIN
* SPI_MOSI_PORT SPI_MOSI_PIN
* SPI_MISO_PORT SPI_MISO_PIN
*
* This sets the mode to Motorola SPI with the following format options:
* Clock phase: 1; data captured on second (rising) edge
* Clock polarity: 1; clock is high when idle
* Data size: 8 bits
*/
#ifndef SPI0_RX_PORT
#define SPI0_RX_PORT (-1)
#endif
#ifndef SPI0_RX_PIN
#define SPI0_RX_PIN (-1)
#endif
#if SPI0_RX_PORT >= 0 && SPI0_RX_PIN < 0 || \
SPI0_RX_PORT < 0 && SPI0_RX_PIN >= 0
#error Both SPI0_RX_PORT and SPI0_RX_PIN must be valid or invalid
#endif
/* Here we check that either all or none of the ports are defined. As
we did already check that both ports + pins are either defined or
not for every pin, this means that we can check for an incomplete
configuration by only looking at the port defines */
/* If some SPI0 pads are valid */
#if SPI0_CLK_PORT >= 0 || SPI0_TX_PORT >= 0 || SPI0_RX_PORT >= 0
/* but not all */
#if SPI0_CLK_PORT < 0 || SPI0_TX_PORT < 0 || SPI0_RX_PORT < 0
#error Some SPI0 pad definitions are invalid
#endif
#define SPI0_PADS_VALID
#endif
/*---------------------------------------------------------------------------*/
/* Check port / pin settings for SPI1 and provide default values for spi_cfg */
#ifndef SPI1_CLK_PORT
#define SPI1_CLK_PORT (-1)
#endif
#ifndef SPI1_CLK_PIN
#define SPI1_CLK_PIN (-1)
#endif
#if SPI1_CLK_PORT >= 0 && SPI1_CLK_PIN < 0 || \
SPI1_CLK_PORT < 0 && SPI1_CLK_PIN >= 0
#error Both SPI1_CLK_PORT and SPI1_CLK_PIN must be valid or invalid
#endif
#ifndef SPI1_TX_PORT
#define SPI1_TX_PORT (-1)
#endif
#ifndef SPI1_TX_PIN
#define SPI1_TX_PIN (-1)
#endif
#if SPI1_TX_PORT >= 0 && SPI1_TX_PIN < 0 || \
SPI1_TX_PORT < 0 && SPI1_TX_PIN >= 0
#error Both SPI1_TX_PORT and SPI1_TX_PIN must be valid or invalid
#endif
#ifndef SPI1_RX_PORT
#define SPI1_RX_PORT (-1)
#endif
#ifndef SPI1_RX_PIN
#define SPI1_RX_PIN (-1)
#endif
#if SPI1_RX_PORT >= 0 && SPI1_RX_PIN < 0 || \
SPI1_RX_PORT < 0 && SPI1_RX_PIN >= 0
#error Both SPI1_RX_PORT and SPI1_RX_PIN must be valid or invalid
#endif
/* If some SPI1 pads are valid */
#if SPI1_CLK_PORT >= 0 || SPI1_TX_PORT >= 0 || SPI1_RX_PORT >= 0
/* but not all */
#if SPI1_CLK_PORT < 0 || SPI1_TX_PORT < 0 || SPI1_RX_PORT < 0
#error Some SPI1 pad definitions are invalid
#endif
#define SPI1_PADS_VALID
#endif
#ifdef SPI_DEFAULT_INSTANCE
#if SPI_DEFAULT_INSTANCE == 0
#ifndef SPI0_PADS_VALID
#error SPI_DEFAULT_INSTANCE is set to SPI0, but its pads are not valid
#endif
#elif SPI_DEFAULT_INSTANCE == 1
#ifndef SPI1_PADS_VALID
#error SPI_DEFAULT_INSTANCE is set to SPI1, but its pads are not valid
#endif
#endif
#endif
#if (SPI0_CPRS_CPSDVSR & 1) == 1 || SPI0_CPRS_CPSDVSR < 2 || SPI0_CPRS_CPSDVSR > 254
#error SPI0_CPRS_CPSDVSR must be an even number between 2 and 254
#endif
#if (SPI1_CPRS_CPSDVSR & 1) == 1 || SPI1_CPRS_CPSDVSR < 2 || SPI1_CPRS_CPSDVSR > 254
#error SPI1_CPRS_CPSDVSR must be an even number between 2 and 254
#endif
/*---------------------------------------------------------------------------*/
typedef struct {
int8_t port;
int8_t pin;
} spi_pad_t;
typedef struct {
uint32_t base;
uint32_t ioc_ssirxd_ssi;
uint32_t ioc_pxx_sel_ssi_clkout;
uint32_t ioc_pxx_sel_ssi_txd;
uint8_t ssi_cprs_cpsdvsr;
spi_pad_t clk;
spi_pad_t tx;
spi_pad_t rx;
} spi_regs_t;
/*---------------------------------------------------------------------------*/
static const spi_regs_t spi_regs[SSI_INSTANCE_COUNT] = {
{
.base = SSI0_BASE,
.ioc_ssirxd_ssi = IOC_SSIRXD_SSI0,
.ioc_pxx_sel_ssi_clkout = IOC_PXX_SEL_SSI0_CLKOUT,
.ioc_pxx_sel_ssi_txd = IOC_PXX_SEL_SSI0_TXD,
.ssi_cprs_cpsdvsr = SPI0_CPRS_CPSDVSR,
.clk = { SPI0_CLK_PORT, SPI0_CLK_PIN },
.tx = { SPI0_TX_PORT, SPI0_TX_PIN },
.rx = { SPI0_RX_PORT, SPI0_RX_PIN }
}, {
.base = SSI1_BASE,
.ioc_ssirxd_ssi = IOC_SSIRXD_SSI1,
.ioc_pxx_sel_ssi_clkout = IOC_PXX_SEL_SSI1_CLKOUT,
.ioc_pxx_sel_ssi_txd = IOC_PXX_SEL_SSI1_TXD,
.ssi_cprs_cpsdvsr = SPI1_CPRS_CPSDVSR,
.clk = { SPI1_CLK_PORT, SPI1_CLK_PIN },
.tx = { SPI1_TX_PORT, SPI1_TX_PIN },
.rx = { SPI1_RX_PORT, SPI1_RX_PIN }
}
};
/*---------------------------------------------------------------------------*/
/* Deprecated function call provided for compatibility reasons */
#ifdef SPI_DEFAULT_INSTANCE
void
spi_init(void)
{
spi_enable();
spix_init(SPI_DEFAULT_INSTANCE);
}
#endif /* #ifdef SPI_DEFAULT_INSTANCE */
/*---------------------------------------------------------------------------*/
void
spix_init(uint8_t spi)
{
const spi_regs_t *regs;
if(spi >= SSI_INSTANCE_COUNT) {
return;
}
regs = &spi_regs[spi];
if(regs->clk.port < 0) {
/* Port / pin configuration invalid. We checked for completeness
above. If clk.port is < 0, this means that all other defines are
< 0 as well */
return;
}
spix_enable(spi);
/* Start by disabling the peripheral before configuring it */
REG(SSI0_BASE + SSI_CR1) = 0;
REG(regs->base + SSI_CR1) = 0;
/* Set the IO clock as the SSI clock */
REG(SSI0_BASE + SSI_CC) = 1;
REG(regs->base + SSI_CC) = 1;
/* Set the mux correctly to connect the SSI pins to the correct GPIO pins */
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(regs->clk.port,
regs->clk.pin,
regs->ioc_pxx_sel_ssi_clkout);
ioc_set_sel(regs->tx.port,
regs->tx.pin,
regs->ioc_pxx_sel_ssi_txd);
REG(regs->ioc_ssirxd_ssi) = (regs->rx.port * 8) + regs->rx.pin;
/* 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(GPIO_PORT_TO_BASE(regs->clk.port),
GPIO_PIN_MASK(regs->clk.pin));
GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->tx.port),
GPIO_PIN_MASK(regs->tx.pin));
GPIO_PERIPHERAL_CONTROL(GPIO_PORT_TO_BASE(regs->rx.port),
GPIO_PIN_MASK(regs->rx.pin));
/* 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(regs->clk.port, regs->clk.pin, IOC_OVERRIDE_DIS);
ioc_set_over(regs->tx.port, regs->tx.pin, IOC_OVERRIDE_DIS);
ioc_set_over(regs->rx.port, regs->rx.pin, IOC_OVERRIDE_DIS);
/* Configure the clock */
REG(SSI0_BASE + SSI_CPSR) = 2;
REG(regs->base + SSI_CPSR) = regs->ssi_cprs_cpsdvsr;
/* Configure the default SPI options.
/*
* 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);
REG(regs->base + SSI_CR0) = SSI_CR0_SPH | SSI_CR0_SPO | (0x07);
/* Enable the SSI */
REG(SSI0_BASE + SSI_CR1) |= SSI_CR1_SSE;
REG(regs->base + SSI_CR1) |= SSI_CR1_SSE;
}
/*---------------------------------------------------------------------------*/
void
spi_cs_init(uint8_t port, uint8_t pin)
spix_enable(uint8_t spi)
{
GPIO_SOFTWARE_CONTROL(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin));
if(spi >= SSI_INSTANCE_COUNT) {
return;
}
REG(SYS_CTRL_RCGCSSI) |= (1 << spi);
}
/*---------------------------------------------------------------------------*/
void
spix_disable(uint8_t spi)
{
if(spi >= SSI_INSTANCE_COUNT) {
return;
}
REG(SYS_CTRL_RCGCSSI) &= ~(1 << spi);
}
/*---------------------------------------------------------------------------*/
void
spix_set_mode(uint8_t spi,
uint32_t frame_format,
uint32_t clock_polarity,
uint32_t clock_phase,
uint32_t data_size)
{
const spi_regs_t *regs;
if(spi >= SSI_INSTANCE_COUNT) {
return;
}
regs = &spi_regs[spi];
/* Disable the SSI peripheral to configure it */
REG(regs->base + SSI_CR1) = 0;
/* Configure the SSI options */
REG(regs->base + SSI_CR0) = clock_phase |
clock_polarity |
frame_format |
(data_size - 1);
/* Re-enable the SSI */
REG(regs->base + SSI_CR1) |= SSI_CR1_SSE;
}
/*---------------------------------------------------------------------------*/
void
spix_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 */
REG(SYS_CTRL_RCGCSSI) |= 1;
}
/*---------------------------------------------------------------------------*/
void
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

@ -45,6 +45,12 @@
#ifndef SSI_H_
#define SSI_H_
/*---------------------------------------------------------------------------*/
/** \name Number of SSI instances supported by this CPU.
* @{
*/
#define SSI_INSTANCE_COUNT 2
/** @} */
/*---------------------------------------------------------------------------*/
/** \name Base register memory locations.
* @{

View File

@ -1,5 +1,9 @@
/*
* Copyright (c) 2013, University of Michigan.
*
* Copyright (c) 2015, Weptech elektronik GmbH
* Author: Ulf Knoblich, ulf.knoblich@weptech.de
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,65 +38,144 @@
* Header file for the cc2538 SPI driver, including macros for the
* implementation of the low-level SPI primitives such as waiting for the TX
* FIFO to be ready, inserting into the TX FIFO, etc.
*
* It supports the usage of SSI_NUM_INSTANCES instances by providing new
* functions calls like
*
* - spix_init(uint8_t instance)
* - spix_enable(uint8_t instance)
* - spix_disable(uint8_t instance)
* - spix_set_mode(unit8_t instance, ...)
*
* and new macros like
*
* - SPIX_WAITFORTxREADY(x)
* - SPIX_WAITFOREOTx(x)
* - SPIX_WAITFOREORx(x)
* - SPIX_FLUSH(x)
*
* Some of the old functions and macros are still supported.
* When using these deprecated functions, the SSI module to use
* has to be be selected by means of the macro SPI_CONF_DEFAULT_INSTANCE.
*
* This SPI driver depends on the following defines:
*
* For the SSI0 module:
*
* - SPI0_CKL_PORT
* - SPI0_CLK_PIN
* - SPI0_TX_PORT
* - SPI0_TX_PIN
* - SPI0_RX_PORT
* - SPI0_RX_PIN
*
* For the SSI1 module:
*
* - SPI1_CKL_PORT
* - SPI1_CLK_PIN
* - SPI1_TX_PORT
* - SPI1_TX_PIN
* - SPI1_RX_PORT
* - SPI1_RX_PIN
*/
#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)
#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)
#define SPI_WAITFOREORx() do { \
while(!(REG(SSI0_BASE + SSI_SR) & SSI_SR_RNE)); \
} while(0)
#ifdef SPI_FLUSH
#error "You must include spi-arch.h before spi.h for the CC2538."
/*---------------------------------------------------------------------------*/
/* The SPI instance to use when using the deprecated SPI API. */
#ifdef SPI_CONF_DEFAULT_INSTANCE
#if SPI_CONF_DEFAULT_INSTANCE > (SSI_INSTANCE_COUNT - 1)
#error Invalid SPI_CONF_DEFAULT_INSTANCE: valid values are 0 and 1
#else
#define SPI_DEFAULT_INSTANCE SPI_CONF_DEFAULT_INSTANCE
#endif
#endif
/*---------------------------------------------------------------------------*/
/* Default values for the clock rate divider */
#ifdef SPI0_CONF_CPRS_CPSDVSR
#define SPI0_CPRS_CPSDVSR SPI0_CONF_CPRS_CPSDVSR
#else
#define SPI0_CPRS_CPSDVSR 2
#endif
#define SPI_FLUSH() do { \
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)); \
#ifdef SPI1_CONF_CPRS_CPSDVSR
#define SPI1_CPRS_CPSDVSR SPI1_CONF_CPRS_CPSDVSR
#else
#define SPI1_CPRS_CPSDVSR 2
#endif
/*---------------------------------------------------------------------------*/
/* New API macros */
#define SPIX_WAITFORTxREADY(spi) do { \
while(!(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_TNF)) ; \
} while(0)
#define SPI_CS_SET(port, pin) do { \
GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \
#define SPIX_BUF(spi) REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_DR)
#define SPIX_WAITFOREOTx(spi) do { \
while(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_BSY) ; \
} while(0)
#define SPIX_WAITFOREORx(spi) do { \
while(!(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_RNE)) ; \
} while(0)
#define SPIX_FLUSH(spi) do { \
while(REG(CC_CONCAT3(SSI, spi, _BASE) + SSI_SR) & SSI_SR_RNE) { \
SPIX_BUF(spi); \
} \
} while(0)
#define SPIX_CS_CLR(port, pin) do { \
GPIO_CLR_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \
} while(0)
#define SPIX_CS_SET(port, pin) do { \
GPIO_SET_PIN(GPIO_PORT_TO_BASE(port), GPIO_PIN_MASK(pin)); \
} while(0)
/*---------------------------------------------------------------------------*/
/* Deprecated macros provided for compatibility reasons */
#ifdef SPI_DEFAULT_INSTANCE
#define SPI_WAITFORTxREADY() SPIX_WAITFORTxREADY(SPI_DEFAULT_INSTANCE)
#define SPI_TXBUF SPIX_BUF(SPI_DEFAULT_INSTANCE)
#define SPI_RXBUF SPI_TXBUF
#define SPI_WAITFOREOTx() SPIX_WAITFOREOTx(SPI_DEFAULT_INSTANCE)
#define SPI_WAITFOREORx() SPIX_WAITFOREORx(SPI_DEFAULT_INSTANCE)
#ifdef SPI_FLUSH
#error You must include spi-arch.h before spi.h for the CC2538
#else
#define SPI_FLUSH() SPIX_FLUSH(SPI_DEFAULT_INSTANCE)
#endif
#define SPI_CS_CLR(port, pin) SPIX_CS_CLR(port, pin)
#define SPI_CS_SET(port, pin) SPIX_CS_SET(port, pin)
#endif /* #ifdef SPI_DEFAULT_INSTANCE */
/*---------------------------------------------------------------------------*/
/** \name Arch-specific SPI functions
* @{
*/
/**
* \brief Configure a GPIO to be the chip select pin
* \brief Initialize the SPI bus for the instance given
*
* This sets the mode to Motorola SPI with the following format options:
* Clock phase: 1; data captured on second (rising) edge
* Clock polarity: 1; clock is high when idle
* Data size: 8 bits
*
* Use spix_set_mode() to change the spi mode.
*/
void spi_cs_init(uint8_t port, uint8_t pin);
/** \brief Enables the SPI peripheral
*/
void spi_enable(void);
/** \brief Disables the SPI peripheral
* \note Call this function to save power when the SPI is unused.
*/
void spi_disable(void);
void spix_init(uint8_t spi);
/**
* \brief Configure the SPI data and clock polarity and the data size.
* \brief Enables the SPI peripheral for the instance given
*/
void spix_enable(uint8_t spi);
/**
* \brief Disables the SPI peripheral for the instance given
* \note Call this function to save power when the SPI is unused.
*/
void spix_disable(uint8_t spi);
/**
* \brief Configure the SPI data and clock polarity and the data size for the
* instance given
*
* This function configures the SSI peripheral to use a particular SPI
* configuration that a slave device requires. It should always be called
@ -100,6 +183,7 @@ void spi_disable(void);
*
* See section 19.4.4 in the CC2538 user guide for more information.
*
* \param spi The SSI instance to use.
* \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
@ -109,8 +193,17 @@ void spi_disable(void);
* \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);
void spix_set_mode(uint8_t spi, uint32_t frame_format,
uint32_t clock_polarity, uint32_t clock_phase,
uint32_t data_size);
/**
* \brief Configure a GPIO to be the chip select pin.
*
* Even if this function does not depend on the SPI instance used, we rename
* it to reflect the new naming convention.
*/
void spix_cs_init(uint8_t port, uint8_t pin);
/** @} */

View File

@ -28,7 +28,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
/**
* \addtogroup cc2538dk
* @{
*
@ -78,28 +78,28 @@
#undef LEDS_RED
#undef LEDS_CONF_ALL
#define LEDS_YELLOW 2 /**< LED2 (Yellow) -> PC1 */
#define LEDS_GREEN 4 /**< LED3 (Green) -> PC2 */
#define LEDS_ORANGE 8 /**< LED4 (Orange) -> PC3 */
#define LEDS_YELLOW 2 /**< LED2 (Yellow) -> PC1 */
#define LEDS_GREEN 4 /**< LED3 (Green) -> PC2 */
#define LEDS_ORANGE 8 /**< LED4 (Orange) -> PC3 */
#if USB_SERIAL_CONF_ENABLE
#define LEDS_CONF_ALL 14
#define LEDS_RED LEDS_ORANGE
#define LEDS_CONF_ALL 14
#define LEDS_RED LEDS_ORANGE
#else
#define LEDS_CONF_ALL 15
#define LEDS_RED 1 /**< LED1 (Red) -> PC0 */
#define LEDS_CONF_ALL 15
#define LEDS_RED 1 /**< LED1 (Red) -> PC0 */
#endif
/* Notify various examples that we have LEDs */
#define PLATFORM_HAS_LEDS 1
#define PLATFORM_HAS_LEDS 1
/** @} */
/*---------------------------------------------------------------------------*/
/** \name USB configuration
*
* The USB pullup is driven by PC0 and is shared with LED1
*/
#define USB_PULLUP_PORT GPIO_C_NUM
#define USB_PULLUP_PIN 0
#define USB_PULLUP_PORT GPIO_C_NUM
#define USB_PULLUP_PIN 0
/** @} */
/*---------------------------------------------------------------------------*/
/** \name UART configuration
@ -115,17 +115,17 @@
* UART1_* below.
* @{
*/
#define UART0_RX_PORT GPIO_A_NUM
#define UART0_RX_PIN 0
#define UART0_RX_PORT GPIO_A_NUM
#define UART0_RX_PIN 0
#define UART0_TX_PORT GPIO_A_NUM
#define UART0_TX_PIN 1
#define UART0_TX_PORT GPIO_A_NUM
#define UART0_TX_PIN 1
#define UART1_CTS_PORT GPIO_B_NUM
#define UART1_CTS_PIN 0
#define UART1_CTS_PORT GPIO_B_NUM
#define UART1_CTS_PIN 0
#define UART1_RTS_PORT GPIO_D_NUM
#define UART1_RTS_PIN 3
#define UART1_RTS_PORT GPIO_D_NUM
#define UART1_RTS_PIN 3
/** @} */
/*---------------------------------------------------------------------------*/
/** \name SmartRF Button configuration
@ -139,32 +139,32 @@
* @{
*/
/** BUTTON_SELECT -> PA3 */
#define BUTTON_SELECT_PORT GPIO_A_NUM
#define BUTTON_SELECT_PIN 3
#define BUTTON_SELECT_VECTOR NVIC_INT_GPIO_PORT_A
#define BUTTON_SELECT_PORT GPIO_A_NUM
#define BUTTON_SELECT_PIN 3
#define BUTTON_SELECT_VECTOR NVIC_INT_GPIO_PORT_A
/** BUTTON_LEFT -> PC4 */
#define BUTTON_LEFT_PORT GPIO_C_NUM
#define BUTTON_LEFT_PIN 4
#define BUTTON_LEFT_VECTOR NVIC_INT_GPIO_PORT_C
#define BUTTON_LEFT_PORT GPIO_C_NUM
#define BUTTON_LEFT_PIN 4
#define BUTTON_LEFT_VECTOR NVIC_INT_GPIO_PORT_C
/** BUTTON_RIGHT -> PC5 */
#define BUTTON_RIGHT_PORT GPIO_C_NUM
#define BUTTON_RIGHT_PIN 5
#define BUTTON_RIGHT_VECTOR NVIC_INT_GPIO_PORT_C
#define BUTTON_RIGHT_PORT GPIO_C_NUM
#define BUTTON_RIGHT_PIN 5
#define BUTTON_RIGHT_VECTOR NVIC_INT_GPIO_PORT_C
/** BUTTON_UP -> PC6 */
#define BUTTON_UP_PORT GPIO_C_NUM
#define BUTTON_UP_PIN 6
#define BUTTON_UP_VECTOR NVIC_INT_GPIO_PORT_C
#define BUTTON_UP_PORT GPIO_C_NUM
#define BUTTON_UP_PIN 6
#define BUTTON_UP_VECTOR NVIC_INT_GPIO_PORT_C
/** BUTTON_DOWN -> PC7 */
#define BUTTON_DOWN_PORT GPIO_C_NUM
#define BUTTON_DOWN_PIN 7
#define BUTTON_DOWN_VECTOR NVIC_INT_GPIO_PORT_C
#define BUTTON_DOWN_PORT GPIO_C_NUM
#define BUTTON_DOWN_PIN 7
#define BUTTON_DOWN_VECTOR NVIC_INT_GPIO_PORT_C
/* Notify various examples that we have Buttons */
#define PLATFORM_HAS_BUTTON 1
#define PLATFORM_HAS_BUTTON 1
/** @} */
/*---------------------------------------------------------------------------*/
/**
@ -176,23 +176,49 @@
* ADC inputs can only be on port A.
* @{
*/
#define ADC_ALS_PWR_PORT GPIO_A_NUM /**< ALS power GPIO control port */
#define ADC_ALS_PWR_PIN 7 /**< ALS power GPIO control pin */
#define ADC_ALS_OUT_PIN 6 /**< ALS output ADC input pin on port A */
#define ADC_ALS_PWR_PORT GPIO_A_NUM /**< ALS power GPIO control port */
#define ADC_ALS_PWR_PIN 7 /**< ALS power GPIO control pin */
#define ADC_ALS_OUT_PIN 6 /**< ALS output ADC input pin on port A */
/** @} */
/*---------------------------------------------------------------------------*/
/**
* \name SPI configuration
*
* These values configure which CC2538 pins to use for the SPI lines.
* These values configure which CC2538 pins to use for the SPI lines. Both
* SPI instances can be used independently by providing the corresponding
* port / pin macros.
* @{
*/
#define SPI_CLK_PORT GPIO_A_NUM /**< Clock port */
#define SPI_CLK_PIN 2 /**< Clock pin */
#define SPI_MOSI_PORT GPIO_A_NUM /**< MOSI port */
#define SPI_MOSI_PIN 4 /**< MOSI pin */
#define SPI_MISO_PORT GPIO_A_NUM /**< MISO port */
#define SPI_MISO_PIN 5 /**< MISO pin */
#define SPI0_IN_USE 0
#define SPI1_IN_USE 0
#if SPI0_IN_USE
/** Clock port SPI0 */
#define SPI0_CLK_PORT GPIO_A_NUM
/** Clock pin SPI0 */
#define SPI0_CLK_PIN 2
/** TX port SPI0 (master mode: MOSI) */
#define SPI0_TX_PORT GPIO_A_NUM
/** TX pin SPI0 */
#define SPI0_TX_PIN 4
/** RX port SPI0 (master mode: MISO */
#define SPI0_RX_PORT GPIO_A_NUM
/** RX pin SPI0 */
#define SPI0_RX_PIN 5
#endif /* #if SPI0_IN_USE */
#if SPI1_IN_USE
/** Clock port SPI1 */
#define SPI1_CLK_PORT GPIO_A_NUM
/** Clock pin SPI1 */
#define SPI1_CLK_PIN 2
/** TX port SPI1 (master mode: MOSI) */
#define SPI1_TX_PORT GPIO_A_NUM
/** TX pin SPI1 */
#define SPI1_TX_PIN 4
/** RX port SPI1 (master mode: MISO) */
#define SPI1_RX_PORT GPIO_A_NUM
/** RX pin SPI1 */
#define SPI1_RX_PIN 5
#endif /* #if SPI1_IN_USE */
/** @} */
/*---------------------------------------------------------------------------*/
/**