From 849ce20f5cf71cc1d81afcc8698a9062a12220e7 Mon Sep 17 00:00:00 2001 From: Hauke Petersen <hauke.petersen@fu-berlin.de> Date: Tue, 8 Nov 2016 18:27:41 +0100 Subject: [PATCH] cpu/sam3+boards: adapted to new SPI API - adapted the SPI driver - adapted all boards using the CPU --- boards/arduino-due/include/periph_conf.h | 33 +- boards/arduino-due/include/w5100_params.h | 14 +- boards/udoo/include/periph_conf.h | 35 +- cpu/sam3/include/periph_cpu.h | 33 +- cpu/sam3/periph/spi.c | 389 ++++------------------ 5 files changed, 135 insertions(+), 369 deletions(-) diff --git a/boards/arduino-due/include/periph_conf.h b/boards/arduino-due/include/periph_conf.h index d6e603c75d..fe187f4396 100644 --- a/boards/arduino-due/include/periph_conf.h +++ b/boards/arduino-due/include/periph_conf.h @@ -88,27 +88,18 @@ static const uart_conf_t uart_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI0 -#define SPI_0_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_SPI0)); -#define SPI_0_CLKDIS() (PMC->PMC_PCER0 &= ~(1 << ID_SPI0)); -#define SPI_0_IRQ SPI0_IRQn -#define SPI_0_IRQ_HANDLER isr_spi0 -#define SPI_0_IRQ_PRIO 1 - -/* SPI 0 pin configuration */ -#define SPI_0_MISO_PIN PIO_PA25A_SPI0_MISO -#define SPI_0_MOSI_PIN PIO_PA26A_SPI0_MOSI -#define SPI_0_SCK_PIN PIO_PA27A_SPI0_SPCK -#define SPI_0_MISO_PORT PIOA -#define SPI_0_MOSI_PORT PIOA -#define SPI_0_SCK_PORT PIOA -#define SPI_0_MISO_PORT_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_PIOA)); -#define SPI_0_MOSI_PORT_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_PIOA)); -#define SPI_0_SCK_PORT_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_PIOA)); +static const spi_conf_t spi_config[] = { + { + .dev = SPI0, + .id = ID_SPI0, + .clk = GPIO_PIN(PA, 27), + .mosi = GPIO_PIN(PA, 26), + .miso = GPIO_PIN(PA, 25), + .mux = GPIO_MUX_A + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/arduino-due/include/w5100_params.h b/boards/arduino-due/include/w5100_params.h index 131bed8ec8..7eefa13bad 100644 --- a/boards/arduino-due/include/w5100_params.h +++ b/boards/arduino-due/include/w5100_params.h @@ -28,10 +28,10 @@ extern "C" { * @{ */ #ifndef W5100_PARAM_SPI -#define W5100_PARAM_SPI (SPI_0) +#define W5100_PARAM_SPI (SPI_DEV(0)) #endif -#ifndef W5100_PARAM_SPI_SPEED -#define W5100_PARAM_SPI_SPEED (SPI_SPEED_5MHZ) +#ifndef W5100_PARAM_SPI_CLK +#define W5100_PARAM_SPI_CLK (SPI_CLK_5MHZ) #endif #ifndef W5100_PARAM_CS #define W5100_PARAM_CS (GPIO_PIN(2, 29)) @@ -46,10 +46,10 @@ extern "C" { */ static const w5100_params_t w5100_params[] = { { - .spi = W5100_PARAM_SPI, - .spi_speed = W5100_PARAM_SPI_SPEED, - .cs = W5100_PARAM_CS, - .evt = W5100_PARAM_EVT + .spi = W5100_PARAM_SPI, + .clk = W5100_PARAM_SPI_CLK, + .cs = W5100_PARAM_CS, + .evt = W5100_PARAM_EVT }, }; /** @} */ diff --git a/boards/udoo/include/periph_conf.h b/boards/udoo/include/periph_conf.h index 1514e2d143..d9a729ece4 100644 --- a/boards/udoo/include/periph_conf.h +++ b/boards/udoo/include/periph_conf.h @@ -86,29 +86,18 @@ static const uart_conf_t uart_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI0 -#define SPI_0_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_SPI0)); -#define SPI_0_CLKDIS() (PMC->PMC_PCER0 &= ~(1 << ID_SPI0)); -#define SPI_0_IRQ SPI0_IRQn -#define SPI_0_IRQ_HANDLER isr_spi0 -#define SPI_0_IRQ_PRIO 1 - -/* SPI 0 pin configuration */ -#define SPI_0_MISO_PIN PIO_PA25A_SPI0_MISO -#define SPI_0_MOSI_PIN PIO_PA26A_SPI0_MOSI -#define SPI_0_SCK_PIN PIO_PA27A_SPI0_SPCK - -#define SPI_0_MISO_PORT PIOA -#define SPI_0_MOSI_PORT PIOA -#define SPI_0_SCK_PORT PIOA - -#define SPI_0_MISO_PORT_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_PIOA)); -#define SPI_0_MOSI_PORT_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_PIOA)); -#define SPI_0_SCK_PORT_CLKEN() (PMC->PMC_PCER0 |= (1 << ID_PIOA)); +static const spi_conf_t spi_config[] = { + { + .dev = SPI0, + .id = ID_SPI0, + .clk = GPIO_PIN(PA, 25), + .mosi = GPIO_PIN(PA, 26), + .miso = GPIO_PIN(PA, 27), + .mux = GPIO_MUX_A + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/cpu/sam3/include/periph_cpu.h b/cpu/sam3/include/periph_cpu.h index 4921a1c1c7..b2097b3337 100644 --- a/cpu/sam3/include/periph_cpu.h +++ b/cpu/sam3/include/periph_cpu.h @@ -24,7 +24,6 @@ #include "cpu.h" - #ifdef __cplusplus extern "C" { #endif @@ -50,7 +49,8 @@ typedef uint32_t gpio_t; * @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 /** @} */ @@ -127,6 +127,23 @@ typedef enum { GPIO_MUX_B = 1, /**< alternate function B */ } gpio_mux_t; +#define HAVE_SPI_MODE_T +typedef enum { + SPI_MODE_0 = (SPI_CSR_NCPHA), /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = (0), /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = (SPI_CSR_CPOL | SPI_CSR_NCPHA), /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = (SPI_CSR_CPOL) /**< CPOL=1, CPHA=1 */ +} spi_mode_t; + +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = (100000), /**< 100KHz */ + SPI_CLK_400KHZ = (400000), /**< 400KHz */ + SPI_CLK_1MHZ = (1000000), /**< 1MHz */ + SPI_CLK_5MHZ = (5000000), /**< 5MHz */ + SPI_CLK_10MHZ = (10000000) /**< 10MHz */ +} spi_clk_t; + /** * @brief Timer configuration data */ @@ -157,6 +174,18 @@ typedef struct { uint8_t hwchan; /**< the HW channel used for a logical channel */ } pwm_chan_conf_t; +/** + * @brief SPI configuration data + */ +typedef struct { + Spi *dev; /**< SPI module to use */ + uint8_t id; /**< corresponding ID of that module */ + gpio_t clk; /**< pin mapped to the CLK line */ + gpio_t mosi; /**< pin mapped to the MOSI line */ + gpio_t miso; /**< pin mapped to the MISO line */ + gpio_mux_t mux; /**< pin MUX setting */ +} spi_conf_t; + /** * @brief Configure the given GPIO pin to be used with the given MUX setting * diff --git a/cpu/sam3/periph/spi.c b/cpu/sam3/periph/spi.c index a86f5e2fd6..72f952e2ae 100644 --- a/cpu/sam3/periph/spi.c +++ b/cpu/sam3/periph/spi.c @@ -1,13 +1,14 @@ /* * Copyright (C) 2014 Hamburg University of Applied Sciences -* -* 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. +* 2016-2017 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. */ /** - * @ingroup cpu_sam3x8e + * @ingroup cpu_sam3 * @{ * * @file @@ -23,347 +24,103 @@ #include "cpu.h" #include "mutex.h" +#include "assert.h" #include "periph/gpio.h" -#include "periph_conf.h" #include "periph/spi.h" -#include "sam3x8e.h" -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF +#define ENABLE_DEBUG (0) +#include "debug.h" /** - * @brief Array holding one pre-initialized mutex for each SPI device + * @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 -#if SPI_2_EN - [SPI_2] = MUTEX_INIT -#endif -}; - -typedef struct { - char(*cb)(char data); -} spi_state_t; - -static inline void irq_handler_transfer(Spi *spi, spi_t dev); +static mutex_t locks[SPI_NUMOF]; -static spi_state_t spi_config[SPI_NUMOF]; - -void spi_poweron(spi_t dev) +static inline Spi *dev(spi_t bus) { - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - break; -#endif /* SPI_0_EN */ - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while (!(SPI_0_DEV->SPI_SR & SPI_SR_SPIENS)) {} /* not busy anymore */ - SPI_0_CLKDIS(); - NVIC_DisableIRQ(SPI_0_IRQ); - break; -#endif /* SPI_0_EN */ - } + return spi_config[bus].dev; } -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +void spi_init(spi_t bus) { - uint8_t speed_divider; - Spi *spi_port; - - spi_poweron(dev); - - switch (speed) { - case SPI_SPEED_400KHZ: - speed_divider = 210; - break; - - case SPI_SPEED_1MHZ: - speed_divider = 84; - break; - - case SPI_SPEED_5MHZ: - speed_divider = 17; - break; - - case SPI_SPEED_10MHZ: /* this might be too fast */ - speed_divider = 8; - break; - - default: - return -1; - } - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - break; -#endif /* SPI_0_EN */ - default: - return -2; - } + assert(bus < SPI_NUMOF); - /* Configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /***************** SPI-Init *****************/ - - /* Chip Select Register */ - spi_port->SPI_CSR[0] = 0; /* This is index 0 since we don't use internal CS-Signals */ - - switch (conf) { - case SPI_CONF_FIRST_RISING: - spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL; - spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA; - break; - - case SPI_CONF_SECOND_RISING: - spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL; - spi_port->SPI_CSR[0] &= ~SPI_CSR_NCPHA; - break; - - case SPI_CONF_FIRST_FALLING: - spi_port->SPI_CSR[0] |= SPI_CSR_CPOL; - spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA; - break; - - case SPI_CONF_SECOND_FALLING: - spi_port->SPI_CSR[0] |= SPI_CSR_CPOL; - spi_port->SPI_CSR[0] &= ~ SPI_CSR_NCPHA; - break; - - default: - return -2; - } - - spi_port->SPI_CSR[0] |= SPI_CSR_SCBR(speed_divider); - spi_port->SPI_CSR[0] |= SPI_CSR_BITS_8_BIT; - - /* Control Register */ - spi_port->SPI_CR |= SPI_CR_SPIEN; - /* Mode Register */ - spi_port->SPI_MR = 0; - spi_port->SPI_MR |= SPI_MR_MSTR; - spi_port->SPI_MR |= SPI_MR_MODFDIS; - spi_port->SPI_MR &= ~SPI_MR_PS; - spi_port->SPI_MR &= ~SPI_MR_PCS(0); - - return 0; + /* initialize device lock */ + mutex_init(&locks[bus]); + /* initialize pins */ + spi_init_pins(bus); } -int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data)) +void spi_init_pins(spi_t bus) { - Spi *spi_port; - - spi_poweron(dev); - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - NVIC_SetPriority(SPI_0_IRQ, SPI_0_IRQ_PRIO); - NVIC_EnableIRQ(SPI_0_IRQ); - /* Initialize predefined NSS pin as output so it is "disabled" */ - PIOA->PIO_PER |= PIO_PA28A_SPI0_NPCS0; - PIOA->PIO_OER |= PIO_PA28A_SPI0_NPCS0; - break; -#endif /* SPI_0_EN */ - default: - return -1; - } - - /* Configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /***************** SPI-Init *****************/ - - /* Chip Select Register */ - spi_port->SPI_CSR[0] = 0; - - switch (conf) { - case SPI_CONF_FIRST_RISING: - spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL; - spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA; - break; - - case SPI_CONF_SECOND_RISING: - spi_port->SPI_CSR[0] &= ~SPI_CSR_CPOL; - spi_port->SPI_CSR[0] &= ~SPI_CSR_NCPHA; - break; - - case SPI_CONF_FIRST_FALLING: - spi_port->SPI_CSR[0] |= SPI_CSR_CPOL; - spi_port->SPI_CSR[0] |= SPI_CSR_NCPHA; - break; - - case SPI_CONF_SECOND_FALLING: - spi_port->SPI_CSR[0] |= SPI_CSR_CPOL; - spi_port->SPI_CSR[0] &= ~ SPI_CSR_NCPHA; - break; - - default: - return -1; - } - - /* Control Register */ - spi_port->SPI_CR |= SPI_CR_SPIEN; - /* Mode Register */ - spi_port->SPI_MR = 0; - spi_port->SPI_MR |= SPI_MR_MODFDIS; - /* Enable SPI interrupts */ - spi_port->SPI_IER = 0; - spi_port->SPI_IDR = ~(0); - spi_port->SPI_IER |= 1; - spi_port->SPI_IDR &= ~SPI_IDR_RDRF; - - /* Set callback */ - spi_config[dev].cb = cb; - - return 0; + gpio_init(spi_config[bus].clk, GPIO_OUT); + gpio_init(spi_config[bus].mosi, GPIO_OUT); + gpio_init(spi_config[bus].miso, GPIO_IN); + gpio_init_mux(spi_config[bus].clk, spi_config[bus].mux); + gpio_init_mux(spi_config[bus].mosi, spi_config[bus].mux); + gpio_init_mux(spi_config[bus].miso, spi_config[bus].mux); } -int spi_conf_pins(spi_t dev) +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) { - switch (dev) { -#if SPI_0_EN - case SPI_0: - /***************** PIO-Init *****************/ - /* Push-pull configuration */ - SPI_0_MISO_PORT->PIO_MDER &= ~SPI_0_MISO_PIN; - SPI_0_MISO_PORT->PIO_MDDR |= SPI_0_MISO_PIN; - SPI_0_MOSI_PORT->PIO_MDER &= ~SPI_0_MOSI_PIN; - SPI_0_MOSI_PORT->PIO_MDDR |= SPI_0_MOSI_PIN; - SPI_0_SCK_PORT->PIO_MDER &= ~SPI_0_SCK_PIN; - SPI_0_SCK_PORT->PIO_MDDR |= SPI_0_SCK_PIN; - - /* With pull-up resistors */ - SPI_0_MISO_PORT->PIO_PUDR &= ~SPI_0_MISO_PIN; - SPI_0_MISO_PORT->PIO_PUER |= SPI_0_MISO_PIN; - SPI_0_MOSI_PORT->PIO_PUDR &= ~SPI_0_MOSI_PIN; - SPI_0_MOSI_PORT->PIO_PUER |= SPI_0_MOSI_PIN; - SPI_0_SCK_PORT->PIO_PUDR &= ~SPI_0_SCK_PIN; - SPI_0_SCK_PORT->PIO_PUER |= SPI_0_SCK_PIN; - - /* Clear output */ - SPI_0_MISO_PORT->PIO_SODR &= ~SPI_0_MISO_PIN; - SPI_0_MISO_PORT->PIO_CODR |= SPI_0_MISO_PIN; - SPI_0_MOSI_PORT->PIO_SODR &= ~SPI_0_MOSI_PIN; - SPI_0_MOSI_PORT->PIO_CODR |= SPI_0_MOSI_PIN; - SPI_0_SCK_PORT->PIO_SODR &= ~SPI_0_SCK_PIN; - SPI_0_SCK_PORT->PIO_CODR |= SPI_0_SCK_PIN; - - /* Peripheral Function Selection */ - SPI_0_MISO_PORT->PIO_PER &= ~SPI_0_MISO_PIN; - SPI_0_MISO_PORT->PIO_PDR |= SPI_0_MISO_PIN; - SPI_0_MOSI_PORT->PIO_PER &= ~SPI_0_MOSI_PIN; - SPI_0_MOSI_PORT->PIO_PDR |= SPI_0_MOSI_PIN; - SPI_0_SCK_PORT->PIO_PER &= ~SPI_0_SCK_PIN; - SPI_0_SCK_PORT->PIO_PDR |= SPI_0_SCK_PIN; - - /* Peripheral A */ - SPI_0_MISO_PORT->PIO_ABSR &= ~SPI_0_MISO_PIN; - SPI_0_MOSI_PORT->PIO_ABSR &= ~SPI_0_MOSI_PIN; - SPI_0_SCK_PORT->PIO_ABSR &= ~SPI_0_SCK_PIN; - - break; -#endif /* SPI_0_EN */ - default: - return -1; - } - - return 0; + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable SPI device clock */ + PMC->PMC_PCER0 |= (1 << spi_config[bus].id); + /* set mode and speed */ + dev(bus)->SPI_CSR[0] = (SPI_CSR_SCBR(CLOCK_CORECLOCK / clk) | mode); + dev(bus)->SPI_MR = (SPI_MR_MSTR | SPI_MR_MODFDIS); + dev(bus)->SPI_CR = SPI_CR_SPIEN; + + return SPI_OK; } -int spi_acquire(spi_t dev) +void spi_release(spi_t bus) { - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; + /* disable device and turn off clock signal */ + dev(bus)->SPI_CR = 0; + PMC->PMC_PCER0 &= ~(1 << spi_config[bus].id); + /* release device lock */ + mutex_unlock(&locks[bus]); } -int spi_release(spi_t dev) +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - Spi *spi_port; + assert(in_buf || out_buf); - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - break; -#endif /* SPI_0_EN */ - default: - return -1; + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); } - while (!(spi_port->SPI_SR & SPI_SR_TDRE)) {} - - spi_port->SPI_TDR = SPI_TDR_TD(out); - - while (!(spi_port->SPI_SR & SPI_SR_RDRF)) {} - - *in = spi_port->SPI_RDR & SPI_RDR_RD_Msk; - - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_DEV->SPI_TDR = SPI_TDR_TD(reset_val); - break; -#endif /* SPI_0_EN */ + if (!in_buf) { + for (size_t i = 0; i < len; i++) { + while(!(dev(bus)->SPI_SR & SPI_SR_TDRE)) {} + dev(bus)->SPI_TDR = out_buf[i]; + } + while (!(dev(bus)->SPI_SR & SPI_SR_RDRF)) {} + dev(bus)->SPI_RDR; } -} - -static inline void irq_handler_transfer(Spi *spi, spi_t dev) -{ - if (spi->SPI_SR & SPI_SR_RDRF) { - char data; - data = spi->SPI_RDR & SPI_RDR_RD_Msk; - data = spi_config[dev].cb(data); - spi->SPI_TDR = SPI_TDR_TD(data); + else if (!out_buf) { + for (size_t i = 0; i < len; i++) { + dev(bus)->SPI_TDR = 0; + while (!(dev(bus)->SPI_SR & SPI_SR_RDRF)) {} + in_buf[i] = dev(bus)->SPI_RDR; + } + } + else { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SPI_SR & SPI_SR_TDRE)); + dev(bus)->SPI_TDR = out_buf[i]; + while (!(dev(bus)->SPI_SR & SPI_SR_RDRF)); + in_buf[i] = dev(bus)->SPI_RDR; + } } - /* See if a thread with higher priority wants to run now */ - cortexm_isr_end(); -} - -#if SPI_0_EN -void SPI_0_IRQ_HANDLER(void) -{ - if (SPI_0_DEV->SPI_SR & SPI_SR_RDRF) { - irq_handler_transfer(SPI_0_DEV, SPI_0); + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t)cs); } } -#endif - -#endif /* SPI_NUMOF */ -- GitLab