diff --git a/boards/weio/include/periph_conf.h b/boards/weio/include/periph_conf.h index 8eff676a5f52a738b9498dd30d2faae003bc3642..597ceee93a41fa852d27948549d5b6c3c3a5964b 100644 --- a/boards/weio/include/periph_conf.h +++ b/boards/weio/include/periph_conf.h @@ -81,9 +81,20 @@ extern "C" { * @brief SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 +static const spi_conf_t spi_config[] = { + { + .dev = LPC_SSP0, + .preset_bit = (1 << 0), + .ahb_bit = (1 << 11) + }, + { + .dev = LPC_SSP1, + .preset_bit = (1 << 2), + .ahb_bit = (1 << 18) + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /* @} */ /** diff --git a/cpu/lpc11u34/include/periph_cpu.h b/cpu/lpc11u34/include/periph_cpu.h index c288c49370264288b715493e62af8e80786ef6bd..f498de2a5e0c5d6c8a8c294300bfb3d9245d9d73 100644 --- a/cpu/lpc11u34/include/periph_cpu.h +++ b/cpu/lpc11u34/include/periph_cpu.h @@ -31,7 +31,8 @@ extern "C" { * @brief declare needed generic SPI functions * @{ */ -#define PERIPH_SPI_NEEDS_TRANSFER_BYTES +#define PERIPH_SPI_NEEDS_INIT_CS +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE #define PERIPH_SPI_NEEDS_TRANSFER_REG #define PERIPH_SPI_NEEDS_TRANSFER_REGS /** @} */ @@ -104,11 +105,6 @@ typedef enum { /** @} */ #endif /* ndef DOXYGEN */ -/** - * @brief PWM channel configuration - */ - - /** * @brief PWM configuration */ @@ -119,6 +115,31 @@ typedef struct { uint8_t af; } pwm_conf_t; +/** + * @brief Override SPI clock speed values + * + * @note The values expect the CPU to run at 12MHz + * @todo Generalize the SPI driver + */ +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = 119, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ = 29, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ = 11, /**< drive the SPI bus with 1MHz */ + SPI_CLK_5MHZ = 2, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ = 0 /**< actual: 12 MHz */ +} spi_clk_t; + + +/** + * @brief SPI configuration data + */ +typedef struct { + LPC_SSPx_Type *dev; /**< SPI device to configure */ + uint32_t preset_bit; /**< mask of the corresponding preset bit */ + uint32_t ahb_bit; /**< mask of the corresponding AHB bit */ +} spi_conf_t; + #ifdef __cplusplus } #endif diff --git a/cpu/lpc11u34/periph/spi.c b/cpu/lpc11u34/periph/spi.c index 325d73fbc363148b20d8d2b1f1f0e37374b4ea63..53672526b9e13cff9a18e947efff3d7d3c8d332f 100644 --- a/cpu/lpc11u34/periph/spi.c +++ b/cpu/lpc11u34/periph/spi.c @@ -1,118 +1,86 @@ /* - * Copyright (C) 2015 Freie Universität Berlin + * Copyright (C) 2015-2016 Freie Universität Berlin * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. */ + /** * @ingroup cpu_lpc11u34 * @{ * * @file - * @brief Low-level GPIO driver implementation + * @brief Low-level SPI driver implementation + * + * @todo this implementation needs to be generalized in some aspects, + * e.g. clock configuration * * @author Paul RATHGEB <paul.rathgeb@skynet.be> + * @author Hauke Petersen <hauke.petersen@fu-berlin.de> * * @} */ #include "cpu.h" -#include "board.h" #include "mutex.h" +#include "assert.h" #include "periph/spi.h" -#include "periph_conf.h" -#include "thread.h" -#include "sched.h" - -/* guard file in case no SPI device is defined */ -#if SPI_NUMOF /** * @brief Array holding one pre-initialized mutex for each SPI device */ -static mutex_t locks[] = { -#if SPI_0_EN - [SPI_0] = MUTEX_INIT, -#endif -#if SPI_1_EN - [SPI_1] = MUTEX_INIT, -#endif -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - LPC_SSPx_Type *spi; - /* power on the SPI device */ - spi_poweron(dev); - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); +static mutex_t locks[SPI_NUMOF]; - switch(dev) { -#if SPI_0_EN - case SPI_0: - spi = LPC_SSP0; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi = LPC_SSP1; - break; -#endif - default: - return -1; - } +static inline LPC_SSPx_Type *dev(spi_t bus) +{ + return spi_config[bus].dev; +} - /* Master mode, SPI disabled */ - spi->CR1 = 0; - /* Base clock frequency : 12MHz */ - spi->CPSR = 4; - /* configure bus clock speed */ - switch (speed) { - case SPI_SPEED_100KHZ: - spi->CR0 |= (119 << 8); - break; - case SPI_SPEED_400KHZ: - spi->CR0 |= (29 << 8); - break; - case SPI_SPEED_1MHZ: - spi->CR0 |= (11 << 8); - break; - case SPI_SPEED_5MHZ: - spi->CR0 |= (2 << 8); /* Actual : 4MHz */ - break; - case SPI_SPEED_10MHZ: - spi->CR0 |= (0 << 8); /* Actual : 12MHz */ - break; - } - /* Set mode and 8-bit transfer */ - spi->CR0 |= 0x07 | (conf << 6); - /* Enable SPI */ - spi->CR1 |= (1 << 1); - - /* Wait while the BUSY flag is set */ - while(spi->SR & (1 << 4)) {} - /* Clear the RX FIFO */ - while(spi->SR & (1 << 2)) { - spi->DR; - } +static inline void poweron(spi_t bus) +{ + /* de-assert SPIx, enable clock and set clock div */ + LPC_SYSCON->PRESETCTRL |= (spi_config[bus].preset_bit); + LPC_SYSCON->SYSAHBCLKCTRL |= (spi_config[bus].ahb_bit); +} - return 0; +static inline void poweroff(spi_t bus) +{ + LPC_SYSCON->SYSAHBCLKCTRL &= ~(spi_config[bus].ahb_bit); + LPC_SYSCON->PRESETCTRL &= ~(spi_config[bus].preset_bit); } -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) +void spi_init(spi_t bus) { - /* Slave mode not supported */ - return -1; + /* check device */ + assert(bus <= SPI_NUMOF); + + /* initialize device lock */ + mutex_init(&locks[bus]); + + /* set clock div for all SPI devices to 1 -> 48MHz */ + LPC_SYSCON->SSP0CLKDIV = 1; + LPC_SYSCON->SSP1CLKDIV = 1; + + /* trigger the pin configuration */ + spi_init_pins(bus); + + /* power on the bus for the duration of initialization */ + poweron(bus); + /* reset configuration */ + dev(bus)->CR1 = 0; + /* configure base clock frequency to 12 MHz CLOCK_CORECLOCK / 4 */ + dev(bus)->CPSR = 4; + /* and power off the bus again */ + poweroff(bus); } -int spi_conf_pins(spi_t dev) +void spi_init_pins(spi_t bus) { - switch (dev) { -#if SPI_0_EN - case SPI_0: + /* this is hacky as hell -> integrate this into the GPIO module */ + switch (bus) { + case SPI_DEV(0): /* SPI0 : MISO */ LPC_IOCON->PIO0_8 |= 1; /* SPI0 : MOSI */ @@ -120,128 +88,69 @@ int spi_conf_pins(spi_t dev) /* SPI0 : SCK */ LPC_IOCON->SWCLK_PIO0_10 |= 2; break; -#endif -#if SPI_1_EN - case SPI_1: + case SPI_DEV(1): /* SPI1 : MISO */ LPC_IOCON->PIO1_21 |= 2; /* SPI1 : MOSI */ LPC_IOCON->PIO0_21 |= 2; /* SPI1 : SCK */ LPC_IOCON->PIO1_20 |= 2; -#endif default: - return -1; + break; } - - return 0; } -int spi_acquire(spi_t dev) +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) { - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; + /* lock an power on the bus */ + mutex_lock(&locks[bus]); + poweron(bus); + + /* configure bus clock and mode and set to 8-bit transfer */ + dev(bus)->CR0 = ((clk << 8) | (mode << 6) | 0x07); + /* enable the bus */ + dev(bus)->CR1 = (1 << 1); + /* wait until ready and flush RX FIFO */ + while(dev(bus)->SR & (1 << 4)) {} + while(dev(bus)->SR & (1 << 2)) { + dev(bus)->DR; } - mutex_lock(&locks[dev]); - return 0; + + return SPI_OK; } -int spi_release(spi_t dev) +void spi_release(spi_t bus) { - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; + /* disable device, power off and release lock */ + dev(bus)->CR1 = 0; + poweroff(bus); + mutex_unlock(&locks[bus]); } -int spi_transfer_byte(spi_t dev, char out, char *in) +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - char tmp; - LPC_SSPx_Type *spi; + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = LPC_SSP0; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi = LPC_SSP1; - break; -#endif - default: - return 0; - } + assert(out_buf || in_buf); - /* Wait while the BUSY flag is set */ - while(spi->SR & (1 << 4)) {} - /* Put byte in the TX Fifo */ - *((volatile uint8_t *)(&spi->DR)) = (uint8_t)out; - /* Wait until the current byte is transfered */ - while(!(spi->SR & (1 << 2)) ) {} - /* Read the returned byte */ - tmp = *((volatile uint8_t *)(&spi->DR)); - /* 'return' response byte if wished for */ - if (in) { - *in = tmp; + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); } - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* Slave mode not supported */ -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - /* De-assert SPI0 */ - LPC_SYSCON->PRESETCTRL |= (1 << 0); - /* Enable SPI0 clock */ - LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 11); - /* Clock div : 48MHz */ - LPC_SYSCON->SSP0CLKDIV = 1; - break; -#endif -#if SPI_1_EN - case SPI_1: - /* De-assert SPI1 */ - LPC_SYSCON->PRESETCTRL |= (1 << 2); - /* Enable SPI1 clock */ - LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 18); - /* Clock div : 48MHz */ - LPC_SYSCON->SSP1CLKDIV = 1; - break; -#endif + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; + while(dev(bus)->SR & (1 << 4)) {} /* wait for BUSY clear */ + *((volatile uint8_t *)(&dev(bus)->DR)) = tmp; + while(!(dev(bus)->SR & (1 << 2))) {} /* wait RXNE */ + tmp = *((volatile uint8_t *)(&dev(bus)->DR)); + if (in_buf) { + in_buf[i] = tmp; + } } -} -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - /* Assert SPI0 */ - LPC_SYSCON->PRESETCTRL &= ~(1 << 0); - /* Disable SPI0 clock */ - LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 11); - break; -#endif -#if SPI_1_EN - case SPI_1: - /* Assert SPI1 */ - LPC_SYSCON->PRESETCTRL &= ~(1 << 2); - /* Disable SPI1 clock */ - LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 18); - break; -#endif + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t)cs); } } - -#endif /* SPI_NUMOF */