From a388a1bcd79fe7384f0cca2d0fb5c52c479775e9 Mon Sep 17 00:00:00 2001 From: Ulf Knoblich Date: Wed, 18 Mar 2015 19:43:02 +0100 Subject: [PATCH] CC2538: added support for SSI1 --- core/dev/spi.h | 36 ++-- core/sys/cc.h | 10 +- cpu/cc2538/dev/spi.c | 313 +++++++++++++++++++++++++++------- cpu/cc2538/dev/ssi.h | 6 + cpu/cc2538/spi-arch.h | 179 ++++++++++++++----- platform/cc2538dk/dev/board.h | 116 ++++++++----- 6 files changed, 487 insertions(+), 173 deletions(-) diff --git a/core/dev/spi.h b/core/dev/spi.h index 1ccbe2bc0..5960c411b 100644 --- a/core/dev/spi.h +++ b/core/dev/spi.h @@ -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_ */ diff --git a/core/sys/cc.h b/core/sys/cc.h index 90ef3e710..6bd87c288 100644 --- a/core/sys/cc.h +++ b/core/sys/cc.h @@ -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_ */ diff --git a/cpu/cc2538/dev/spi.c b/cpu/cc2538/dev/spi.c index bff1783b5..6b363bd7b 100644 --- a/cpu/cc2538/dev/spi.c +++ b/cpu/cc2538/dev/spi.c @@ -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; -} /** @} */ diff --git a/cpu/cc2538/dev/ssi.h b/cpu/cc2538/dev/ssi.h index da41a5b0a..ca06969ee 100644 --- a/cpu/cc2538/dev/ssi.h +++ b/cpu/cc2538/dev/ssi.h @@ -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. * @{ diff --git a/cpu/cc2538/spi-arch.h b/cpu/cc2538/spi-arch.h index ddbf9daac..137220b2f 100644 --- a/cpu/cc2538/spi-arch.h +++ b/cpu/cc2538/spi-arch.h @@ -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); /** @} */ diff --git a/platform/cc2538dk/dev/board.h b/platform/cc2538dk/dev/board.h index d5514839d..2d9c5ac48 100644 --- a/platform/cc2538dk/dev/board.h +++ b/platform/cc2538dk/dev/board.h @@ -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 */ /** @} */ /*---------------------------------------------------------------------------*/ /**