diff --git a/boards/airfy-beacon/include/periph_conf.h b/boards/airfy-beacon/include/periph_conf.h index bc7d1a009053..4aac804ea10b 100644 --- a/boards/airfy-beacon/include/periph_conf.h +++ b/boards/airfy-beacon/include/periph_conf.h @@ -1,9 +1,9 @@ /* * Copyright (C) 2014 Christian Mehlis * - * 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. */ /** @@ -83,15 +83,16 @@ static const timer_conf_t timer_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI_0 device configuration */ -#define SPI_0_DEV NRF_SPI0 -#define SPI_0_PIN_MOSI 13 -#define SPI_0_PIN_MISO 14 -#define SPI_0_PIN_SCK 15 +static const spi_conf_t spi_config[] = { + { + .dev = NRF_SPI0, + .sclk = 15, + .mosi = 13, + .miso = 14 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/arduino-due/include/periph_conf.h b/boards/arduino-due/include/periph_conf.h index d6e603c75d81..fe187f43965b 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/sdcard_spi_params.h b/boards/arduino-due/include/sdcard_spi_params.h new file mode 100644 index 000000000000..0cd2a1e4c19f --- /dev/null +++ b/boards/arduino-due/include/sdcard_spi_params.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017 Michel Rottleuthner + * 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 boards_arduino-due + * @{ + * + * @file + * @brief SD card configuration for the Arduino due + * + * @author Michel Rottleuthner + * @author Hauke Petersen + */ + +#ifndef SDCARD_SPI_PARAMS_H +#define SDCARD_SPI_PARAMS_H + +#include "board.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set default configuration parameters for the sdcard_spi driver + * @{ + */ +#ifndef SDCARD_SPI_PARAM_SPI +#define SDCARD_SPI_PARAM_SPI (SPI_DEV(0)) +#endif +#ifndef SDCARD_SPI_PARAM_CS +#define SDCARD_SPI_PARAM_CS (GPIO_PIN(PA, 29)) +#endif +#ifndef SDCARD_SPI_PARAM_CLK +#define SDCARD_SPI_PARAM_CLK (GPIO_PIN(PA, 27)) +#endif +#ifndef SDCARD_SPI_PARAM_MOSI +#define SDCARD_SPI_PARAM_MOSI (GPIO_PIN(PA, 26)) +#endif +#ifndef SDCARD_SPI_PARAM_MISO +#define SDCARD_SPI_PARAM_MISO (GPIO_PIN(PA, 25)) +#endif +#ifndef SDCARD_SPI_PARAM_POWER +#define SDCARD_SPI_PARAM_POWER (GPIO_UNDEF) +#endif +#ifndef SDCARD_SPI_PARAM_POWER_AH +/** treated as 'don't care' if SDCARD_SPI_PARAM_POWER is GPIO_UNDEF */ +#define SDCARD_SPI_PARAM_POWER_AH (true) +#endif +/** @} */ + +/** + * @brief sdcard_spi configuration + */ +static const sdcard_spi_params_t sdcard_spi_params[] = { + { + .spi_dev = SDCARD_SPI_PARAM_SPI, + .cs = SDCARD_SPI_PARAM_CS, + .clk = SDCARD_SPI_PARAM_CLK, + .mosi = SDCARD_SPI_PARAM_MOSI, + .miso = SDCARD_SPI_PARAM_MISO, + .power = SDCARD_SPI_PARAM_POWER, + .power_act_high = SDCARD_SPI_PARAM_POWER_AH + }, +}; +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* SDCARD_SPI_PARAMS_H */ +/** @} */ diff --git a/boards/arduino-due/include/w5100_params.h b/boards/arduino-due/include/w5100_params.h index 131bed8ec825..7eefa13bade2 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/arduino-zero/include/periph_conf.h b/boards/arduino-zero/include/periph_conf.h index 177882619bf6..4b17f99498ef 100644 --- a/boards/arduino-zero/include/periph_conf.h +++ b/boards/arduino-zero/include/periph_conf.h @@ -183,23 +183,21 @@ static const pwm_conf_t pwm_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (1) -#define SPI_0_EN 1 - -/* SPI0 */ -#define SPI_0_DEV SERCOM4->SPI -#define SPI_IRQ_0 SERCOM4_IRQn -#define SPI_0_GCLK_ID SERCOM4_GCLK_ID_CORE -/* SPI 0 pin configuration */ -#define SPI_0_SCLK GPIO_PIN(PB, 11) -#define SPI_0_SCLK_MUX GPIO_MUX_D -#define SPI_0_MISO GPIO_PIN(PA, 12) -#define SPI_0_MISO_MUX GPIO_MUX_D -#define SPI_0_MISO_PAD SPI_PAD_MISO_0 -#define SPI_0_MOSI GPIO_PIN(PB, 10) -#define SPI_0_MOSI_MUX GPIO_MUX_D -#define SPI_0_MOSI_PAD SPI_PAD_MOSI_2_SCK_3 +static const spi_conf_t spi_config[] = { + { + .dev = &SERCOM4->SPI, + .miso_pin = GPIO_PIN(PA, 12), + .mosi_pin = GPIO_PIN(PB, 10), + .clk_pin = GPIO_PIN(PB, 11), + .miso_mux = GPIO_MUX_D, + .mosi_mux = GPIO_MUX_D, + .clk_mux = GPIO_MUX_D, + .miso_pad = SPI_PAD_MISO_0, + .mosi_pad = SPI_PAD_MOSI_2_SCK_3 + } +}; +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/cc2538dk/include/periph_conf.h b/boards/cc2538dk/include/periph_conf.h index 55222f9dfa73..575a8a653ffa 100644 --- a/boards/cc2538dk/include/periph_conf.h +++ b/boards/cc2538dk/include/periph_conf.h @@ -58,7 +58,6 @@ static const timer_conf_t timer_config[] = { #define TIMER_IRQ_PRIO 1 /** @} */ - /** * @name UART configuration * @{ @@ -112,22 +111,36 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = { }; /** @} */ +/** + * @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz) + * + * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where + * 1 < CPSR < 255 and + * 0 < SCR < 256 + */ +static const spi_clk_conf_t spi_clk_config[] = { + { .cpsr = 10, .scr = 31 }, /* 100khz */ + { .cpsr = 2, .scr = 39 }, /* 400khz */ + { .cpsr = 2, .scr = 15 }, /* 1MHz */ + { .cpsr = 2, .scr = 2 }, /* ~4.5MHz */ + { .cpsr = 2, .scr = 1 } /* ~10.7MHz */ +}; + /** * @name SPI configuration * @{ */ -#define SPI_NUMOF 1 -#define SPI_0_EN 1 - -static const periph_spi_conf_t spi_config[SPI_NUMOF] = { +static const spi_conf_t spi_config[] = { { .dev = SSI0, .mosi_pin = GPIO_PA4, .miso_pin = GPIO_PA5, .sck_pin = GPIO_PA2, - .cs_pin = GPIO_PD0, - }, + .cs_pin = GPIO_PD0 + } }; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/fox/include/board.h b/boards/fox/include/board.h index 24316d18efba..d87e492d07cb 100644 --- a/boards/fox/include/board.h +++ b/boards/fox/include/board.h @@ -43,8 +43,8 @@ extern "C" { * * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin} */ -#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_0, \ - .spi_speed = SPI_SPEED_5MHZ, \ +#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_DEV(0), \ + .spi_clk = SPI_CLK_5MHZ, \ .cs_pin = GPIO_PIN(PORT_A, 1), \ .int_pin = GPIO_PIN(PORT_C, 2), \ .sleep_pin = GPIO_PIN(PORT_A, 0), \ diff --git a/boards/fox/include/periph_conf.h b/boards/fox/include/periph_conf.h index 13565ad61939..ffe99f22e2d6 100644 --- a/boards/fox/include/periph_conf.h +++ b/boards/fox/include/periph_conf.h @@ -115,21 +115,42 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @brief SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device configuration */ -#define SPI_0_DEV SPI2 -#define SPI_0_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_0_BUS_DIV 0 /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */ -/* SPI 0 pin configuration */ -#define SPI_0_CLK_PIN GPIO_PIN(PORT_B,13) -#define SPI_0_MOSI_PIN GPIO_PIN(PORT_B,15) -#define SPI_0_MISO_PIN GPIO_PIN(PORT_B,14) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/frdm-k64f/include/periph_conf.h b/boards/frdm-k64f/include/periph_conf.h index 4af0e403b1cd..9abbbb2f1f22 100644 --- a/boards/frdm-k64f/include/periph_conf.h +++ b/boards/frdm-k64f/include/periph_conf.h @@ -147,35 +147,67 @@ static const pwm_conf_t pwm_config[] = { /** -* @name SPI configuration + * @name SPI configuration + * + * Clock configuration values based on the configured 30Mhz module clock. + * + * Auto-generated by: + * cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c + * * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 -#define SPI_IRQ_PRIO 1 -#define KINETIS_SPI_USE_HW_CS 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI0 -#define SPI_0_INDEX 0 -#define SPI_0_CTAS 0 -#define SPI_0_CLKEN() (SIM->SCGC6 |= (SIM_SCGC6_SPI0_MASK)) -#define SPI_0_CLKDIS() (SIM->SCGC6 &= ~(SIM_SCGC6_SPI0_MASK)) -#define SPI_0_IRQ SPI0_IRQn -#define SPI_0_IRQ_HANDLER isr_spi0 -#define SPI_0_FREQ CLOCK_CORECLOCK - -/* SPI 0 pin configuration */ -#define SPI_0_PORT PORTD -#define SPI_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTD_MASK)) -#define SPI_0_AF 2 - -#define SPI_0_PCS0_PIN 0 -#define SPI_0_SCK_PIN 1 -#define SPI_0_SOUT_PIN 2 -#define SPI_0_SIN_PIN 3 - -#define SPI_0_PCS0_ACTIVE_LOW 1 +static const uint32_t spi_clk_config[] = { + ( + SPI_CTAR_PBR(2) | SPI_CTAR_BR(6) | /* -> 93750Hz */ + SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(5) | + SPI_CTAR_PASC(2) | SPI_CTAR_ASC(5) | + SPI_CTAR_PDT(2) | SPI_CTAR_DT(5) + ), + ( + SPI_CTAR_PBR(2) | SPI_CTAR_BR(4) | /* -> 375000Hz */ + SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(3) | + SPI_CTAR_PASC(2) | SPI_CTAR_ASC(3) | + SPI_CTAR_PDT(2) | SPI_CTAR_DT(3) + ), + ( + SPI_CTAR_PBR(2) | SPI_CTAR_BR(2) | /* -> 1000000Hz */ + SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(4) | + SPI_CTAR_PASC(0) | SPI_CTAR_ASC(4) | + SPI_CTAR_PDT(0) | SPI_CTAR_DT(4) + ), + ( + SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | /* -> 5000000Hz */ + SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(0) | + SPI_CTAR_PASC(1) | SPI_CTAR_ASC(0) | + SPI_CTAR_PDT(1) | SPI_CTAR_DT(0) + ), + ( + SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | /* -> 7500000Hz */ + SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(1) | + SPI_CTAR_PASC(0) | SPI_CTAR_ASC(1) | + SPI_CTAR_PDT(0) | SPI_CTAR_DT(1) + ) +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI0, + .pin_miso = GPIO_PIN(PORT_D, 3), + .pin_mosi = GPIO_PIN(PORT_D, 2), + .pin_clk = GPIO_PIN(PORT_D, 1), + .pin_cs = { + GPIO_PIN(PORT_D, 0), + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF + }, + .pcr = GPIO_AF_2, + .simmask = SIM_SCGC6_SPI0_MASK + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ diff --git a/boards/iotlab-a8-m3/include/periph_conf.h b/boards/iotlab-a8-m3/include/periph_conf.h index 8b4db8ecbc55..ac4ba9c33867 100644 --- a/boards/iotlab-a8-m3/include/periph_conf.h +++ b/boards/iotlab-a8-m3/include/periph_conf.h @@ -31,18 +31,19 @@ extern "C" { * @brief SPI configuration * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device configuration */ -#define SPI_0_DEV SPI2 -#define SPI_0_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */ -/* SPI 0 pin configuration */ -#define SPI_0_CLK_PIN GPIO_PIN(PORT_B,13) -#define SPI_0_MISO_PIN GPIO_PIN(PORT_B,14) -#define SPI_0_MOSI_PIN GPIO_PIN(PORT_B,15) +static const spi_conf_t spi_config[] = { + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/iotlab-common/include/board_common.h b/boards/iotlab-common/include/board_common.h index ed9b98837884..f0161d7b8484 100644 --- a/boards/iotlab-common/include/board_common.h +++ b/boards/iotlab-common/include/board_common.h @@ -53,10 +53,10 @@ extern "C" { * * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin} */ -#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_0, \ - .spi_speed = SPI_SPEED_5MHZ, \ - .cs_pin = GPIO_PIN(PORT_A, 4), \ - .int_pin = GPIO_PIN(PORT_C, 4), \ +#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_DEV(0), \ + .spi_clk = SPI_CLK_5MHZ, \ + .cs_pin = GPIO_PIN(PORT_A, 4), \ + .int_pin = GPIO_PIN(PORT_C, 4), \ .sleep_pin = GPIO_PIN(PORT_A, 2), \ .reset_pin = GPIO_PIN(PORT_C, 1)} diff --git a/boards/iotlab-common/include/periph_conf_common.h b/boards/iotlab-common/include/periph_conf_common.h index 3e1aa028ba43..b0d104c9701b 100644 --- a/boards/iotlab-common/include/periph_conf_common.h +++ b/boards/iotlab-common/include/periph_conf_common.h @@ -159,6 +159,29 @@ static const uart_conf_t uart_config[] = { #define I2C_0_SDA_PIN GPIO_PIN(PORT_B,7) /** @} */ +/** + * @brief Shared SPI clock div table + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` + */ +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + #ifdef __cplusplus } #endif diff --git a/boards/iotlab-m3/include/board.h b/boards/iotlab-m3/include/board.h index a88fca79a67e..37618a386032 100644 --- a/boards/iotlab-m3/include/board.h +++ b/boards/iotlab-m3/include/board.h @@ -38,7 +38,7 @@ extern "C" { * @name Define the interface for the connected flash memory * @{ */ -#define EXTFLASH_SPI SPI_1 +#define EXTFLASH_SPI SPI_DEV(1) #define EXTFLASH_CS GPIO_PIN(PORT_A,11) #define EXTFLASH_WRITE GPIO_PIN(PORT_C,6) #define EXTFLASH_HOLD GPIO_PIN(PORT_C,9) diff --git a/boards/iotlab-m3/include/periph_conf.h b/boards/iotlab-m3/include/periph_conf.h index ae7d37b4b0cd..4cf77ad22bc2 100644 --- a/boards/iotlab-m3/include/periph_conf.h +++ b/boards/iotlab-m3/include/periph_conf.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-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. */ /** @@ -31,18 +31,19 @@ extern "C" { * @brief SPI configuration * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device configuration */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */ -/* SPI 0 pin configuration */ -#define SPI_0_CLK_PIN GPIO_PIN(PORT_A,5) -#define SPI_0_MOSI_PIN GPIO_PIN(PORT_A,7) -#define SPI_0_MISO_PIN GPIO_PIN(PORT_A,6) +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/limifrog-v1/include/periph_conf.h b/boards/limifrog-v1/include/periph_conf.h index 457ec3580fd6..bec60ee54bf5 100644 --- a/boards/limifrog-v1/include/periph_conf.h +++ b/boards/limifrog-v1/include/periph_conf.h @@ -109,40 +109,53 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @brief SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 - -/* SPI 0 device configuration */ -#define SPI_0_DEV SPI1 /* Densitron DD-160128FC-1a OLED display; external pins */ -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_ISR isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_PORT GPIOA -#define SPI_0_PIN_SCK 5 -#define SPI_0_PIN_MOSI 7 -#define SPI_0_PIN_MISO 6 -#define SPI_0_PIN_AF 5 - -/* SPI 1 device configuration */ -#define SPI_1_DEV SPI3 /* Adesto AT45DB641E data flash */ -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI3EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI3EN)) -#define SPI_1_IRQ SPI3_IRQn -#define SPI_1_ISR isr_spi3 -/* SPI 1 pin configuration */ -#define SPI_1_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOBEN)) -#define SPI_1_PORT GPIOB -#define SPI_1_PIN_SCK 3 -#define SPI_1_PIN_MOSI 5 -#define SPI_1_PIN_MISO 4 -#define SPI_1_PIN_AF 6 +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 32000000Hz */ + 7, /* -> 125000Hz */ + 5, /* -> 500000Hz */ + 4, /* -> 1000000Hz */ + 2, /* -> 4000000Hz */ + 1 /* -> 8000000Hz */ + }, + { /* for APB2 @ 32000000Hz */ + 7, /* -> 125000Hz */ + 5, /* -> 500000Hz */ + 4, /* -> 1000000Hz */ + 2, /* -> 4000000Hz */ + 1 /* -> 8000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI3, + .mosi_pin = GPIO_PIN(PORT_B, 5), + .miso_pin = GPIO_PIN(PORT_B, 4), + .sclk_pin = GPIO_PIN(PORT_B, 3), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF6, + .rccmask = RCC_APB1ENR_SPI3EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/maple-mini/include/periph_conf.h b/boards/maple-mini/include/periph_conf.h index f48e95caccfe..a8998b99ee9d 100644 --- a/boards/maple-mini/include/periph_conf.h +++ b/boards/maple-mini/include/periph_conf.h @@ -163,39 +163,55 @@ static const uart_conf_t uart_config[] = { #define I2C_1_SDA_PIN GPIO_PIN(PORT_B, 11) /* D0 */ /** @} */ +/** + * @brief Shared SPI clock div table + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` + */ +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + /** * @name SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 0 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_SPI1EN) -#define SPI_0_CLKDIS() (RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -#define SPI_0_BUS_DIV 1 - -/* SPI 0 pin configuration */ -#define SPI_0_CLK_PIN GPIO_PIN(PORT_A, 5) /* D6 */ -#define SPI_0_MISO_PIN GPIO_PIN(PORT_A, 6) /* D5 */ -#define SPI_0_MOSI_PIN GPIO_PIN(PORT_A, 7) /* D4 */ - -/* SPI 1 device config */ -#define SPI_1_DEV SPI2 -#define SPI_1_CLKEN() (RCC->APB1ENR |= RCC_APB1ENR_SPI2EN) -#define SPI_1_CLKDIS() (RCC->APB1ENR &= ~RCC_APB1ENR_SPI2EN) -#define SPI_1_IRQ SPI2_IRQn -#define SPI_1_IRQ_HANDLER isr_spi2 -#define SPI_1_BUS_DIV 1 -/* SPI 1 pin configuration */ -#define SPI_1_CLK_PIN GPIO_PIN(PORT_B, 13) /* D30 */ -#define SPI_1_MISO_PIN GPIO_PIN(PORT_B, 14) /* D29 */ -#define SPI_1_MOSI_PIN GPIO_PIN(PORT_B, 15) /* D28 */ +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/msb-430/Makefile.features b/boards/msb-430/Makefile.features index be3115c5de3a..90ca83aa3e51 100644 --- a/boards/msb-430/Makefile.features +++ b/boards/msb-430/Makefile.features @@ -1,6 +1,7 @@ # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart # Various other features (if any) diff --git a/boards/msb-430/include/periph_conf.h b/boards/msb-430/include/periph_conf.h index cc7c57b82759..97d4d487c764 100644 --- a/boards/msb-430/include/periph_conf.h +++ b/boards/msb-430/include/periph_conf.h @@ -75,7 +75,7 @@ extern "C" { #define SPI_0_EN (1U) /* SPI configuration */ -#define SPI_DEV (USART_0) +#define SPI_BASE (USART_0) #define SPI_IE (SFR->IE1) #define SPI_IF (SFR->IFG1) #define SPI_IE_RX_BIT (1 << 6) diff --git a/boards/msb-430h/include/periph_conf.h b/boards/msb-430h/include/periph_conf.h index 0f51ec4a730b..3a9c485fa444 100644 --- a/boards/msb-430h/include/periph_conf.h +++ b/boards/msb-430h/include/periph_conf.h @@ -77,7 +77,7 @@ extern "C" { #define SPI_0_EN (1U) /* SPI configuration */ -#define SPI_DEV (USART_0) +#define SPI_BASE (USART_0) #define SPI_IE (SFR->IE1) #define SPI_IF (SFR->IFG1) #define SPI_IE_RX_BIT (1 << 6) diff --git a/boards/msba2/include/periph_conf.h b/boards/msba2/include/periph_conf.h index 062da79bac0f..4c47032c9ed8 100644 --- a/boards/msba2/include/periph_conf.h +++ b/boards/msba2/include/periph_conf.h @@ -82,10 +82,12 @@ extern "C" { /** * @brief SPI configuration + * + * The SPI implementation is very much fixed, so we don't need to configure + * anything besides the mandatory SPI_NUMOF. * @{ */ #define SPI_NUMOF (1) -#define SPI_0_EN (1) /** @} */ #ifdef __cplusplus diff --git a/boards/msbiot/include/board.h b/boards/msbiot/include/board.h index 5199702afb8b..38b7eff4f084 100644 --- a/boards/msbiot/include/board.h +++ b/boards/msbiot/include/board.h @@ -32,7 +32,7 @@ extern "C" { * @name Configure connected CC1101 (radio) device * @{ */ -#define CC110X_SPI SPI_0 +#define CC110X_SPI SPI_DEV(0) #define CC110X_CS GPIO_PIN(PORT_B, 12) #define CC110X_GDO0 GPIO_PIN(PORT_C, 4) #define CC110X_GDO1 GPIO_PIN(PORT_A, 6) diff --git a/boards/msbiot/include/periph_conf.h b/boards/msbiot/include/periph_conf.h index acfb0caf49d5..80bc37a54209 100644 --- a/boards/msbiot/include/periph_conf.h +++ b/boards/msbiot/include/periph_conf.h @@ -187,34 +187,43 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF 1 -#define SPI_0_EN 1 -#define SPI_1_EN 0 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 42000000Hz */ + 7, /* -> 164062Hz */ + 6, /* -> 328125Hz */ + 4, /* -> 1312500Hz */ + 2, /* -> 5250000Hz */ + 1 /* -> 10500000Hz */ + }, + { /* for APB2 @ 84000000Hz */ + 7, /* -> 328125Hz */ + 7, /* -> 328125Hz */ + 5, /* -> 1312500Hz */ + 3, /* -> 5250000Hz */ + 2 /* -> 10500000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/mulle/board.c b/boards/mulle/board.c index ec0fbc29b2b2..3bc2899f6328 100644 --- a/boards/mulle/board.c +++ b/boards/mulle/board.c @@ -34,6 +34,7 @@ static nvram_t mulle_nvram_dev; nvram_t *mulle_nvram = &mulle_nvram_dev; static nvram_spi_params_t nvram_spi_params = { .spi = MULLE_NVRAM_SPI_DEV, + .clk = MULLE_NVRAM_SPI_CLK, .cs = MULLE_NVRAM_SPI_CS, .address_count = MULLE_NVRAM_SPI_ADDRESS_COUNT, }; @@ -184,10 +185,6 @@ static int mulle_nvram_init(void) } rec; rec.u32 = 0; - if (spi_init_master(MULLE_NVRAM_SPI_DEV, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ) != 0) { - return -1; - } - if (nvram_spi_init(mulle_nvram, &nvram_spi_params, MULLE_NVRAM_CAPACITY) != 0) { return -2; } diff --git a/boards/mulle/include/board.h b/boards/mulle/include/board.h index 80b24c885614..a875dbae2a13 100644 --- a/boards/mulle/include/board.h +++ b/boards/mulle/include/board.h @@ -108,8 +108,8 @@ void board_init(void); * * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin} */ -#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_0, \ - .spi_speed = SPI_SPEED_5MHZ, \ +#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_DEV(0), \ + .spi_clk = SPI_CLK_5MHZ, \ .cs_pin = GPIO_PIN(PORT_D, 4), \ .int_pin = GPIO_PIN(PORT_B, 9), \ .sleep_pin = GPIO_PIN(PORT_E, 6), \ @@ -121,31 +121,31 @@ void board_init(void); * @{ */ -#define LIS3DH_INT1 GPIO_PIN(PORT_C, 18) -#define LIS3DH_INT2 GPIO_PIN(PORT_C, 17) -#define LIS3DH_CS GPIO_PIN(PORT_D, 0) -#define LIS3DH_SPI SPI_2 - +#define LIS3DH_INT1 GPIO_PIN(PORT_C, 18) +#define LIS3DH_INT2 GPIO_PIN(PORT_C, 17) +#define LIS3DH_CS GPIO_PIN(PORT_D, 0) +#define LIS3DH_CLK SPI_CLK_5MHZ +#define LIS3DH_SPI SPI_DEV(0) /** @} */ /** * @name Mulle power control configuration */ /** @{ */ -#define MULLE_POWER_AVDD GPIO_PIN(PORT_B, 17) /**< AVDD enable pin */ -#define MULLE_POWER_VPERIPH GPIO_PIN(PORT_D, 7) /**< VPERIPH enable pin */ -#define MULLE_POWER_VSEC GPIO_PIN(PORT_B, 16) /**< VSEC enable pin */ +#define MULLE_POWER_AVDD GPIO_PIN(PORT_B, 17) /**< AVDD enable pin */ +#define MULLE_POWER_VPERIPH GPIO_PIN(PORT_D, 7) /**< VPERIPH enable pin */ +#define MULLE_POWER_VSEC GPIO_PIN(PORT_B, 16) /**< VSEC enable pin */ /** @} */ /** * @name Mulle NVRAM hardware configuration */ /** @{ */ -/** FRAM SPI bus, SPI_2 in RIOT is mapped to hardware bus SPI0, see periph_conf.h */ -#define MULLE_NVRAM_SPI_DEV SPI_2 -#define MULLE_NVRAM_SPI_CS GPIO_PIN(PORT_D, 6) /**< FRAM CS pin */ -#define MULLE_NVRAM_CAPACITY 512 /**< FRAM size, in bytes */ -#define MULLE_NVRAM_SPI_ADDRESS_COUNT 1 /**< FRAM addressing size, in bytes */ +#define MULLE_NVRAM_SPI_DEV SPI_DEV(0) +#define MULLE_NVRAM_SPI_CLK SPI_CLK_5MHZ +#define MULLE_NVRAM_SPI_CS GPIO_PIN(PORT_D, 6) /**< FRAM CS pin */ +#define MULLE_NVRAM_CAPACITY 512 /**< FRAM size, in bytes */ +#define MULLE_NVRAM_SPI_ADDRESS_COUNT 1 /**< FRAM addressing size, in bytes */ /** @} */ /** diff --git a/boards/mulle/include/lis3dh_params.h b/boards/mulle/include/lis3dh_params.h index d91f198770ec..5a42f90eacc0 100644 --- a/boards/mulle/include/lis3dh_params.h +++ b/boards/mulle/include/lis3dh_params.h @@ -33,6 +33,7 @@ static const lis3dh_params_t lis3dh_params[] = { { .spi = LIS3DH_SPI, + .clk = LIS3DH_CLK, .cs = LIS3DH_CS, .int1 = LIS3DH_INT1, .int2 = LIS3DH_INT2, diff --git a/boards/mulle/include/periph_conf.h b/boards/mulle/include/periph_conf.h index f51b9f13b7ae..80b5dc64566b 100644 --- a/boards/mulle/include/periph_conf.h +++ b/boards/mulle/include/periph_conf.h @@ -216,159 +216,83 @@ static const pwm_conf_t pwm_config[] = { /** * @name SPI configuration + * + * Clock configuration values based on the configured 47988736Hz module clock. + * + * Auto-generated by: + * cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c + * * @{ */ -#define SPI_NUMOF 3 -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_2_EN 1 -#define SPI_3_EN 0 -#define SPI_4_EN 0 -#define SPI_5_EN 0 -#define SPI_6_EN 0 -#define SPI_7_EN 0 - -#define MULLE_PASTE_PARTS(left, index, right) MULLE_PASTE_PARTS2(left, index, right) -#define MULLE_PASTE_PARTS2(left, index, right) left##index##right - -/* SPI 0 device config */ -/* SPI_0 (in RIOT) is mapped to SPI0, CTAS=0 in hardware */ -#define SPI_0_INDEX 0 -#define SPI_0_CTAS 0 -#define SPI_0_DEV MULLE_PASTE_PARTS(SPI, SPI_0_INDEX, ) -#define SPI_0_CLKEN() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 1) -#define SPI_0_CLKDIS() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 0) -#define SPI_0_IRQ MULLE_PASTE_PARTS(SPI, SPI_0_INDEX, _IRQn) -#define SPI_0_IRQ_HANDLER MULLE_PASTE_PARTS(isr_spi, SPI_0_INDEX, ) -#define SPI_0_IRQ_PRIO CPU_DEFAULT_IRQ_PRIO -#define SPI_0_FREQ SystemBusClock -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT PORTD -#define SPI_0_SCK_PIN 1 -#define SPI_0_SCK_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_0_SCK_AF 2 -#define SPI_0_SIN_PORT PORTD -#define SPI_0_SIN_PIN 3 -#define SPI_0_SIN_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_0_SIN_AF 2 -#define SPI_0_SOUT_PORT PORTD -#define SPI_0_SOUT_PIN 2 -#define SPI_0_SOUT_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_0_SOUT_AF 2 -#define SPI_0_PCS0_PORT PORTD -#define SPI_0_PCS0_PIN 0 -#define SPI_0_PCS0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_0_PCS0_AF 2 -/* SPI chip select polarity */ -#define SPI_0_PCS0_ACTIVE_LOW 1 -#define SPI_0_PCS1_ACTIVE_LOW 1 -#define SPI_0_PCS2_ACTIVE_LOW 1 -#define SPI_0_PCS3_ACTIVE_LOW 1 - -/* SPI 1 device config */ -/* SPI_1 (in RIOT) is mapped to SPI1, CTAS=0 in hardware */ -#define SPI_1_INDEX 1 -#define SPI_1_CTAS 0 -#define SPI_1_DEV MULLE_PASTE_PARTS(SPI, SPI_1_INDEX, ) -#define SPI_1_CLKEN() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI1_SHIFT) = 1) -#define SPI_1_CLKDIS() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI1_SHIFT) = 0) -#define SPI_1_IRQ MULLE_PASTE_PARTS(SPI, SPI_1_INDEX, _IRQn) -#define SPI_1_IRQ_HANDLER MULLE_PASTE_PARTS(isr_spi, SPI_1_INDEX, ) -#define SPI_1_IRQ_PRIO CPU_DEFAULT_IRQ_PRIO -#define SPI_1_FREQ SystemBusClock -/* SPI 0 pin configuration */ -#define SPI_1_SCK_PORT PORTE -#define SPI_1_SCK_PIN 2 -#define SPI_1_SCK_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1) -#define SPI_1_SCK_AF 2 -#define SPI_1_SIN_PORT PORTE -#define SPI_1_SIN_PIN 3 -#define SPI_1_SIN_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1) -#define SPI_1_SIN_AF 2 -#define SPI_1_SOUT_PORT PORTE -#define SPI_1_SOUT_PIN 1 -#define SPI_1_SOUT_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1) -#define SPI_1_SOUT_AF 2 -#define SPI_1_PCS0_PORT PORTE -#define SPI_1_PCS0_PIN 4 -#define SPI_1_PCS0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTE_SHIFT) = 1) -#define SPI_1_PCS0_AF 2 -/* SPI chip select polarity */ -#define SPI_1_PCS0_ACTIVE_LOW 1 -#define SPI_1_PCS1_ACTIVE_LOW 1 -#define SPI_1_PCS2_ACTIVE_LOW 1 -#define SPI_1_PCS3_ACTIVE_LOW 1 - -/* SPI 2 device config */ -/* SPI_2 (in RIOT) is mapped to SPI0, CTAS=1 in hardware */ -#define SPI_2_INDEX 0 -#define SPI_2_CTAS 1 -#define SPI_2_DEV MULLE_PASTE_PARTS(SPI, SPI_2_INDEX, ) -#define SPI_2_CLKEN() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 1) -#define SPI_2_CLKDIS() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_SPI0_SHIFT) = 0) -#define SPI_2_IRQ MULLE_PASTE_PARTS(SPI, SPI_2_INDEX, _IRQn) -/* #define SPI_2_IRQ_HANDLER MULLE_PASTE_PARTS(isr_spi, SPI_2_INDEX, ) */ -#define SPI_2_IRQ_PRIO CPU_DEFAULT_IRQ_PRIO -#define SPI_2_FREQ SystemBusClock -/* SPI 2 pin configuration, must be the same as the other RIOT device using this - * hardware module */ -#define SPI_2_SCK_PORT PORTD -#define SPI_2_SCK_PIN 1 -#define SPI_2_SCK_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_2_SCK_AF 2 -#define SPI_2_SIN_PORT PORTD -#define SPI_2_SIN_PIN 3 -#define SPI_2_SIN_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_2_SIN_AF 2 -#define SPI_2_SOUT_PORT PORTD -#define SPI_2_SOUT_PIN 2 -#define SPI_2_SOUT_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_2_SOUT_AF 2 -#define SPI_2_PCS0_PORT PORTD -#define SPI_2_PCS0_PIN 0 -#define SPI_2_PCS0_PORT_CLKEN() (BITBAND_REG32(SIM->SCGC5, SIM_SCGC5_PORTD_SHIFT) = 1) -#define SPI_2_PCS0_AF 2 -/* SPI chip select polarity */ -#define SPI_2_PCS0_ACTIVE_LOW 1 -#define SPI_2_PCS1_ACTIVE_LOW 1 -#define SPI_2_PCS2_ACTIVE_LOW 1 -#define SPI_2_PCS3_ACTIVE_LOW 1 - -/** - * @name SPI delay timing configuration - * @{ */ -/* These values are necessary for communicating with the AT86RF212B when running - * the MCU core at high clock frequencies. */ -/* NB: The given values are the reciprocals of the time, in order to compute the - * scalers using only integer math. */ -#define SPI_0_TCSC_FREQ (5555555) /* It looks silly, but this is correct. 1/180e-9 */ -#define SPI_0_TASC_FREQ (5454545) /* It looks silly, but this is correct. 1/183e-9 */ -#define SPI_0_TDT_FREQ (4000000) /* 1/250e-9 */ - -/* SPI_1 timings */ -#define SPI_1_TCSC_FREQ (0) -#define SPI_1_TASC_FREQ (0) -#define SPI_1_TDT_FREQ (0) - -/* SPI_2 timings */ -#define SPI_2_TCSC_FREQ (0) -#define SPI_2_TASC_FREQ (0) -#define SPI_2_TDT_FREQ (0) +static const uint32_t spi_clk_config[] = { + ( + SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | /* -> 93728Hz */ + SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(8) | + SPI_CTAR_PASC(0) | SPI_CTAR_ASC(8) | + SPI_CTAR_PDT(0) | SPI_CTAR_DT(8) + ), + ( + SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | /* -> 374912Hz */ + SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(6) | + SPI_CTAR_PASC(0) | SPI_CTAR_ASC(6) | + SPI_CTAR_PDT(0) | SPI_CTAR_DT(6) + ), + ( + SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) | /* -> 999765Hz */ + SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(3) | + SPI_CTAR_PASC(1) | SPI_CTAR_ASC(3) | + SPI_CTAR_PDT(1) | SPI_CTAR_DT(3) + ), + ( + SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | /* -> 4798873Hz */ + SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(0) | + SPI_CTAR_PASC(2) | SPI_CTAR_ASC(0) | + SPI_CTAR_PDT(2) | SPI_CTAR_DT(0) + ), + ( + SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | /* -> 7998122Hz */ + SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(0) | + SPI_CTAR_PASC(1) | SPI_CTAR_ASC(0) | + SPI_CTAR_PDT(1) | SPI_CTAR_DT(0) + ) +}; -/** @} */ +static const spi_conf_t spi_config[] = { + { + .dev = SPI0, + .pin_miso = GPIO_PIN(PORT_D, 3), + .pin_mosi = GPIO_PIN(PORT_D, 2), + .pin_clk = GPIO_PIN(PORT_D, 1), + .pin_cs = { + GPIO_PIN(PORT_D, 0), + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF + }, + .pcr = GPIO_AF_2, + .simmask = SIM_SCGC6_SPI0_MASK + }, + { + .dev = SPI1, + .pin_miso = GPIO_PIN(PORT_E, 3), + .pin_mosi = GPIO_PIN(PORT_E, 1), + .pin_clk = GPIO_PIN(PORT_E, 2), + .pin_cs = { + GPIO_PIN(PORT_E, 4), + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF + }, + .pcr = GPIO_AF_2, + .simmask = SIM_SCGC6_SPI1_MASK + } +}; +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ - -/** - * @name I2C configuration - * @{ - */ -#define I2C_NUMOF (1U) -#define I2C_CLK SystemBusClock -#define I2C_0_EN 1 -#define I2C_1_EN 0 -#define I2C_IRQ_PRIO CPU_DEFAULT_IRQ_PRIO /** * @name I2C baud rate configuration * @{ @@ -387,6 +311,16 @@ static const pwm_conf_t pwm_config[] = { #define KINETIS_I2C_F_MULT_FAST_PLUS (0) /** @} */ +/** + * @name I2C configuration + * @{ + */ +#define I2C_NUMOF (1U) +#define I2C_CLK SystemBusClock +#define I2C_0_EN 1 +#define I2C_1_EN 0 +#define I2C_IRQ_PRIO CPU_DEFAULT_IRQ_PRIO + /* I2C 0 device configuration */ #define I2C_0_DEV I2C0 #define I2C_0_CLKEN() (BITBAND_REG32(SIM->SCGC4, SIM_SCGC4_I2C0_SHIFT) = 1) @@ -402,7 +336,6 @@ static const pwm_conf_t pwm_config[] = { #define I2C_0_PORT_CFG (PORT_PCR_MUX(I2C_0_PIN_AF) | PORT_PCR_ODE_MASK) /** @} */ - /** * @name GPIO configuration * @{ diff --git a/boards/nrf52dk/Makefile.features b/boards/nrf52dk/Makefile.features index a12def18a02e..748d31f89616 100644 --- a/boards/nrf52dk/Makefile.features +++ b/boards/nrf52dk/Makefile.features @@ -4,6 +4,7 @@ FEATURES_PROVIDED += periph_flashpage FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_hwrng FEATURES_PROVIDED += periph_rtt +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart diff --git a/boards/nrf52dk/include/periph_conf.h b/boards/nrf52dk/include/periph_conf.h index 2975d5968f1f..5f128385b685 100644 --- a/boards/nrf52dk/include/periph_conf.h +++ b/boards/nrf52dk/include/periph_conf.h @@ -74,6 +74,21 @@ static const timer_conf_t timer_config[] = { #define UART_PIN_TX 6 /** @} */ +/** + * @name SPI configuration + * @{ + */ +static const spi_conf_t spi_config[] = { + { + .dev = NRF_SPI0, + .sclk = 15, + .mosi = 13, + .miso = 14 } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/boards/nrf6310/include/periph_conf.h b/boards/nrf6310/include/periph_conf.h index 636b4e0f05a2..cc53add56499 100644 --- a/boards/nrf6310/include/periph_conf.h +++ b/boards/nrf6310/include/periph_conf.h @@ -100,22 +100,22 @@ static const timer_conf_t timer_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI Master 0 pin configuration */ -#define SPI_0_DEV NRF_SPI0 -#define SPI_0_PIN_SCK 23 -#define SPI_0_PIN_MISO 22 -#define SPI_0_PIN_MOSI 20 - -/* SPI Master 1 pin configuration */ -#define SPI_1_DEV NRF_SPI1 -#define SPI_1_PIN_SCK 16 -#define SPI_1_PIN_MISO 17 -#define SPI_1_PIN_MOSI 18 +static const spi_conf_t spi_config[] = { + { + .dev = NRF_SPI0, + .sclk = 23, + .mosi = 22, + .miso = 20 + }, + { + .dev = NRF_SPI1, + .sclk = 16, + .mosi = 17, + .miso = 18 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/nucleo-f072/Makefile.features b/boards/nucleo-f072/Makefile.features index 5942339b26cf..4a5c8488bc8d 100644 --- a/boards/nucleo-f072/Makefile.features +++ b/boards/nucleo-f072/Makefile.features @@ -6,6 +6,7 @@ FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_spi # load the common Makefile.features for Nucleo boards include $(RIOTBOARD)/nucleo-common/Makefile.features diff --git a/boards/nucleo-f072/include/periph_conf.h b/boards/nucleo-f072/include/periph_conf.h index 5bf6742b7c2d..014db5e4af33 100644 --- a/boards/nucleo-f072/include/periph_conf.h +++ b/boards/nucleo-f072/include/periph_conf.h @@ -161,6 +161,46 @@ static const pwm_conf_t pwm_config[] = { #define PWM_NUMOF (sizeof(pwm_config) / sizeof(pwm_config[0])) /** @} */ +/** + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` + * @{ + */ +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + }, + { /* for APB2 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF0, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) +/** @} */ + /** * @brief ADC configuration * @{ diff --git a/boards/nucleo-f091/Makefile.features b/boards/nucleo-f091/Makefile.features index 5942339b26cf..4a5c8488bc8d 100644 --- a/boards/nucleo-f091/Makefile.features +++ b/boards/nucleo-f091/Makefile.features @@ -6,6 +6,7 @@ FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_spi # load the common Makefile.features for Nucleo boards include $(RIOTBOARD)/nucleo-common/Makefile.features diff --git a/boards/nucleo-f091/include/periph_conf.h b/boards/nucleo-f091/include/periph_conf.h index 5052e1c22ed3..d80a09285614 100644 --- a/boards/nucleo-f091/include/periph_conf.h +++ b/boards/nucleo-f091/include/periph_conf.h @@ -104,6 +104,48 @@ static const uart_conf_t uart_config[] = { #define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0])) /** @} */ + +/** + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` + * @{ + */ +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + }, + { /* for APB2 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_B, 6), + .af = GPIO_AF0, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) +/** @} */ + + /** * @brief PWM configuration * @{ diff --git a/boards/nucleo-f103/include/periph_conf.h b/boards/nucleo-f103/include/periph_conf.h index 335c15ffe2a8..7a4a898db669 100644 --- a/boards/nucleo-f103/include/periph_conf.h +++ b/boards/nucleo-f103/include/periph_conf.h @@ -160,38 +160,51 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 0 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -#define SPI_0_BUS_DIV 1 - -/* SPI 0 pin configuration */ -#define SPI_0_CLK_PIN GPIO_PIN(PORT_A, 5) -#define SPI_0_MISO_PIN GPIO_PIN(PORT_A, 6) -#define SPI_0_MOSI_PIN GPIO_PIN(PORT_A, 7) - -/* SPI 1 device config */ -#define SPI_1_DEV SPI2 -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_IRQ SPI2_IRQn -#define SPI_1_IRQ_HANDLER isr_spi2 -#define SPI_1_BUS_DIV 1 -/* SPI 1 pin configuration */ -#define SPI_1_CLK_PIN GPIO_PIN(PORT_B, 13) -#define SPI_1_MISO_PIN GPIO_PIN(PORT_B, 14) -#define SPI_1_MOSI_PIN GPIO_PIN(PORT_B, 15) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/nucleo-f207/include/periph_conf.h b/boards/nucleo-f207/include/periph_conf.h index 664f183fd5d0..59554be7eba3 100644 --- a/boards/nucleo-f207/include/periph_conf.h +++ b/boards/nucleo-f207/include/periph_conf.h @@ -167,58 +167,55 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 30000000Hz */ + 7, /* -> 117187Hz */ + 5, /* -> 468750Hz */ + 4, /* -> 937500Hz */ + 2, /* -> 3750000Hz */ + 1 /* -> 7500000Hz */ + }, + { /* for APB2 @ 60000000Hz */ + 7, /* -> 234375Hz */ + 6, /* -> 468750Hz */ + 5, /* -> 937500Hz */ + 3, /* -> 3750000Hz */ + 2 /* -> 7500000Hz */ + } +}; -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA /* A5 pin is shared with the green LED. */ -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_C, 2), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_PIN(PORT_B, 12), + .af = GPIO_AF5, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; -/* SPI 1 device config */ -#define SPI_1_DEV SPI2 -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_BUS_DIV 0 /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_1_IRQ SPI2_IRQn -#define SPI_1_IRQ_HANDLER isr_spi2 -/* SPI 1 pin configuration */ -#define SPI_1_SCK_PORT GPIOB -#define SPI_1_SCK_PIN 3 -#define SPI_1_SCK_AF 5 -#define SPI_1_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN)) -#define SPI_1_MISO_PORT GPIOB -#define SPI_1_MISO_PIN 4 -#define SPI_1_MISO_AF 5 -#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN)) -#define SPI_1_MOSI_PORT GPIOB -#define SPI_1_MOSI_PIN 5 -#define SPI_1_MOSI_AF 5 -#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN)) +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ - /** * @name I2C configuration * @{ @@ -258,7 +255,7 @@ static const uart_conf_t uart_config[] = { */ #define ADC_CONFIG { \ {GPIO_PIN(PORT_A, 4), 0, 0}, \ - {GPIO_PIN(PORT_A, 5), 1, 0} \ + {GPIO_PIN(PORT_C, 0), 1, 0} \ } #define ADC_NUMOF (2) diff --git a/boards/nucleo-f303/include/periph_conf.h b/boards/nucleo-f303/include/periph_conf.h index 5b81d5b5c931..ccab5c0e3fe5 100755 --- a/boards/nucleo-f303/include/periph_conf.h +++ b/boards/nucleo-f303/include/periph_conf.h @@ -138,53 +138,53 @@ static const pwm_conf_t pwm_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) - -/* SPI 1 device config */ -#define SPI_1_DEV SPI3 -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI3EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI3EN)) -#define SPI_1_IRQ SPI3_IRQn -#define SPI_1_IRQ_HANDLER isr_spi3 -/* SPI 1 pin configuration */ -#define SPI_1_SCK_PORT GPIOC -#define SPI_1_SCK_PIN 10 -#define SPI_1_SCK_AF 6 -#define SPI_1_SCK_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN)) -#define SPI_1_MISO_PORT GPIOC -#define SPI_1_MISO_PIN 11 -#define SPI_1_MISO_AF 6 -#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN)) -#define SPI_1_MOSI_PORT GPIOC -#define SPI_1_MOSI_PIN 12 -#define SPI_1_MOSI_AF 6 -#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN)) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_C, 12), + .miso_pin = GPIO_PIN(PORT_C, 11), + .sclk_pin = GPIO_PIN(PORT_C, 10), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF6, + .rccmask = RCC_APB1ENR_SPI3EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/nucleo-f334/include/periph_conf.h b/boards/nucleo-f334/include/periph_conf.h index d7b602d0ba61..06bd731cd3b6 100644 --- a/boards/nucleo-f334/include/periph_conf.h +++ b/boards/nucleo-f334/include/periph_conf.h @@ -122,32 +122,43 @@ static const pwm_conf_t pwm_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/nucleo-f401/include/periph_conf.h b/boards/nucleo-f401/include/periph_conf.h index 5ff2e339c8fc..f011f1bbfcc1 100644 --- a/boards/nucleo-f401/include/periph_conf.h +++ b/boards/nucleo-f401/include/periph_conf.h @@ -141,33 +141,43 @@ static const pwm_conf_t pwm_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA /* A5 pin is shared with the green LED. */ -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 42000000Hz */ + 7, /* -> 164062Hz */ + 6, /* -> 328125Hz */ + 4, /* -> 1312500Hz */ + 2, /* -> 5250000Hz */ + 1 /* -> 10500000Hz */ + }, + { /* for APB2 @ 84000000Hz */ + 7, /* -> 328125Hz */ + 7, /* -> 328125Hz */ + 5, /* -> 1312500Hz */ + 3, /* -> 5250000Hz */ + 2 /* -> 10500000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ diff --git a/boards/nucleo-f446/include/periph_conf.h b/boards/nucleo-f446/include/periph_conf.h index b6738f594137..47ed25898c81 100644 --- a/boards/nucleo-f446/include/periph_conf.h +++ b/boards/nucleo-f446/include/periph_conf.h @@ -167,33 +167,43 @@ static const pwm_conf_t pwm_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI bus runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA /* A5 pin is shared with the green LED. */ -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 90000000Hz */ + 7, /* -> 351562Hz */ + 7, /* -> 351562Hz */ + 6, /* -> 703125Hz */ + 3, /* -> 5625000Hz */ + 2 /* -> 11250000Hz */ + }, + { /* for APB2 @ 180000000Hz */ + 7, /* -> 703125Hz */ + 7, /* -> 703125Hz */ + 7, /* -> 703125Hz */ + 4, /* -> 5625000Hz */ + 3 /* -> 11250000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ diff --git a/boards/nucleo-l1/include/periph_conf.h b/boards/nucleo-l1/include/periph_conf.h index 409a8e1bc730..dbec32fe24a8 100644 --- a/boards/nucleo-l1/include/periph_conf.h +++ b/boards/nucleo-l1/include/periph_conf.h @@ -1,9 +1,9 @@ /* * Copyright (C) 2014-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. */ /** @@ -105,25 +105,43 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @brief SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device configuration */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_ISR isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_PORT GPIOA -#define SPI_0_PIN_SCK 5 -#define SPI_0_PIN_MOSI 7 -#define SPI_0_PIN_MISO 6 -#define SPI_0_PIN_AF 5 +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 32000000Hz */ + 7, /* -> 125000Hz */ + 5, /* -> 500000Hz */ + 4, /* -> 1000000Hz */ + 2, /* -> 4000000Hz */ + 1 /* -> 8000000Hz */ + }, + { /* for APB2 @ 32000000Hz */ + 7, /* -> 125000Hz */ + 5, /* -> 500000Hz */ + 4, /* -> 1000000Hz */ + 2, /* -> 4000000Hz */ + 1 /* -> 8000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/opencm9-04/include/periph_conf.h b/boards/opencm9-04/include/periph_conf.h index 4a24abdf2e1b..91168e89a1d9 100644 --- a/boards/opencm9-04/include/periph_conf.h +++ b/boards/opencm9-04/include/periph_conf.h @@ -135,13 +135,6 @@ static const uart_conf_t uart_config[] = { #define I2C_NUMOF (0) /** @} */ -/** - * @name SPI configuration - * @{ - */ -#define SPI_NUMOF (0) -/** @} */ - #ifdef __cplusplus } #endif diff --git a/boards/openmote-cc2538/include/periph_conf.h b/boards/openmote-cc2538/include/periph_conf.h index 845487b02dac..88b9fa8e3b46 100644 --- a/boards/openmote-cc2538/include/periph_conf.h +++ b/boards/openmote-cc2538/include/periph_conf.h @@ -30,7 +30,7 @@ * @name Clock system configuration * @{ */ -#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency, 32MHz */ +#define CLOCK_CORECLOCK (32000000U) /* desired core clock frequency, 32MHz */ /** @} */ /** @@ -104,14 +104,26 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = { }; /** @} */ +/** + * @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz) + * + * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where + * 1 < CPSR < 255 and + * 0 < SCR < 256 + */ +static const spi_clk_conf_t spi_clk_config[] = { + { .cpsr = 10, .scr = 31 }, /* 100khz */ + { .cpsr = 2, .scr = 39 }, /* 400khz */ + { .cpsr = 2, .scr = 15 }, /* 1MHz */ + { .cpsr = 2, .scr = 2 }, /* ~4.5MHz */ + { .cpsr = 2, .scr = 1 } /* ~10.7MHz */ +}; + /** * @name SPI configuration * @{ */ -#define SPI_NUMOF 1 -#define SPI_0_EN 1 - -static const periph_spi_conf_t spi_config[SPI_NUMOF] = { +static const spi_conf_t spi_config[] = { { .dev = SSI0, .mosi_pin = GPIO_PA5, @@ -120,6 +132,8 @@ static const periph_spi_conf_t spi_config[SPI_NUMOF] = { .cs_pin = GPIO_PA3, }, }; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/pba-d-01-kw2x/include/board.h b/boards/pba-d-01-kw2x/include/board.h index d29b40bda896..2cb1159ac665 100644 --- a/boards/pba-d-01-kw2x/include/board.h +++ b/boards/pba-d-01-kw2x/include/board.h @@ -68,10 +68,10 @@ extern "C" @name KW2XRF configuration @{ */ -#define KW2XRF_SPI (SPI_1) +#define KW2XRF_SPI (SPI_DEV(1)) #define KW2XRF_CS (GPIO_PIN(KW2XDRF_PORT, KW2XDRF_PCS0_PIN)) #define KW2XRF_INT (GPIO_PIN(KW2XDRF_PORT, KW2XDRF_IRQ_PIN)) -#define KW2XRF_SPI_SPEED (SPI_SPEED_10MHZ) +#define KW2XRF_SPI_SPEED (SPI_CLK_10MHZ) #define KW2XRF_SHARED_SPI 0 /** @}*/ diff --git a/boards/pba-d-01-kw2x/include/periph_conf.h b/boards/pba-d-01-kw2x/include/periph_conf.h index bc8de6c30c12..c587b9970020 100644 --- a/boards/pba-d-01-kw2x/include/periph_conf.h +++ b/boards/pba-d-01-kw2x/include/periph_conf.h @@ -163,59 +163,82 @@ static const pwm_conf_t pwm_config[] = { /** - * @name SPI configuration + * @name SPI device configuration + * + * Clock configuration values based on the configured 48Mhz module clock. + * + * Auto-generated by: + * cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c + * * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 -#define KINETIS_SPI_USE_HW_CS 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI0 -#define SPI_0_INDEX 0 -#define SPI_0_CTAS 0 -#define SPI_0_CLKEN() (SIM->SCGC6 |= (SIM_SCGC6_SPI0_MASK)) -#define SPI_0_CLKDIS() (SIM->SCGC6 &= ~(SIM_SCGC6_SPI0_MASK)) -#define SPI_0_IRQ SPI0_IRQn -#define SPI_0_IRQ_HANDLER isr_spi0 -#define SPI_0_FREQ (48e6) - -/* SPI 0 pin configuration */ -#define SPI_0_PORT PORTC -#define SPI_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTC_MASK)) -#define SPI_0_AF 2 - -#define SPI_0_PCS0_PIN 4 -#define SPI_0_SCK_PIN 5 -#define SPI_0_SOUT_PIN 6 -#define SPI_0_SIN_PIN 7 - -#define SPI_0_PCS0_ACTIVE_LOW 1 - -/* SPI 1 device config */ -#define SPI_1_DEV SPI1 -#define SPI_1_INDEX 1 -#define SPI_1_CTAS 0 -#define SPI_1_CLKEN() (SIM->SCGC6 |= (SIM_SCGC6_SPI1_MASK)) -#define SPI_1_CLKDIS() (SIM->SCGC6 &= ~(SIM_SCGC6_SPI1_MASK)) -#define SPI_1_IRQ SPI1_IRQn -#define SPI_1_IRQ_HANDLER isr_spi1 -#define SPI_1_FREQ (48e6) - -/* SPI 1 pin1configuration */ -#define SPI_1_PORT KW2XDRF_PORT_DEV -#define SPI_1_PORT_CLKEN() KW2XDRF_PORT_CLKEN(); -#define SPI_1_AF KW2XDRF_PIN_AF - -#define SPI_1_PCS0_PIN KW2XDRF_PCS0_PIN -#define SPI_1_SCK_PIN KW2XDRF_SCK_PIN -#define SPI_1_SOUT_PIN KW2XDRF_SOUT_PIN -#define SPI_1_SIN_PIN KW2XDRF_SIN_PIN - -#define SPI_1_PCS0_ACTIVE_LOW 1 +static const uint32_t spi_clk_config[] = { + ( + SPI_CTAR_PBR(0) | SPI_CTAR_BR(8) | /* -> 93750Hz */ + SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(8) | + SPI_CTAR_PASC(0) | SPI_CTAR_ASC(8) | + SPI_CTAR_PDT(0) | SPI_CTAR_DT(8) + ), + ( + SPI_CTAR_PBR(0) | SPI_CTAR_BR(6) | /* -> 375000Hz */ + SPI_CTAR_PCSSCK(0) | SPI_CTAR_CSSCK(6) | + SPI_CTAR_PASC(0) | SPI_CTAR_ASC(6) | + SPI_CTAR_PDT(0) | SPI_CTAR_DT(6) + ), + ( + SPI_CTAR_PBR(1) | SPI_CTAR_BR(4) | /* -> 1000000Hz */ + SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(3) | + SPI_CTAR_PASC(1) | SPI_CTAR_ASC(3) | + SPI_CTAR_PDT(1) | SPI_CTAR_DT(3) + ), + ( + SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | /* -> 4800000Hz */ + SPI_CTAR_PCSSCK(2) | SPI_CTAR_CSSCK(0) | + SPI_CTAR_PASC(2) | SPI_CTAR_ASC(0) | + SPI_CTAR_PDT(2) | SPI_CTAR_DT(0) + ), + ( + SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | /* -> 8000000Hz */ + SPI_CTAR_PCSSCK(1) | SPI_CTAR_CSSCK(0) | + SPI_CTAR_PASC(1) | SPI_CTAR_ASC(0) | + SPI_CTAR_PDT(1) | SPI_CTAR_DT(0) + ) +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI0, + .pin_miso = GPIO_PIN(PORT_C, 7), + .pin_mosi = GPIO_PIN(PORT_C, 6), + .pin_clk = GPIO_PIN(PORT_C, 5), + .pin_cs = { + GPIO_PIN(PORT_C, 4), + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF + }, + .simmask = SIM_SCGC6_SPI0_MASK, + .pcr = GPIO_AF_2 + }, + { + .dev = SPI1, + .pin_miso = GPIO_PIN(PORT_B, 17), + .pin_mosi = GPIO_PIN(PORT_B, 16), + .pin_clk = GPIO_PIN(PORT_B, 11), + .pin_cs = { + GPIO_PIN(PORT_B, 10), + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF, + GPIO_UNDEF + }, + .simmask = SIM_SCGC6_SPI1_MASK, + .pcr = GPIO_AF_2 + } +}; +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ diff --git a/boards/pca10005/include/periph_conf.h b/boards/pca10005/include/periph_conf.h index de0ebb2cf5a9..09d183d89ed3 100644 --- a/boards/pca10005/include/periph_conf.h +++ b/boards/pca10005/include/periph_conf.h @@ -83,22 +83,22 @@ static const timer_conf_t timer_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI_0 device configuration */ -#define SPI_0_DEV NRF_SPI0 -#define SPI_0_PIN_MOSI 17 -#define SPI_0_PIN_MISO 18 -#define SPI_0_PIN_SCK 19 - -/* SPI_1 device configuration */ -#define SPI_1_DEV NRF_SPI1 -#define SPI_1_PIN_MOSI 20 -#define SPI_1_PIN_MISO 21 -#define SPI_1_PIN_SCK 22 +static const spi_conf_t spi_config[] = { + { + .dev = NRF_SPI0, + .sclk = 19, + .mosi = 17, + .miso = 18 + }, + { + .dev = NRF_SPI1, + .sclk = 22, + .mosi = 20, + .miso = 21 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/remote-common/include/periph_common.h b/boards/remote-common/include/periph_common.h index 5a018d251937..51404de41254 100644 --- a/boards/remote-common/include/periph_common.h +++ b/boards/remote-common/include/periph_common.h @@ -21,7 +21,6 @@ #ifndef PERIPH_COMMON_H #define PERIPH_COMMON_H -#include "cc2538_gpio.h" #include "periph_cpu.h" #ifdef __cplusplus diff --git a/boards/remote-pa/include/board.h b/boards/remote-pa/include/board.h index 59ff1d90d1ec..407957515b42 100644 --- a/boards/remote-pa/include/board.h +++ b/boards/remote-pa/include/board.h @@ -24,8 +24,6 @@ #define BOARD_H #include "cpu.h" -#include "periph/gpio.h" -#include "board_common.h" #ifdef __cplusplus extern "C" { @@ -74,6 +72,11 @@ #define RF_SWITCH_TOGGLE (RF_SWITCH_PORT->DATA ^= (1 << RF_SWITCH_PIN)) /** @} */ +/** + * @brief Initialize board specific hardware, including clock, LEDs and std-IO + */ +void board_init(void); + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/boards/remote-pa/include/periph_conf.h b/boards/remote-pa/include/periph_conf.h index ee753928d466..d82249a62d93 100644 --- a/boards/remote-pa/include/periph_conf.h +++ b/boards/remote-pa/include/periph_conf.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 Zolertia SL + * Copyright (C) 2014-2016 Freie Universität Berlin + * 2015 Zolertia SL * - * 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. */ /** @@ -15,14 +15,12 @@ * @brief Peripheral MCU configuration for the Re-Mote board prototype A * * @author Hauke Petersen - * Antonio Lignan + * @author Antonio Lignan */ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -#include "cc2538_gpio.h" -#include "periph_cpu.h" #include "periph_common.h" #ifdef __cplusplus @@ -70,29 +68,43 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = { }; /** @} */ +/** + * @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz) + * + * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where + * 1 < CPSR < 255 and + * 0 < SCR < 256 + */ +static const spi_clk_conf_t spi_clk_config[] = { + { .cpsr = 10, .scr = 31 }, /* 100khz */ + { .cpsr = 2, .scr = 39 }, /* 400khz */ + { .cpsr = 2, .scr = 15 }, /* 1MHz */ + { .cpsr = 2, .scr = 2 }, /* ~4.5MHz */ + { .cpsr = 2, .scr = 1 } /* ~10.7MHz */ +}; + /** * @name SPI configuration * @{ */ -#define SPI_NUMOF 2 -#define SPI_0_EN 1 -#define SPI_1_EN 1 - -static const periph_spi_conf_t spi_config[SPI_NUMOF] = { +static const spi_conf_t spi_config[] = { { .dev = SSI0, .mosi_pin = GPIO_PD0, .miso_pin = GPIO_PC4, .sck_pin = GPIO_PD1, - .cs_pin = GPIO_PD3, + .cs_pin = GPIO_PD3 }, { .dev = SSI1, .mosi_pin = GPIO_PC7, .miso_pin = GPIO_PA4, .sck_pin = GPIO_PB5, - }, + .cs_pin = GPIO_UNDEF + } }; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/remote-reva/include/board.h b/boards/remote-reva/include/board.h index b93dd9f8f5e8..637206258d11 100644 --- a/boards/remote-reva/include/board.h +++ b/boards/remote-reva/include/board.h @@ -23,9 +23,6 @@ #define BOARD_H #include "cpu.h" -#include "periph/gpio.h" -#include "periph/spi.h" -#include "board_common.h" #ifdef __cplusplus extern "C" { @@ -111,6 +108,11 @@ #define CC1200_GPD2_GPIO GPIO_PB0 /** @} */ +/** + * @brief Initialize board specific hardware, including clock, LEDs and std-IO + */ +void board_init(void); + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/boards/remote-reva/include/periph_conf.h b/boards/remote-reva/include/periph_conf.h index 2dfd7b1b2ef2..6ccb84f87fcf 100644 --- a/boards/remote-reva/include/periph_conf.h +++ b/boards/remote-reva/include/periph_conf.h @@ -1,10 +1,10 @@ /* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 Zolertia SL + * Copyright (C) 2014-2016 Freie Universität Berlin + * 2015 Zolertia SL * - * 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. */ /** @@ -15,14 +15,12 @@ * @brief Peripheral MCU configuration for the RE-Mote board revision A * * @author Hauke Petersen - * Antonio Lignan + * @author Antonio Lignan */ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -#include "cc2538_gpio.h" -#include "periph_cpu.h" #include "periph_common.h" #ifdef __cplusplus @@ -70,30 +68,43 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = { }; /** @} */ +/** + * @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz) + * + * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where + * 1 < CPSR < 255 and + * 0 < SCR < 256 + */ +static const spi_clk_conf_t spi_clk_config[] = { + { .cpsr = 10, .scr = 31 }, /* 100khz */ + { .cpsr = 2, .scr = 39 }, /* 400khz */ + { .cpsr = 2, .scr = 15 }, /* 1MHz */ + { .cpsr = 2, .scr = 2 }, /* ~4.5MHz */ + { .cpsr = 2, .scr = 1 } /* ~10.7MHz */ +}; + /** * @name SPI configuration * @{ */ -#define SPI_NUMOF 2 -#define SPI_0_EN 1 -#define SPI_1_EN 1 - -static const periph_spi_conf_t spi_config[SPI_NUMOF] = { +static const spi_conf_t spi_config[] = { { .dev = SSI0, .mosi_pin = GPIO_PB1, .miso_pin = GPIO_PB3, .sck_pin = GPIO_PB2, - .cs_pin = GPIO_PB5, + .cs_pin = GPIO_PB5 }, { .dev = SSI1, .mosi_pin = GPIO_PC5, .miso_pin = GPIO_PC6, .sck_pin = GPIO_PC4, - .cs_pin = GPIO_PA7, - }, + .cs_pin = GPIO_PA7 + } }; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/remote-revb/include/board.h b/boards/remote-revb/include/board.h index 7e1e212e99c3..6d1eb842a853 100644 --- a/boards/remote-revb/include/board.h +++ b/boards/remote-revb/include/board.h @@ -23,9 +23,6 @@ #define BOARD_H #include "cpu.h" -#include "periph/gpio.h" -#include "periph/spi.h" -#include "board_common.h" #ifdef __cplusplus extern "C" { @@ -114,7 +111,7 @@ * @name Onboard micro-sd slot pin definitions * @{ */ -#define SDCARD_SPI_PARAM_SPI SPI_1 +#define SDCARD_SPI_PARAM_SPI SPI_DEV(1) #define SDCARD_SPI_PARAM_CS GPIO_PIN(0,7) #define SDCARD_SPI_PARAM_CLK GPIO_PIN(2,4) #define SDCARD_SPI_PARAM_MOSI GPIO_PIN(2,5) @@ -123,6 +120,11 @@ #define SDCARD_SPI_PARAM_POWER_AH false /** @} */ +/** + * @brief Initialize board specific hardware, including clock, LEDs and std-IO + */ +void board_init(void); + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/boards/remote-revb/include/periph_conf.h b/boards/remote-revb/include/periph_conf.h index 4890135cce8a..a4269867ae7c 100644 --- a/boards/remote-revb/include/periph_conf.h +++ b/boards/remote-revb/include/periph_conf.h @@ -70,30 +70,43 @@ static const i2c_conf_t i2c_config[I2C_NUMOF] = { }; /** @} */ +/** + * @brief Pre-calculated clock divider values based on a CLOCK_CORECLOCK (32MHz) + * + * Calculated with (CPSR * (SCR + 1)) = (CLOCK_CORECLOCK / bus_freq), where + * 1 < CPSR < 255 and + * 0 < SCR < 256 + */ +static const spi_clk_conf_t spi_clk_config[] = { + { .cpsr = 10, .scr = 31 }, /* 100khz */ + { .cpsr = 2, .scr = 39 }, /* 400khz */ + { .cpsr = 2, .scr = 15 }, /* 1MHz */ + { .cpsr = 2, .scr = 2 }, /* ~4.5MHz */ + { .cpsr = 2, .scr = 1 } /* ~10.7MHz */ +}; + /** * @name SPI configuration * @{ */ -#define SPI_NUMOF 2 -#define SPI_0_EN 1 -#define SPI_1_EN 1 - -static const periph_spi_conf_t spi_config[SPI_NUMOF] = { +static const spi_conf_t spi_config[] = { { .dev = SSI0, .mosi_pin = GPIO_PB1, .miso_pin = GPIO_PB3, .sck_pin = GPIO_PB2, - .cs_pin = GPIO_PB5, + .cs_pin = GPIO_PB5 }, { .dev = SSI1, .mosi_pin = GPIO_PC5, .miso_pin = GPIO_PC6, .sck_pin = GPIO_PC4, - .cs_pin = GPIO_PA7, - }, + .cs_pin = GPIO_PA7 + } }; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h index aedcae7c999e..b4d2d2d0447b 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2015 Kaspar Schleiser * 2015 FreshTemp, LLC. - * 2014 Freie Universität Berlin + * 2014-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 @@ -16,12 +16,15 @@ * @brief Peripheral MCU configuration for the Atmel SAM L21 Xplained Pro board * * @author Thomas Eichinger - * @autor Kaspar Schleiser + * @author Kaspar Schleiser + * @author Hauke Petersen */ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif @@ -29,7 +32,7 @@ extern "C" { /** * @brief GCLK reference speed */ -#define GCLK_REF (16000000U) +#define CLOCK_CORECLOCK (16000000U) /** * @name Timer peripheral configuration @@ -71,8 +74,22 @@ extern "C" { * @name SPI configuration * @{ */ -#define SPI_NUMOF (1) -#define SPI_0_EN 1 +static const spi_conf_t spi_config[] = { + { + .dev = &(SERCOM0->SPI), + .miso_pin = GPIO_PIN(PA, 4), + .mosi_pin = GPIO_PIN(PA, 6), + .clk_pin = GPIO_PIN(PA, 7), + .miso_mux = GPIO_MUX_D, + .mosi_mux = GPIO_MUX_D, + .clk_mux = GPIO_MUX_D, + .miso_pad = SPI_PAD_MISO_0, + .mosi_pad = SPI_PAD_MOSI_2_SCK_3 + + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/samr21-xpro/include/board.h b/boards/samr21-xpro/include/board.h index 418a4f726d76..373cb35e3461 100644 --- a/boards/samr21-xpro/include/board.h +++ b/boards/samr21-xpro/include/board.h @@ -43,8 +43,8 @@ extern "C" { * * {spi bus, spi speed, cs pin, int pin, reset pin, sleep pin} */ -#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_0, \ - .spi_speed = SPI_SPEED_5MHZ, \ +#define AT86RF2XX_PARAMS_BOARD {.spi = SPI_DEV(0), \ + .spi_clk = SPI_CLK_5MHZ, \ .cs_pin = GPIO_PIN(PB, 31), \ .int_pin = GPIO_PIN(PB, 0), \ .sleep_pin = GPIO_PIN(PA, 20), \ diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 9834707849c3..29f47cd2cd1f 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -168,37 +168,32 @@ static const pwm_conf_t pwm_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (2) -#define SPI_0_EN 1 -#define SPI_1_EN 1 - -/* SPI0 */ -#define SPI_0_DEV SERCOM4->SPI -#define SPI_IRQ_0 SERCOM4_IRQn -#define SPI_0_GCLK_ID SERCOM4_GCLK_ID_CORE -/* SPI 0 pin configuration */ -#define SPI_0_SCLK GPIO_PIN(PC, 18) -#define SPI_0_SCLK_MUX GPIO_MUX_F -#define SPI_0_MISO GPIO_PIN(PC, 19) -#define SPI_0_MISO_MUX GPIO_MUX_F -#define SPI_0_MISO_PAD SPI_PAD_MISO_0 -#define SPI_0_MOSI GPIO_PIN(PB, 30) -#define SPI_0_MOSI_MUX GPIO_MUX_F -#define SPI_0_MOSI_PAD SPI_PAD_MOSI_2_SCK_3 - -/* SPI1 */ -#define SPI_1_DEV SERCOM5->SPI -#define SPI_IRQ_1 SERCOM5_IRQn -#define SPI_1_GCLK_ID SERCOM5_GCLK_ID_CORE -/* SPI 1 pin configuration */ -#define SPI_1_SCLK GPIO_PIN(PB, 23) -#define SPI_1_SCLK_MUX GPIO_MUX_D -#define SPI_1_MISO GPIO_PIN(PB, 02) -#define SPI_1_MISO_MUX GPIO_MUX_D -#define SPI_1_MISO_PAD SPI_PAD_MISO_0 -#define SPI_1_MOSI GPIO_PIN(PB, 22) -#define SPI_1_MOSI_MUX GPIO_MUX_D -#define SPI_1_MOSI_PAD SPI_PAD_MOSI_2_SCK_3 +static const spi_conf_t spi_config[] = { + { + .dev = &SERCOM4->SPI, + .miso_pin = GPIO_PIN(PC, 19), + .mosi_pin = GPIO_PIN(PB, 30), + .clk_pin = GPIO_PIN(PC, 18), + .miso_mux = GPIO_MUX_F, + .mosi_mux = GPIO_MUX_F, + .clk_mux = GPIO_MUX_F, + .miso_pad = SPI_PAD_MISO_0, + .mosi_pad = SPI_PAD_MOSI_2_SCK_3 + }, + { + .dev = &SERCOM5->SPI, + .miso_pin = GPIO_PIN(PB, 2), + .mosi_pin = GPIO_PIN(PB, 22), + .clk_pin = GPIO_PIN(PB, 23), + .miso_mux = GPIO_MUX_D, + .mosi_mux = GPIO_MUX_D, + .clk_mux = GPIO_MUX_D, + .miso_pad = SPI_PAD_MISO_0, + .mosi_pad = SPI_PAD_MOSI_2_SCK_3 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/sodaq-autonomo/include/periph_conf.h b/boards/sodaq-autonomo/include/periph_conf.h index a5793881e1d6..456196ef0d5a 100644 --- a/boards/sodaq-autonomo/include/periph_conf.h +++ b/boards/sodaq-autonomo/include/periph_conf.h @@ -133,7 +133,7 @@ static const uart_conf_t uart_config[] = { .mux = GPIO_MUX_C, .rx_pad = UART_PAD_RX_1, .tx_pad = UART_PAD_TX_2, - }, + } }; /* interrupt function name mapping */ @@ -184,27 +184,21 @@ static const pwm_conf_t pwm_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (1) -#define SPI_0_EN 1 -#define SPI_1_EN 0 - -/* SPI0 */ -#define SPI_0_DEV SERCOM3->SPI -#define SPI_IRQ_0 SERCOM3_IRQn -#define SPI_0_GCLK_ID SERCOM3_GCLK_ID_CORE -/* SPI 0 pin configuration */ -#define SPI_0_SCLK GPIO_PIN(PA, 21) -#define SPI_0_SCLK_MUX GPIO_MUX_D -#define SPI_0_MISO GPIO_PIN(PA, 22) -#define SPI_0_MISO_MUX GPIO_MUX_C -#define SPI_0_MISO_PAD SPI_PAD_MISO_0 -#define SPI_0_MOSI GPIO_PIN(PA, 20) -#define SPI_0_MOSI_MUX GPIO_MUX_D -#define SPI_0_MOSI_PAD SPI_PAD_MOSI_2_SCK_3 - -// How/where do we define SS? -#define SPI_0_SS GPIO_PIN(PA, 23) +static const spi_conf_t spi_config[] = { + { + .dev = &SERCOM3->SPI, + .miso_pin = GPIO_PIN(PA, 22), + .mosi_pin = GPIO_PIN(PA, 20), + .clk_pin = GPIO_PIN(PA, 21), + .miso_mux = GPIO_MUX_C, + .mosi_mux = GPIO_MUX_D, + .clk_mux = GPIO_MUX_D, + .miso_pad = SPI_PAD_MISO_0, + .mosi_pad = SPI_PAD_MOSI_2_SCK_3, + }, +}; +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/spark-core/Makefile.features b/boards/spark-core/Makefile.features index 1442fd8e7ed0..3de96ca4b345 100644 --- a/boards/spark-core/Makefile.features +++ b/boards/spark-core/Makefile.features @@ -1,6 +1,7 @@ # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart # Various other features (if any) diff --git a/boards/spark-core/include/board.h b/boards/spark-core/include/board.h index 0d46ed3e5d6b..6b9bae98d3b1 100644 --- a/boards/spark-core/include/board.h +++ b/boards/spark-core/include/board.h @@ -81,7 +81,7 @@ * @name CC3000 pin configuration * @{ */ -#define CC3000_SPI SPI_0 +#define CC3000_SPI SPI_DEV(0) #define CC3000_CS GPIO_PIN(PORT_B,12) #define CC3000_EN GPIO_PIN(PORT_B,8) #define CC3000_INT GPIO_PIN(PORT_B,11) @@ -91,7 +91,7 @@ * @name EXTFLASH pin configuration * @{ */ -#define EXTFLASH_SPI SPI_0 +#define EXTFLASH_SPI SPI_DEV(0) #define EXTFLASH GPIO_PIN(PORT_B,9) /** @} */ diff --git a/boards/spark-core/include/periph_conf.h b/boards/spark-core/include/periph_conf.h index 77697481e373..28432466354b 100644 --- a/boards/spark-core/include/periph_conf.h +++ b/boards/spark-core/include/periph_conf.h @@ -106,21 +106,42 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @brief SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (1U) -#define SPI_0_EN 1 - -/* SPI 0 device configuration */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 0 /* 1 -> SPI runs with full CPU clock, 0 -> half CPU clock */ -/* SPI 0 pin configuration */ -#define SPI_0_CLK_PIN GPIO_PIN(PORT_B,15) -#define SPI_0_MOSI_PIN GPIO_PIN(PORT_B,17) -#define SPI_0_MISO_PIN GPIO_PIN(PORT_B,16) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_B, 17), + .miso_pin = GPIO_PIN(PORT_B, 16), + .sclk_pin = GPIO_PIN(PORT_B, 15), + .cs_pin = GPIO_UNDEF, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/stm32f0discovery/include/periph_conf.h b/boards/stm32f0discovery/include/periph_conf.h index cb2f3c72e0c4..5b277917695b 100644 --- a/boards/stm32f0discovery/include/periph_conf.h +++ b/boards/stm32f0discovery/include/periph_conf.h @@ -123,38 +123,47 @@ static const uart_conf_t uart_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_ISR isr_spi1 -/* SPI 1 pin configuration */ -#define SPI_0_PORT GPIOA -#define SPI_0_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_PIN_SCK 5 -#define SPI_0_PIN_MISO 6 -#define SPI_0_PIN_MOSI 7 -#define SPI_0_PIN_AF 0 - -/* SPI 1 device config */ -#define SPI_1_DEV SPI2 -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_IRQ SPI2_IRQn -#define SPI_1_ISR isr_spi2 -/* SPI 1 pin configuration */ -#define SPI_1_PORT GPIOB -#define SPI_1_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOBEN)) -#define SPI_1_PIN_SCK 13 -#define SPI_1_PIN_MISO 14 -#define SPI_1_PIN_MOSI 15 -#define SPI_1_PIN_AF 0 +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + }, + { /* for APB2 @ 48000000Hz */ + 7, /* -> 187500Hz */ + 6, /* -> 375000Hz */ + 5, /* -> 750000Hz */ + 2, /* -> 6000000Hz */ + 1 /* -> 12000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF0, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF0, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ #ifdef __cplusplus diff --git a/boards/stm32f3discovery/include/periph_conf.h b/boards/stm32f3discovery/include/periph_conf.h index fda093ae63c2..cf658a87e9ba 100644 --- a/boards/stm32f3discovery/include/periph_conf.h +++ b/boards/stm32f3discovery/include/periph_conf.h @@ -153,50 +153,47 @@ static const pwm_conf_t pwm_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOAEN)) - -/* SPI 1 device config */ -#define SPI_1_DEV SPI3 -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI3EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI3EN)) -#define SPI_1_IRQ SPI3_IRQn -#define SPI_1_IRQ_HANDLER isr_spi3 -/* SPI 1 pin configuration */ -#define SPI_1_SCK_PORT GPIOC -#define SPI_1_SCK_PIN 10 -#define SPI_1_SCK_AF 6 -#define SPI_1_SCK_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN)) -#define SPI_1_MISO_PORT GPIOC -#define SPI_1_MISO_PIN 11 -#define SPI_1_MISO_AF 6 -#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN)) -#define SPI_1_MOSI_PORT GPIOC -#define SPI_1_MOSI_PIN 12 -#define SPI_1_MOSI_AF 6 -#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB, RCC_AHBENR_GPIOCEN)) +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 36000000Hz */ + 7, /* -> 140625Hz */ + 6, /* -> 281250Hz */ + 4, /* -> 1125000Hz */ + 2, /* -> 4500000Hz */ + 1 /* -> 9000000Hz */ + }, + { /* for APB2 @ 72000000Hz */ + 7, /* -> 281250Hz */ + 7, /* -> 281250Hz */ + 5, /* -> 1125000Hz */ + 3, /* -> 4500000Hz */ + 2 /* -> 9000000Hz */ + } +}; + +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_UNDEF, + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI3, + .mosi_pin = GPIO_PIN(PORT_C, 12), + .miso_pin = GPIO_PIN(PORT_C, 11), + .sclk_pin = GPIO_PIN(PORT_C, 10), + .cs_pin = GPIO_PIN(PORT_A, 15), + .af = GPIO_AF6, + .rccmask = RCC_APB1ENR_SPI3EN, + .apbbus = APB1 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/stm32f4discovery/include/periph_conf.h b/boards/stm32f4discovery/include/periph_conf.h index 0263c03ee1c9..a41819bc54c6 100644 --- a/boards/stm32f4discovery/include/periph_conf.h +++ b/boards/stm32f4discovery/include/periph_conf.h @@ -182,55 +182,53 @@ static const pwm_conf_t pwm_config[] = { /** @} */ /** - * @name SPI configuration + * @brief SPI configuration + * + * @note The spi_divtable is auto-generated from + * `cpu/stm32_common/dist/spi_divtable/spi_divtable.c` * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 +static const uint8_t spi_divtable[2][5] = { + { /* for APB1 @ 42000000Hz */ + 7, /* -> 164062Hz */ + 6, /* -> 328125Hz */ + 4, /* -> 1312500Hz */ + 2, /* -> 5250000Hz */ + 1 /* -> 10500000Hz */ + }, + { /* for APB2 @ 84000000Hz */ + 7, /* -> 328125Hz */ + 7, /* -> 328125Hz */ + 5, /* -> 1312500Hz */ + 3, /* -> 5250000Hz */ + 2 /* -> 10500000Hz */ + } +}; -/* SPI 0 device config */ -#define SPI_0_DEV SPI1 -#define SPI_0_CLKEN() (periph_clk_en(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_CLKDIS() (periph_clk_dis(APB2, RCC_APB2ENR_SPI1EN)) -#define SPI_0_BUS_DIV 1 /* 1 -> SPI runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_0_IRQ SPI1_IRQn -#define SPI_0_IRQ_HANDLER isr_spi1 -/* SPI 0 pin configuration */ -#define SPI_0_SCK_PORT GPIOA -#define SPI_0_SCK_PIN 5 -#define SPI_0_SCK_AF 5 -#define SPI_0_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MISO_PORT GPIOA -#define SPI_0_MISO_PIN 6 -#define SPI_0_MISO_AF 5 -#define SPI_0_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) -#define SPI_0_MOSI_PORT GPIOA -#define SPI_0_MOSI_PIN 7 -#define SPI_0_MOSI_AF 5 -#define SPI_0_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOAEN)) +static const spi_conf_t spi_config[] = { + { + .dev = SPI1, + .mosi_pin = GPIO_PIN(PORT_A, 7), + .miso_pin = GPIO_PIN(PORT_A, 6), + .sclk_pin = GPIO_PIN(PORT_A, 5), + .cs_pin = GPIO_PIN(PORT_A, 4), + .af = GPIO_AF5, + .rccmask = RCC_APB2ENR_SPI1EN, + .apbbus = APB2 + }, + { + .dev = SPI2, + .mosi_pin = GPIO_PIN(PORT_B, 15), + .miso_pin = GPIO_PIN(PORT_B, 14), + .sclk_pin = GPIO_PIN(PORT_B, 13), + .cs_pin = GPIO_PIN(PORT_B, 12), + .af = GPIO_AF5, + .rccmask = RCC_APB1ENR_SPI2EN, + .apbbus = APB1 + } +}; -/* SPI 1 device config */ -#define SPI_1_DEV SPI2 -#define SPI_1_CLKEN() (periph_clk_en(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_CLKDIS() (periph_clk_dis(APB1, RCC_APB1ENR_SPI2EN)) -#define SPI_1_BUS_DIV 0 /* 1 -> SPI runs with half CPU clock, 0 -> quarter CPU clock */ -#define SPI_1_IRQ SPI2_IRQn -#define SPI_1_IRQ_HANDLER isr_spi2 -/* SPI 1 pin configuration */ -#define SPI_1_SCK_PORT GPIOB -#define SPI_1_SCK_PIN 13 -#define SPI_1_SCK_AF 5 -#define SPI_1_SCK_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN)) -#define SPI_1_MISO_PORT GPIOB -#define SPI_1_MISO_PIN 14 -#define SPI_1_MISO_AF 5 -#define SPI_1_MISO_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN)) -#define SPI_1_MOSI_PORT GPIOB -#define SPI_1_MOSI_PIN 15 -#define SPI_1_MOSI_AF 5 -#define SPI_1_MOSI_PORT_CLKEN() (periph_clk_en(AHB1, RCC_AHB1ENR_GPIOBEN)) +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/telosb/include/board.h b/boards/telosb/include/board.h index b84ffc2ab8c8..4e700d9779e0 100644 --- a/boards/telosb/include/board.h +++ b/boards/telosb/include/board.h @@ -102,8 +102,8 @@ extern "C" { /** * @brief Definition of the interface to the CC2420 radio */ -#define CC2420_PARAMS_BOARD {.spi = SPI_0, \ - .spi_clk = SPI_SPEED_1MHZ , \ +#define CC2420_PARAMS_BOARD {.spi = SPI_DEV(0), \ + .spi_clk = SPI_CLK_1MHZ , \ .pin_cs = GPIO_PIN(P4, 2), \ .pin_fifo = GPIO_PIN(P1, 3), \ .pin_fifop = GPIO_PIN(P1, 0), \ diff --git a/boards/telosb/include/periph_conf.h b/boards/telosb/include/periph_conf.h index d684542de133..e86752e6a3b1 100644 --- a/boards/telosb/include/periph_conf.h +++ b/boards/telosb/include/periph_conf.h @@ -75,7 +75,7 @@ extern "C" { #define SPI_0_EN (1U) /* SPI configuration */ -#define SPI_DEV (USART_0) +#define SPI_BASE (USART_0) #define SPI_IE (SFR->IE1) #define SPI_IF (SFR->IFG1) #define SPI_IE_RX_BIT (1 << 6) diff --git a/boards/udoo/include/periph_conf.h b/boards/udoo/include/periph_conf.h index 1514e2d14389..d9a729ece450 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/boards/weio/include/periph_conf.h b/boards/weio/include/periph_conf.h index 8eff676a5f52..597ceee93a41 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/boards/wsn430-common/include/periph_conf.h b/boards/wsn430-common/include/periph_conf.h index 80aed6f41c70..0ad41ec7a913 100644 --- a/boards/wsn430-common/include/periph_conf.h +++ b/boards/wsn430-common/include/periph_conf.h @@ -75,7 +75,7 @@ extern "C" { #define SPI_0_EN (1U) /* SPI configuration */ -#define SPI_DEV (USART_0) +#define SPI_BASE (USART_0) #define SPI_IE (SFR->IE1) #define SPI_IF (SFR->IFG1) #define SPI_IE_RX_BIT (1 << 6) diff --git a/boards/wsn430-v1_3b/Makefile.features b/boards/wsn430-v1_3b/Makefile.features index 8c46a99149b8..c3dad712131c 100644 --- a/boards/wsn430-v1_3b/Makefile.features +++ b/boards/wsn430-v1_3b/Makefile.features @@ -1,6 +1,7 @@ # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart # Various other features (if any) diff --git a/boards/wsn430-v1_4/Makefile.features b/boards/wsn430-v1_4/Makefile.features index 8c46a99149b8..c3dad712131c 100644 --- a/boards/wsn430-v1_4/Makefile.features +++ b/boards/wsn430-v1_4/Makefile.features @@ -1,6 +1,7 @@ # Put defined MCU peripherals here (in alphabetical order) FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_uart # Various other features (if any) diff --git a/boards/yunjia-nrf51822/include/periph_conf.h b/boards/yunjia-nrf51822/include/periph_conf.h index 2e67cc9b36e5..ae07c27b1b59 100644 --- a/boards/yunjia-nrf51822/include/periph_conf.h +++ b/boards/yunjia-nrf51822/include/periph_conf.h @@ -81,22 +81,22 @@ static const timer_conf_t timer_config[] = { * @name SPI configuration * @{ */ -#define SPI_NUMOF (2U) -#define SPI_0_EN 1 -#define SPI_1_EN 1 -#define SPI_IRQ_PRIO 1 - -/* SPI_0 device configuration */ -#define SPI_0_DEV NRF_SPI0 -#define SPI_0_PIN_MOSI 17 -#define SPI_0_PIN_MISO 18 -#define SPI_0_PIN_SCK 19 - -/* SPI_1 device configuration */ -#define SPI_1_DEV NRF_SPI1 -#define SPI_1_PIN_MOSI 20 -#define SPI_1_PIN_MISO 21 -#define SPI_1_PIN_SCK 22 +static const spi_conf_t spi_config[] = { + { + .dev = NRF_SPI0, + .sclk = 19, + .mosi = 17, + .miso = 18 + }, + { + .dev = NRF_SPI1, + .sclk = 22, + .mosi = 20, + .miso = 21 + } +}; + +#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0])) /** @} */ /** diff --git a/boards/z1/include/board.h b/boards/z1/include/board.h index d3c1bc799341..1646253bf387 100644 --- a/boards/z1/include/board.h +++ b/boards/z1/include/board.h @@ -110,8 +110,8 @@ extern "C" { /** * @brief Definition of the interface to the CC2420 radio */ -#define CC2420_PARAMS_BOARD {.spi = SPI_0, \ - .spi_clk = SPI_SPEED_5MHZ, \ +#define CC2420_PARAMS_BOARD {.spi = SPI_DEV(0), \ + .spi_clk = SPI_CLK_5MHZ, \ .pin_cs = GPIO_PIN(P3, 0), \ .pin_fifo = GPIO_PIN(P1, 3), \ .pin_fifop = GPIO_PIN(P1, 2), \ diff --git a/boards/z1/include/periph_conf.h b/boards/z1/include/periph_conf.h index 3196da8df627..a0261978d571 100644 --- a/boards/z1/include/periph_conf.h +++ b/boards/z1/include/periph_conf.h @@ -76,7 +76,7 @@ extern "C" { /* SPI configuration */ #define SPI_USE_USCI -#define SPI_DEV (USCI_0_B_SPI) +#define SPI_BASE (USCI_0_B_SPI) #define SPI_IE (SFR->IE2) #define SPI_IF (SFR->IFG2) #define SPI_IE_RX_BIT (1 << 2) diff --git a/cpu/atmega1281/cpu.c b/cpu/atmega1281/cpu.c index 0159ec5b8c55..2d184cf544db 100644 --- a/cpu/atmega1281/cpu.c +++ b/cpu/atmega1281/cpu.c @@ -18,12 +18,13 @@ */ #include "cpu.h" +#include "periph/init.h" /** * @brief Initialize the CPU, set IRQ priorities */ void cpu_init(void) { - /* Right now we need to do nothing here */ - ; + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/atmega2560/cpu.c b/cpu/atmega2560/cpu.c index e79c67dc6b08..8ea4e28b5f0f 100644 --- a/cpu/atmega2560/cpu.c +++ b/cpu/atmega2560/cpu.c @@ -18,12 +18,13 @@ */ #include "cpu.h" +#include "periph/init.h" /** * @brief Initialize the CPU, set IRQ priorities */ void cpu_init(void) { - /* Right now we need to do nothing here */ - ; + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/atmega328p/cpu.c b/cpu/atmega328p/cpu.c index 3de168ab4f36..ed865bd42a56 100644 --- a/cpu/atmega328p/cpu.c +++ b/cpu/atmega328p/cpu.c @@ -18,12 +18,13 @@ */ #include "cpu.h" +#include "periph/init.h" /** * @brief Initialize the CPU, set IRQ priorities */ void cpu_init(void) { - /* Right now we need to do nothing here */ - ; + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/atmega_common/include/periph_cpu_common.h b/cpu/atmega_common/include/periph_cpu_common.h index 62d3e200d26d..c355a843ccb6 100644 --- a/cpu/atmega_common/include/periph_cpu_common.h +++ b/cpu/atmega_common/include/periph_cpu_common.h @@ -32,6 +32,16 @@ extern "C" { */ #define GPIO_PIN(x, y) ((x << 4) | y) +/** + * @brief Use some common SPI functions + * @{ + */ +#define PERIPH_SPI_NEEDS_INIT_CS +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE +#define PERIPH_SPI_NEEDS_TRANSFER_REG +#define PERIPH_SPI_NEEDS_TRANSFER_REGS +/** @} */ + /** * @brief SPI mode select macro * @@ -47,13 +57,13 @@ extern "C" { * correct configuration there * @{ */ -#define HAVE_SPI_CONF_T +#define HAVE_SPI_MODE_T typedef enum { - SPI_CONF_FIRST_RISING = SPI_MODE_SEL(0, 0), /**< mode 0 */ - SPI_CONF_SECOND_RISING = SPI_MODE_SEL(0, 1), /**< mode 1 */ - SPI_CONF_FIRST_FALLING = SPI_MODE_SEL(1, 0), /**< mode 2 */ - SPI_CONF_SECOND_FALLING = SPI_MODE_SEL(1, 1) /**< mode 3 */ -} spi_conf_t; + SPI_MODE_0 = SPI_MODE_SEL(0, 0), /**< mode 0 */ + SPI_MODE_1 = SPI_MODE_SEL(0, 1), /**< mode 1 */ + SPI_MODE_2 = SPI_MODE_SEL(1, 0), /**< mode 2 */ + SPI_MODE_3 = SPI_MODE_SEL(1, 1) /**< mode 3 */ +} spi_mode_t; /** @} */ /** @@ -62,7 +72,7 @@ typedef enum { * We encode the speed in bits 2, 1, and 0, where bit0 and bit1 hold the SPCR * prescaler bits, while bit2 holds the SPI2X bit. */ -#define SPI_SPEED_SEL(s2x, pr1, pr0) ((s2x << 2) | (pr1 << 1) | pr0) +#define SPI_CLK_SEL(s2x, pr1, pr0) ((s2x << 2) | (pr1 << 1) | pr0) /** * @brief Override SPI speed values @@ -70,14 +80,14 @@ typedef enum { * We assume a master clock speed of 16MHz here. * @{ */ -#define HAVE_SPI_SPEED_T +#define HAVE_SPI_CLK_T typedef enum { - SPI_SPEED_100KHZ = SPI_SPEED_SEL(0, 1, 1), /**< 16/128 -> 125KHz */ - SPI_SPEED_400KHZ = SPI_SPEED_SEL(1, 1, 0), /**< 16/32 -> 500KHz */ - SPI_SPEED_1MHZ = SPI_SPEED_SEL(0, 0, 1), /**< 16/16 -> 1MHz */ - SPI_SPEED_5MHZ = SPI_SPEED_SEL(0, 0, 0), /**< 16/4 -> 4MHz */ - SPI_SPEED_10MHZ = SPI_SPEED_SEL(1, 0, 0) /**< 16/2 -> 8MHz */ -} spi_speed_t; + SPI_CLK_100KHZ = SPI_CLK_SEL(0, 1, 1), /**< 16/128 -> 125KHz */ + SPI_CLK_400KHZ = SPI_CLK_SEL(1, 1, 0), /**< 16/32 -> 500KHz */ + SPI_CLK_1MHZ = SPI_CLK_SEL(0, 0, 1), /**< 16/16 -> 1MHz */ + SPI_CLK_5MHZ = SPI_CLK_SEL(0, 0, 0), /**< 16/4 -> 4MHz */ + SPI_CLK_10MHZ = SPI_CLK_SEL(1, 0, 0) /**< 16/2 -> 8MHz */ +} spi_clk_t; /** @} */ #ifdef __cplusplus diff --git a/cpu/atmega_common/periph/spi.c b/cpu/atmega_common/periph/spi.c index 7d1338ae6ec5..9464f68ac9a7 100644 --- a/cpu/atmega_common/periph/spi.c +++ b/cpu/atmega_common/periph/spi.c @@ -22,31 +22,30 @@ #include "cpu.h" #include "mutex.h" +#include "assert.h" #include "periph/spi.h" -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - /** * @brief Extract BR0, BR1 and SPI2X bits from speed value * @{ */ -#define SPEED_MASK (0x3) +#define CLK_MASK (0x3) #define S2X_SHIFT (2) /** @} */ static mutex_t lock = MUTEX_INIT; -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +void spi_init(spi_t bus) +{ + assert(bus == 0); + /* power off the SPI peripheral */ + MEGA_PRR |= (1 << PRSPI); + /* trigger the pin configuration */ + spi_init_pins(bus);; +} + +void spi_init_pins(spi_t bus) { - DEBUG("spi.c: conf = %d, speed = %d\n", conf, speed); - /* make sure device is valid (there is only one...) */ - if (dev != 0) { - return -1; - } /* the pin configuration for this CPU is fixed: * - PB3: MISO (configure as input - done automatically) @@ -59,93 +58,59 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) * select externally for now) */ DDRB |= ((1 << DDB2) | (1 << DDB1) | (1 << DDB0)); +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + (void)cs; - /* make sure the SPI is not powered off */ + /* lock the bus and power on the SPI peripheral */ + mutex_lock(&lock); MEGA_PRR &= ~(1 << PRSPI); /* configure as master, with given mode and clock */ - SPSR = (speed >> S2X_SHIFT); - SPCR = ((1 << SPE) | (1 << MSTR) | conf | (speed & SPEED_MASK)); + SPSR = (clk >> S2X_SHIFT); + SPCR = ((1 << SPE) | (1 << MSTR) | mode | (clk & CLK_MASK)); + SPCR |= (1 << SPE); - /* clear interrupt flag by reading SPSR */ + /* clear interrupt flag by reading SPSR and data register by reading SPDR */ (void)SPSR; - - /* clear data register */ (void)SPDR; - return 0; -} - -int spi_acquire(spi_t dev) -{ - mutex_lock(&lock); - return 0; + return SPI_OK; } -int spi_release(spi_t dev) +void spi_release(spi_t bus) { + /* power off and release the bus */ + SPCR &= ~(1 << SPE); + MEGA_PRR |= (1 << PRSPI); mutex_unlock(&lock); - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) -{ - (void) dev; - (void) conf; - (void) cb; - - /* not implemented */ - return -1; } -void spi_transmission_begin(spi_t dev, char reset_val) +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - (void)dev; - (void)reset_val; + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; - /* not implemented */ -} + assert(out_buf || in_buf); -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - return spi_transfer_bytes(dev, &out, in, 1); -} + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); + } -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) -{ - for (unsigned int i = 0; i < length; i++) { - char tmp = (out) ? out[i] : 0; + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; SPDR = tmp; while (!(SPSR & (1 << SPIF))) {} tmp = SPDR; - if (in) { - in[i] = tmp; + if (in_buf) { + in_buf[i] = tmp; } } - return (int)length; -} - -int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in) -{ - spi_transfer_bytes(dev, (char *)®, NULL, 1); - return spi_transfer_bytes(dev, &out, in, 1); -} - -int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length) -{ - spi_transfer_bytes(dev, (char *)®, NULL, 1); - return spi_transfer_bytes(dev, out, in, length); -} - -void spi_poweron(spi_t dev) -{ - SPCR |= (1 << SPE); -} - -void spi_poweroff(spi_t dev) -{ - SPCR &= ~(1 << SPE); + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t)cs); + } } - -#endif /* SPI_NUMOF */ diff --git a/cpu/cc2538/cpu.c b/cpu/cc2538/cpu.c index 68c7b39e9148..60bf9342bf35 100644 --- a/cpu/cc2538/cpu.c +++ b/cpu/cc2538/cpu.c @@ -20,6 +20,7 @@ #include #include "cpu.h" +#include "periph/init.h" #define BIT(n) ( 1UL << (n) ) @@ -47,6 +48,8 @@ void cpu_init(void) SYS_CTRL->I_MAP = 1; /* initialize the clock system */ cpu_clock_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/cc2538/include/cc2538_ssi.h b/cpu/cc2538/include/cc2538_ssi.h index 2dc08cff02e4..5fbdc004dbc7 100644 --- a/cpu/cc2538/include/cc2538_ssi.h +++ b/cpu/cc2538/include/cc2538_ssi.h @@ -77,6 +77,46 @@ typedef struct { #define SSI0 ( (cc2538_ssi_t*)0x40008000 ) /**< SSI0 Instance */ #define SSI1 ( (cc2538_ssi_t*)0x40009000 ) /**< SSI1 Instance */ +/** + * @brief Define CR0 register bitfields + * @{ + */ +#define SSI_CR0_DSS(x) ((x - 1) << 0) +#define SSI_CR0_SPO (1 << 6) +#define SSI_CR0_SPH (1 << 7) +/** @} */ + +/** + * @brief Define CR1 register bitfields + * @{ + */ +#define SSI_CR1_LBM (1 << 0) +#define SSI_CR1_SSE (1 << 1) +#define SSI_CR1_MS (1 << 2) +#define SSI_CR1_SOD (1 << 3) +/** @} */ + +/** + * @brief Define SR register bitfields + * @{ + */ +#define SSI_SR_TFE (1 << 0) +#define SSI_SR_TNF (1 << 1) +#define SSI_SR_RNE (1 << 2) +#define SSI_SR_RFF (1 << 3) +#define SSI_SR_BSY (1 << 4) +/** @} */ + +/** + * @brief Define CC register bitfields + * @{ + */ +#define SSI_SS_PIOSC (1 << 0) +#define SSI_SS_DSEN (1 << 2) +#define SSI_SS_SYSDIV (0) +#define SSI_SS_IODIV (SSI_SS_PIOSC) +/** @} */ + #ifdef __cplusplus } /* end extern "C" */ #endif diff --git a/cpu/cc2538/include/cpu_conf.h b/cpu/cc2538/include/cpu_conf.h index 8c7695d46ec3..7376a9024132 100644 --- a/cpu/cc2538/include/cpu_conf.h +++ b/cpu/cc2538/include/cpu_conf.h @@ -26,6 +26,7 @@ #include "cc2538_gptimer.h" #include "cc2538_ioc.h" #include "cc2538_soc_adc.h" +#include "cc2538_ssi.h" #include "cc2538_rfcore.h" #include "cc2538_sys_ctrl.h" diff --git a/cpu/cc2538/include/periph_cpu.h b/cpu/cc2538/include/periph_cpu.h index 78f1194d2ac2..2fbe199bbb8c 100644 --- a/cpu/cc2538/include/periph_cpu.h +++ b/cpu/cc2538/include/periph_cpu.h @@ -21,9 +21,7 @@ #include -#include "cc2538_gptimer.h" -#include "cc2538_ssi.h" -#include "cc2538_gpio.h" +#include "cpu.h" #ifdef __cplusplus extern "C" { @@ -50,10 +48,25 @@ typedef uint32_t gpio_t; */ #define GPIO_PIN(port, pin) (gpio_t)(((uint32_t)GPIO_A + (port << 12)) | pin) +/** + * @brief Define a custom GPIO_UNDEF value + */ +#define GPIO_UNDEF 99 + +/** + * @brief I2C configuration options + */ +typedef struct { + gpio_t scl_pin; /**< pin used for SCL */ + gpio_t sda_pin; /**< pin used for SDA */ +} i2c_conf_t; + /** * @brief declare needed generic SPI functions * @{ */ +#define PERIPH_SPI_NEEDS_INIT_CS +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE #define PERIPH_SPI_NEEDS_TRANSFER_REG #define PERIPH_SPI_NEEDS_TRANSFER_REGS /** @} */ @@ -74,12 +87,39 @@ typedef enum { /** @} */ /** - * @brief I2C configuration options + * @brief Override SPI mode settings + * @{ + */ +#define HAVE_SPI_MODE_T +typedef enum { + SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = (SSI_CR0_SPH), /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = (SSI_CR0_SPO), /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = (SSI_CR0_SPO | SSI_CR0_SPH) /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +/** @ */ + +/** + * @brief Override SPI clock settings + * @{ + */ +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = 0, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ = 1, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ = 2, /**< drive the SPI bus with 1MHz */ + SPI_CLK_5MHZ = 3, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ = 4 /**< drive the SPI bus with 10MHz */ +} spi_clk_t; +/** @} */ + +/** + * @brief Datafields for static SPI clock configuration values */ typedef struct { - gpio_t scl_pin; /**< pin used for SCL */ - gpio_t sda_pin; /**< pin used for SDA */ -} i2c_conf_t; + uint8_t cpsr; /**< CPSR clock divider */ + uint8_t scr; /**< SCR clock divider */ +} spi_clk_conf_t; /** * @brief SPI configuration data structure @@ -91,7 +131,7 @@ typedef struct { gpio_t miso_pin; /**< pin used for MISO */ gpio_t sck_pin; /**< pin used for SCK */ gpio_t cs_pin; /**< pin used for CS */ -} periph_spi_conf_t; +} spi_conf_t; /** @} */ /** diff --git a/cpu/cc2538/periph/spi.c b/cpu/cc2538/periph/spi.c index 75dd2cba50a1..8a3a3add9a47 100644 --- a/cpu/cc2538/periph/spi.c +++ b/cpu/cc2538/periph/spi.c @@ -1,327 +1,175 @@ /* * Copyright (C) 2015 Loci Controls Inc. + * 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. */ /** - * @addtogroup driver_periph + * @addtogroup cpu_cc2538 * @{ * * @file * @brief Low-level SPI driver implementation * * @author Ian Martin + * @author Hauke Petersen * * @} */ -#include -#include - -#include "cc2538_ssi.h" - #include "cpu.h" #include "mutex.h" +#include "assert.h" #include "periph/spi.h" -#include "periph_conf.h" - -/* guard file in case no SPI device is defined */ -#if SPI_NUMOF - -/* clock sources for the SSI_CC register */ -#define CS_SYS_DIV 0 -#define CS_IO_DIV 1 - -#define SSI0_MASK (1 << 0) -#define SSI1_MASK (1 << 1) - -#ifndef SPI_DATA_BITS_NUMOF -#define SPI_DATA_BITS_NUMOF 8 -#endif - -#define spin_until(condition) while (!(condition)) thread_yield() /** - * @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[SPI_NUMOF] = {MUTEX_INIT}; +static mutex_t locks[SPI_NUMOF]; -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +static inline cc2538_ssi_t *dev(spi_t bus) { - cc2538_ssi_t* ssi = spi_config[dev].dev; - - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - - /* power on the SPI device */ - spi_poweron(dev); - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /* Disable the SSI and configure it for SPI master mode */ - ssi->CR1 = 0; - - /* 3. Configure the SSI clock source */ - ssi->CC = CS_SYS_DIV; - - /* 4. Configure the clock prescale divisor by writing the SSI_CPSR register. - * frequency of the SSIClk is defined by: SSIClk = SysClk / (CPSDVSR x (1 + SCR)) - */ - - const int32_t speed_lut[] = { - [SPI_SPEED_100KHZ] = 100000 /* Hz */, - [SPI_SPEED_400KHZ] = 400000 /* Hz */, - [SPI_SPEED_1MHZ ] = 1000000 /* Hz */, - [SPI_SPEED_5MHZ ] = 5000000 /* Hz */, - [SPI_SPEED_10MHZ ] = 10000000 /* Hz */, - }; - - int32_t SysClk = sys_clock_freq(); - int32_t f_desired = speed_lut[speed]; - int32_t f_actual; - int32_t err; - int32_t best_err = INT32_MAX; - int32_t div1; - int32_t div2; - int32_t best_div1 = 2; - int32_t best_div2 = 1; - - /* System clock is first divided by CPSDVSR, then by SCR */ - for (div1 = 2; div1 <= 254; div1++) { - div2 = SysClk; - int32_t denom = div1 * f_desired; - div2 += denom / 2; - div2 /= denom; - - if (div2 < 1) { - div2 = 1; - } - else if (div2 > 256) { - div2 = 256; - } - - f_actual = SysClk / (div1 * div2); - err = f_actual - f_desired; - if (err < 0) { - err = -err; - } - if (err <= best_err) { - best_div1 = div1; - best_div2 = div2; - best_err = err; - } - } - - ssi->CPSR = best_div1; /* CPSDVSR */ - ssi->CR0bits.SCR = best_div2 - 1; /* Serial clock rate (SCR) */ - - switch (conf) { - case SPI_CONF_FIRST_RISING: - ssi->CR0bits.SPO = 0; - ssi->CR0bits.SPH = 0; - break; - - case SPI_CONF_SECOND_RISING: - ssi->CR0bits.SPO = 0; - ssi->CR0bits.SPH = 1; - break; - - case SPI_CONF_FIRST_FALLING: - ssi->CR0bits.SPO = 1; - ssi->CR0bits.SPH = 0; - break; - - case SPI_CONF_SECOND_FALLING: - ssi->CR0bits.SPO = 1; - ssi->CR0bits.SPH = 1; - break; - } - - ssi->CR0bits.FRF = 0; /* SPI protocol mode */ - ssi->CR0bits.DSS = SPI_DATA_BITS_NUMOF - 1; /* The data size */ - - ssi->CR1bits.SSE = 1; + return spi_config[bus].dev; +} - return 0; +static inline void poweron(spi_t bus) +{ + SYS_CTRL_RCGCSSI |= (1 << bus); + SYS_CTRL_SCGCSSI |= (1 << bus); + SYS_CTRL_DCGCSSI |= (1 << bus); } -int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data)) +static inline void poweroff(spi_t bus) { - /* slave mode is not (yet) supported */ - return -1; + SYS_CTRL_RCGCSSI &= ~(1 << bus); + SYS_CTRL_SCGCSSI &= ~(1 << bus); + SYS_CTRL_DCGCSSI &= ~(1 << bus); } -int spi_conf_pins(spi_t dev) +void spi_init(spi_t bus) { - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } + assert(bus <= SPI_NUMOF); + + /* temporarily power on the device */ + poweron(bus); + /* configure device to be a master and disable SSI operation mode */ + dev(bus)->CR1 = 0; + /* configure system clock as SSI clock source */ + dev(bus)->CC = SSI_SS_IODIV; + /* and power off the bus again */ + poweroff(bus); + + /* trigger SPI pin configuration */ + spi_init_pins(bus); +} - switch ((uintptr_t)spi_config[dev].dev) { +void spi_init_pins(spi_t bus) +{ + switch ((uintptr_t)spi_config[bus].dev) { case (uintptr_t)SSI0: - IOC_PXX_SEL[spi_config[dev].mosi_pin] = SSI0_TXD; - IOC_PXX_SEL[spi_config[dev].sck_pin ] = SSI0_CLKOUT; - IOC_PXX_SEL[spi_config[dev].cs_pin ] = SSI0_FSSOUT; + IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI0_TXD; + IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI0_CLKOUT; + IOC_PXX_SEL[spi_config[bus].cs_pin ] = SSI0_FSSOUT; - IOC_SSIRXD_SSI0 = spi_config[dev].miso_pin; + IOC_SSIRXD_SSI0 = spi_config[bus].miso_pin; break; case (uintptr_t)SSI1: - IOC_PXX_SEL[spi_config[dev].mosi_pin] = SSI1_TXD; - IOC_PXX_SEL[spi_config[dev].sck_pin ] = SSI1_CLKOUT; - IOC_PXX_SEL[spi_config[dev].cs_pin ] = SSI1_FSSOUT; + IOC_PXX_SEL[spi_config[bus].mosi_pin] = SSI1_TXD; + IOC_PXX_SEL[spi_config[bus].sck_pin ] = SSI1_CLKOUT; + IOC_PXX_SEL[spi_config[bus].cs_pin ] = SSI1_FSSOUT; - IOC_SSIRXD_SSI1 = spi_config[dev].miso_pin; + IOC_SSIRXD_SSI1 = spi_config[bus].miso_pin; break; } - IOC_PXX_OVER[spi_config[dev].mosi_pin] = IOC_OVERRIDE_OE; - IOC_PXX_OVER[spi_config[dev].sck_pin ] = IOC_OVERRIDE_OE; - IOC_PXX_OVER[spi_config[dev].cs_pin ] = IOC_OVERRIDE_OE; - IOC_PXX_OVER[spi_config[dev].miso_pin] = IOC_OVERRIDE_DIS; - - gpio_hardware_control(spi_config[dev].mosi_pin); - gpio_hardware_control(spi_config[dev].miso_pin); - gpio_hardware_control(spi_config[dev].sck_pin); - gpio_hardware_control(spi_config[dev].cs_pin); + IOC_PXX_OVER[spi_config[bus].mosi_pin] = IOC_OVERRIDE_OE; + IOC_PXX_OVER[spi_config[bus].miso_pin] = IOC_OVERRIDE_DIS; + IOC_PXX_OVER[spi_config[bus].sck_pin ] = IOC_OVERRIDE_OE; + IOC_PXX_OVER[spi_config[bus].cs_pin ] = IOC_OVERRIDE_OE; - return 0; + gpio_hardware_control(spi_config[bus].mosi_pin); + gpio_hardware_control(spi_config[bus].miso_pin); + gpio_hardware_control(spi_config[bus].sck_pin); + gpio_hardware_control(spi_config[bus].cs_pin); } -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; - } - mutex_lock(&locks[dev]); - return 0; + /* lock the bus */ + mutex_lock(&locks[bus]); + /* power on device */ + poweron(bus); + /* configure SCR clock field, data-width and mode */ + dev(bus)->CR0 = 0; + dev(bus)->CPSR = (spi_clk_config[clk].cpsr); + dev(bus)->CR0 = ((spi_clk_config[clk].scr << 8) | mode | SSI_CR0_DSS(8)); + /* enable SSI device */ + dev(bus)->CR1 = SSI_CR1_SSE; + + 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 and power off device */ + dev(bus)->CR1 = 0; + poweroff(bus); + /* and release lock... */ + mutex_unlock(&locks[bus]); } -static char ssi_flush_input(cc2538_ssi_t *ssi) +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - char tmp = 0; - - while (ssi->SRbits.RNE) { - tmp = ssi->DR; - } + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; - return tmp; -} + assert(out_buf || in_buf); -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - cc2538_ssi_t* ssi = spi_config[dev].dev; - char tmp; - - ssi_flush_input(ssi); - - /* transmit byte */ - spin_until(ssi->SRbits.TNF); - ssi->DR = out; - - /* receive byte */ - spin_until(ssi->SRbits.RNE); - tmp = ssi->DR; - - if (in) { - *in = tmp; + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); } - return 1; -} - -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) -{ - cc2538_ssi_t* ssi = spi_config[dev].dev; - unsigned int tx_n = 0, rx_n = 0; - - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - - ssi_flush_input(ssi); - - /* transmit and receive bytes */ - while (tx_n < length) { - spin_until(ssi->SRbits.TNF || ssi->SRbits.RNE); - - if (ssi->SRbits.TNF) { - ssi->DR = out[tx_n]; - tx_n++; + if (!in_buf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SSI_SR_TNF)) {} + dev(bus)->DR = out_buf[i]; } - else if (ssi->SRbits.RNE) { - assert(rx_n < length); - in[rx_n] = ssi->DR; - rx_n++; + /* flush RX FIFO while busy*/ + while ((dev(bus)->SR & SSI_SR_BSY)) { + dev(bus)->DR; } } - - /* receive remaining bytes */ - while (rx_n < length) { - spin_until(ssi->SRbits.RNE); - assert(rx_n < length); - in[rx_n] = ssi->DR; - rx_n++; + else if (!out_buf) { /*TODO this case is currently untested */ + size_t in_cnt = 0; + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SSI_SR_TNF)) {} + dev(bus)->DR = 0; + if (dev(bus)->SR & SSI_SR_RNE) { + in_buf[in_cnt++] = dev(bus)->DR; + } + } + /* get remaining bytes */ + while (dev(bus)->SR & SSI_SR_RNE) { + in_buf[in_cnt++] = dev(bus)->DR; + } } - - return rx_n; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* slave mode is not (yet) supported */ -} - -void spi_poweron(spi_t dev) -{ - switch ((uintptr_t)spi_config[dev].dev) { - case (uintptr_t)SSI0: - /* enable SSI0 in all three power modes */ - SYS_CTRL_RCGCSSI |= SSI0_MASK; - SYS_CTRL_SCGCSSI |= SSI0_MASK; - SYS_CTRL_DCGCSSI |= SSI0_MASK; - break; - - case (uintptr_t)SSI1: - /* enable SSI1 in all three power modes */ - SYS_CTRL_RCGCSSI |= SSI1_MASK; - SYS_CTRL_SCGCSSI |= SSI1_MASK; - SYS_CTRL_DCGCSSI |= SSI1_MASK; - break; + else { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SSI_SR_TNF)) {} + dev(bus)->DR = out_buf[i]; + while (!(dev(bus)->SR & SSI_SR_RNE)){} + in_buf[i] = dev(bus)->DR; + } + /* wait until no more busy */ + while ((dev(bus)->SR & SSI_SR_BSY)) {} } -} - -void spi_poweroff(spi_t dev) -{ - switch ((uintptr_t)spi_config[dev].dev) { - case (uintptr_t)SSI0: - /* disable SSI0 in all three power modes */ - SYS_CTRL_RCGCSSI &= ~SSI0_MASK; - SYS_CTRL_SCGCSSI &= ~SSI0_MASK; - SYS_CTRL_DCGCSSI &= ~SSI0_MASK; - break; - case (uintptr_t)SSI1: - /* disable SSI1 in all three power modes */ - SYS_CTRL_RCGCSSI &= ~SSI1_MASK; - SYS_CTRL_SCGCSSI &= ~SSI1_MASK; - SYS_CTRL_DCGCSSI &= ~SSI1_MASK; - break; + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t)cs); } } - -#endif /* SPI_NUMOF */ diff --git a/cpu/cc26x0/cpu.c b/cpu/cc26x0/cpu.c index 2f4f55ecd21d..232bdc343ee8 100644 --- a/cpu/cc26x0/cpu.c +++ b/cpu/cc26x0/cpu.c @@ -17,8 +17,9 @@ * @} */ - #include "cpu.h" - #include "periph_conf.h" +#include "cpu.h" +#include "periph_conf.h" +#include "periph/init.h" #ifndef HF_CLOCK_SOURCE #define HF_CLOCK_SOURCE DDI_0_OSC_CTL0_SCLK_HF_SRC_SEL_RCOSC /* set 48MHz RCOSC */ @@ -42,6 +43,9 @@ void cpu_init(void) /* initialize the system clock */ cpu_clock_init(); + + /* trigger static peripheral initialization */ + periph_init(); } static void cpu_clock_init(void) diff --git a/cpu/ezr32wg/cpu.c b/cpu/ezr32wg/cpu.c index d48dc6e3464b..afa1927184f7 100644 --- a/cpu/ezr32wg/cpu.c +++ b/cpu/ezr32wg/cpu.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /** * @brief Configure clock sources and the CPU frequency @@ -59,4 +60,6 @@ void cpu_init(void) cortexm_init(); /* Initialise clock sources and generic clocks */ clk_init(); + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/k60/cpu.c b/cpu/k60/cpu.c index f25d4056ccee..327100e9b166 100644 --- a/cpu/k60/cpu.c +++ b/cpu/k60/cpu.c @@ -9,6 +9,7 @@ #include #include "cpu.h" #include "board.h" +#include "periph/init.h" /** * @ingroup cpu_k60 @@ -48,6 +49,8 @@ void cpu_init(void) cortexm_init(); /* Check that we are running on the CPU that this code was built for */ check_running_cpu_revision(); + /* trigger static peripheral initialization */ + periph_init(); } static void check_running_cpu_revision(void) diff --git a/cpu/k64f/cpu.c b/cpu/k64f/cpu.c index 567ce64e4239..cfb6583bc6eb 100644 --- a/cpu/k64f/cpu.c +++ b/cpu/k64f/cpu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "mcg.h" #include "cpu_conf.h" +#include "periph/init.h" #define SIM_CLKDIV1_60MHZ (SIM_CLKDIV1_OUTDIV1(0) | \ SIM_CLKDIV1_OUTDIV2(0) | \ @@ -40,6 +41,8 @@ void cpu_init(void) cortexm_init(); /* initialize the clock system */ cpu_clock_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/kinetis_common/Makefile.include b/cpu/kinetis_common/Makefile.include index b98008a42823..a0464ae67fe4 100644 --- a/cpu/kinetis_common/Makefile.include +++ b/cpu/kinetis_common/Makefile.include @@ -9,6 +9,7 @@ export UNDEF += $(BINDIR)/kinetis_common/fcfield.o # include kinetis common periph drivers export USEMODULE += kinetis_common_periph +export USEMODULE += periph_common #include layered power mode module USEMODULE += pm_layered diff --git a/cpu/kinetis_common/dist/calc_spi_scalers/Makefile b/cpu/kinetis_common/dist/calc_spi_scalers/Makefile new file mode 100644 index 000000000000..1ada319e2da4 --- /dev/null +++ b/cpu/kinetis_common/dist/calc_spi_scalers/Makefile @@ -0,0 +1,12 @@ +NAME = calc_spi_scalers +CC = gcc +CFLAGS = -std=c99 -Wall +SRC = $(wildcard *.c) + +.PHONY: all clean + +all: + $(CC) $(CFLAGS) -o $(NAME) $(SRC) + +clean: + rm -f $(NAME) diff --git a/cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c b/cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c new file mode 100644 index 000000000000..a80045b462b4 --- /dev/null +++ b/cpu/kinetis_common/dist/calc_spi_scalers/calc_spi_scalers.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences + * 2014 PHYTEC Messtechnik GmbH + * 2015 Eistec AB + * 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. + */ + +/** + * @brief SPI bus scaler computation + * + * This helper tool calculates the needed SPI scaler values for a given APB bus + * clock speed. The result of the computation must be placed in a board's + * periph_conf.h for quick reference by the SPI drivers. + * + * @author Peter Kietzmann + * @author Johann Fischer + * @author Joakim Nohlgård + * @author Hauke Petersen + * + * @} + */ + +#include +#include +#include + +/** + * @brief Targeted SPI bus speed values (pre-defined by RIOT) + */ +static uint32_t targets[] = { 100000, 400000, 1000000, 5000000, 10000000 }; + +/** + * @brief Helper function for finding optimal baud rate scalers. + * + * Find the prescaler and scaler settings that will yield a clock frequency + * as close as possible (but not above) the target frequency, given the module + * runs at module_clock Hz. + * + * Hardware properties (Baud rate configuration): + * Possible prescalers: 2, 3, 5, 7 + * Possible scalers: 2, 4, 6 (sic!), 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 + * + * SCK baud rate = (f_BUS/PBR) x [(1+DBR)/BR] + * + * where PBR is the prescaler, BR is the scaler, DBR is the Double BaudRate bit. + * + * @note We are not using the DBR bit because it may affect the SCK duty cycle. + * + * @param module_clock Module clock frequency (e.g. F_BUS) + * @param target_clock Desired baud rate + * @param closest_prescaler pointer where to write the optimal prescaler index. + * @param closest_scaler pointer where to write the optimal scaler index. + * + * @return The actual achieved frequency on success + * @return Less than 0 on error. + */ + +static long find_closest_baudrate_scalers(const uint32_t module_clock, const long target_clock, + uint8_t *closest_prescaler, uint8_t *closest_scaler) +{ + uint8_t i; + uint8_t k; + long freq; + static const uint8_t num_scalers = 16; + static const uint8_t num_prescalers = 4; + static const int br_scalers[16] = { + 2, 4, 6, 8, 16, 32, 64, 128, + 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 + }; + static const int br_prescalers[4] = {2, 3, 5, 7}; + + long closest_frequency = -1; + + /* Test all combinations until we arrive close to the target clock */ + for (i = 0; i < num_prescalers; ++i) { + for (k = 0; k < num_scalers; ++k) { + freq = module_clock / (br_scalers[k] * br_prescalers[i]); + + if (freq <= target_clock) { + /* Found closest lower frequency at this prescaler setting, + * compare to the best result */ + if (closest_frequency < freq) { + closest_frequency = freq; + *closest_scaler = k; + *closest_prescaler = i; + } + + break; + } + } + } + + if (closest_frequency < 0) { + /* Error, no solution found, this line is never reachable with current + * hardware settings unless a _very_ low target clock is requested. + * (scaler_max * prescaler_max) = 229376 => target_min@100MHz = 435 Hz*/ + return -1; + } + + return closest_frequency; +} + +/** + * @brief Helper function for finding optimal delay scalers. + * + * Find the prescaler and scaler settings that will yield a delay timing + * as close as possible (but not shorter than) the target delay, given the + * module runs at module_clock Hz. + * + * Hardware properties (delay configuration): + * Possible prescalers: 1, 3, 5, 7 + * Possible scalers: 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 + * + * delay = (1/f_BUS) x prescaler x scaler + * + * Because we want to do this using only integers, the target_freq parameter is + * the reciprocal of the delay time. + * + * @param module_clock Module clock frequency (e.g. F_BUS) + * @param target_freq Reciprocal (i.e. 1/t [Hz], frequency) of the desired delay time. + * @param closest_prescaler pointer where to write the optimal prescaler index. + * @param closest_scaler pointer where to write the optimal scaler index. + * + * @return The actual achieved frequency on success + * @return Less than 0 on error. + */ +static long find_closest_delay_scalers(const uint32_t module_clock, const long target_freq, + uint8_t *closest_prescaler, uint8_t *closest_scaler) +{ + uint8_t i; + uint8_t k; + long freq; + int prescaler; + int scaler; + static const uint8_t num_scalers = 16; + static const uint8_t num_prescalers = 4; + + long closest_frequency = -1; + + /* Test all combinations until we arrive close to the target clock */ + for (i = 0; i < num_prescalers; ++i) { + for (k = 0; k < num_scalers; ++k) { + prescaler = (i * 2) + 1; + scaler = (1 << (k + 1)); /* 2^(k+1) */ + freq = module_clock / (prescaler * scaler); + + if (freq <= target_freq) { + /* Found closest lower frequency at this prescaler setting, + * compare to the best result */ + if (closest_frequency < freq) { + closest_frequency = freq; + *closest_scaler = k; + *closest_prescaler = i; + } + + break; + } + } + } + + if (closest_frequency < 0) { + /* Error, no solution found, this line is never reachable with current + * hardware settings unless a _very_ low target clock is requested. + * (scaler_max * prescaler_max) = 458752 */ + return -1; + } + + return closest_frequency; +} + + +int main(int argc, char **argv) +{ + uint32_t modclk; + int i; + + if (argc != 2) { + printf("usage: %s \n", argv[0]); + return 1; + } + + modclk = (uint32_t)atoi(argv[1]); + if (modclk == 0) { + printf("error: invalid input value\n"); + return 1; + } + + printf("\nCalculating SPI clock scalers for a module clock of: %iHz\n\n", + (int)modclk); + + + puts("static const uint32_t spi_clk_config[] = {"); + + for (i = 0; i < (sizeof(targets) / sizeof(targets[0])); i++) { + uint8_t tmp, ptmp; + long res; + /* bus clock */ + res = find_closest_baudrate_scalers(modclk, targets[i], &ptmp, &tmp); + if (res < 0) { + puts("error: no applicable bus clock scalers could be found!"); + return 1; + } + puts(" ("); + printf(" SPI_CTAR_PBR(%i) | SPI_CTAR_BR(%i) | /* -> %iHz */\n", + (int)ptmp, (int)tmp, (int)res); + + /* t_csc: chip select to fist clock signal delay */ + if (find_closest_delay_scalers(modclk, targets[i], &ptmp, &tmp) < 0) { + puts("error: no applicable delay values for t_csc found\n"); + return 1; + } + printf(" SPI_CTAR_PCSSCK(%i) | SPI_CTAR_CSSCK(%i) |\n", (int)ptmp, (int)tmp); + + /* t_asc: delay after last clock signal to release of chip select */ + if (find_closest_delay_scalers(modclk, targets[i], &ptmp, &tmp) < 0) { + puts("error: no applicable delay values for t_asc found\n"); + return 1; + } + printf(" SPI_CTAR_PASC(%i) | SPI_CTAR_ASC(%i) |\n", (int)ptmp, (int)tmp); + + /* t_psc: delay between release and next assertion of chip select */ + if (find_closest_delay_scalers(modclk, targets[i], &ptmp, &tmp) < 0) { + puts("error: no applicable delay values for t_csc found\n"); + return 1; + } + printf(" SPI_CTAR_PDT(%i) | SPI_CTAR_DT(%i)\n", (int)ptmp, (int)tmp); + + if (i == (sizeof(targets) / sizeof(targets[0])) - 1) { + puts(" )"); + } + else { + puts(" ),"); + } + } + puts("};"); + + return 0; +} diff --git a/cpu/kinetis_common/include/periph_cpu.h b/cpu/kinetis_common/include/periph_cpu.h index c87c7f85815c..5be69a2800d3 100644 --- a/cpu/kinetis_common/include/periph_cpu.h +++ b/cpu/kinetis_common/include/periph_cpu.h @@ -66,6 +66,28 @@ typedef uint16_t gpio_t; */ #define PWM_CHAN_MAX (4U) +/** + * @brief Define a CPU specific SPI hardware chip select line macro + * + * We simply map the 5 hardware channels to the numbers [0-4], this still allows + * us to differentiate between GPIP_PINs and SPI_HWSC lines. + */ +#define SPI_HWCS(x) (x) + +/** + * @brief Kinetis CPUs have a maximum number of 5 hardware chip select lines + */ +#define SPI_HWCS_NUMOF (5) + +/** + * @brief This CPU makes use of the following shared SPI functions + * @{ + */ +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE +#define PERIPH_SPI_NEEDS_TRANSFER_REG +#define PERIPH_SPI_NEEDS_TRANSFER_REGS +/** @} */ + #ifndef DOXYGEN /** * @brief Override GPIO modes @@ -88,7 +110,7 @@ typedef enum { * * To combine values just aggregate them using a logical OR. */ -enum { +typedef enum { GPIO_AF_ANALOG = PORT_PCR_MUX(0), /**< use pin as analog input */ GPIO_AF_GPIO = PORT_PCR_MUX(1), /**< use pin as GPIO */ GPIO_AF_2 = PORT_PCR_MUX(2), /**< use alternate function 2 */ @@ -100,7 +122,7 @@ enum { GPIO_PCR_OD = (PORT_PCR_ODE_MASK), /**< open-drain mode */ GPIO_PCR_PD = (PORT_PCR_PE_MASK), /**< enable pull-down */ GPIO_PCR_PU = (PORT_PCR_PE_MASK | PORT_PCR_PS_MASK) /**< enable PU */ -}; +} gpio_pcr_t; #ifndef DOXYGEN /** @@ -161,6 +183,21 @@ typedef enum { /** @} */ #endif /* ndef DOXYGEN */ +#ifndef DOXYGEN +/** + * @brief Override default ADC resolution values + * @{ + */ +#define HAVE_SPI_MODE_T +typedef enum { + SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = (SPI_CTAR_CPHA_MASK), /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = (SPI_CTAR_CPOL_MASK), /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = (SPI_CTAR_CPOL_MASK | SPI_CTAR_CPHA_MASK) /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +/** @} */ +#endif /* ndef DOXYGEN */ + /** * @brief CPU specific ADC configuration */ @@ -208,15 +245,28 @@ typedef struct { */ typedef struct { FTM_Type* ftm; /**< used FTM */ - struct { /**< logical channel configuration */ + struct { gpio_t pin; /**< GPIO pin used, set to GPIO_UNDEF */ uint8_t af; /**< alternate function mapping */ uint8_t ftm_chan; /**< the actual FTM channel used */ - } chan[PWM_CHAN_MAX]; + } chan[PWM_CHAN_MAX]; /**< logical channel configuration */ uint8_t chan_numof; /**< number of actually configured channels */ uint8_t ftm_num; /**< FTM number used */ } pwm_conf_t; +/** + * @brief SPI module configuration options + */ +typedef struct { + SPI_Type *dev; /**< SPI device to use */ + gpio_t pin_miso; /**< MISO pin used */ + gpio_t pin_mosi; /**< MOSI pin used */ + gpio_t pin_clk; /**< CLK pin used */ + gpio_t pin_cs[SPI_HWCS_NUMOF]; /**< pins used for HW cs lines */ + gpio_pcr_t pcr; /**< alternate pin function values */ + uint32_t simmask; /**< bit in the SIM register */ +} spi_conf_t; + /** * @brief Possible timer module types */ @@ -227,9 +277,11 @@ enum { /** * @brief Hardware timer type-specific device macros + * @{ */ #define TIMER_PIT_DEV(x) (TIMER_DEV(0 + (x))) #define TIMER_LPTMR_DEV(x) (TIMER_DEV(PIT_NUMOF + (x))) +/** @} */ /** * @brief CPU internal function for initializing PORTs diff --git a/cpu/kinetis_common/periph/spi.c b/cpu/kinetis_common/periph/spi.c index a03b63d72b5d..a781e423befd 100644 --- a/cpu/kinetis_common/periph/spi.c +++ b/cpu/kinetis_common/periph/spi.c @@ -1,28 +1,14 @@ /* * Copyright (C) 2014 Hamburg University of Applied Sciences - * Copyright (C) 2014 PHYTEC Messtechnik GmbH - * Copyright (C) 2015 Eistec AB + * 2014 PHYTEC Messtechnik GmbH + * 2015 Eistec AB + * 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. */ -#include - -#include "board.h" -#include "cpu.h" -#include "periph/spi.h" -#include "periph_conf.h" -#include "mutex.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -#ifndef KINETIS_SPI_USE_HW_CS -#define KINETIS_SPI_USE_HW_CS 0 -#endif - /** * @ingroup cpu_kinetis_common_spi * @@ -34,1541 +20,179 @@ * @author Peter Kietzmann * @author Johann Fischer * @author Joakim Nohlgård + * @author Hauke Petersen * * @} */ -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - -#if SPI_0_EN -#ifdef SPI_0_PORT -#define SPI_0_SCK_PORT SPI_0_PORT -#define SPI_0_SOUT_PORT SPI_0_PORT -#define SPI_0_SIN_PORT SPI_0_PORT -#define SPI_0_PCS0_PORT SPI_0_PORT -#endif - -#ifdef SPI_0_PORT_CLKEN -#define SPI_0_SCK_PORT_CLKEN SPI_0_PORT_CLKEN -#define SPI_0_SOUT_PORT_CLKEN SPI_0_PORT_CLKEN -#define SPI_0_SIN_PORT_CLKEN SPI_0_PORT_CLKEN -#define SPI_0_PCS0_PORT_CLKEN SPI_0_PORT_CLKEN -#endif - -#ifdef SPI_0_AF -#define SPI_0_SCK_AF SPI_0_AF -#define SPI_0_SOUT_AF SPI_0_AF -#define SPI_0_SIN_AF SPI_0_AF -#define SPI_0_PCS0_AF SPI_0_AF -#endif - -#ifndef SPI_0_TCSC_FREQ -#define SPI_0_TCSC_FREQ (0) -#endif - -#ifndef SPI_0_TASC_FREQ -#define SPI_0_TASC_FREQ (0) -#endif - -#ifndef SPI_0_TDT_FREQ -#define SPI_0_TDT_FREQ (0) -#endif -#endif /* SPI_0_EN */ - -#if SPI_1_EN -#ifdef SPI_1_PORT -#define SPI_1_SCK_PORT SPI_1_PORT -#define SPI_1_SOUT_PORT SPI_1_PORT -#define SPI_1_SIN_PORT SPI_1_PORT -#define SPI_1_PCS0_PORT SPI_1_PORT -#endif - -#ifdef SPI_1_PORT_CLKEN -#define SPI_1_SCK_PORT_CLKEN SPI_1_PORT_CLKEN -#define SPI_1_SOUT_PORT_CLKEN SPI_1_PORT_CLKEN -#define SPI_1_SIN_PORT_CLKEN SPI_1_PORT_CLKEN -#define SPI_1_PCS0_PORT_CLKEN SPI_1_PORT_CLKEN -#endif - -#ifdef SPI_1_AF -#define SPI_1_SCK_AF SPI_1_AF -#define SPI_1_SOUT_AF SPI_1_AF -#define SPI_1_SIN_AF SPI_1_AF -#define SPI_1_PCS0_AF SPI_1_AF -#endif - -#ifndef SPI_1_TCSC_FREQ -#define SPI_1_TCSC_FREQ (0) -#endif - -#ifndef SPI_1_TASC_FREQ -#define SPI_1_TASC_FREQ (0) -#endif - -#ifndef SPI_1_TDT_FREQ -#define SPI_1_TDT_FREQ (0) -#endif -#endif /* SPI_1_EN */ - -#if SPI_2_EN -#ifdef SPI_2_PORT -#define SPI_2_SCK_PORT SPI_2_PORT -#define SPI_2_SOUT_PORT SPI_2_PORT -#define SPI_2_SIN_PORT SPI_2_PORT -#define SPI_2_PCS0_PORT SPI_2_PORT -#endif - -#ifdef SPI_2_PORT_CLKEN -#define SPI_2_SCK_PORT_CLKEN SPI_2_PORT_CLKEN -#define SPI_2_SOUT_PORT_CLKEN SPI_2_PORT_CLKEN -#define SPI_2_SIN_PORT_CLKEN SPI_2_PORT_CLKEN -#define SPI_2_PCS0_PORT_CLKEN SPI_2_PORT_CLKEN -#endif - -#ifdef SPI_2_AF -#define SPI_2_SCK_AF SPI_2_AF -#define SPI_2_SOUT_AF SPI_2_AF -#define SPI_2_SIN_AF SPI_2_AF -#define SPI_2_PCS0_AF SPI_2_AF -#endif - -#ifndef SPI_2_TCSC_FREQ -#define SPI_2_TCSC_FREQ (0) -#endif - -#ifndef SPI_2_TASC_FREQ -#define SPI_2_TASC_FREQ (0) -#endif - -#ifndef SPI_2_TDT_FREQ -#define SPI_2_TDT_FREQ (0) -#endif -#endif /* SPI_2_EN */ - -#if SPI_3_EN -#ifdef SPI_3_PORT -#define SPI_3_SCK_PORT SPI_3_PORT -#define SPI_3_SOUT_PORT SPI_3_PORT -#define SPI_3_SIN_PORT SPI_3_PORT -#define SPI_3_PCS0_PORT SPI_3_PORT -#endif - -#ifdef SPI_3_PORT_CLKEN -#define SPI_3_SCK_PORT_CLKEN SPI_3_PORT_CLKEN -#define SPI_3_SOUT_PORT_CLKEN SPI_3_PORT_CLKEN -#define SPI_3_SIN_PORT_CLKEN SPI_3_PORT_CLKEN -#define SPI_3_PCS0_PORT_CLKEN SPI_3_PORT_CLKEN -#endif - -#ifdef SPI_3_AF -#define SPI_3_SCK_AF SPI_3_AF -#define SPI_3_SOUT_AF SPI_3_AF -#define SPI_3_SIN_AF SPI_3_AF -#define SPI_3_PCS0_AF SPI_3_AF -#endif - -#ifndef SPI_3_TCSC_FREQ -#define SPI_3_TCSC_FREQ (0) -#endif - -#ifndef SPI_3_TASC_FREQ -#define SPI_3_TASC_FREQ (0) -#endif - -#ifndef SPI_3_TDT_FREQ -#define SPI_3_TDT_FREQ (0) -#endif -#endif /* SPI_3_EN */ - -#if SPI_4_EN -#ifdef SPI_4_PORT -#define SPI_4_SCK_PORT SPI_4_PORT -#define SPI_4_SOUT_PORT SPI_4_PORT -#define SPI_4_SIN_PORT SPI_4_PORT -#define SPI_4_PCS0_PORT SPI_4_PORT -#endif - -#ifdef SPI_4_PORT_CLKEN -#define SPI_4_SCK_PORT_CLKEN SPI_4_PORT_CLKEN -#define SPI_4_SOUT_PORT_CLKEN SPI_4_PORT_CLKEN -#define SPI_4_SIN_PORT_CLKEN SPI_4_PORT_CLKEN -#define SPI_4_PCS0_PORT_CLKEN SPI_4_PORT_CLKEN -#endif - -#ifdef SPI_4_AF -#define SPI_4_SCK_AF SPI_4_AF -#define SPI_4_SOUT_AF SPI_4_AF -#define SPI_4_SIN_AF SPI_4_AF -#define SPI_4_PCS0_AF SPI_4_AF -#endif - -#ifndef SPI_4_TCSC_FREQ -#define SPI_4_TCSC_FREQ (0) -#endif - -#ifndef SPI_4_TASC_FREQ -#define SPI_4_TASC_FREQ (0) -#endif - -#ifndef SPI_4_TDT_FREQ -#define SPI_4_TDT_FREQ (0) -#endif -#endif /* SPI_4_EN */ - -#if SPI_5_EN -#ifdef SPI_5_PORT -#define SPI_5_SCK_PORT SPI_5_PORT -#define SPI_5_SOUT_PORT SPI_5_PORT -#define SPI_5_SIN_PORT SPI_5_PORT -#define SPI_5_PCS0_PORT SPI_5_PORT -#endif - -#ifdef SPI_5_PORT_CLKEN -#define SPI_5_SCK_PORT_CLKEN SPI_5_PORT_CLKEN -#define SPI_5_SOUT_PORT_CLKEN SPI_5_PORT_CLKEN -#define SPI_5_SIN_PORT_CLKEN SPI_5_PORT_CLKEN -#define SPI_5_PCS0_PORT_CLKEN SPI_5_PORT_CLKEN -#endif - -#ifdef SPI_5_AF -#define SPI_5_SCK_AF SPI_5_AF -#define SPI_5_SOUT_AF SPI_5_AF -#define SPI_5_SIN_AF SPI_5_AF -#define SPI_5_PCS0_AF SPI_5_AF -#endif - -#ifndef SPI_5_TCSC_FREQ -#define SPI_5_TCSC_FREQ (0) -#endif - -#ifndef SPI_5_TASC_FREQ -#define SPI_5_TASC_FREQ (0) -#endif - -#ifndef SPI_5_TDT_FREQ -#define SPI_5_TDT_FREQ (0) -#endif -#endif /* SPI_5_EN */ - -#if SPI_6_EN -#ifdef SPI_6_PORT -#define SPI_6_SCK_PORT SPI_6_PORT -#define SPI_6_SOUT_PORT SPI_6_PORT -#define SPI_6_SIN_PORT SPI_6_PORT -#define SPI_6_PCS0_PORT SPI_6_PORT -#endif - -#ifdef SPI_6_PORT_CLKEN -#define SPI_6_SCK_PORT_CLKEN SPI_6_PORT_CLKEN -#define SPI_6_SOUT_PORT_CLKEN SPI_6_PORT_CLKEN -#define SPI_6_SIN_PORT_CLKEN SPI_6_PORT_CLKEN -#define SPI_6_PCS0_PORT_CLKEN SPI_6_PORT_CLKEN -#endif - -#ifdef SPI_6_AF -#define SPI_6_SCK_AF SPI_6_AF -#define SPI_6_SOUT_AF SPI_6_AF -#define SPI_6_SIN_AF SPI_6_AF -#define SPI_6_PCS0_AF SPI_6_AF -#endif - -#ifndef SPI_6_TCSC_FREQ -#define SPI_6_TCSC_FREQ (0) -#endif - -#ifndef SPI_6_TASC_FREQ -#define SPI_6_TASC_FREQ (0) -#endif - -#ifndef SPI_6_TDT_FREQ -#define SPI_6_TDT_FREQ (0) -#endif -#endif /* SPI_6_EN */ - -#if SPI_7_EN -#ifdef SPI_7_PORT -#define SPI_7_SCK_PORT SPI_7_PORT -#define SPI_7_SOUT_PORT SPI_7_PORT -#define SPI_7_SIN_PORT SPI_7_PORT -#define SPI_7_PCS0_PORT SPI_7_PORT -#endif - -#ifdef SPI_7_PORT_CLKEN -#define SPI_7_SCK_PORT_CLKEN SPI_7_PORT_CLKEN -#define SPI_7_SOUT_PORT_CLKEN SPI_7_PORT_CLKEN -#define SPI_7_SIN_PORT_CLKEN SPI_7_PORT_CLKEN -#define SPI_7_PCS0_PORT_CLKEN SPI_7_PORT_CLKEN -#endif - -#ifdef SPI_7_AF -#define SPI_7_SCK_AF SPI_7_AF -#define SPI_7_SOUT_AF SPI_7_AF -#define SPI_7_SIN_AF SPI_7_AF -#define SPI_7_PCS0_AF SPI_7_AF -#endif - -#ifndef SPI_7_TCSC_FREQ -#define SPI_7_TCSC_FREQ (0) -#endif - -#ifndef SPI_7_TASC_FREQ -#define SPI_7_TASC_FREQ (0) -#endif - -#ifndef SPI_7_TDT_FREQ -#define SPI_7_TDT_FREQ (0) -#endif -#endif /* SPI_7_EN */ - -#define KINETIS_CFG_SPI_IO(num) \ - spi_dev = SPI_ ## num ## _DEV;\ - module_clock = SPI_ ## num ## _FREQ;\ - tcsc_freq = SPI_ ## num ## _TCSC_FREQ;\ - tasc_freq = SPI_ ## num ## _TASC_FREQ;\ - tdt_freq = SPI_ ## num ## _TDT_FREQ;\ - ctas = SPI_ ## num ## _CTAS;\ - /* enable clocks */\ - SPI_ ## num ## _CLKEN();\ - SPI_ ## num ## _SCK_PORT_CLKEN();\ - SPI_ ## num ## _SOUT_PORT_CLKEN();\ - SPI_ ## num ## _SIN_PORT_CLKEN();\ - /* Set PORT to AF mode */\ - SPI_ ## num ## _SCK_PORT->PCR[SPI_ ## num ## _SCK_PIN] =\ - PORT_PCR_MUX(SPI_ ## num ## _SCK_AF);\ - SPI_ ## num ## _SOUT_PORT->PCR[SPI_ ## num ## _SOUT_PIN] =\ - PORT_PCR_MUX(SPI_ ## num ## _SOUT_AF);\ - SPI_ ## num ## _SIN_PORT->PCR[SPI_ ## num ## _SIN_PIN] =\ - PORT_PCR_MUX(SPI_ ## num ## _SIN_AF);\ - if (KINETIS_SPI_USE_HW_CS) {\ - SPI_ ## num ## _PCS0_PORT_CLKEN();\ - SPI_ ## num ## _PCS0_PORT->PCR[SPI_ ## num ## _PCS0_PIN] =\ - PORT_PCR_MUX(SPI_ ## num ## _PCS0_AF);\ - } - -/** - * @brief Array holding one pre-initialized mutex for each hardware SPI device - */ -/* We try to avoid adding duplicate entries with the same index by comparing the - * SPI_x_INDEX macros, the #if statements become quite long though. - * - * If not checking for multiple initializations GCC will warn about it - * but the binary still works. It does look strange in the preprocessed output, however. - * - * The warning message is: - * warning: initialized field overwritten [-Woverride-init] - * warning: (near initialization for ‘locks[0]’) [-Woverride-init] - * - * Example of preprocessed source: - * static mutex_t locks[] = { - * [0] = { 0, { ((void *)0) } }, - * [1] = { 0, { ((void *)0) } }, - * [0] = { 0, { ((void *)0) } }, // index [0] is given (the same, again) initial value. - * }; - */ +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" -static mutex_t locks[] = { -#if SPI_0_EN - [SPI_0_INDEX] = MUTEX_INIT, -#endif -#if SPI_1_EN && (SPI_1_INDEX != SPI_0_INDEX) - [SPI_1_INDEX] = MUTEX_INIT, -#endif -#if SPI_2_EN && (SPI_2_INDEX != SPI_0_INDEX) && (SPI_2_INDEX != SPI_1_INDEX) - [SPI_2_INDEX] = MUTEX_INIT, -#endif -#if SPI_3_EN && (SPI_3_INDEX != SPI_0_INDEX) && (SPI_3_INDEX != SPI_1_INDEX) \ - && (SPI_3_INDEX != SPI_2_INDEX) - [SPI_3_INDEX] = MUTEX_INIT, -#endif -#if SPI_4_EN && (SPI_4_INDEX != SPI_0_INDEX) && (SPI_4_INDEX != SPI_1_INDEX) \ - && (SPI_4_INDEX != SPI_2_INDEX) && (SPI_4_INDEX != SPI_3_INDEX) - [SPI_4_INDEX] = MUTEX_INIT, -#endif -#if SPI_5_EN && (SPI_5_INDEX != SPI_0_INDEX) && (SPI_5_INDEX != SPI_1_INDEX) \ - && (SPI_5_INDEX != SPI_2_INDEX) && (SPI_5_INDEX != SPI_3_INDEX) \ - && (SPI_5_INDEX != SPI_4_INDEX) - [SPI_5_INDEX] = MUTEX_INIT, -#endif -#if SPI_6_EN && (SPI_6_INDEX != SPI_0_INDEX) && (SPI_6_INDEX != SPI_1_INDEX) \ - && (SPI_6_INDEX != SPI_2_INDEX) && (SPI_6_INDEX != SPI_3_INDEX) \ - && (SPI_6_INDEX != SPI_4_INDEX) && (SPI_6_INDEX != SPI_5_INDEX) - [SPI_6_INDEX] = MUTEX_INIT, -#endif -#if SPI_7_EN && (SPI_7_INDEX != SPI_0_INDEX) && (SPI_7_INDEX != SPI_1_INDEX) \ - && (SPI_7_INDEX != SPI_2_INDEX) && (SPI_7_INDEX != SPI_3_INDEX) \ - && (SPI_7_INDEX != SPI_4_INDEX) && (SPI_7_INDEX != SPI_5_INDEX) \ - && (SPI_7_INDEX != SPI_6_INDEX) - [SPI_7_INDEX] = MUTEX_INIT, -#endif -}; +#define ENABLE_DEBUG (0) +#include "debug.h" /** - * @brief Array of pointers that map RIOT SPI device number to actual hardware - * module lock. - * - * Every RIOT device shares the bus lock with any other bus devices for the same - * hardware module. This allows us to let two RIOT devices point to the same - * hardware but using different CTAR registers for timing information. + * @brief We use this mask to differentiate between SPI_HWCS() and GPIO_PIN() */ -static mutex_t *locks_map[] = { -#if SPI_0_EN - [SPI_0] = &locks[SPI_0_INDEX], -#endif -#if SPI_1_EN - [SPI_1] = &locks[SPI_1_INDEX], -#endif -#if SPI_2_EN - [SPI_2] = &locks[SPI_2_INDEX], -#endif -#if SPI_3_EN - [SPI_3] = &locks[SPI_3_INDEX], -#endif -#if SPI_4_EN - [SPI_4] = &locks[SPI_4_INDEX], -#endif -#if SPI_5_EN - [SPI_5] = &locks[SPI_5_INDEX], -#endif -#if SPI_6_EN - [SPI_6] = &locks[SPI_6_INDEX], -#endif -#if SPI_7_EN - [SPI_7] = &locks[SPI_7_INDEX], -#endif -}; - -typedef struct { - char(*cb)(char data); -} spi_state_t; - -static inline void irq_handler_transfer(SPI_Type *spi, spi_t dev); - -static spi_state_t spi_config[SPI_NUMOF]; - -#define SPI_IDLE_DATA (0xff) +#define SWCS_MASK (0xfff0) /** - * @brief Helper function for finding optimal baud rate scalers. - * - * Find the prescaler and scaler settings that will yield a clock frequency - * as close as possible (but not above) the target frequency, given the module - * runs at module_clock Hz. - * - * Hardware properties (Baud rate configuration): - * Possible prescalers: 2, 3, 5, 7 - * Possible scalers: 2, 4, 6 (sic!), 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 - * - * SCK baud rate = (f_BUS/PBR) x [(1+DBR)/BR] - * - * where PBR is the prescaler, BR is the scaler, DBR is the Double BaudRate bit. - * - * @note We are not using the DBR bit because it may affect the SCK duty cycle. - * - * @param module_clock Module clock frequency (e.g. F_BUS) - * @param target_clock Desired baud rate - * @param closest_prescaler pointer where to write the optimal prescaler index. - * @param closest_scaler pointer where to write the optimal scaler index. - * - * @return The actual achieved frequency on success - * @return Less than 0 on error. + * @brief Allocation device locks */ -static long find_closest_baudrate_scalers(const uint32_t module_clock, const long target_clock, - uint8_t *closest_prescaler, uint8_t *closest_scaler) -{ - uint8_t i; - uint8_t k; - long freq; - static const uint8_t num_scalers = 16; - static const uint8_t num_prescalers = 4; - static const int br_scalers[16] = { - 2, 4, 6, 8, 16, 32, 64, 128, - 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 - }; - static const int br_prescalers[4] = {2, 3, 5, 7}; - - long closest_frequency = -1; - - /* Test all combinations until we arrive close to the target clock */ - for (i = 0; i < num_prescalers; ++i) { - for (k = 0; k < num_scalers; ++k) { - freq = module_clock / (br_scalers[k] * br_prescalers[i]); - - if (freq <= target_clock) { - /* Found closest lower frequency at this prescaler setting, - * compare to the best result */ - if (closest_frequency < freq) { - closest_frequency = freq; - *closest_scaler = k; - *closest_prescaler = i; - } - - break; - } - } - } +static mutex_t locks[SPI_NUMOF]; - if (closest_frequency < 0) { - /* Error, no solution found, this line is never reachable with current - * hardware settings unless a _very_ low target clock is requested. - * (scaler_max * prescaler_max) = 229376 => target_min@100MHz = 435 Hz*/ - return -1; - } - - return closest_frequency; -} - -/** - * @brief Helper function for finding optimal delay scalers. - * - * Find the prescaler and scaler settings that will yield a delay timing - * as close as possible (but not shorter than) the target delay, given the - * module runs at module_clock Hz. - * - * Hardware properties (delay configuration): - * Possible prescalers: 1, 3, 5, 7 - * Possible scalers: 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 - * - * delay = (1/f_BUS) x prescaler x scaler - * - * Because we want to do this using only integers, the target_freq parameter is - * the reciprocal of the delay time. - * - * @param module_clock Module clock frequency (e.g. F_BUS) - * @param target_freq Reciprocal (i.e. 1/t [Hz], frequency) of the desired delay time. - * @param closest_prescaler pointer where to write the optimal prescaler index. - * @param closest_scaler pointer where to write the optimal scaler index. - * - * @return The actual achieved frequency on success - * @return Less than 0 on error. - */ -static long find_closest_delay_scalers(const uint32_t module_clock, const long target_freq, - uint8_t *closest_prescaler, uint8_t *closest_scaler) +static inline SPI_Type *dev(spi_t bus) { - uint8_t i; - uint8_t k; - long freq; - int prescaler; - int scaler; - static const uint8_t num_scalers = 16; - static const uint8_t num_prescalers = 4; - - long closest_frequency = -1; - - /* Test all combinations until we arrive close to the target clock */ - for (i = 0; i < num_prescalers; ++i) { - for (k = 0; k < num_scalers; ++k) { - prescaler = (i * 2) + 1; - scaler = (1 << (k + 1)); /* 2^(k+1) */ - freq = module_clock / (prescaler * scaler); - - if (freq <= target_freq) { - /* Found closest lower frequency at this prescaler setting, - * compare to the best result */ - if (closest_frequency < freq) { - closest_frequency = freq; - *closest_scaler = k; - *closest_prescaler = i; - } - - break; - } - } - } - - if (closest_frequency < 0) { - /* Error, no solution found, this line is never reachable with current - * hardware settings unless a _very_ low target clock is requested. - * (scaler_max * prescaler_max) = 458752 */ - return -1; - } - - return closest_frequency; + return spi_config[bus].dev; } -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +static inline void poweron(spi_t bus) { - SPI_Type *spi_dev; - uint8_t br_prescaler = 0xff; - uint8_t br_scaler = 0xff; - uint8_t prescaler_tmp = 0xff; - uint8_t scaler_tmp = 0xff; - uint32_t ctas = 0; - uint32_t ctar = 0; - uint32_t br_desired; - uint32_t module_clock; - uint32_t tcsc_freq; - uint32_t tasc_freq; - uint32_t tdt_freq; - - switch (speed) { - case SPI_SPEED_100KHZ: - br_desired = 100000; - break; - - case SPI_SPEED_400KHZ: - br_desired = 400000; + switch((uint32_t)dev(bus)) { + case (uint32_t)SPI0: + case (uint32_t)SPI1: + SIM->SCGC6 |= (spi_config[bus].simmask); break; - - case SPI_SPEED_1MHZ: - br_desired = 1000000; - break; - - case SPI_SPEED_5MHZ: - br_desired = 5000000; - break; - - case SPI_SPEED_10MHZ: - br_desired = 10000000; +#ifdef SPI2 + case (uint32_t)SPI2: + SIM->SCGC3 |= (spi_config[bus].simmask); break; - - default: - return -2; +#endif } +} - switch (dev) { -#if SPI_0_EN - - case SPI_0: - KINETIS_CFG_SPI_IO(0); - break; -#endif /* SPI_0_EN */ - -#if SPI_1_EN - - case SPI_1: - KINETIS_CFG_SPI_IO(1); - break; -#endif /* SPI_1_EN */ - -#if SPI_2_EN - - case SPI_2: - KINETIS_CFG_SPI_IO(2); - break; -#endif /* SPI_2_EN */ - -#if SPI_3_EN - - case SPI_3: - KINETIS_CFG_SPI_IO(3); - break; -#endif /* SPI_3_EN */ - -#if SPI_4_EN - - case SPI_4: - KINETIS_CFG_SPI_IO(4); - break; -#endif /* SPI_4_EN */ - -#if SPI_5_EN - - case SPI_5: - KINETIS_CFG_SPI_IO(5); - break; -#endif /* SPI_5_EN */ - -#if SPI_6_EN - - case SPI_6: - KINETIS_CFG_SPI_IO(6); +static inline void poweroff(spi_t bus) +{ + switch((uint32_t)dev(bus)) { + case (uint32_t)SPI0: + case (uint32_t)SPI1: + SIM->SCGC6 &= ~(spi_config[bus].simmask); break; -#endif /* SPI_6_EN */ - -#if SPI_7_EN - - case SPI_7: - KINETIS_CFG_SPI_IO(7); +#ifdef SPI2 + case (uint32_t)SPI2: + SIM->SCGC3 &= ~(spi_config[bus].simmask); break; -#endif /* SPI_7_EN */ - - default: - return -1; +#endif } +} - /* Find baud rate scaler and prescaler settings */ - if (find_closest_baudrate_scalers(module_clock, br_desired, - &br_prescaler, &br_scaler) < 0) { - /* Desired baud rate is too low to be reachable at current module clock frequency. */ - return -2; - } +void spi_init(spi_t bus) +{ + /* make sure given bus device is valid */ + assert(bus < SPI_NUMOF); - ctar |= SPI_CTAR_PBR(br_prescaler) | SPI_CTAR_BR(br_scaler); + /* initialize the buses lock */ + mutex_init(&locks[bus]); + /* trigger pin initialization */ + spi_init_pins(bus); + /* power on the bus temporarily */ + poweron(bus); - /* Find the other delay divisors */ - /* tCSC */ - if (tcsc_freq == 0) { - /* Default to same as baud rate if set to zero. */ - tcsc_freq = br_desired; - } + /* make the base configuration: configure as SPI master, set CS inactive + * state (for HWCS lines) and clear FIFO counters and disable FIFOs */ + dev(bus)->MCR = (SPI_MCR_MSTR_MASK | SPI_MCR_PCSIS_MASK | + SPI_MCR_CLR_RXF_MASK | SPI_MCR_CLR_TXF_MASK | + SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK | + SPI_MCR_DOZE_MASK | SPI_MCR_HALT_MASK | SPI_MCR_MDIS_MASK); - if (find_closest_delay_scalers(module_clock, tcsc_freq, - &prescaler_tmp, &scaler_tmp) < 0) { - /* failed to find a solution */ - return -2; - } + /* disable all DMA and interrupt requests */ + dev(bus)->RSER = 0; - ctar |= SPI_CTAR_PCSSCK(prescaler_tmp) | SPI_CTAR_CSSCK(scaler_tmp); + /* and power off the bus until it is actually used */ + poweroff(bus); +} - /* tASC */ - if (tasc_freq == 0) { - /* Default to same as baud rate if set to zero. */ - tasc_freq = br_desired; - } +void spi_init_pins(spi_t bus) +{ + gpio_init_port(spi_config[bus].pin_miso, spi_config[bus].pcr); + gpio_init_port(spi_config[bus].pin_mosi, spi_config[bus].pcr); + gpio_init_port(spi_config[bus].pin_clk , spi_config[bus].pcr); +} - if (find_closest_delay_scalers(module_clock, tasc_freq, - &prescaler_tmp, &scaler_tmp) < 0) { - /* failed to find a solution */ - return -2; +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + if (bus >= SPI_NUMOF) { + return SPI_NODEV; } - - ctar |= SPI_CTAR_PASC(prescaler_tmp) | SPI_CTAR_ASC(scaler_tmp); - - /* tDT */ - if (tdt_freq == 0) { - /* Default to same as baud rate if set to zero. */ - tdt_freq = br_desired; + if (cs == SPI_CS_UNDEF) { + return SPI_NOCS; } - if (find_closest_delay_scalers(module_clock, tdt_freq, - &prescaler_tmp, &scaler_tmp) < 0) { - /* failed to find a solution */ - return -2; + if (cs & SWCS_MASK) { + gpio_init((gpio_t)cs, GPIO_OUT); } - - ctar |= SPI_CTAR_PDT(prescaler_tmp) | SPI_CTAR_DT(scaler_tmp); - - - /* Set clock polarity and phase. */ - switch (conf) { - case SPI_CONF_FIRST_RISING: - break; - - case SPI_CONF_SECOND_RISING: - ctar |= SPI_CTAR_CPHA_MASK; - break; - - case SPI_CONF_FIRST_FALLING: - ctar |= SPI_CTAR_CPOL_MASK; - break; - - case SPI_CONF_SECOND_FALLING: - ctar |= SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK; - break; - - default: - return -2; + else { + if ((cs >= SPI_HWCS_NUMOF) || + (spi_config[bus].pin_cs[cs] == GPIO_UNDEF)) { + return SPI_NOCS; + } + gpio_init_port(spi_config[bus].pin_cs[cs], spi_config[bus].pcr); } - /* Update CTAR register with new timing settings, 8-bit frame size. */ - spi_dev->CTAR[ctas] = SPI_CTAR_FMSZ(7) | ctar; + return SPI_OK; +} - /* enable SPI */ - spi_dev->MCR = SPI_MCR_MSTR_MASK - | SPI_MCR_DOZE_MASK - | SPI_MCR_CLR_TXF_MASK - | SPI_MCR_CLR_RXF_MASK; +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + /* lock and power on the bus */ + mutex_lock(&locks[bus]); + poweron(bus); - if (KINETIS_SPI_USE_HW_CS) { - spi_dev->MCR |= SPI_MCR_PCSIS(1); - } + /* enable the device */ + dev(bus)->MCR &= ~(SPI_MCR_HALT_MASK | SPI_MCR_MDIS_MASK); - spi_dev->RSER = (uint32_t)0; + /* configure clock and mode */ + dev(bus)->CTAR[0] = (mode | SPI_CTAR_FMSZ(7) | spi_clk_config[clk]); - return 0; + return SPI_OK; } -int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data)) +void spi_release(spi_t bus) { - SPI_Type *spi_dev; + /* disable, power off, and unlock the bus */ + dev(bus)->MCR |= (SPI_MCR_HALT_MASK | SPI_MCR_MDIS_MASK); + poweroff(bus); + mutex_unlock(&locks[bus]); +} - switch (dev) { -#if SPI_0_EN +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; + uint32_t flags = SPI_PUSHR_CONT_MASK; - case SPI_0: - spi_dev = SPI_0_DEV; - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_PCS0_PORT_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_SOUT_PORT_CLKEN(); - SPI_0_SIN_PORT_CLKEN(); - /* Set PORT to AF mode */ - SPI_0_PCS0_PORT->PCR[SPI_0_PCS0_PIN] = PORT_PCR_MUX(SPI_0_PCS0_AF); - SPI_0_SCK_PORT->PCR[SPI_0_SCK_PIN] = PORT_PCR_MUX(SPI_0_SCK_AF); - SPI_0_SOUT_PORT->PCR[SPI_0_SOUT_PIN] = PORT_PCR_MUX(SPI_0_SOUT_AF); - SPI_0_SIN_PORT->PCR[SPI_0_SIN_PIN] = PORT_PCR_MUX(SPI_0_SIN_AF); - break; -#endif /* SPI_0_EN */ + assert(out_buf || in_buf); - default: - return -1; + /* handle chip select */ + if (cs != SPI_CS_UNDEF) { + if (cs & SWCS_MASK) { + gpio_clear((gpio_t)cs); + } + else { + flags |= (uint32_t)(1 << (cs + SPI_PUSHR_PCS_SHIFT)); + } } - /* set frame size, slave mode always uses CTAR0 */ - spi_dev->CTAR[0] = SPI_CTAR_SLAVE_FMSZ(7); - - /* Set clock polarity and phase. */ - switch (conf) { - case SPI_CONF_FIRST_RISING: - spi_dev->CTAR[0] &= ~(SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK); - break; - - case SPI_CONF_SECOND_RISING: - spi_dev->CTAR[0] &= ~(SPI_CTAR_CPOL_MASK); - spi_dev->CTAR[0] |= SPI_CTAR_CPHA_MASK; - break; - - case SPI_CONF_FIRST_FALLING: - spi_dev->CTAR[0] &= ~(SPI_CTAR_CPHA_MASK); - spi_dev->CTAR[0] |= SPI_CTAR_CPOL_MASK; - break; + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; + if ((i == (len - 1)) && (!cont)) { + flags &= ~(SPI_PUSHR_CONT_MASK); + } - case SPI_CONF_SECOND_FALLING: - spi_dev->CTAR[0] |= SPI_CTAR_CPHA_MASK | SPI_CTAR_CPOL_MASK; - break; + while (!(dev(bus)->SR & SPI_SR_TFFF_MASK)) {} + dev(bus)->PUSHR = (tmp | flags); - default: - return -2; + while (!(dev(bus)->SR & SPI_SR_RXCTR_MASK)) {} + tmp = dev(bus)->POPR; + if (in_buf) { + in_buf[i] = tmp; + } } - /* enable SPI */ - spi_dev->MCR = SPI_MCR_DOZE_MASK - | SPI_MCR_PCSIS(SPI_0_PCS0_ACTIVE_LOW << 0) - | SPI_MCR_CLR_TXF_MASK - | SPI_MCR_CLR_RXF_MASK; - - spi_dev->RSER = (uint32_t)0; - - /* set callback */ - spi_config[dev].cb = cb; - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; + if ((!cont) && (cs != SPI_CS_UNDEF) && (cs & SWCS_MASK)) { + gpio_set((gpio_t)cs); } - - mutex_lock(locks_map[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - - mutex_unlock(locks_map[dev]); - return 0; -} - -static inline uint8_t spi_transfer_internal(SPI_Type *spi_dev, uint32_t flags, uint8_t byte_out) -{ - /* Wait until there is space in the TXFIFO */ - while (!(spi_dev->SR & SPI_SR_TFFF_MASK)); - -#if KINETIS_SPI_USE_HW_CS - spi_dev->PUSHR = flags | SPI_PUSHR_TXDATA(byte_out) | SPI_PUSHR_PCS(1); -#else - spi_dev->PUSHR = flags | SPI_PUSHR_TXDATA(byte_out); -#endif - - /* Wait until we have received a byte */ - while (!(spi_dev->SR & SPI_SR_RXCTR_MASK)); - - return (uint8_t)spi_dev->POPR; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - SPI_Type *spi_dev; - uint8_t byte_in; - uint32_t flags; - - /* The chip select lines are expected to be controlled via software in RIOT. - * Don't set PCS bits in flags. */ - switch (dev) { -#if SPI_0_EN - - case SPI_0: - spi_dev = SPI_0_DEV; - flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_1_EN - - case SPI_1: - spi_dev = SPI_1_DEV; - flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_2_EN - - case SPI_2: - spi_dev = SPI_2_DEV; - flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_3_EN - - case SPI_3: - spi_dev = SPI_3_DEV; - flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_4_EN - - case SPI_4: - spi_dev = SPI_4_DEV; - flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_5_EN - - case SPI_5: - spi_dev = SPI_5_DEV; - flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_6_EN - - case SPI_6: - spi_dev = SPI_6_DEV; - flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - -#if SPI_7_EN - - case SPI_7: - spi_dev = SPI_7_DEV; - flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_EOQ_MASK); - break; -#endif - - default: - return -1; - } - - byte_in = spi_transfer_internal(spi_dev, flags, out); - - /* Clear End-of-Queue status flag */ - spi_dev->SR = SPI_SR_EOQF_MASK; - - if (in != NULL) { - *in = (char)byte_in; - } - - return 1; -} - -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) -{ - SPI_Type *spi_dev; - uint8_t byte_in; - uint8_t byte_out; - uint32_t flags; - int i; - - switch (dev) { -#if SPI_0_EN - - case SPI_0: - spi_dev = SPI_0_DEV; - flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_1_EN - - case SPI_1: - spi_dev = SPI_1_DEV; - flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_2_EN - - case SPI_2: - spi_dev = SPI_2_DEV; - flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_3_EN - - case SPI_3: - spi_dev = SPI_3_DEV; - flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_4_EN - - case SPI_4: - spi_dev = SPI_4_DEV; - flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_5_EN - - case SPI_5: - spi_dev = SPI_5_DEV; - flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_6_EN - - case SPI_6: - spi_dev = SPI_6_DEV; - flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_7_EN - - case SPI_7: - spi_dev = SPI_7_DEV; - flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - - default: - return -1; - } - - /* Default: send idle data */ - byte_out = (uint8_t)SPI_IDLE_DATA; - - for (i = 0; i < (int)length; i++) { - if (out != NULL) { - /* Send given out data */ - byte_out = (uint8_t)out[i]; - } - - if (i >= (int)length - 1) { - /* Last byte, set End-of-Queue flag, clear Continue flag. */ - flags &= ~(SPI_PUSHR_CONT_MASK); - flags |= SPI_PUSHR_EOQ_MASK; - } - - byte_in = spi_transfer_internal(spi_dev, flags, byte_out); - - if (in != NULL) { - /* Save input byte to buffer */ - in[i] = (char)byte_in; - } - } - - /* Clear End-of-Queue status flag */ - spi_dev->SR = SPI_SR_EOQF_MASK; - - return i; } - -int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in) -{ - SPI_Type *spi_dev; - uint8_t byte_in; - uint32_t flags; - - switch (dev) { -#if SPI_0_EN - - case SPI_0: - spi_dev = SPI_0_DEV; - flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_1_EN - - case SPI_1: - spi_dev = SPI_1_DEV; - flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_2_EN - - case SPI_2: - spi_dev = SPI_2_DEV; - flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_3_EN - - case SPI_3: - spi_dev = SPI_3_DEV; - flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_4_EN - - case SPI_4: - spi_dev = SPI_4_DEV; - flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_5_EN - - case SPI_5: - spi_dev = SPI_5_DEV; - flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_6_EN - - case SPI_6: - spi_dev = SPI_6_DEV; - flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_7_EN - - case SPI_7: - spi_dev = SPI_7_DEV; - flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - - default: - return -1; - } - - /* Transfer the register address first. */ - spi_transfer_internal(spi_dev, flags, reg); - - /* Last byte, set End-of-Queue flag, clear Continue flag. */ - flags &= ~(SPI_PUSHR_CONT_MASK); - flags |= SPI_PUSHR_EOQ_MASK; - - /* Transfer the value. */ - byte_in = spi_transfer_internal(spi_dev, flags, out); - - if (in != NULL) { - /* Save input byte to buffer */ - *in = (char)byte_in; - } - - /* Clear End-of-Queue status flag */ - spi_dev->SR = SPI_SR_EOQF_MASK; - - return 2; -} - -int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length) -{ - SPI_Type *spi_dev; - uint8_t byte_in; - uint8_t byte_out; - uint32_t flags; - int i; - - switch (dev) { -#if SPI_0_EN - - case SPI_0: - spi_dev = SPI_0_DEV; - flags = (SPI_PUSHR_CTAS(SPI_0_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_1_EN - - case SPI_1: - spi_dev = SPI_1_DEV; - flags = (SPI_PUSHR_CTAS(SPI_1_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_2_EN - - case SPI_2: - spi_dev = SPI_2_DEV; - flags = (SPI_PUSHR_CTAS(SPI_2_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_3_EN - - case SPI_3: - spi_dev = SPI_3_DEV; - flags = (SPI_PUSHR_CTAS(SPI_3_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_4_EN - - case SPI_4: - spi_dev = SPI_4_DEV; - flags = (SPI_PUSHR_CTAS(SPI_4_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_5_EN - - case SPI_5: - spi_dev = SPI_5_DEV; - flags = (SPI_PUSHR_CTAS(SPI_5_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_6_EN - - case SPI_6: - spi_dev = SPI_6_DEV; - flags = (SPI_PUSHR_CTAS(SPI_6_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - -#if SPI_7_EN - - case SPI_7: - spi_dev = SPI_7_DEV; - flags = (SPI_PUSHR_CTAS(SPI_7_CTAS) | SPI_PUSHR_CONT_MASK); - break; -#endif - - default: - return -1; - } - - byte_out = reg; - - /* Send register address */ - spi_transfer_internal(spi_dev, flags, byte_out); - - /* Default: send idle data */ - byte_out = (uint8_t)SPI_IDLE_DATA; - - for (i = 0; i < (int)length; i++) { - if (out != NULL) { - /* Send given out data */ - byte_out = (uint8_t)out[i]; - } - - if (i >= (int)length - 1) { - /* Last byte, set End-of-Queue flag, clear Continue flag. */ - flags &= ~(SPI_PUSHR_CONT_MASK); - flags |= SPI_PUSHR_EOQ_MASK; - } - - byte_in = spi_transfer_internal(spi_dev, flags, byte_out); - - if (in != NULL) { - /* Save input byte to buffer */ - in[i] = (char)byte_in; - } - } - - /* Clear End-of-Queue status flag */ - spi_dev->SR = SPI_SR_EOQF_MASK; - - return i; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - - switch (dev) { -#if SPI_0_EN - - case SPI_0: - SPI_0_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_0_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_1_EN - - case SPI_1: - SPI_1_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_1_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_2_EN - - case SPI_2: - SPI_2_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_2_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_3_EN - - case SPI_3: - SPI_3_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_3_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_4_EN - - case SPI_4: - SPI_4_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_4_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_5_EN - - case SPI_5: - SPI_5_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_5_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_6_EN - - case SPI_6: - SPI_6_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_6_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif -#if SPI_7_EN - - case SPI_7: - SPI_7_DEV->PUSHR = SPI_PUSHR_CTAS(SPI_7_CTAS) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(reset_val); - break; -#endif - } -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - - case SPI_0: - SPI_0_CLKEN(); - break; -#endif -#if SPI_1_EN - - case SPI_1: - SPI_1_CLKEN(); - break; -#endif -#if SPI_2_EN - - case SPI_2: - SPI_2_CLKEN(); - break; -#endif -#if SPI_3_EN - - case SPI_3: - SPI_3_CLKEN(); - break; -#endif -#if SPI_4_EN - - case SPI_4: - SPI_4_CLKEN(); - break; -#endif -#if SPI_5_EN - - case SPI_5: - SPI_5_CLKEN(); - break; -#endif -#if SPI_6_EN - - case SPI_6: - SPI_6_CLKEN(); - break; -#endif -#if SPI_7_EN - - case SPI_7: - SPI_7_CLKEN(); - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - /* Wait until the last byte has been transmitted before turning off - * the clock. */ - switch (dev) { -#if SPI_0_EN - - case SPI_0: - while ((SPI_0_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_0_CLKDIS(); - break; -#endif -#if SPI_1_EN - - case SPI_1: - while ((SPI_1_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_1_CLKDIS(); - break; -#endif -#if SPI_2_EN - - case SPI_2: - while ((SPI_2_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_2_CLKDIS(); - break; -#endif -#if SPI_3_EN - - case SPI_3: - while ((SPI_3_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_3_CLKDIS(); - break; -#endif -#if SPI_4_EN - - case SPI_4: - while ((SPI_4_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_4_CLKDIS(); - break; -#endif -#if SPI_5_EN - - case SPI_5: - while ((SPI_5_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_5_CLKDIS(); - break; -#endif -#if SPI_6_EN - - case SPI_6: - while ((SPI_6_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_6_CLKDIS(); - break; -#endif -#if SPI_7_EN - - case SPI_7: - while ((SPI_7_DEV->SR & SPI_SR_TXCTR_MASK) != 0); - - SPI_7_CLKDIS(); - break; -#endif - } -} - -static inline void irq_handler_transfer(SPI_Type *spi, spi_t dev) -{ - - if (spi->SR & SPI_SR_RFDF_MASK) { - char data; - data = (char)spi->POPR; - data = spi_config[dev].cb(data); - spi->PUSHR = SPI_PUSHR_CTAS(0) - | SPI_PUSHR_EOQ_MASK - | SPI_PUSHR_TXDATA(data); - } - - /* see if a thread with higher priority wants to run now */ - cortexm_isr_end(); -} - -#if SPI_0_EN -#ifdef SPI_0_IRQ_HANDLER -void SPI_0_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_0_DEV, SPI_0); -} -#endif -#endif - -#if SPI_1_EN -#ifdef SPI_1_IRQ_HANDLER -void SPI_1_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_1_DEV, SPI_1); -} -#endif -#endif - -#if SPI_2_EN -#ifdef SPI_2_IRQ_HANDLER -void SPI_2_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_2_DEV, SPI_2); -} -#endif -#endif - -#if SPI_3_EN -#ifdef SPI_3_IRQ_HANDLER -void SPI_3_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_3_DEV, SPI_3); -} -#endif -#endif - -#if SPI_4_EN -#ifdef SPI_4_IRQ_HANDLER -void SPI_4_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_4_DEV, SPI_4); -} -#endif -#endif - -#if SPI_5_EN -#ifdef SPI_5_IRQ_HANDLER -void SPI_5_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_5_DEV, SPI_5); -} -#endif -#endif - -#if SPI_6_EN -#ifdef SPI_6_IRQ_HANDLER -void SPI_6_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_6_DEV, SPI_6); -} -#endif -#endif - -#if SPI_7_EN -#ifdef SPI_7_IRQ_HANDLER -void SPI_7_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_7_DEV, SPI_7); -} -#endif -#endif - -#endif /* SPI_NUMOF */ diff --git a/cpu/kw2x/cpu.c b/cpu/kw2x/cpu.c index 41f95e6c1621..bcbffa75b8f3 100644 --- a/cpu/kw2x/cpu.c +++ b/cpu/kw2x/cpu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "mcg.h" #include "cpu_conf.h" +#include "periph/init.h" #define FLASH_BASE (0x00000000) @@ -37,6 +38,8 @@ void cpu_init(void) cortexm_init(); /* initialize the clock system */ cpu_clock_init(); + /* trigger static peripheral initialization */ + periph_init(); } static inline void modem_clock_init(void) diff --git a/cpu/lm4f120/cpu.c b/cpu/lm4f120/cpu.c index 05ffbdaa116b..a4b1598381d2 100644 --- a/cpu/lm4f120/cpu.c +++ b/cpu/lm4f120/cpu.c @@ -23,6 +23,7 @@ #include "thread.h" #include "arch/thread_arch.h" #include "arch/irq_arch.h" +#include "periph/init.h" /** * @brief Initialize the CPU, set IRQ priorities @@ -34,6 +35,9 @@ void cpu_init(void) /* initialize the clock system */ cpu_clock_init(CLOCK_SOURCE); + + /* trigger static peripheral initialization */ + periph_init(); } void setup_fpu(void) diff --git a/cpu/lpc11u34/cpu.c b/cpu/lpc11u34/cpu.c index a41832e25468..561aefd2bba4 100644 --- a/cpu/lpc11u34/cpu.c +++ b/cpu/lpc11u34/cpu.c @@ -18,6 +18,7 @@ */ #include "cpu.h" +#include "periph/init.h" #define SYSOSCCTRL_Val 0x00000000 /* Reset: 0x000 */ @@ -111,4 +112,6 @@ void cpu_init(void) cortexm_init(); /* initialize the clock */ clk_init(); + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/lpc11u34/include/periph_cpu.h b/cpu/lpc11u34/include/periph_cpu.h index c288c4937026..0c791c3c68e5 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 /** @} */ @@ -105,19 +106,41 @@ typedef enum { #endif /* ndef DOXYGEN */ /** - * @brief PWM channel configuration + * @brief PWM configuration */ +typedef struct { + LPC_CTxxBx_Type *dev; /**< PWM device */ + __IO uint32_t *pins[PWM_CHAN_NUMOF]; /**< set to NULL if channel is not used */ + uint16_t clk_bit; /**< clock enable bit */ + uint8_t af; /**< alternate pin function */ +} 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 PWM configuration + * @brief SPI configuration data */ typedef struct { - LPC_CTxxBx_Type *dev; - __IO uint32_t *pins[PWM_CHAN_NUMOF]; /**< set to NULL if channel is not used */ - uint16_t clk_bit; - uint8_t af; -} pwm_conf_t; + 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 } diff --git a/cpu/lpc11u34/periph/spi.c b/cpu/lpc11u34/periph/spi.c index 325d73fbc363..53672526b9e1 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 + * @author Hauke Petersen * * @} */ #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 */ diff --git a/cpu/lpc1768/cpu.c b/cpu/lpc1768/cpu.c index 69b856f611c6..9018d8b7567f 100644 --- a/cpu/lpc1768/cpu.c +++ b/cpu/lpc1768/cpu.c @@ -18,6 +18,7 @@ */ #include "cpu.h" +#include "periph/init.h" /** * @brief Initialize the CPU, set IRQ priorities @@ -26,4 +27,6 @@ void cpu_init(void) { /* initialize the Cortex-M core */ cortexm_init(); + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/lpc2387/include/periph_cpu.h b/cpu/lpc2387/include/periph_cpu.h index dbb757ffdb31..841b63bbf355 100644 --- a/cpu/lpc2387/include/periph_cpu.h +++ b/cpu/lpc2387/include/periph_cpu.h @@ -74,11 +74,26 @@ typedef enum { * @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 /* @} */ +/** + * @brief Override SPI clock speed values + * @{ + */ +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = 100, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ = 400, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ = 1000, /**< drive the SPI bus with 1MHz */ + SPI_CLK_5MHZ = 5000, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ = 10000 /**< drive the SPI bus with 10MHz */ +} spi_clk_t; +/** @} */ + /* @} */ #ifdef __cplusplus } diff --git a/cpu/lpc2387/periph/spi.c b/cpu/lpc2387/periph/spi.c index fef1b277dfe6..60a3a7785b5d 100644 --- a/cpu/lpc2387/periph/spi.c +++ b/cpu/lpc2387/periph/spi.c @@ -1,9 +1,10 @@ /* * Copyright (C) 2015 Kaspar Schleiser + * 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. */ /** @@ -13,22 +14,25 @@ * @file * @brief Low-level SPI driver implementation * + * This implementation is very basic and only supports a single SPI device with + * limited configuration options. + * + * @todo This implementation needs a major rework + * * @author Kaspar Schleiser + * @author Hauke Petersen * * @} */ #include "cpu.h" #include "mutex.h" -#include "periph/gpio.h" +#include "assert.h" #include "periph/spi.h" -#include "periph_conf.h" -#include "board.h" + #define ENABLE_DEBUG (0) #include "debug.h" -#if SPI_0_EN - #define SPI_TX_EMPTY (SSP0SR & SSPSR_TFE) #define SPI_BUSY (SSP0SR & SSPSR_BSY) #define SPI_RX_AVAIL (SSP0SR & SSPSR_RNE) @@ -36,178 +40,94 @@ /** * @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 -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +static mutex_t lock = MUTEX_INIT; + +void spi_init(spi_t bus) { - (void ) conf; - if (dev) { - return -1; - } + assert(bus == SPI_DEV(0)); - uint32_t f_baud = 0; - switch(speed) - { - case SPI_SPEED_100KHZ: - f_baud = 100; - break; - case SPI_SPEED_400KHZ: - f_baud = 400; - break; - case SPI_SPEED_1MHZ: - f_baud = 1000; - break; - case SPI_SPEED_5MHZ: - f_baud = 5000; - break; - case SPI_SPEED_10MHZ: - f_baud = 10000; - break; - } + /* interface setup */ + SSP0CR0 = 7; + /* configure pins */ + spi_init_pins(bus); + /* power off the bus (default is on) */ + PCONP &= ~(PCSSP0); +} -#if 0 - /* TODO */ - switch(conf) - { - case SPI_CONF_FIRST_RISING: - /**< first data bit is transacted on the first rising SCK edge */ - cpha = 0; - cpol = 0; - break; - case SPI_CONF_SECOND_RISING: - /**< first data bit is transacted on the second rising SCK edge */ - cpha = 1; - cpol = 0; - break; - case SPI_CONF_FIRST_FALLING: - /**< first data bit is transacted on the first falling SCK edge */ - cpha = 0; - cpol = 1; - break; - case SPI_CONF_SECOND_FALLING: - /**< first data bit is transacted on the second falling SCK edge */ - cpha = 1; - cpol = 1; - break; - } -#endif +void spi_init_pins(spi_t bus) +{ + PINSEL3 |= (BIT8 | BIT9); /* SCLK */ + PINSEL3 |= (BIT14 | BIT15); /* MISO */ + PINSEL3 |= (BIT16 | BIT17); /* MOSI */ +} - /* Power*/ - PCONP |= PCSSP0; /* Enable power for SSP0 (default is on)*/ +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + uint32_t pclksel; + uint32_t cpsr; - /* PIN Setup*/ - spi_conf_pins(dev); + /* only support for mode 0 at the moment */ + if (mode != SPI_MODE_0) { + return SPI_NOMODE; + } - /* Interface Setup*/ - SSP0CR0 = 7; + /* lock bus */ + mutex_lock(&lock); + /* power on */ + PCONP |= (PCSSP0); - /* Clock Setup*/ - uint32_t pclksel; - uint32_t cpsr; - lpc2387_pclk_scale(CLOCK_CORECLOCK / 1000, f_baud, &pclksel, &cpsr); + /* configure bus clock */ + lpc2387_pclk_scale(CLOCK_CORECLOCK / 1000, (uint32_t)clk, &pclksel, &cpsr); PCLKSEL1 &= ~(BIT10 | BIT11); /* CCLK to PCLK divider*/ PCLKSEL1 |= pclksel << 10; SSP0CPSR = cpsr; - /* Enable*/ - SSP0CR1 |= BIT1; /* SSP-Enable*/ - int dummy; + /* enable the bus */ + SSP0CR1 |= BIT1; - /* Clear RxFIFO:*/ - while (SPI_RX_AVAIL) { /* while RNE (Receive FIFO Not Empty)...*/ - dummy = SSP0DR; /* read data*/ + /* clear RxFIFO */ + int dummy; + while (SPI_RX_AVAIL) { /* while RNE (Receive FIFO Not Empty)...*/ + dummy = SSP0DR; /* read data*/ } + (void) dummy; /* to suppress unused-but-set-variable */ - /* to suppress unused-but-set-variable */ - (void) dummy; - return 0; + return SPI_OK; } -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char)) +void spi_release(spi_t bus) { - (void)dev; - (void)conf; - (void)cb; - printf("%s:%s(): stub\n", RIOT_FILE_RELATIVE, __func__); - /* TODO */ - return -1; + /* disable, power off, and release the bus */ + SSP0CR1 &= ~(BIT1); + PCONP &= ~(PCSSP0); + mutex_unlock(&lock); } -void spi_transmission_begin(spi_t dev, char reset_val) +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - (void)dev; - (void)reset_val; - printf("%s:%s(): stub\n", RIOT_FILE_RELATIVE, __func__); - /* TODO*/ -} + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; -int spi_acquire(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} + assert(out_buf || in_buf); -int spi_release(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - (void) dev; - while (!SPI_TX_EMPTY) {} - SSP0DR = out; - while (SPI_BUSY) {} - while (!SPI_RX_AVAIL) {} - - char tmp = (char)SSP0DR; - if (in != NULL) { - *in = tmp; + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; + while (!SPI_TX_EMPTY) {} + SSP0DR = tmp; + while (SPI_BUSY) {} + while (!SPI_RX_AVAIL) {} + tmp = (uint8_t)SSP0DR; + if (in_buf) { + in_buf[i] = tmp; + } } - return 1; -} - -void spi_poweron(spi_t dev) -{ - (void) dev; -} - -void spi_poweroff(spi_t dev) -{ - (void) dev; - (void) dev; -} - -int spi_conf_pins(spi_t dev) -{ - switch (dev) { - case 0: - PINSEL3 |= BIT8 + BIT9; /* SCLK */ - PINSEL3 |= BIT14 + BIT15; /* MISO */ - PINSEL3 |= BIT16 + BIT17; /* MOSI */ - return 0; - default: - return -1; + if ((!cont) && cs != SPI_CS_UNDEF) { + gpio_set((gpio_t)cs); } } - -#endif /* SPI_0_EN */ diff --git a/cpu/msp430fxyz/include/periph_cpu.h b/cpu/msp430fxyz/include/periph_cpu.h index f045de48fe60..85ab53d5fbbe 100644 --- a/cpu/msp430fxyz/include/periph_cpu.h +++ b/cpu/msp430fxyz/include/periph_cpu.h @@ -45,6 +45,11 @@ typedef uint16_t gpio_t; */ #define GPIO_PIN(x, y) ((gpio_t)(((x & 0xff) << 8) | (1 << (y & 0xff)))) +/** + * @brief No support for HW chip select... + */ +#define SPI_HWCS(x) (SPI_CS_UNDEF) + #ifndef DOXYGEN /** * @brief Override flank selection values @@ -57,6 +62,40 @@ typedef enum { GPIO_BOTH = 0xab /**< not supported -> random value*/ } gpio_flank_t; /** @} */ + +/** + * @brief Override SPI mode selection values + */ +#define HAVE_SPI_MODE_T +#ifndef SPI_USE_USCI +typedef enum { + SPI_MODE_0 = (USART_TCTL_CKPH), /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = 0, /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = (USART_TCTL_CKPL | USART_TCTL_CKPH), /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = (USART_TCTL_CKPL) /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +#else +typedef enum { + SPI_MODE_0 = (USCI_SPI_CTL0_CKPH), /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = 0, /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = (USCI_SPI_CTL0_CKPL | USCI_SPI_CTL0_CKPH), /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = (USCI_SPI_CTL0_CKPL) /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +#endif +/** @} */ + +/** + * @brief Override SPI clock speed selection values + */ +#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 = 0, /**< not supported */ +} spi_clk_t; +/** @} */ #endif /* ndef DOXYGEN */ /** @@ -83,6 +122,7 @@ void gpio_periph_mode(gpio_t pin, bool enable); * @brief declare needed generic SPI functions * @{ */ +#define PERIPH_SPI_NEEDS_INIT_CS #define PERIPH_SPI_NEEDS_TRANSFER_BYTE #define PERIPH_SPI_NEEDS_TRANSFER_REG #define PERIPH_SPI_NEEDS_TRANSFER_REGS diff --git a/cpu/msp430fxyz/periph/spi.c b/cpu/msp430fxyz/periph/spi.c index e7f5fe2602dd..76a95466ece1 100644 --- a/cpu/msp430fxyz/periph/spi.c +++ b/cpu/msp430fxyz/periph/spi.c @@ -1,5 +1,5 @@ /* - * 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 @@ -25,8 +25,6 @@ #include "cpu.h" #include "mutex.h" #include "assert.h" -#include "periph_cpu.h" -#include "periph_conf.h" #include "periph/spi.h" /** @@ -34,233 +32,128 @@ */ static mutex_t spi_lock = MUTEX_INIT; -/* per default, we use the legacy MSP430 USART module for UART functionality */ -#ifndef SPI_USE_USCI -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +void spi_init(spi_t bus) { - if (dev != 0) { - return -2; - } - - /* reset SPI device */ - SPI_DEV->CTL = USART_CTL_SWRST; - /* configure pins */ - spi_conf_pins(dev); - /* configure USART to SPI mode with SMCLK driving it */ - SPI_DEV->CTL |= (USART_CTL_CHAR | USART_CTL_SYNC | USART_CTL_MM); - SPI_DEV->RCTL = 0; - SPI_DEV->TCTL = (USART_TCTL_SSEL_SMCLK | USART_TCTL_STC); - /* set polarity and phase */ - switch (conf) { - case SPI_CONF_FIRST_RISING: - SPI_DEV->TCTL |= USART_TCTL_CKPH; - break; - case SPI_CONF_SECOND_RISING: - /* nothing to be done here */ - break; - case SPI_CONF_FIRST_FALLING: - SPI_DEV->TCTL |= (USART_TCTL_CKPH & USART_TCTL_CKPL); - break; - case SPI_CONF_SECOND_FALLING: - SPI_DEV->TCTL |= USART_TCTL_CKPL; - break; - default: - /* invalid clock setting */ - return -2; - } - /* configure clock - we use no modulation for now */ - uint32_t br = CLOCK_CMCLK; - switch (speed) { - case SPI_SPEED_100KHZ: - br /= 100000; - break; - case SPI_SPEED_400KHZ: - br /= 400000; - break; - case SPI_SPEED_1MHZ: - br /= 1000000; - break; - case SPI_SPEED_5MHZ: - br /= 5000000; - break; - default: - /* other clock speeds are not supported */ - return -1; - } + assert(bus <= SPI_NUMOF); - /* make sure the is not smaller then 2 */ - if (br < 2) { - br = 2; - } - - SPI_DEV->BR0 = (uint8_t)br; - SPI_DEV->BR1 = (uint8_t)(br >> 8); - SPI_DEV->MCTL = 0; +/* we need to differentiate between the legacy SPI device and USCI */ +#ifndef SPI_USE_USCI + /* put SPI device in reset state */ + SPI_BASE->CTL = USART_CTL_SWRST; + SPI_BASE->CTL |= (USART_CTL_CHAR | USART_CTL_SYNC | USART_CTL_MM); + SPI_BASE->RCTL = 0; + SPI_BASE->MCTL = 0; /* enable SPI mode */ SPI_ME |= SPI_ME_BIT; - /* release from software reset */ - SPI_DEV->CTL &= ~(USART_CTL_SWRST); - return 0; +#else + /* reset SPI device */ + SPI_BASE->CTL1 = USCI_SPI_CTL1_SWRST; + SPI_BASE->CTL1 |= (USCI_SPI_CTL1_SSEL_SMCLK); +#endif + + /* trigger the pin configuration */ + spi_init_pins(bus); } -/* we use alternative SPI code in case the board used the USCI module for SPI - * instead of the (older) USART module */ -#else /* SPI_USE_USCI */ +void spi_init_pins(spi_t bus) +{ + gpio_periph_mode(SPI_PIN_MISO, true); + gpio_periph_mode(SPI_PIN_MOSI, true); + gpio_periph_mode(SPI_PIN_CLK, true); +} -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) { - if (dev != 0) { - return -2; + if (clk == SPI_CLK_10MHZ) { + return SPI_NOCLK; } - /* reset SPI device */ - SPI_DEV->CTL1 |= USCI_SPI_CTL1_SWRST; - /* configure pins */ - spi_conf_pins(dev); - /* configure USART to SPI mode with SMCLK driving it */ - SPI_DEV->CTL0 |= (USCI_SPI_CTL0_UCSYNC | USCI_SPI_CTL0_MST - | USCI_SPI_CTL0_MODE_0 | USCI_SPI_CTL0_MSB); - SPI_DEV->CTL1 |= (USCI_SPI_CTL1_SSEL_SMCLK); - - /* set polarity and phase */ - switch (conf) { - case SPI_CONF_FIRST_RISING: - SPI_DEV->CTL0 |= USCI_SPI_CTL0_CKPH; - break; - case SPI_CONF_SECOND_RISING: - /* nothing to be done here */ - break; - case SPI_CONF_FIRST_FALLING: - SPI_DEV->CTL0 |= (USCI_SPI_CTL0_CKPH & USCI_SPI_CTL0_CKPL); - break; - case SPI_CONF_SECOND_FALLING: - SPI_DEV->CTL0 |= USCI_SPI_CTL0_CKPL; - break; - default: - /* invalid clock setting */ - return -2; - } - /* configure clock - we use no modulation for now */ - uint32_t br = CLOCK_CMCLK; - switch (speed) { - case SPI_SPEED_100KHZ: - br /= 100000; - break; - case SPI_SPEED_400KHZ: - br /= 400000; - break; - case SPI_SPEED_1MHZ: - br /= 1000000; - break; - case SPI_SPEED_5MHZ: - br /= 5000000; - break; - default: - /* other clock speeds are not supported */ - return -1; - } + /* lock the bus */ + mutex_lock(&spi_lock); + /* calculate baudrate */ + uint32_t br = CLOCK_CMCLK / clk; /* make sure the is not smaller then 2 */ if (br < 2) { br = 2; } + SPI_BASE->BR0 = (uint8_t)br; + SPI_BASE->BR1 = (uint8_t)(br >> 8); - SPI_DEV->BR0 = (uint8_t)br; - SPI_DEV->BR1 = (uint8_t)(br >> 8); + /* configure bus mode */ +#ifndef SPI_USE_USCI + /* configure mode */ + SPI_BASE->TCTL = (USART_TCTL_SSEL_SMCLK | USART_TCTL_STC | mode); /* release from software reset */ - SPI_DEV->CTL1 &= ~(USCI_SPI_CTL1_SWRST); - return 0; -} - -#endif /* SPI_USE_USCI */ - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) -{ - /* not supported so far */ - (void)dev; - (void)conf; - (void)cb; - return -1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* not supported so far */ - (void)dev; - (void)reset_val; -} + SPI_BASE->CTL &= ~(USART_CTL_SWRST); +#else + /* configure mode */ + SPI_BASE->CTL0 = (USCI_SPI_CTL0_UCSYNC | USCI_SPI_CTL0_MST| + USCI_SPI_CTL0_MODE_0 | USCI_SPI_CTL0_MSB | mode); + /* release from software reset */ + SPI_BASE->CTL1 &= ~(USCI_SPI_CTL1_SWRST); +#endif -int spi_conf_pins(spi_t dev) -{ - (void)dev; - gpio_periph_mode(SPI_PIN_MISO, true); - gpio_periph_mode(SPI_PIN_MOSI, true); - gpio_periph_mode(SPI_PIN_CLK, true); - return 0; + return SPI_OK; } -int spi_acquire(spi_t dev) +void spi_release(spi_t dev) { - (void)dev; - mutex_lock(&spi_lock); - return 0; -} + /* put SPI device back in reset state */ +#ifndef SPI_USE_USCI + SPI_BASE->CTL |= (USART_CTL_SWRST); +#else + SPI_BASE->CTL1 |= (USCI_SPI_CTL1_SWRST); +#endif -int spi_release(spi_t dev) -{ - (void)dev; + /* release the bus */ mutex_unlock(&spi_lock); - return 0; } -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) { - (void)dev; + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; + + assert(out_buf || in_buf); - assert(out || in); + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); + } /* if we only send out data, we do this the fast way... */ - if (!in) { - for (unsigned i = 0; i < length; i++) { + if (!in_buf) { + for (size_t i = 0; i < len; i++) { while (!(SPI_IF & SPI_IE_TX_BIT)) {} - SPI_DEV->TXBUF = (uint8_t)out[i]; + SPI_BASE->TXBUF = (uint8_t)out_buf[i]; } /* finally we need to wait, until all transfers are complete */ #ifndef SPI_USE_USCI while (!(SPI_IF & SPI_IE_TX_BIT) || !(SPI_IF & SPI_IE_RX_BIT)) {} #else - while (SPI_DEV->STAT & USCI_SPI_STAT_UCBUSY) {} + while (SPI_BASE->STAT & USCI_SPI_STAT_UCBUSY) {} #endif - SPI_DEV->RXBUF; + SPI_BASE->RXBUF; } - else if (!out) { - for (unsigned i = 0; i < length; i++) { - SPI_DEV->TXBUF = 0; + else if (!out_buf) { + for (size_t i = 0; i < len; i++) { + SPI_BASE->TXBUF = 0; while (!(SPI_IF & SPI_IE_RX_BIT)) {} - in[i] = (char)SPI_DEV->RXBUF; + in_buf[i] = (char)SPI_BASE->RXBUF; } } else { - for (unsigned i = 0; i < length; i++) { + for (size_t i = 0; i < len; i++) { while (!(SPI_IF & SPI_IE_TX_BIT)) {} - SPI_DEV->TXBUF = out[i]; + SPI_BASE->TXBUF = out_buf[i]; while (!(SPI_IF & SPI_IE_RX_BIT)) {} - in[i] = (char)SPI_DEV->RXBUF; + in_buf[i] = (char)SPI_BASE->RXBUF; } } - return length; -} - -void spi_poweron(spi_t dev) -{ - /* not supported so far */ - (void)dev; -} - -void spi_poweroff(spi_t dev) -{ - /* not supported so far */ - (void)dev; + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t)cs); + } } diff --git a/cpu/nrf51/cpu.c b/cpu/nrf51/cpu.c index 1d00dc7a40d8..db19c2681a7b 100644 --- a/cpu/nrf51/cpu.c +++ b/cpu/nrf51/cpu.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /** * @brief Initialize the CPU, set IRQ priorities @@ -39,4 +40,6 @@ void cpu_init(void) NRF_CLOCK->TASKS_HFCLKSTART = 1; while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {} #endif + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/nrf51/include/periph_cpu.h b/cpu/nrf51/include/periph_cpu.h index 9e69280edb75..594414a936a1 100644 --- a/cpu/nrf51/include/periph_cpu.h +++ b/cpu/nrf51/include/periph_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Freie Universität Berlin + * Copyright (C) 2015-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 @@ -31,6 +31,9 @@ extern "C" { */ #define GPIO_BASE (NRF_GPIO) #define UART_IRQN (UART0_IRQn) +#define SPI_SCKSEL (dev(bus)->PSELSCK) +#define SPI_MOSISEL (dev(bus)->PSELMOSI) +#define SPI_MISOSEL (dev(bus)->PSELMISO) /** @} */ /** diff --git a/cpu/nrf51/periph/spi.c b/cpu/nrf51/periph/spi.c deleted file mode 100644 index 12bdd1b3dae7..000000000000 --- a/cpu/nrf51/periph/spi.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2014 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_nrf51822 - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Hauke Petersen - * @author Frank Holtz - * - * @} - */ - -#include "cpu.h" -#include "mutex.h" -#include "periph/spi.h" -#include "periph_conf.h" - -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - -/* static port mapping */ -static NRF_SPI_Type *const spi[] = { -#if SPI_0_EN - SPI_0_DEV, -#endif -#if SPI_1_EN - SPI_1_DEV -#endif -}; - -/** - * @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) -{ - spi_poweron(dev); - - /* disable the device -> nRF51822 reference 3.0 26.1.1 and 27.1*/ - spi[dev]->ENABLE = 0; - - switch(dev) { -#if SPI_0_EN - case SPI_0: - /* disable TWI Interface */ - NRF_TWI0->ENABLE = 0; - break; -#endif -#if SPI_1_EN - case SPI_1: - /* disable SPI Slave */ - NRF_SPIS1->ENABLE = 0; - /* disable TWI Interface */ - NRF_TWI1->ENABLE = 0; - break; -#endif - default: - return -1; - } - - /* configure direction of used pins */ - spi_conf_pins(dev); - /* configure SPI mode */ - switch (conf) { - case SPI_CONF_FIRST_RISING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Leading << 1); - break; - case SPI_CONF_SECOND_RISING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Trailing << 1); - break; - case SPI_CONF_FIRST_FALLING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Leading << 1); - break; - case SPI_CONF_SECOND_FALLING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Trailing << 1); - break; - } - - /* select bus speed */ - switch (speed) { - case SPI_SPEED_100KHZ: /* 125 KHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K125; - break; - case SPI_SPEED_400KHZ: /* 500 KHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K500; - break; - case SPI_SPEED_1MHZ: /* 1 MHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M1; - break; - case SPI_SPEED_5MHZ: /* 4 MHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M4; - break; - case SPI_SPEED_10MHZ: /* 8 MHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M8; - break; - } - - /* finally enable the device */ - spi[dev]->ENABLE = 1; - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) -{ - (void) dev; - (void) conf; - (void) cb; - /* This API is incompatible with nRF51 SPIS */ - return -1; -} - -int spi_conf_pins(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - /* set pin direction */ - NRF_GPIO->DIRSET = (1 << SPI_0_PIN_MOSI) | (1 << SPI_0_PIN_SCK); - NRF_GPIO->DIRCLR = (1 << SPI_0_PIN_MISO); - /* select pins to be used by SPI */ - spi[dev]->PSELMOSI = SPI_0_PIN_MOSI; - spi[dev]->PSELMISO = SPI_0_PIN_MISO; - spi[dev]->PSELSCK = SPI_0_PIN_SCK; - break; -#endif -#if SPI_1_EN - case SPI_1: - /* set pin direction */ - NRF_GPIO->DIRSET = (1 << SPI_1_PIN_MOSI) | (1 << SPI_1_PIN_SCK); - NRF_GPIO->DIRCLR = (1 << SPI_1_PIN_MISO); - /* select pins to be used by SPI */ - spi[dev]->PSELMOSI = SPI_1_PIN_MOSI; - spi[dev]->PSELMISO = SPI_1_PIN_MISO; - spi[dev]->PSELSCK = SPI_1_PIN_SCK; - break; -#endif - default: - return -1; - } - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - return spi_transfer_bytes(dev, &out, in, 1); -} - -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - - for (unsigned i = 0; i < length; i++) { - char tmp = (out) ? out[i] : 0; - spi[dev]->EVENTS_READY = 0; - spi[dev]->TXD = (uint8_t)tmp; - while (spi[dev]->EVENTS_READY != 1) {} - tmp = (char)spi[dev]->RXD; - if (in) { - in[i] = tmp; - } - } - - return length; -} - -int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in) -{ - spi_transfer_byte(dev, reg, 0); - return spi_transfer_byte(dev, out, in); -} - -int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length) -{ - spi_transfer_byte(dev, reg, 0); - return spi_transfer_bytes(dev, out, in, length); -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - (void) dev; - (void) reset_val; - /* spi slave is not implemented */ -} - -void spi_poweron(spi_t dev) -{ - if ((unsigned int)dev < SPI_NUMOF) { - spi[dev]->POWER = 1; - } -} - -void spi_poweroff(spi_t dev) -{ - if ((unsigned int)dev < SPI_NUMOF) { - spi[dev]->POWER = 0; - } -} - -#endif /* SPI_NUMOF */ diff --git a/cpu/nrf52/cpu.c b/cpu/nrf52/cpu.c index 173531915d3c..85687fb9d8fa 100644 --- a/cpu/nrf52/cpu.c +++ b/cpu/nrf52/cpu.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /* FTPAN helper functions */ static bool ftpan_32(void); @@ -82,6 +83,9 @@ void cpu_init(void) NVIC_EnableIRQ(SWI0_EGU0_IRQn); NVIC_SetPriority(SWI0_EGU0_IRQn, 6); #endif + + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h index c263b3dead13..e315106e648e 100644 --- a/cpu/nrf52/include/periph_cpu.h +++ b/cpu/nrf52/include/periph_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Freie Universität Berlin + * Copyright (C) 2015-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 @@ -31,6 +31,9 @@ extern "C" { */ #define GPIO_BASE (NRF_P0) #define UART_IRQN (UARTE0_UART0_IRQn) +#define SPI_SCKSEL (dev(bus)->PSEL.SCK) +#define SPI_MOSISEL (dev(bus)->PSEL.MOSI) +#define SPI_MISOSEL (dev(bus)->PSEL.MISO) /** @} */ #ifdef __cplusplus diff --git a/cpu/nrf52/periph/spi.c b/cpu/nrf52/periph/spi.c deleted file mode 100644 index bd7012a82af4..000000000000 --- a/cpu/nrf52/periph/spi.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 2015 Jan Wagner - * 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. - */ - -/** - * @ingroup cpu_nrf52 - * @{ - * - * @file - * @brief Implementation of the peripheral SPI interface - * - * @author Hauke Petersen - * @author Frank Holtz - * @author Jan Wagner - * - * @} - */ - -#include "cpu.h" -#include "mutex.h" -#include "periph/spi.h" -#include "periph_conf.h" - -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - -/* static port mapping */ -static NRF_SPI_Type *const spi[] = { -#if SPI_0_EN - SPI_0_DEV, -#endif -#if SPI_1_EN - SPI_1_DEV -#endif -}; - -/** - * @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) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - - spi_poweron(dev); - - /* disable the device -> nRF51822 reference 3.0 26.1.1 and 27.1*/ - spi[dev]->ENABLE = 0; - - switch (dev) { -#if SPI_0_EN - - case SPI_0: - /* disable TWI Interface */ - NRF_TWI0->ENABLE = 0; - break; -#endif -#if SPI_1_EN - - case SPI_1: - /* disable SPI Slave */ - NRF_SPIS1->ENABLE = 0; - /* disable TWI Interface */ - NRF_TWI1->ENABLE = 0; - break; -#endif - - default: - return -1; - } - - /* configure direction of used pins */ - spi_conf_pins(dev); - - /* configure SPI mode */ - switch (conf) { - case SPI_CONF_FIRST_RISING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Leading << 1); - break; - - case SPI_CONF_SECOND_RISING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveHigh << 2) | (SPI_CONFIG_CPHA_Trailing << 1); - break; - - case SPI_CONF_FIRST_FALLING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Leading << 1); - break; - - case SPI_CONF_SECOND_FALLING: - spi[dev]->CONFIG = (SPI_CONFIG_CPOL_ActiveLow << 2) | (SPI_CONFIG_CPHA_Trailing << 1); - break; - } - - /* select bus speed */ - switch (speed) { - case SPI_SPEED_100KHZ: /* 125 KHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K125; - break; - - case SPI_SPEED_400KHZ: /* 500 KHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_K500; - break; - - case SPI_SPEED_1MHZ: /* 1 MHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M1; - break; - - case SPI_SPEED_5MHZ: /* 4 MHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M4; - break; - - case SPI_SPEED_10MHZ: /* 8 MHz for this device */ - spi[dev]->FREQUENCY = SPI_FREQUENCY_FREQUENCY_M8; - break; - } - - /* finally enable the device */ - spi[dev]->ENABLE = 1; - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) -{ - /* This API is incompatible with nRF51 SPIS */ - return -1; -} - -int spi_conf_pins(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - - switch (dev) { -#if SPI_0_EN - - case SPI_0: - /* set pin direction */ - NRF_P0->DIRSET = (1 << SPI_0_PIN_MOSI) | (1 << SPI_0_PIN_SCK); - NRF_P0->DIRCLR = (1 << SPI_0_PIN_MISO); - /* select pins to be used by SPI */ - spi[dev]->PSELMOSI = SPI_0_PIN_MOSI; - spi[dev]->PSELMISO = SPI_0_PIN_MISO; - spi[dev]->PSELSCK = SPI_0_PIN_SCK; - break; -#endif -#if SPI_1_EN - - case SPI_1: - /* set pin direction */ - NRF_P0->DIRSET = (1 << SPI_1_PIN_MOSI) | (1 << SPI_1_PIN_SCK); - NRF_P0->DIRCLR = (1 << SPI_1_PIN_MISO); - /* select pins to be used by SPI */ - spi[dev]->PSELMOSI = SPI_1_PIN_MOSI; - spi[dev]->PSELMISO = SPI_1_PIN_MISO; - spi[dev]->PSELSCK = SPI_1_PIN_SCK; - break; -#endif - } - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - return spi_transfer_bytes(dev, &out, in, 1); -} - -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - - for (int i = 0; i < length; i++) { - char tmp = (out) ? out[i] : 0; - spi[dev]->EVENTS_READY = 0; - spi[dev]->TXD = (uint8_t)tmp; - - while (spi[dev]->EVENTS_READY != 1); - - tmp = (char)spi[dev]->RXD; - - if (in) { - in[i] = tmp; - } - } - - return length; -} - -int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in) -{ - spi_transfer_byte(dev, reg, 0); - return spi_transfer_byte(dev, out, in); -} - -int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length) -{ - spi_transfer_byte(dev, reg, 0); - return spi_transfer_bytes(dev, out, in, length); -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* spi slave is not implemented */ -} - -void spi_poweron(spi_t dev) -{ - if (dev < SPI_NUMOF) { - spi[dev]->POWER = 1; - } -} - -void spi_poweroff(spi_t dev) -{ - if (dev < SPI_NUMOF) { - spi[dev]->POWER = 0; - } -} - -#endif /* SPI_NUMOF */ diff --git a/cpu/nrf5x_common/include/periph_cpu_common.h b/cpu/nrf5x_common/include/periph_cpu_common.h index b22de8f0636f..dbb681aa8fc6 100644 --- a/cpu/nrf5x_common/include/periph_cpu_common.h +++ b/cpu/nrf5x_common/include/periph_cpu_common.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Freie Universität Berlin + * Copyright (C) 2015-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 @@ -47,6 +47,21 @@ extern "C" { */ #define GPIO_MODE(oe, ic, pr) (oe | (ic << 1) | (pr << 2)) +/** + * @brief No support for HW chip select... + */ +#define SPI_HWCS(x) (SPI_CS_UNDEF) + +/** + * @brief Declare needed shared SPI functions + * @{ + */ +#define PERIPH_SPI_NEEDS_INIT_CS +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE +#define PERIPH_SPI_NEEDS_TRANSFER_REG +#define PERIPH_SPI_NEEDS_TRANSFER_REGS +/** @} */ + #ifndef DOXYGEN /** * @brief Override GPIO modes @@ -106,6 +121,43 @@ typedef struct { uint8_t irqn; /**< IRQ number of the timer device */ } timer_conf_t; +/** + * @brief Override SPI mode values + * @{ + */ +#define HAVE_SPI_MODE_T +typedef enum { + SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = SPI_CONFIG_CPHA_Msk, /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = SPI_CONFIG_CPOL_Msk, /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = (SPI_CONFIG_CPOL_Msk | SPI_CONFIG_CPHA_Msk) /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +/** @} */ + +/** + * @brief Override SPI clock values + * @{ + */ +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = SPI_FREQUENCY_FREQUENCY_K125, /**< 100KHz */ + SPI_CLK_400KHZ = SPI_FREQUENCY_FREQUENCY_K500, /**< 400KHz */ + SPI_CLK_1MHZ = SPI_FREQUENCY_FREQUENCY_M1, /**< 1MHz */ + SPI_CLK_5MHZ = SPI_FREQUENCY_FREQUENCY_M4, /**< 5MHz */ + SPI_CLK_10MHZ = SPI_FREQUENCY_FREQUENCY_M8 /**< 10MHz */ +} spi_clk_t; +/** @} */ + +/** + * @brief SPI configuration values + */ +typedef struct { + NRF_SPI_Type *dev; /**< SPI device used */ + uint8_t sclk; /**< CLK pin */ + uint8_t mosi; /**< MOSI pin */ + uint8_t miso; /**< MISO pin */ +} spi_conf_t; + #ifdef __cplusplus } #endif diff --git a/cpu/nrf5x_common/periph/spi.c b/cpu/nrf5x_common/periph/spi.c new file mode 100644 index 000000000000..913f56e957d7 --- /dev/null +++ b/cpu/nrf5x_common/periph/spi.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2014-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. + */ + +/** + * @ingroup cpu_nrf5x_common + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Hauke Petersen + * @author Frank Holtz + * @author Jan Wagner + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +#ifdef SPI_NUMOF + +/** + * @brief array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline NRF_SPI_Type *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + /* initialize mutex */ + mutex_init(&locks[bus]); + /* initialize pins */ + spi_init_pins(bus); +} + +void spi_init_pins(spi_t bus) +{ + /* set pin direction */ + GPIO_BASE->DIRSET = ((1 << spi_config[bus].sclk) | + (1 << spi_config[bus].mosi)); + GPIO_BASE->DIRCLR = (1 << spi_config[bus].miso); + /* select pins for the SPI device */ + SPI_SCKSEL = spi_config[bus].sclk; + SPI_MOSISEL = spi_config[bus].mosi; + SPI_MISOSEL = spi_config[bus].miso; +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + mutex_lock(&locks[bus]); +#ifdef CPU_FAM_NRF51 + /* power on the bus (NRF51 only) */ + dev(bus)->POWER = 1; +#endif + /* configure bus */ + dev(bus)->CONFIG = mode; + dev(bus)->FREQUENCY = clk; + /* enable the bus */ + dev(bus)->ENABLE = 1; + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* power off everything */ + dev(bus)->ENABLE = 0; +#ifdef CPU_FAM_NRF51 + dev(bus)->POWER = 0; +#endif + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *in_buf = (uint8_t *)in; + uint8_t *out_buf = (uint8_t *)out; + + assert(out_buf || in_buf); + + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); + } + + for (int i = 0; i < (int)len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; + + dev(bus)->EVENTS_READY = 0; + dev(bus)->TXD = (uint8_t)tmp; + while (dev(bus)->EVENTS_READY != 1); + tmp = (uint8_t)dev(bus)->RXD; + + if (in_buf) { + in_buf[i] = tmp; + } + } + + if ((cs != SPI_CS_UNDEF) && (!cont)) { + gpio_set((gpio_t)cs); + } +} + +#endif /* SPI_NUMOF */ diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 721ca0da1ff7..954877d0b985 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -34,7 +34,8 @@ extern "C" { * @brief Use shared 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,15 +128,46 @@ typedef enum { } spi_mosipad_t; /** - * @brief Possible selections for SERCOM SPI clock mode (inspired by Arduino) + * @brief Override SPI modes + * @{ */ -typedef enum -{ - SERCOM_SPI_MODE_0 = 0, // CPOL : 0 | CPHA : 0 - SERCOM_SPI_MODE_1 = 1, // CPOL : 0 | CPHA : 1 - SERCOM_SPI_MODE_2 = 2, // CPOL : 1 | CPHA : 0 - SERCOM_SPI_MODE_3 = 3, // CPOL : 1 | CPHA : 1 -} sercom_spi_clockmode_t; +#define HAVE_SPI_MODE_T +typedef enum { + SPI_MODE_0 = 0x0, /**< CPOL=0, CPHA=0 */ + SPI_MODE_1 = 0x1, /**< CPOL=0, CPHA=1 */ + SPI_MODE_2 = 0x2, /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 = 0x3 /**< CPOL=1, CPHA=1 */ +} spi_mode_t; +/** @} */ + +/** + * @brief Override SPI clock speed values + * @{ + */ +#define HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = 100000U, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ = 400000U, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ = 1000000U, /**< drive the SPI bus with 1MHz */ + SPI_CLK_5MHZ = 5000000U, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ = 10000000U /**< drive the SPI bus with 10MHz */ +} spi_clk_t; +/** @} */ + +/** + * @brief SPI device configuration + */ +typedef struct { + SercomSpi *dev; /**< pointer to the used SPI device */ + gpio_t miso_pin; /**< used MISO pin */ + gpio_t mosi_pin; /**< used MOSI pin */ + gpio_t clk_pin; /**< used CLK pin */ + gpio_mux_t miso_mux; /**< alternate function for MISO pin (mux) */ + gpio_mux_t mosi_mux; /**< alternate function for MOSI pin (mux) */ + gpio_mux_t clk_mux; /**< alternate function for CLK pin (mux) */ + spi_misopad_t miso_pad; /**< pad to use for MISO line */ + spi_mosipad_t mosi_pad; /**< pad to use for MOSI and CLK line */ +} spi_conf_t; /** * @brief Set up alternate function (PMUX setting) for a PORT pin @@ -145,6 +177,18 @@ typedef enum */ void gpio_init_mux(gpio_t pin, gpio_mux_t mux); +/** + * @brief Return the numeric id of a SERCOM device derived from its address + * + * @param[in] sercom SERCOM device + * + * @return numeric id of the given SERCOM device + */ +static inline int sercom_id(void *sercom) +{ + return ((((uint32_t)sercom) >> 10) & 0x7) - 2; +} + #ifdef __cplusplus } #endif diff --git a/cpu/sam0_common/periph/spi.c b/cpu/sam0_common/periph/spi.c new file mode 100644 index 000000000000..65b78e78c3ee --- /dev/null +++ b/cpu/sam0_common/periph/spi.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014-2016 Freie Universität Berlin + * 2015 Kaspar Schleiser + * 2015 FreshTemp, LLC. + * + * 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_samd21 + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Thomas Eichinger + * @author Troels Hoffmeyer + * @author Hauke Petersen + * @author Joakim Nohlgård + * @author Kaspar Schleiser + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief Array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +/** + * @brief Shortcut for accessing the used SPI SERCOM device + */ +static inline SercomSpi *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +static inline void poweron(spi_t bus) +{ +#if defined(CPU_FAM_SAMD21) + PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(dev(bus))); +#elif defined(CPU_FAM_SAML21) + MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom_id(dev(bus))); +#endif +} + +static inline void poweroff(spi_t bus) +{ +#if defined(CPU_FAM_SAMD21) + PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(dev(bus))); +#elif defined(CPU_FAM_SAML21) + MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom_id(dev(bus))); +#endif +} + +void spi_init(spi_t bus) +{ + /* make sure given bus is good */ + assert(bus < SPI_NUMOF); + + /* initialize the device lock */ + mutex_init(&locks[bus]); + + /* configure pins and their muxes */ + spi_init_pins(bus); + + /* wake up device */ + poweron(bus); + + /* reset all device configuration */ + dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_SWRST; + while ((dev(bus)->CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) || + (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_SWRST)); + + /* configure base clock: using GLK GEN 0 */ +#if defined(CPU_FAM_SAMD21) + GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | + (SERCOM0_GCLK_ID_CORE + sercom_id(dev(bus)))); + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} +#elif defined(CPU_FAM_SAML21) + GCLK->PCHCTRL[SERCOM0_GCLK_ID_CORE + sercom_id(dev(bus))].reg = + (GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0); +#endif + + /* enable receiver and configure character size to 8-bit + * no synchronization needed, as SERCOM device is not enabled */ + dev(bus)->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN); + + /* put device back to sleep */ + poweroff(bus); +} + +void spi_init_pins(spi_t bus) +{ + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); + gpio_init(spi_config[bus].clk_pin, GPIO_OUT); + gpio_init_mux(spi_config[bus].miso_pin, spi_config[bus].miso_mux); + gpio_init_mux(spi_config[bus].mosi_pin, spi_config[bus].mosi_mux); + gpio_init_mux(spi_config[bus].clk_pin, spi_config[bus].clk_mux); +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + /* get exclusive access to the device */ + mutex_lock(&locks[bus]); + /* power on the device */ + poweron(bus); + + /* configure bus clock, in synchronous mode its calculated from + * BAUD.reg = (f_ref / (2 * f_bus) - 1) + * with f_ref := CLOCK_CORECLOCK as defined by the board */ + dev(bus)->BAUD.reg = (uint8_t)(((uint32_t)CLOCK_CORECLOCK) / (2 * clk) - 1); + + /* configure device to be master and set mode and pads, + * + * NOTE: we could configure the pads already during spi_init, but for + * efficiency reason we do that here, so we can do all in one single write + * to the CTRLA register */ + dev(bus)->CTRLA.reg = (SERCOM_SPI_CTRLA_MODE(0x3) | /* 0x3 -> master */ + SERCOM_SPI_CTRLA_DOPO(spi_config[bus].mosi_pad) | + SERCOM_SPI_CTRLA_DIPO(spi_config[bus].miso_pad) | + (mode << SERCOM_SPI_CTRLA_CPOL_Pos)); + /* also no synchronization needed here, as CTRLA is write-synchronized */ + + /* finally enable the device */ + dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; + while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {} + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and put it back to sleep */ + dev(bus)->CTRLA.reg &= ~(SERCOM_SPI_CTRLA_ENABLE); + while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {} + poweroff(bus); + /* release access to the device */ + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; + + assert(out || in); + + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); + } + + for (int i = 0; i < (int)len; i++) { + uint8_t tmp = (out_buf) ? out_buf[i] : 0; + while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_DRE)) {} + dev(bus)->DATA.reg = tmp; + while (!(dev(bus)->INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC)) {} + tmp = (uint8_t)dev(bus)->DATA.reg; + if (in_buf) { + in_buf[i] = tmp; + } + } + + if ((!cont) && (cs != SPI_CS_UNDEF)) { + gpio_set((gpio_t)cs); + } +} diff --git a/cpu/sam3/cpu.c b/cpu/sam3/cpu.c index aaa18578b67d..2b7ff7db4d06 100644 --- a/cpu/sam3/cpu.c +++ b/cpu/sam3/cpu.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /** * @brief Keys needed for editing certain PMC registers @@ -88,4 +89,7 @@ void cpu_init(void) PMC->PMC_MCKR = PMC_MCKR_CSS_PLLA_CLK; /* wait for master clock to be ready */ while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); + + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/sam3/include/periph_cpu.h b/cpu/sam3/include/periph_cpu.h index 4921a1c1c779..89b44b92c9a3 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,33 @@ typedef enum { GPIO_MUX_B = 1, /**< alternate function B */ } gpio_mux_t; +/** + * @brief Override default SPI modes + * @{ + */ +#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; +/** @} */ + +/** + * @brief Override default SPI clock values + * @{ + */ +#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 +184,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 a86f5e2fd65b..72f952e2aefe 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 */ diff --git a/cpu/samd21/cpu.c b/cpu/samd21/cpu.c index cef8383a0136..a4a80864c7f7 100644 --- a/cpu/samd21/cpu.c +++ b/cpu/samd21/cpu.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /** * @brief Configure clock sources and the cpu frequency @@ -107,4 +108,6 @@ void cpu_init(void) cortexm_init(); /* Initialise clock sources and generic clocks */ clk_init(); + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index 14ad374ebe15..97dc3a21407c 100644 --- a/cpu/samd21/include/periph_cpu.h +++ b/cpu/samd21/include/periph_cpu.h @@ -19,6 +19,8 @@ #ifndef CPU_PERIPH_H #define CPU_PERIPH_H +#include + #include "periph_cpu_common.h" #ifdef __cplusplus @@ -44,6 +46,13 @@ enum { */ #define GPIO_MODE(pr, ie, pe) (pr | (ie << 1) | (pe << 2)) +/** + * @brief Override SPI hardware chip select macro + * + * As of now, we do not support HW CS, so we always set it to a fixed value + */ +#define SPI_HWCS(x) (UINT_MAX - 1) + #ifndef DOXYGEN /** * @brief Override GPIO modes diff --git a/cpu/samd21/periph/spi.c b/cpu/samd21/periph/spi.c deleted file mode 100644 index f7eef079f677..000000000000 --- a/cpu/samd21/periph/spi.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2014 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_samd21 - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Thomas Eichinger - * @author Troels Hoffmeyer - * @author Hauke Petersen - * @author Joakim Nohlgård - * - * @} - */ - -#include "cpu.h" -#include "mutex.h" -#include "periph/gpio.h" -#include "periph/spi.h" -#include "periph_conf.h" -#include "board.h" -#define ENABLE_DEBUG (0) -#include "debug.h" - -#if SPI_0_EN || SPI_1_EN - -/** - * @brief Internal helper function to do the actual work for spi_poweroff - */ -static void _spi_poweroff(SercomSpi* spi_dev); - -/** - * @brief Internal helper function to do the actual work for spi_poweron - */ -static void _spi_poweron(SercomSpi* spi_dev); - -/** - * @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 -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - SercomSpi* spi_dev = 0; - uint8_t sercom_gclk_id = 0; - gpio_t pin_sclk = 0; - gpio_t pin_miso = 0; - gpio_t pin_mosi = 0; - gpio_mux_t mux_sclk = 0; - gpio_mux_t mux_miso = 0; - gpio_mux_t mux_mosi = 0; - spi_mosipad_t mosi_pad = 0; - spi_misopad_t miso_pad = 0; - uint32_t cpha = 0; - uint32_t cpol = 0; - uint32_t f_baud = 0; - switch (speed) - { - case SPI_SPEED_100KHZ: - f_baud = 100000; - break; - case SPI_SPEED_400KHZ: - f_baud = 400000; - break; - case SPI_SPEED_1MHZ: - f_baud = 1000000; - break; - case SPI_SPEED_5MHZ: -#if CLOCK_CORECLOCK >= 5000000 - f_baud = 5000000; - break; -#else - return -1; -#endif - case SPI_SPEED_10MHZ: -#if CLOCK_CORECLOCK >= 10000000 - f_baud = 10000000; - break; -#else - return -1; -#endif - } - switch (conf) - { - case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */ - cpha = 0; - cpol = 0; - break; - case SPI_CONF_SECOND_RISING: /**< first data bit is transacted on the second rising SCK edge */ - cpha = SERCOM_SPI_CTRLA_CPHA; - cpol = 0; - break; - case SPI_CONF_FIRST_FALLING: /**< first data bit is transacted on the first falling SCK edge */ - cpha = 0; - cpol = SERCOM_SPI_CTRLA_CPOL; - break; - case SPI_CONF_SECOND_FALLING: /**< first data bit is transacted on the second falling SCK edge */ - cpha = SERCOM_SPI_CTRLA_CPHA; - cpol = SERCOM_SPI_CTRLA_CPOL; - break; - } - switch (dev) - { -#if SPI_0_EN - case SPI_0: - spi_dev = &SPI_0_DEV; - sercom_gclk_id = SPI_0_GCLK_ID; - pin_sclk = SPI_0_SCLK; - mux_sclk = SPI_0_SCLK_MUX; - pin_miso = SPI_0_MISO; - mux_miso = SPI_0_MISO_MUX; - pin_mosi = SPI_0_MOSI; - mux_mosi = SPI_0_MOSI_MUX; - mosi_pad = SPI_0_MOSI_PAD; - miso_pad = SPI_0_MISO_PAD; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi_dev = &SPI_1_DEV; - sercom_gclk_id = SPI_1_GCLK_ID; - pin_sclk = SPI_1_SCLK; - mux_sclk = SPI_1_SCLK_MUX; - pin_miso = SPI_1_MISO; - mux_miso = SPI_1_MISO_MUX; - pin_mosi = SPI_1_MOSI; - mux_mosi = SPI_1_MOSI_MUX; - mosi_pad = SPI_1_MOSI_PAD; - miso_pad = SPI_1_MISO_PAD; - break; -#endif - default: - return -1; - } - - /* Use the same sequence as ArduinoCore - * - setup pins - * - disable SPI - * - init SPI (reset, init clock NVIC, CTRLA, CTRLB) - * - init cpha/cpol, BAUD.reg - * - enable SPI - */ - gpio_init(pin_miso, GPIO_IN_PD); - gpio_init_mux(pin_sclk, mux_sclk); - gpio_init_mux(pin_miso, mux_miso); - gpio_init_mux(pin_mosi, mux_mosi); - - /* Disable spi to write confs */ - _spi_poweroff(spi_dev); - - /* reset */ - // Setting the Software Reset bit to 1 - spi_dev->CTRLA.bit.SWRST = 1; - - // Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0 - while (spi_dev->CTRLA.bit.SWRST || spi_dev->SYNCBUSY.bit.SWRST) {} - - /* Turn on power manager for sercom */ - PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << (sercom_gclk_id - GCLK_CLKCTRL_ID_SERCOM0_CORE_Val)); - - /* Setup clock */ - /* SPI using CLK GEN 0 */ - GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | - GCLK_CLKCTRL_GEN_GCLK0 | - GCLK_CLKCTRL_ID(sercom_gclk_id)); - while (GCLK->STATUS.bit.SYNCBUSY) {} - - /* ???? init NVIC. Maybe not needed in master mode. */ - - /* Master mode */ - spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER; - while (spi_dev->SYNCBUSY.reg) {}// ???? not needed - - spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t)CLOCK_CORECLOCK) / (2 * f_baud) - 1); /* Synchronous mode*/ - - spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_DOPO(mosi_pad) - | SERCOM_SPI_CTRLA_DIPO(miso_pad) - | cpha - | cpol; - while (spi_dev->SYNCBUSY.reg) {} // ???? not needed - - /* datasize 0 => 8 bits */ - spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN); - while (spi_dev->SYNCBUSY.reg) {} // ???? Only wait for clear of spi_dev->SYNCBUSY.bit.CTRLB - - /* enable */ - _spi_poweron(spi_dev); - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char)) -{ - (void)dev; - (void)conf; - (void)cb; - /* TODO */ - assert(false); - return -1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - (void)dev; - (void)reset_val; - /* TODO */ - assert(false); -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - SercomSpi* spi_dev = 0; - char tmp; - - switch(dev) - { -#if SPI_0_EN - case SPI_0: - spi_dev = &(SPI_0_DEV); - break; -#endif -#if SPI_1_EN - case SPI_1: - spi_dev = &(SPI_1_DEV); - break; -#endif - } - - while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty*/ - spi_dev->DATA.bit.DATA = out; - - while (!spi_dev->INTFLAG.bit.DRE || !spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete*/ - tmp = (char)spi_dev->DATA.bit.DATA; - - if (in != NULL) - { - in[0] = tmp; - } - return 1; -} - -static void _spi_poweron(SercomSpi* spi_dev) -{ - if (spi_dev == NULL) { - return; - } - spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; - while (spi_dev->SYNCBUSY.bit.ENABLE) {} -} - -void spi_poweron(spi_t dev) -{ - switch(dev) { -#if SPI_0_EN - case SPI_0: - _spi_poweron(&SPI_0_DEV); - break; -#endif -#if SPI_1_EN - case SPI_1: - _spi_poweron(&SPI_1_DEV); - break; -#endif - } -} - -static void _spi_poweroff(SercomSpi* spi_dev) -{ - if (spi_dev == NULL) { - return; - } - spi_dev->CTRLA.bit.ENABLE = 0; /* Disable spi */ - while (spi_dev->SYNCBUSY.bit.ENABLE) {} -} - -void spi_poweroff(spi_t dev) -{ - switch(dev) { -#if SPI_0_EN - case SPI_0: - _spi_poweroff(&SPI_0_DEV); - break; -#endif -#if SPI_1_EN - case SPI_1: - _spi_poweroff(&SPI_1_DEV); - break; -#endif - } -} - -#endif /* SPI_0_EN || SPI_1_EN */ diff --git a/cpu/samd21/periph/uart.c b/cpu/samd21/periph/uart.c index a325b2e9e776..2d17cde60525 100644 --- a/cpu/samd21/periph/uart.c +++ b/cpu/samd21/periph/uart.c @@ -57,7 +57,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) uart_ctx[uart].arg = arg; /* configure interrupts and enable RX interrupt */ _uart(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC; - NVIC_EnableIRQ(SERCOM0_IRQn + _sercom_id(_uart(uart))); + NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(_uart(uart))); return UART_OK; } @@ -112,18 +112,18 @@ void uart_write(uart_t uart, const uint8_t *data, size_t len) void uart_poweron(uart_t uart) { - PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart))); + PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart))); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | - (SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) << + (SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) << GCLK_CLKCTRL_ID_Pos); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} } void uart_poweroff(uart_t uart) { - PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart))); - GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) << + PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart))); + GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) << GCLK_CLKCTRL_ID_Pos); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} } diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index 75a945165fff..e5ea27fa2c9f 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -19,6 +19,7 @@ */ #include "cpu.h" +#include "periph/init.h" static void _gclk_setup(int gclk, uint32_t reg) { @@ -77,4 +78,7 @@ void cpu_init(void) */ SUPC->BOD33.bit.ENABLE=0; #endif + + /* trigger static peripheral initialization */ + periph_init(); } diff --git a/cpu/saml21/periph/spi.c b/cpu/saml21/periph/spi.c deleted file mode 100644 index 56ed843df836..000000000000 --- a/cpu/saml21/periph/spi.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (C) 2014 Freie Universität Berlin - * 2015 Kaspar Schleiser - * FreshTemp, LLC. - * - * 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_samd21 - * @{ - * - * @file spi.c - * @brief Low-level SPI driver implementation - * - * @author Thomas Eichinger - * @author Troels Hoffmeyer - * @author Hauke Petersen - * @author Joakim Nohlgård - * @author Kaspar Schleiser - * - * @} - */ - -#include "cpu.h" -#include "mutex.h" -#include "periph/gpio.h" -#include "periph/spi.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -#if SPI_0_EN || SPI_1_EN - -/** - * @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 spi_saml21_pin { - uint32_t pin; - uint32_t pmux; -} spi_saml21_pin_t; - -typedef struct spi_saml21 { - SercomSpi* dev; - uint32_t mclk; - uint32_t gclk_id; - - spi_saml21_pin_t sclk; - spi_saml21_pin_t miso; - spi_saml21_pin_t mosi; - - int dipo; - int dopo; -} spi_saml21_t; - -static const spi_saml21_t spi[] = { -#if SPI_0_EN - /* SPI device */ /* MCLK flag */ /* GLCK id */ /* SCLK */ /* MISO */ /* MOSI */ /* dipo+dopo */ - { &(SERCOM0->SPI), MCLK_APBCMASK_SERCOM0, SERCOM0_GCLK_ID_CORE, { GPIO_PIN(PA,7), 3 }, { GPIO_PIN(PA,4), 3 }, { GPIO_PIN(PA,6), 3 }, 0, 1 } -#endif -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - SercomSpi* spi_dev = spi[dev].dev; - - uint8_t dopo = 0; - uint8_t dipo = 0; - uint8_t cpha = 0; - uint8_t cpol = 0; - uint32_t f_baud = 0; - - switch(speed) - { - case SPI_SPEED_100KHZ: - f_baud = 100000; - break; - case SPI_SPEED_400KHZ: - f_baud = 400000; - break; - case SPI_SPEED_1MHZ: - f_baud = 1000000; - break; - case SPI_SPEED_5MHZ: - return -1; - case SPI_SPEED_10MHZ: - return -1; - } - - switch(conf) - { - case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */ - cpha = 0; - cpol = 0; - break; - case SPI_CONF_SECOND_RISING:/**< first data bit is transacted on the second rising SCK edge */ - cpha = 1; - cpol = 0; - break; - case SPI_CONF_FIRST_FALLING:/**< first data bit is transacted on the first falling SCK edge */ - cpha = 0; - cpol = 1; - break; - case SPI_CONF_SECOND_FALLING:/**< first data bit is transacted on the second falling SCK edge */ - cpha = 1; - cpol = 1; - break; - } - - /* Enable sercom4 in power manager */ - MCLK->APBCMASK.reg |= spi[dev].mclk; - - /* Setup clock */ - GCLK->PCHCTRL[ spi[dev].gclk_id ].reg = - GCLK_PCHCTRL_CHEN | - GCLK_PCHCTRL_GEN_GCLK0; - - while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN)) {} - - /* SCLK+MOSI = output */ - gpio_init(spi[dev].sclk.pin, GPIO_OUT); - gpio_init(spi[dev].mosi.pin, GPIO_OUT); - /* MISO = input */ - gpio_init(spi[dev].miso.pin, GPIO_IN); - - /* - * Set alternate funcion (PMUX) for our ports. - */ - gpio_init_mux(spi[dev].sclk.pin, spi[dev].sclk.pmux); - gpio_init_mux(spi[dev].miso.pin, spi[dev].miso.pmux); - gpio_init_mux(spi[dev].mosi.pin, spi[dev].mosi.pmux); - - /* pin pad mapping */ - dipo = spi[dev].dipo; - dopo = spi[dev].dopo; - - /* Disable spi to write config */ - spi_dev->CTRLA.bit.ENABLE = 0; - while (spi_dev->SYNCBUSY.reg) {} - - /* setup baud */ - spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t) GCLK_REF) / (2 * f_baud) - 1); /* Syncronous mode*/ - - spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3) /* 0x2 = slave 0x3 = master */ - | (SERCOM_SPI_CTRLA_DOPO(dopo)) - | (SERCOM_SPI_CTRLA_DIPO(dipo)) - | (cpha << SERCOM_SPI_CTRLA_CPHA_Pos) - | (cpol << SERCOM_SPI_CTRLA_CPOL_Pos); - - while (spi_dev->SYNCBUSY.reg) {} - spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN); - while(spi_dev->SYNCBUSY.reg) {} - spi_poweron(dev); - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char)) -{ - /* TODO */ - return -1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* TODO*/ -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - SercomSpi* spi_dev = spi[dev].dev; - - while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty */ - spi_dev->DATA.bit.DATA = out; - - if (in) - { - while (!spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete */ - *in = spi_dev->DATA.bit.DATA; - } - else - { - /* clear input byte even if we're not interested */ - spi_dev->DATA.bit.DATA; - } - return 1; -} - -void spi_poweron(spi_t dev) -{ - SercomSpi* spi_dev = spi[dev].dev; - spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; - while(spi_dev->SYNCBUSY.bit.ENABLE) {} -} - -void spi_poweroff(spi_t dev) -{ - SercomSpi* spi_dev = spi[dev].dev; - spi_dev->CTRLA.bit.ENABLE = 0; - while(spi_dev->SYNCBUSY.bit.ENABLE) {} -} - -#endif /* SPI_0_EN || SPI_1_EN */ diff --git a/cpu/stm32_common/dist/spi_divtable/Makefile b/cpu/stm32_common/dist/spi_divtable/Makefile new file mode 100644 index 000000000000..e5b546197292 --- /dev/null +++ b/cpu/stm32_common/dist/spi_divtable/Makefile @@ -0,0 +1,12 @@ +NAME = spi_divtable +CC = gcc +CFLAGS = -std=c99 -Wall +SRC = $(wildcard *.c) + +.PHONY: all clean + +all: + $(CC) $(CFLAGS) -o $(NAME) $(SRC) + +clean: + rm -f $(NAME) diff --git a/cpu/stm32_common/dist/spi_divtable/spi_divtable.c b/cpu/stm32_common/dist/spi_divtable/spi_divtable.c new file mode 100644 index 000000000000..70eed10901c5 --- /dev/null +++ b/cpu/stm32_common/dist/spi_divtable/spi_divtable.c @@ -0,0 +1,105 @@ +/* + * Copyright (C) 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. + */ + +/** + * @brief Compute SPI clock scaler values for STM32x CPUs + * + * This helper tool calculates the needed SPI scaler values for the APBx buses. + * It outputs the values for the possible SPI clock speeds based on the clock + * speeds of the APB1 and the APB2 bus. + * + * @author Hauke Petersen + * + * @} + */ + +#include +#include +#include + + +static int targets[] = { 100000, 400000, 1000000, 5000000, 10000000 }; + +/** + * @brief Find the best fitting divisor value base on target and APB clock + * + * The SPI bus clock speed is calculated as follows: + * + * clk_bus = clk_apb / 2 ^ (x + 1) + * + * In this function we will try to find the x-value, that brings clk_bus as + * close as possible to the value given in @p target. + * + * @param[in] bus clock speed of the given APB bus + * @param[in] target targeted SPI clock speed + * + * @return the closes divisor value to be used in the clock config register + */ +static int find_best(int bus, int target) +{ + int br = -1; + int tmp = bus; + + do { + // printf("b: x: %i - tmp: %i\n", br, tmp); + ++br; + tmp /= 2; + if (tmp == target) { + return br; + } + // printf("a: x: %i - tmp: %i\n", br, tmp); + // printf(" (tmp - target):%i\n", (tmp - target)); + } while ((tmp - target > 0) && (br < 7)); + + int old = tmp * 2; + // printf("(target - tmp):%i, (old - target): %i\n", (target - tmp), (old - target)); + + if ((target - tmp) > (old - target)) { + return (br - 1); + } + return br; +} + +static int real_clk(int bus, int br) +{ + return bus / (2 << br); +} + +int main(int argc, char **argv) +{ + int tnum = sizeof(targets) / sizeof(targets[0]); + int apb[2]; + + if (argc != 3) { + printf("usage: %s (in Hz)\n", argv[0]); + return 1; + } + + apb[0] = atoi(argv[1]); /* APB1 */ + apb[1] = atoi(argv[2]); /* APB2 */ + + if ((apb[0] <= 0) || (apb[1] <= 0)) { + puts("error: invalid APB clock speed values"); + return 1; + } + + printf("static const uint8_t spi_divtable[2][%i] = {\n", tnum); + + for (int bus = 0; bus < (sizeof(apb) / sizeof(apb[0])); bus ++) { + printf(" { /* for APB%i @ %iHz */\n", (bus + 1), apb[bus]); + for (int t = 0; t < tnum; t++) { + int br = find_best(apb[bus], targets[t]); + printf(" %i%c /* -> %iHz */\n", + br, ((t < (tnum - 1)) ? ',' : ' '), real_clk(apb[bus], br)); + } + printf(" }%c\n", ((bus == 0) ? ',' : ' ')); + } + puts("};"); + + return 0; +} diff --git a/cpu/stm32_common/include/periph_cpu_common.h b/cpu/stm32_common/include/periph_cpu_common.h index c2040ad6b765..2422473b0379 100644 --- a/cpu/stm32_common/include/periph_cpu_common.h +++ b/cpu/stm32_common/include/periph_cpu_common.h @@ -39,7 +39,7 @@ extern "C" { * @brief Use the shared SPI functions * @{ */ -#define PERIPH_SPI_NEEDS_TRANSFER_BYTES +#define PERIPH_SPI_NEEDS_TRANSFER_BYTE #define PERIPH_SPI_NEEDS_TRANSFER_REG #define PERIPH_SPI_NEEDS_TRANSFER_REGS /** @} */ @@ -89,6 +89,22 @@ typedef uint32_t gpio_t; */ #define GPIO_PIN(x, y) ((GPIOA_BASE + (x << 10)) | y) +/** + * @brief Define a magic number that tells us to use hardware chip select + * + * We use a random value here, that does clearly differentiate from any possible + * GPIO_PIN(x) value. + */ +#define SPI_HWCS_MASK (0xffffff00) + +/** + * @brief Override the default SPI hardware chip select access macro + * + * Since the CPU does only support one single hardware chip select line, we can + * detect the usage of non-valid lines by comparing to SPI_HWCS_VALID. + */ +#define SPI_HWCS(x) (SPI_HWCS_MASK | x) + /** * @brief Available MUX values for configuring a pin's alternate function */ @@ -169,6 +185,22 @@ typedef struct { #endif } uart_conf_t; +/** + * @brief Structure for SPI configuration data + */ +typedef struct { + SPI_TypeDef *dev; /**< SPI device base register address */ + gpio_t mosi_pin; /**< MOSI pin */ + gpio_t miso_pin; /**< MISO pin */ + gpio_t sclk_pin; /**< SCLK pin */ + gpio_t cs_pin; /**< HWCS pin, set to GPIO_UNDEF if not mapped */ +#ifndef CPU_FAM_STM32F1 + gpio_af_t af; /**< pin alternate function */ +#endif + uint32_t rccmask; /**< bit in the RCC peripheral enable register */ + uint8_t apbbus; /**< APBx bus the device is connected to */ +} spi_conf_t; + /** * @brief Get the actual bus clock frequency for the APB buses * diff --git a/cpu/stm32_common/periph/spi.c b/cpu/stm32_common/periph/spi.c new file mode 100644 index 000000000000..60f0a8592454 --- /dev/null +++ b/cpu/stm32_common/periph/spi.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences + * 2014-2017 Freie Universität Berlin + * 2016 OTA keys S.A. + * + * 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_stm32_common + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Peter Kietzmann + * @author Fabian Nack + * @author Hauke Petersen + * @author Vincent Dupont + * @author Joakim Nohlgård + * @author Thomas Eichinger + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +/* Remove this ugly guard once we selectively build the periph drivers */ +#ifdef SPI_NUMOF + +/** + * @brief Number of bits to shift the BR value in the CR1 register + */ +#define BR_SHIFT (3U) + +/** + * @brief Allocate one lock per SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline SPI_TypeDef *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + /* initialize device lock */ + mutex_init(&locks[bus]); + /* trigger pin initialization */ + spi_init_pins(bus); + + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + /* reset configuration */ + dev(bus)->CR1 = 0; +#ifdef SPI_I2SCFGR_I2SE + dev(bus)->I2SCFGR = 0; +#endif + /* configure SPI for 8-bit data width */ +#ifdef SPI_CR2_FRXTH + dev(bus)->CR2 = (SPI_CR2_FRXTH | SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2); +#else + dev(bus)->CR2 = 0; +#endif + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); +} + +void spi_init_pins(spi_t bus) +{ +#ifdef CPU_FAM_STM32F1 + gpio_init_af(spi_config[bus].sclk_pin, GPIO_AF_OUT_PP); + gpio_init_af(spi_config[bus].mosi_pin, GPIO_AF_OUT_PP); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); +#else + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].sclk_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af); +#endif +} + +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + if (bus >= SPI_NUMOF) { + return SPI_NODEV; + } + if (cs == SPI_CS_UNDEF || + (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) { + return SPI_NOCS; + } + + if (cs == SPI_HWCS_MASK) { + if (spi_config[bus].cs_pin == GPIO_UNDEF) { + return SPI_NOCS; + } +#ifdef CPU_FAM_STM32F1 + gpio_init_af(spi_config[bus].cs_pin, GPIO_AF_OUT_PP); +#else + gpio_init(spi_config[bus].cs_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af); +#endif + } + else { + gpio_init((gpio_t)cs, GPIO_OUT); + gpio_set((gpio_t)cs); + } + + return SPI_OK; +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ)); + + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable SPI device clock */ + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + /* enable device */ + uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; + dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR); + if (cs != SPI_HWCS_MASK) { + dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); + } + else { + dev(bus)->CR2 |= (SPI_CR2_SSOE); + } + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and release lock */ + dev(bus)->CR1 = 0; + dev(bus)->CR2 &= ~(SPI_CR2_SSOE); + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *inbuf = (uint8_t *)in; + uint8_t *outbuf = (uint8_t *)out; + + /* make sure at least one input or one output buffer is given */ + assert(outbuf || inbuf); + + /* we need to recast the data register to uint_8 to force 8-bit access */ + volatile uint8_t *DR = (volatile uint8_t*)&(dev(bus)->DR); + + /* active the given chip select line */ + dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */ + if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) { + gpio_clear((gpio_t)cs); + } + + /* transfer data, use shortpath if only sending data */ + if (!inbuf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + *DR = outbuf[i]; + } + /* wait until everything is finished and empty the receive buffer */ + while (dev(bus)->SR & SPI_SR_BSY) {} + while (dev(bus)->SR & SPI_SR_RXNE) { + dev(bus)->DR; /* we might just read 2 bytes at once here */ + } + } + else if (!outbuf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + *DR = 0; + while (!(dev(bus)->SR & SPI_SR_RXNE)); + inbuf[i] = *DR; + } + } + else { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + *DR = outbuf[i]; + while (!(dev(bus)->SR & SPI_SR_RXNE)); + inbuf[i] = *DR; + } + } + + /* make sure the transfer is completed before continuing, see reference + * manual(s) -> section 'Disabling the SPI' */ + while (!(dev(bus)->SR & SPI_SR_TXE)) {} + while (dev(bus)->SR & SPI_SR_BSY) {} + + /* release the chip select if not specified differently */ + if ((!cont) && (cs != SPI_CS_UNDEF)) { + dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */ + if (cs != SPI_HWCS_MASK) { + gpio_set((gpio_t)cs); + } + } +} + +#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f0/cpu.c b/cpu/stm32f0/cpu.c index 557176afa50a..88884d123cbf 100644 --- a/cpu/stm32f0/cpu.c +++ b/cpu/stm32f0/cpu.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /* Check the source to be used for the PLL */ #if defined(CLOCK_HSI) && defined(CLOCK_HSE) @@ -54,6 +55,8 @@ void cpu_init(void) cortexm_init(); /* initialize the clock system */ clock_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/stm32f0/periph/spi.c b/cpu/stm32f0/periph/spi.c deleted file mode 100644 index 4bfce9ba455f..000000000000 --- a/cpu/stm32f0/periph/spi.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (C) 2014 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_stm32f0 - * @{ - * - * @file - * @brief Low-level GPIO driver implementation - * - * @author Peter Kietzmann - * @author Hauke Petersen - * @author Fabian Nack - * @author Joakim Nohlgård - * - * @} - */ - -#include "cpu.h" -#include "board.h" -#include "mutex.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 -#if SPI_2_EN - [SPI_2] = MUTEX_INIT -#endif -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - SPI_TypeDef *spi; - - /* power on the SPI device */ - spi_poweron(dev); - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = SPI_0_DEV; - SPI_0_PORT_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - spi = SPI_1_DEV; - SPI_1_PORT_CLKEN(); - break; -#endif - default: - return -1; - } - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /* reset SPI configuration registers */ - spi->CR1 = 0; - spi->CR2 = 0; - spi->I2SCFGR = 0; /* this makes sure SPI mode is selected */ - - /* configure bus clock speed */ - switch (speed) { - case SPI_SPEED_100KHZ: - spi->CR1 |= (7 << 3); /* actual clock: 187.5KHz (lowest possible) */ - break; - case SPI_SPEED_400KHZ: - spi->CR1 |= (6 << 3); /* actual clock: 375KHz */ - break; - case SPI_SPEED_1MHZ: - spi->CR1 |= (4 << 3); /* actual clock: 1.5MHz */ - break; - case SPI_SPEED_5MHZ: - spi->CR1 |= (2 << 3); /* actual clock: 6MHz */ - break; - case SPI_SPEED_10MHZ: - spi->CR1 |= (1 << 3); /* actual clock 12MHz */ - } - - /* select clock polarity and clock phase */ - spi->CR1 |= conf; - /* select master mode */ - spi->CR1 |= SPI_CR1_MSTR; - /* the NSS (chip select) is managed purely by software */ - spi->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; - /* set data-size to 8-bit */ - spi->CR2 |= (0x7 << 8); - /* set FIFO threshold to set RXNE when 8 bit are received */ - spi->CR2 |= SPI_CR2_FRXTH; - /* enable the SPI device */ - spi->CR1 |= SPI_CR1_SPE; - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) -{ - /* due to issues with the send buffer, the master mode is not (yet) supported */ - return -1; -} - -int spi_conf_pins(spi_t dev) -{ - GPIO_TypeDef *port; - int pin[3]; /* 3 pins: sck, miso, mosi */ - int af = 0; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - port = SPI_0_PORT; - pin[0] = SPI_0_PIN_SCK; - pin[1] = SPI_0_PIN_MISO; - pin[2] = SPI_0_PIN_MOSI; - af = SPI_0_PIN_AF; - break; -#endif -#if SPI_1_EN - case SPI_1: - port = SPI_1_PORT; - pin[0] = SPI_1_PIN_SCK; - pin[1] = SPI_1_PIN_MISO; - pin[2] = SPI_1_PIN_MOSI; - af = SPI_1_PIN_AF; - break; -#endif - default: - return -1; - } - - /* configure pins for their correct alternate function */ - for (int i = 0; i < 3; i++) { - port->MODER &= ~(3 << (pin[i] * 2)); - port->MODER |= (2 << (pin[i] * 2)); - port->OSPEEDR |= (3 << (pin[i] * 2)); - int hl = (pin[i] < 8) ? 0 : 1; - port->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4)); - port->AFR[hl] |= (af << ((pin[i] - (hl * 8)) * 4)); - } - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - char tmp; - SPI_TypeDef *spi = 0; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = SPI_0_DEV; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi = SPI_1_DEV; - break; -#endif - default: - return 0; - } - - /* wait for an eventually previous byte to be readily transferred */ - while(!(spi->SR & SPI_SR_TXE)) {} - /* put next byte into the output register */ - *((volatile uint8_t *)(&spi->DR)) = (uint8_t)out; - /* wait until the current byte was successfully transferred */ - while(!(spi->SR & SPI_SR_RXNE)) {} - /* read response byte to reset flags */ - tmp = *((volatile uint8_t *)(&spi->DR)); - /* 'return' response byte if wished for */ - if (in) { - *in = tmp; - } - - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* slave mode is not (yet) supported */ -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_CLKEN(); - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while (SPI_0_DEV->SR & SPI_SR_BSY) {} - SPI_0_CLKDIS(); - break; -#endif -#if SPI_1_EN - case SPI_1: - while (SPI_1_DEV->SR & SPI_SR_BSY) {} - SPI_1_CLKDIS(); - break; -#endif - } -} - -#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f0/periph/spi.cold b/cpu/stm32f0/periph/spi.cold new file mode 100644 index 000000000000..894e4603ff26 --- /dev/null +++ b/cpu/stm32f0/periph/spi.cold @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2014-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. + */ + +/** + * @ingroup cpu_stm32f0 + * @{ + * + * @file + * @brief Low-level GPIO driver implementation + * + * @author Peter Kietzmann + * @author Hauke Petersen + * @author Fabian Nack + * @author Joakim Nohlgård + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Remove this ugly guard once we selectively build the periph drivers */ +#ifdef SPI_NUMOF + +/** + * @brief Number of bits to shift the BR value in the CR1 register + */ +#define BR_SHIFT (3U) + +/** + * @brief Array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline SPI_TypeDef *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + /* initialize device lock */ + mutex_lock(&locks[bus]); + /* trigger pin initialization */ + spi_init_pins(bus); +} + +void spi_init_pins(spi_t bus) +{ + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].sclk_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af); +} + +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + if (bus >= SPI_NUMOF) { + return SPI_NODEV; + } + if (cs == SPI_CS_UNDEF || + (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) { + return SPI_NOCS; + } + + if (cs == SPI_HWCS_MASK) { + if (spi_config[bus].cs_pin == GPIO_UNDEF) { + return SPI_NOCS; + } + gpio_init(spi_config[bus].cs_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af); + } + else { + gpio_init((gpio_t)cs, GPIO_OUT); + gpio_set((gpio_t)cs); + } + + return SPI_OK; +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ)); + + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable SPI device clock */ + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + /* enable device */ + uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; + dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR); + if (cs != SPI_HWCS_MASK) { + dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); + } + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and release lock */ + dev(bus)->CR1 = 0; + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *inbuf = (uint8_t *)in; + uint8_t *outbuf = (uint8_t *)out; + + /* make sure at least one input or one output buffer is given */ + assert(outbuf || inbuf); + + /* active the given chip select line */ + dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */ + if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) { + gpio_clear((gpio_t)cs); + } + + /* transfer data, use shortpath if only sending data */ + if (!inbuf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = outbuf[i]; + } + /* wait until everything is finished and empty the receive buffer */ + while (dev(bus)->SR & SPI_SR_BSY) {} + dev(bus)->DR; + } + else { + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (outbuf) ? outbuf[i] : 0; + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = tmp; + while (!(dev(bus)->SR & SPI_SR_RXNE)); + inbuf[i] = dev(bus)->DR; + } + } + + /* release the chip select if not specified differently */ + if ((!cont) && (cs != SPI_CS_UNDEF)) { + dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */ + if (cs != SPI_HWCS_MASK) { + gpio_set((gpio_t)cs); + } + } +} + +#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f1/cpu.c b/cpu/stm32f1/cpu.c index b611b228cf29..c2d465a64054 100644 --- a/cpu/stm32f1/cpu.c +++ b/cpu/stm32f1/cpu.c @@ -27,6 +27,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /* Configuration of flash access cycles */ #if CLOCK_CORECLOCK <= 24000000 @@ -103,6 +104,8 @@ void cpu_init(void) cortexm_init(); /* initialize system clocks */ clk_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/stm32f1/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h index 035eec70f4a4..b1e7f3642296 100644 --- a/cpu/stm32f1/include/periph_cpu.h +++ b/cpu/stm32f1/include/periph_cpu.h @@ -31,11 +31,14 @@ extern "C" { #define ADC_DEVS (2U) /** - * @brief declare needed generic SPI functions - * @{ + * @brief All timers for the STM32F1 have 4 CC channels */ -#undef PERIPH_SPI_NEEDS_TRANSFER_BYTES -#define PERIPH_SPI_NEEDS_TRANSFER_BYTE +#define TIMER_CHANNELS (4U) + +/** + * @brief All timers have a width of 16-bit + */ +#define TIMER_MAXVAL (0xffff) /** * @brief Generate GPIO mode bitfields @@ -48,6 +51,11 @@ extern "C" { */ #define GPIO_MODE(mode, cnf, odr) (mode | (cnf << 2) | (odr << 4)) +/** + * @brief Define the number of available PM modes + */ +#define PM_NUM_MODES (2U) + #ifndef DOXYGEN /** * @brief Override GPIO mode options @@ -123,8 +131,6 @@ typedef struct { uint8_t chan; /**< DAC device used for this line */ } dac_conf_t; -#define PM_NUM_MODES (2U) - #ifdef __cplusplus } #endif diff --git a/cpu/stm32f1/periph/spi.c b/cpu/stm32f1/periph/spi.c deleted file mode 100644 index 005e547dadc6..000000000000 --- a/cpu/stm32f1/periph/spi.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Copyright (C) 2014 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_stm32f1 - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Thomas Eichinger - * @author Fabian Nack - * @author Hauke Petersen - * @author Joakim Nohlgård - * - * @} - */ - -#include "cpu.h" -#include "mutex.h" -#include "periph/gpio.h" -#include "periph/spi.h" -#include "periph_conf.h" -#include "board.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* guard file in case no SPI device is defined */ -#if SPI_0_EN || SPI_1_EN || SPI_2_EN - -/** - * @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 -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - SPI_TypeDef *spi; - uint16_t br_div; - uint8_t bus_div; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = SPI_0_DEV; - bus_div = SPI_0_BUS_DIV; - SPI_0_CLKEN(); - break; -#endif - -#if SPI_1_EN - case SPI_1: - spi = SPI_1_DEV; - bus_div = SPI_1_BUS_DIV; - SPI_1_CLKEN(); - break; -#endif - -#if SPI_2_EN - case SPI_2: - spi = SPI_2_DEV; - bus_div = SPI_2_BUS_DIV; - SPI_2_CLKEN(); - break; -#endif - default: - return -1; - } - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /* configure SPI bus speed */ - switch (speed) { - case SPI_SPEED_10MHZ: - br_div = 0x01 + bus_div; /* actual speed: 9MHz */ - break; - case SPI_SPEED_5MHZ: - br_div = 0x02 + bus_div; /* actual speed: 4.5MHz */ - break; - case SPI_SPEED_1MHZ: - br_div = 0x04 + bus_div; /* actual speed: 1.1MHz */ - break; - case SPI_SPEED_400KHZ: - br_div = 0x05 + bus_div; /* actual speed: 560kHz */ - break; - case SPI_SPEED_100KHZ: - br_div = 0x07; /* actual speed: 280kHz on APB2, 140KHz on APB1 */ - break; - default: - return -2; - } - - /* set up SPI */ - spi->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR | (conf & 0x3) | (br_div << 3); - spi->I2SCFGR &= 0xF7FF; /* select SPI mode */ - spi->CRCPR = 0x7; /* reset CRC polynomial */ - /* enable the SPI device */ - spi->CR1 |= SPI_CR1_SPE; - - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char)) -{ - (void) dev; - (void) conf; - (void) cb; - /* TODO */ - return -1; -} - -int spi_conf_pins(spi_t dev) -{ - gpio_t mosi, miso, clk; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - clk = SPI_0_CLK_PIN; - mosi = SPI_0_MOSI_PIN; - miso = SPI_0_MISO_PIN; - break; -#endif - -#if SPI_1_EN - case SPI_1: - clk = SPI_1_CLK_PIN; - mosi = SPI_1_MOSI_PIN; - miso = SPI_1_MISO_PIN; - break; -#endif - -#if SPI_2_EN - case SPI_2: - clk = SPI_2_CLK_PIN; - mosi = SPI_2_MOSI_PIN; - miso = SPI_2_MISO_PIN; - break; -#endif - default: - return -1; - } - - /* configure pins for alternate function input (MISO) or output (MOSI, CLK) */ - gpio_init_af(clk, GPIO_AF_OUT_PP); - gpio_init_af(mosi, GPIO_AF_OUT_PP); - gpio_init(miso, GPIO_IN); - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) -{ - - SPI_TypeDef *spi; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = SPI_0_DEV; - break; -#endif - -#if SPI_1_EN - case SPI_1: - spi = SPI_1_DEV; - break; -#endif - -#if SPI_2_EN - case SPI_2: - spi = SPI_2_DEV; - break; -#endif - default: - return -1; - } - - if(!in){ - for (unsigned i = 0; i < length; i++) { - while (!(spi->SR & SPI_SR_TXE)) {} - spi->DR = (uint8_t)out[i]; - } - /* SPI busy */ - while ((spi->SR & SPI_SR_BSY)) {} - spi->DR; - } - else if(!out) { - for (unsigned i = 0; i < length; i++) { - spi->DR = 0; - while (!(spi->SR & SPI_SR_RXNE)) {} - in[i] = (char)spi->DR; - } - } - else { - for (unsigned i = 0; i < length; i++) { - while (!(spi->SR & SPI_SR_TXE)) {} - spi->DR = out[i]; - while (!(spi->SR & SPI_SR_RXNE)) {} - in[i] = (char)spi->DR; - } - } - -#if ENABLE_DEBUG - if (in != NULL) { - DEBUG("\nSPI: transferred %i Bytes\n", length); - } -#endif /*ENABLE_DEBUG */ - - return length; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - (void) dev; - (void) reset_val; - /* slave mode not implemented, yet */ -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - SPI_0_DEV->CR1 |= SPI_CR1_SPE; /* turn SPI peripheral on */ - break; -#endif - -#if SPI_1_EN - case SPI_1: - SPI_1_CLKEN(); - SPI_1_DEV->CR1 |= SPI_CR1_SPE; /* turn SPI peripheral on */ - break; -#endif - -#if SPI_2_EN - case SPI_2: - SPI_2_CLKEN(); - SPI_2_DEV->CR1 |= SPI_CR1_SPE; /* turn SPI peripheral on */ - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while ((SPI_0_DEV->SR & SPI_SR_BSY)) {} - SPI_0_DEV->CR1 &= ~(SPI_CR1_SPE); /* turn SPI peripheral off */ - SPI_0_CLKDIS(); - break; -#endif - -#if SPI_1_EN - case SPI_1: - while ((SPI_1_DEV->SR & SPI_SR_BSY)) {} - SPI_1_DEV->CR1 &= ~(SPI_CR1_SPE); /* turn SPI peripheral off */ - SPI_1_CLKDIS(); - break; -#endif - -#if SPI_2_EN - case SPI_2: - while ((SPI_2_DEV->SR & SPI_SR_BSY)) {} - SPI_2_DEV->CR1 &= ~(SPI_CR1_SPE); /* turn SPI peripheral off */ - SPI_2_CLKDIS(); - break; -#endif - } -} - -#endif /* SPI_0_EN */ diff --git a/cpu/stm32f1/periph/spi.cold b/cpu/stm32f1/periph/spi.cold new file mode 100644 index 000000000000..9fb51dabe8a8 --- /dev/null +++ b/cpu/stm32f1/periph/spi.cold @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2014-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. + */ + +/** + * @ingroup cpu_stm32f1 + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Thomas Eichinger + * @author Fabian Nack + * @author Hauke Petersen + * @author Joakim Nohlgård + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Remove this ugly guard once we selectively build the periph drivers */ +#ifdef SPI_NUMOF + +/** + * @brief Number of bits to shift the BR value in the CR1 register + */ +#define BR_SHIFT (3U) + +/** + * @brief Array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline SPI_TypeDef *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + /* make sure given bus is valid */ + assert(bus <= SPI_NUMOF); + /* initialize the bus lock */ + mutex_init(&locks[bus]); + /* trigger pin configuration */ + spi_init_pins(bus); +} + +void spi_init_pins(spi_t bus) +{ + gpio_init_af(spi_config[bus].pin_clk, GPIO_AF_OUT_PP); + gpio_init_af(spi_config[bus].pin_mosi, GPIO_AF_OUT_PP); + gpio_init(spi_config[bus].pin_miso, GPIO_IN); +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ)); + + /* get exclusive bus access */ + mutex_lock(&locks[bus]); + /* power on the peripheral */ + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + + + /* configure mode and bus clock */ + uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; + dev(bus)->CR1 = (SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR | + (mode & 0x3) | (br << BR_SHIFT)); + /* enable the SPI device */ + dev(bus)->CR1 |= SPI_CR1_SPE; + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable, power off, and release the bus */ + dev(bus)->CR1 = 0; + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *out_buf = (uint8_t *)out; + uint8_t *in_buf = (uint8_t *)in; + + assert(in || out); + + /* take care of the chip select */ + if (cs != SPI_CS_UNDEF) { + gpio_clear((gpio_t)cs); + } + + if (!in_buf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)) {} + dev(bus)->DR = out_buf[i]; + } + while ((dev(bus)->SR & SPI_SR_BSY)) {} + dev(bus)->DR; + } + else if (!out_buf) { + for (size_t i = 0; i < len; i++) { + dev(bus)->DR = 0; + while (!dev(bus)->SR & SPI_SR_RXNE) {} + in_buf[i] = (uint8_t)dev(bus)->DR; + } + } + else { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)) {} + dev(bus)->DR = out_buf[i]; + while (!(dev(bus)->SR & SPI_SR_RXNE)) {} + in_buf[i] = (uint8_t)dev(bus)->DR; + } + } + + /* finally release chip select line if requested */ + if ((cs != SPI_CS_UNDEF) && (!cont)) { + gpio_set((gpio_t)cs); + } +} + +#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f2/cpu.c b/cpu/stm32f2/cpu.c index 8304176755be..2437e6ddb6f2 100644 --- a/cpu/stm32f2/cpu.c +++ b/cpu/stm32f2/cpu.c @@ -19,6 +19,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" #ifdef HSI_VALUE # define RCC_CR_SOURCE RCC_CR_HSION @@ -38,6 +39,8 @@ void cpu_init(void) cortexm_init(); /* initialize system clocks */ clk_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/stm32f2/include/periph_cpu.h b/cpu/stm32f2/include/periph_cpu.h index d9197f38958e..ffd10918ac44 100644 --- a/cpu/stm32f2/include/periph_cpu.h +++ b/cpu/stm32f2/include/periph_cpu.h @@ -104,13 +104,6 @@ typedef struct { uint8_t chan; /**< DAC device used for this line */ } dac_conf_t; -/** - * @brief Configure the given pin to be used as ADC input - * - * @param[in] pin pin to configure - */ -void gpio_init_analog(gpio_t pin); - /** * @brief Power on the DMA device the given stream belongs to * @@ -185,6 +178,11 @@ static inline uint32_t dma_ifc(int stream) } } +/** + * @brief Enable DMA interrupts + * + * @param[in] stream logical DMA stream + */ static inline void dma_isr_enable(int stream) { if (stream < 7) { diff --git a/cpu/stm32f2/periph/spi.c b/cpu/stm32f2/periph/spi.c deleted file mode 100644 index 3da216b9445c..000000000000 --- a/cpu/stm32f2/periph/spi.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * 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. - */ - -/** - * @ingroup cpu_stm32f2 - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Peter Kietzmann - * @author Fabian Nack - * @author Hauke Petersen - * - * @} - */ -#include - -#include "board.h" -#include "cpu.h" -#include "mutex.h" -#include "periph/spi.h" -#include "periph_conf.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - -/** - * @brief Data-structure holding the state for a SPI device - */ -typedef struct { - char(*cb)(char data); -} spi_state_t; - -static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev); - -/** - * @brief Reserve memory for saving the SPI device's state - */ -static spi_state_t spi_config[SPI_NUMOF]; - -/* static bus div mapping */ -static const uint8_t spi_bus_div_map[SPI_NUMOF] = { -#if SPI_0_EN - [SPI_0] = SPI_0_BUS_DIV, -#endif -#if SPI_1_EN - [SPI_1] = SPI_1_BUS_DIV, -#endif -#if SPI_2_EN - [SPI_2] = SPI_2_BUS_DIV, -#endif -}; - -/** - * @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 -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - uint8_t speed_devider; - SPI_TypeDef *spi_port; - - switch (speed) { - case SPI_SPEED_100KHZ: - return -2; /* not possible for stm32f2, APB2 minimum is 328 kHz */ - break; - case SPI_SPEED_400KHZ: - speed_devider = 0x05 + spi_bus_div_map[dev]; /* makes 656 kHz */ - break; - case SPI_SPEED_1MHZ: - speed_devider = 0x04 + spi_bus_div_map[dev]; /* makes 1.3 MHz */ - break; - case SPI_SPEED_5MHZ: - speed_devider = 0x02 + spi_bus_div_map[dev]; /* makes 5.3 MHz */ - break; - case SPI_SPEED_10MHZ: - speed_devider = 0x01 + spi_bus_div_map[dev]; /* makes 10.5 MHz */ - break; - default: - return -1; - } - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - spi_port = SPI_1_DEV; - /* enable clocks */ - SPI_1_CLKEN(); - SPI_1_SCK_PORT_CLKEN(); - SPI_1_MISO_PORT_CLKEN(); - SPI_1_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - spi_port = SPI_2_DEV; - /* enable clocks */ - SPI_2_CLKEN(); - SPI_2_SCK_PORT_CLKEN(); - SPI_2_MISO_PORT_CLKEN(); - SPI_2_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_2_EN */ - default: - return -2; - } - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /**************** SPI-Init *****************/ - spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */ - spi_port->CR1 = 0; - spi_port->CR2 = 0; - /* the NSS (chip select) is managed purely by software */ - spi_port->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; - spi_port->CR1 |= (speed_devider << 3); /* Define serial clock baud rate. 001 leads to f_PCLK/4 */ - spi_port->CR1 |= (SPI_CR1_MSTR); /* 1: master configuration */ - spi_port->CR1 |= (conf); - /* enable SPI */ - spi_port->CR1 |= (SPI_CR1_SPE); - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data)) -{ - SPI_TypeDef *spi_port; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_0_IRQ, SPI_IRQ_PRIO); /* set SPI interrupt priority */ - NVIC_EnableIRQ(SPI_0_IRQ); /* set SPI interrupt priority */ - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - spi_port = SPI_1_DEV; - /* enable clocks */ - SPI_1_CLKEN(); - SPI_1_SCK_PORT_CLKEN(); - SPI_1_MISO_PORT_CLKEN(); - SPI_1_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_1_IRQ, SPI_IRQ_PRIO); - NVIC_EnableIRQ(SPI_1_IRQ); - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - spi_port = SPI_2_DEV; - /* enable clocks */ - SPI_2_CLKEN(); - SPI_2_SCK_PORT_CLKEN(); - SPI_2_MISO_PORT_CLKEN(); - SPI_2_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_2_IRQ, SPI_IRQ_PRIO); - NVIC_EnableIRQ(SPI_2_IRQ); - break; -#endif /* SPI_2_EN */ - default: - return -1; - } - - /* configure sck, miso and mosi pin */ - spi_conf_pins(dev); - - /***************** SPI-Init *****************/ - spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD); - spi_port->CR1 = 0; - spi_port->CR2 = 0; - /* enable RXNEIE flag to enable rx buffer not empty interrupt */ - spi_port->CR2 |= (SPI_CR2_RXNEIE); /*1:not masked */ - spi_port->CR1 |= (conf); - /* the NSS (chip select) is managed by software and NSS is low (slave enabled) */ - spi_port->CR1 |= SPI_CR1_SSM; - /* set callback */ - spi_config[dev].cb = cb; - /* enable SPI device */ - spi_port->CR1 |= SPI_CR1_SPE; - return 0; -} - -int spi_conf_pins(spi_t dev) -{ - GPIO_TypeDef *port[3]; - int pin[3], af[3]; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - port[0] = SPI_0_SCK_PORT; - pin[0] = SPI_0_SCK_PIN; - af[0] = SPI_0_SCK_AF; - port[1] = SPI_0_MOSI_PORT; - pin[1] = SPI_0_MOSI_PIN; - af[1] = SPI_0_MOSI_AF; - port[2] = SPI_0_MISO_PORT; - pin[2] = SPI_0_MISO_PIN; - af[2] = SPI_0_MISO_AF; - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - port[0] = SPI_1_SCK_PORT; - pin[0] = SPI_1_SCK_PIN; - af[0] = SPI_1_SCK_AF; - port[1] = SPI_1_MOSI_PORT; - pin[1] = SPI_1_MOSI_PIN; - af[1] = SPI_1_MOSI_AF; - port[2] = SPI_1_MISO_PORT; - pin[2] = SPI_1_MISO_PIN; - af[2] = SPI_1_MISO_AF; - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - port[0] = SPI_2_SCK_PORT; - pin[0] = SPI_2_SCK_PIN; - af[0] = SPI_2_SCK_AF; - port[1] = SPI_2_MOSI_PORT; - pin[1] = SPI_2_MOSI_PIN; - af[1] = SPI_2_MOSI_AF; - port[2] = SPI_2_MISO_PORT; - pin[2] = SPI_2_MISO_PIN; - af[2] = SPI_2_MISO_AF; - break; -#endif /* SPI_2_EN */ - default: - return -1; - } - - /***************** GPIO-Init *****************/ - for (int i = 0; i < 3; i++) { - /* Set GPIOs to AF mode */ - port[i]->MODER &= ~(3 << (2 * pin[i])); - port[i]->MODER |= (2 << (2 * pin[i])); - /* Set speed */ - port[i]->OSPEEDR &= ~(3 << (2 * pin[i])); - port[i]->OSPEEDR |= (3 << (2 * pin[i])); - /* Set to push-pull configuration */ - port[i]->OTYPER &= ~(1 << pin[i]); - /* Configure push-pull resistors */ - port[i]->PUPDR &= ~(3 << (2 * pin[i])); - port[i]->PUPDR |= (2 << (2 * pin[i])); - /* Configure GPIOs for the SPI alternate function */ - int hl = (pin[i] < 8) ? 0 : 1; - port[i]->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4)); - port[i]->AFR[hl] |= (af[i] << ((pin[i] - (hl * 8)) * 4)); - } - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if (dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - SPI_TypeDef *spi_port; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi_port = SPI_1_DEV; - break; -#endif -#if SPI_2_EN - case SPI_2: - spi_port = SPI_2_DEV; - break; -#endif - default: - return -1; - } - - while (!(spi_port->SR & SPI_SR_TXE)); - spi_port->DR = out; - - while (!(spi_port->SR & SPI_SR_RXNE)); - - if (in != NULL) { - *in = spi_port->DR; - } - else { - spi_port->DR; - } - - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_DEV->DR = reset_val; - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_DEV->DR = reset_val; - break; -#endif -#if SPI_2_EN - case SPI_2: - SPI_2_DEV->DR = reset_val; - break; -#endif - } -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_CLKEN(); - break; -#endif -#if SPI_2_EN - case SPI_2: - SPI_2_CLKEN(); - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while (SPI_0_DEV->SR & SPI_SR_BSY); - SPI_0_CLKDIS(); - break; -#endif -#if SPI_1_EN - case SPI_1: - while (SPI_1_DEV->SR & SPI_SR_BSY); - SPI_1_CLKDIS(); - break; -#endif -#if SPI_2_EN - case SPI_2: - while (SPI_2_DEV->SR & SPI_SR_BSY); - SPI_2_CLKDIS(); - break; -#endif - } -} - -static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev) -{ - - if (spi->SR & SPI_SR_RXNE) { - char data; - data = spi->DR; - data = spi_config[dev].cb(data); - spi->DR = data; - } - /* see if a thread with higher priority wants to run now */ - cortexm_isr_end(); -} - -#if SPI_0_EN -void SPI_0_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_0_DEV, SPI_0); -} -#endif - -#if SPI_1_EN -void SPI_1_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_1_DEV, SPI_1); -} -#endif - -#if SPI_2_EN -void SPI_2_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_2_DEV, SPI_2); -} -#endif - -#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f2/periph/spi.cold b/cpu/stm32f2/periph/spi.cold new file mode 100644 index 000000000000..d7a9cd5bbd3b --- /dev/null +++ b/cpu/stm32f2/periph/spi.cold @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences + * 2016 OTA keys S.A. + * 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. + */ + +/** + * @ingroup cpu_stm32f2 + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Peter Kietzmann + * @author Fabian Nack + * @author Hauke Petersen + * @author Vincent Dupont + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Remove this ugly guard once we selectively build the periph drivers */ +#ifdef SPI_NUMOF + +/** + * @brief Number of bits to shift the BR value in the CR1 register + */ +#define BR_SHIFT (3U) + +/** + * @brief Array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline SPI_TypeDef *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + mutex_init(&locks[bus]); + + /* trigger pin initialization */ + spi_init_pins(bus); +} + +void spi_init_pins(spi_t bus) +{ + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].sclk_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af); +} + +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + if (bus >= SPI_NUMOF) { + return SPI_NODEV; + } + if (cs == SPI_CS_UNDEF || + (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) { + return SPI_NOCS; + } + + if (cs == SPI_HWCS_MASK) { + if (spi_config[bus].cs_pin == GPIO_UNDEF) { + return SPI_NOCS; + } + gpio_init(spi_config[bus].cs_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af); + } + else { + gpio_init((gpio_t)cs, GPIO_OUT); + gpio_set((gpio_t)cs); + } + + return SPI_OK; +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + /* check clock speed for validity */ + if (clk >= 0x0f) { + return SPI_NOCLK; + } + + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable SPI device clock */ + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + /* enable device */ + uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; + dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR); + dev(bus)->CR2 = 0; + if (cs != SPI_HWCS_MASK) { + dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); + } + else { + dev(bus)->CR2 |= (SPI_CR2_SSOE); + } + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and release lock */ + dev(bus)->CR1 = 0; + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *inbuf = (uint8_t *)in; + uint8_t *outbuf = (uint8_t *)out; + + /* make sure at least one input or one output buffer is given */ + assert(outbuf || inbuf); + + /* active the given chip select line */ + dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */ + if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) { + gpio_clear((gpio_t)cs); + } + + /* transfer data, use shortpath if only sending data */ + if (!inbuf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = outbuf[i]; + } + /* wait until everything is finished and empty the receive buffer */ + while (dev(bus)->SR & SPI_SR_BSY) {} + dev(bus)->DR; + } + else { + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (outbuf) ? outbuf[i] : 0; + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = tmp; + while (!(dev(bus)->SR & SPI_SR_RXNE)); + inbuf[i] = dev(bus)->DR; + } + } + + /* release the chip select if not specified differently */ + if ((!cont) && (cs != SPI_CS_UNDEF)) { + dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */ + if (cs != SPI_HWCS_MASK) { + gpio_set((gpio_t)cs); + } + } +} + +#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f3/cpu.c b/cpu/stm32f3/cpu.c index 969a5c5a69d8..66bb7763a761 100644 --- a/cpu/stm32f3/cpu.c +++ b/cpu/stm32f3/cpu.c @@ -21,6 +21,7 @@ #include #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /* Check the source to be used for the PLL */ #if defined(CLOCK_HSI) && defined(CLOCK_HSE) @@ -57,6 +58,8 @@ void cpu_init(void) cortexm_init(); /* initialize the clock system */ cpu_clock_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/stm32f3/periph/spi.c b/cpu/stm32f3/periph/spi.c deleted file mode 100644 index d128a4f84c20..000000000000 --- a/cpu/stm32f3/periph/spi.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2014 Hamburg University of Applied Sciences - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 Kaspar Schleiser - * - * 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_stm32f3 - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Peter Kietzmann - * @author Fabian Nack - * @author Hauke Petersen - * @author Joakim Nohlgård - * @author Kaspar Schleiser - * - * @} - */ -#include - -#include "board.h" -#include "cpu.h" -#include "mutex.h" -#include "periph/spi.h" -#include "periph_conf.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - -typedef struct { - char(*cb)(char data); -} spi_state_t; - -/* static device mapping */ -static SPI_TypeDef *const spi[] = { -#if SPI_0_EN - SPI_0_DEV, -#endif -#if SPI_1_EN - SPI_1_DEV, -#endif -#if SPI_2_EN - SPI_2_DEV -#endif -}; - -static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev); - -static spi_state_t spi_config[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 -#if SPI_2_EN - [SPI_2] = MUTEX_INIT -#endif -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - uint8_t speed_divider; - - switch (speed) { - case SPI_SPEED_100KHZ: - return -2; /* not possible for stm32f3 */ - break; - case SPI_SPEED_400KHZ: - speed_divider = 7; /* makes 656 kHz */ - break; - case SPI_SPEED_1MHZ: - speed_divider = 6; /* makes 1.3 MHz */ - break; - case SPI_SPEED_5MHZ: - speed_divider = 4; /* makes 5.3 MHz */ - break; - case SPI_SPEED_10MHZ: - speed_divider = 3; /* makes 10.5 MHz */ - break; - default: - return -1; - } - - switch (dev) { -#if SPI_0_EN - case SPI_0: - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - /* enable clocks */ - SPI_1_CLKEN(); - SPI_1_SCK_PORT_CLKEN(); - SPI_1_MISO_PORT_CLKEN(); - SPI_1_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - /* enable clocks */ - SPI_2_CLKEN(); - SPI_2_SCK_PORT_CLKEN(); - SPI_2_MISO_PORT_CLKEN(); - SPI_2_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_2_EN */ - default: - return -2; - } - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /**************** SPI-Init *****************/ -#ifdef CPU_MODEL_STM32F303VC - spi[dev]->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */ -#endif - spi[dev]->CR1 = 0; - spi[dev]->CR2 = 0; - /* the NSS (chip select) is managed purely by software */ - spi[dev]->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; - spi[dev]->CR1 |= (speed_divider << 3); /* Define serial clock baud rate. 001 leads to f_PCLK/4 */ - spi[dev]->CR1 |= (SPI_CR1_MSTR); /* 1: master configuration */ - spi[dev]->CR1 |= (conf); - - spi[dev]->CR2 |= SPI_CR2_FRXTH; /* set FIFO reception threshold to 8bit (default: 16bit) */ - - /* enable SPI */ - spi[dev]->CR1 |= (SPI_CR1_SPE); - - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data)) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_0_IRQ, SPI_IRQ_PRIO); /* set SPI interrupt priority */ - NVIC_EnableIRQ(SPI_0_IRQ); /* set SPI interrupt priority */ - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - /* enable clocks */ - SPI_1_CLKEN(); - SPI_1_SCK_PORT_CLKEN(); - SPI_1_MISO_PORT_CLKEN(); - SPI_1_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_1_IRQ, SPI_IRQ_PRIO); - NVIC_EnableIRQ(SPI_1_IRQ); - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - /* enable clocks */ - SPI_2_CLKEN(); - SPI_2_SCK_PORT_CLKEN(); - SPI_2_MISO_PORT_CLKEN(); - SPI_2_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_2_IRQ, SPI_IRQ_PRIO); - NVIC_EnableIRQ(SPI_2_IRQ); - break; -#endif /* SPI_2_EN */ - default: - return -1; - } - - /* configure sck, miso and mosi pin */ - spi_conf_pins(dev); - - /***************** SPI-Init *****************/ -#ifdef CPU_MODEL_STM32F303VC - spi[dev]->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD); -#endif - spi[dev]->CR1 = 0; - spi[dev]->CR2 = 0; - /* enable RXNEIE flag to enable rx buffer not empty interrupt */ - spi[dev]->CR2 |= (SPI_CR2_RXNEIE); /*1:not masked */ - spi[dev]->CR1 |= (conf); - /* the NSS (chip select) is managed by software and NSS is low (slave enabled) */ - spi[dev]->CR1 |= SPI_CR1_SSM; - /* set callback */ - spi_config[dev].cb = cb; - /* enable SPI device */ - spi[dev]->CR1 |= SPI_CR1_SPE; - return 0; -} - -int spi_conf_pins(spi_t dev) -{ - GPIO_TypeDef *port[3]; - int pin[3], af[3]; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - port[0] = SPI_0_SCK_PORT; - pin[0] = SPI_0_SCK_PIN; - af[0] = SPI_0_SCK_AF; - port[1] = SPI_0_MOSI_PORT; - pin[1] = SPI_0_MOSI_PIN; - af[1] = SPI_0_MOSI_AF; - port[2] = SPI_0_MISO_PORT; - pin[2] = SPI_0_MISO_PIN; - af[2] = SPI_0_MISO_AF; - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - port[0] = SPI_1_SCK_PORT; - pin[0] = SPI_1_SCK_PIN; - af[0] = SPI_1_SCK_AF; - port[1] = SPI_1_MOSI_PORT; - pin[1] = SPI_1_MOSI_PIN; - af[1] = SPI_1_MOSI_AF; - port[2] = SPI_1_MISO_PORT; - pin[2] = SPI_1_MISO_PIN; - af[2] = SPI_1_MISO_AF; - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - port[0] = SPI_2_SCK_PORT; - pin[0] = SPI_2_SCK_PIN; - af[0] = SPI_2_SCK_AF; - port[1] = SPI_2_MOSI_PORT; - pin[1] = SPI_2_MOSI_PIN; - af[1] = SPI_2_MOSI_AF; - port[2] = SPI_2_MISO_PORT; - pin[2] = SPI_2_MISO_PIN; - af[2] = SPI_2_MISO_AF; - break; -#endif /* SPI_2_EN */ - default: - return -1; - } - - for (int i = 0; i < 3; i++) { - /* Set GPIOs to AF mode */ - port[i]->MODER &= ~(3 << (2 * pin[i])); - port[i]->MODER |= (2 << (2 * pin[i])); - /* Set speed */ - port[i]->OSPEEDR &= ~(3 << (2 * pin[i])); - port[i]->OSPEEDR |= (3 << (2 * pin[i])); - /* Set to push-pull configuration */ - port[i]->OTYPER &= ~(1 << pin[i]); - /* Configure push-pull resistors */ - port[i]->PUPDR &= ~(3 << (2 * pin[i])); - port[i]->PUPDR |= (2 << (2 * pin[i])); - /* Configure GPIOs for the SPI alternate function */ - int hl = (pin[i] < 8) ? 0 : 1; - port[i]->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4)); - port[i]->AFR[hl] |= (af[i] << ((pin[i] - (hl * 8)) * 4)); - } - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - char tmp; - - /* recast to uint_8 to force 8bit access */ - volatile uint8_t *DR = (volatile uint8_t*) &spi[dev]->DR; - - /* wait for an eventually previous byte to be readily transferred */ - while(!(spi[dev]->SR & SPI_SR_TXE)) {} - - /* put next byte into the output register */ - *DR = out; - - /* wait until the current byte was successfully transferred */ - while(!(spi[dev]->SR & SPI_SR_RXNE)) {} - - /* read response byte to reset flags */ - tmp = *DR; - - /* 'return' response byte if wished for */ - if (in) { - *in = tmp; - } - - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - if ((unsigned int)dev < SPI_NUMOF) { - spi[dev]->DR = reset_val; - } -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_CLKEN(); - break; -#endif -#if SPI_2_EN - case SPI_2: - SPI_2_CLKEN(); - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while (SPI_0_DEV->SR & SPI_SR_BSY) {} - SPI_0_CLKDIS(); - break; -#endif -#if SPI_1_EN - case SPI_1: - while (SPI_1_DEV->SR & SPI_SR_BSY) {} - SPI_1_CLKDIS(); - break; -#endif -#if SPI_2_EN - case SPI_2: - while (SPI_2_DEV->SR & SPI_SR_BSY) {} - SPI_2_CLKDIS(); - break; -#endif - } -} - -static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev) -{ - - if (spi->SR & SPI_SR_RXNE) { - char data; - data = spi->DR; - data = spi_config[dev].cb(data); - spi->DR = data; - } - /* see if a thread with higher priority wants to run now */ - cortexm_isr_end(); -} - -#if SPI_0_EN -void SPI_0_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_0_DEV, SPI_0); -} -#endif - -#if SPI_1_EN -void SPI_1_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_1_DEV, SPI_1); -} -#endif - -#if SPI_2_EN -void SPI_2_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_2_DEV, SPI_2); -} -#endif - -#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f3/periph/spi.cold b/cpu/stm32f3/periph/spi.cold new file mode 100644 index 000000000000..1f12f893b9f6 --- /dev/null +++ b/cpu/stm32f3/periph/spi.cold @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2014 Hamburg University of Applied Sciences + * 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. + */ + +/** + * @ingroup cpu_stm32f4 + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Peter Kietzmann + * @author Fabian Nack + * @author Hauke Petersen + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* Remove this ugly guard once we selectively build the periph drivers */ +#ifdef SPI_NUMOF + +/** + * @brief Number of bits to shift the BR value in the CR1 register + */ +#define BR_SHIFT (3U) + +/** + * @brief Array holding one pre-initialized mutex for each SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline SPI_TypeDef *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + /* initialize device lock */ + mutex_lock(&locks[bus]); + /* trigger pin initialization */ + spi_init_pins(bus); +} + +void spi_init_pins(spi_t bus) +{ + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].sclk_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].miso_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af); +} + +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + if (bus >= SPI_NUMOF) { + return SPI_NODEV; + } + if (cs == SPI_CS_UNDEF || + (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) { + return SPI_NOCS; + } + + if (cs == SPI_HWCS_MASK) { + if (spi_config[bus].cs_pin == GPIO_UNDEF) { + return SPI_NOCS; + } + gpio_init(spi_config[bus].cs_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af); + } + else { + gpio_init((gpio_t)cs, GPIO_OUT); + gpio_set((gpio_t)cs); + } + + return SPI_OK; +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + assert((clk >= SPI_CLK_100KHZ) && (clk <= SPI_CLK_10MHZ)); + + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable SPI device clock */ + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + /* configure clock and mode */ + uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; + dev(bus)->CR1 = ((br << 3) | mode | SPI_CR1_MSTR); + if (cs != SPI_HWCS_MASK) { + dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); + } + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and release lock */ + dev(bus)->CR1 = 0; + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *inbuf = (uint8_t *)in; + uint8_t *outbuf = (uint8_t *)out; + + /* make sure at least one input or one output buffer is given */ + assert(outbuf || inbuf); + + /* active the given chip select line */ + dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */ + if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) { + gpio_clear((gpio_t)cs); + } + + /* transfer data, use shortpath if only sending data */ + if (!inbuf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = outbuf[i]; + } + /* wait until everything is finished and empty the receive buffer */ + while (dev(bus)->SR & SPI_SR_BSY) {} + dev(bus)->DR; + } + else { + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (outbuf) ? outbuf[i] : 0; + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = tmp; + while (!(dev(bus)->SR & SPI_SR_RXNE)); + inbuf[i] = dev(bus)->DR; + } + } + + /* release the chip select if not specified differently */ + if ((!cont) && (cs != SPI_CS_UNDEF)) { + dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */ + if (cs != SPI_HWCS_MASK) { + gpio_set((gpio_t)cs); + } + } +} + +#endif /* SPI_NUMOF */ diff --git a/cpu/stm32f4/Makefile.include b/cpu/stm32f4/Makefile.include index 8d5704e1c371..bf4156f52dce 100644 --- a/cpu/stm32f4/Makefile.include +++ b/cpu/stm32f4/Makefile.include @@ -4,4 +4,5 @@ export CPU_FAM = stm32f4 USEMODULE += pm_layered include $(RIOTCPU)/stm32_common/Makefile.include + include $(RIOTCPU)/Makefile.include.cortexm_common diff --git a/cpu/stm32f4/cpu.c b/cpu/stm32f4/cpu.c index b2e50c6988cb..09e2b71e1cc1 100644 --- a/cpu/stm32f4/cpu.c +++ b/cpu/stm32f4/cpu.c @@ -21,6 +21,7 @@ #include #include "cpu.h" #include "periph_conf.h" +#include "periph/init.h" /* Check the source to be used for the PLL */ #if defined(CLOCK_HSI) && defined(CLOCK_HSE) @@ -50,6 +51,8 @@ void cpu_init(void) cortexm_init(); /* initialize the clock system */ cpu_clock_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/stm32f4/include/periph_cpu.h b/cpu/stm32f4/include/periph_cpu.h index e71b75b59cf5..141620483de3 100644 --- a/cpu/stm32f4/include/periph_cpu.h +++ b/cpu/stm32f4/include/periph_cpu.h @@ -34,15 +34,6 @@ extern "C" { #define ADC_DEVS (3U) #endif -/** - * @brief declare needed generic SPI functions - * @{ - */ -#define PERIPH_SPI_NEEDS_TRANSFER_BYTES -#define PERIPH_SPI_NEEDS_TRANSFER_REG -#define PERIPH_SPI_NEEDS_TRANSFER_REGS -/** @} */ - #ifndef DOXYGEN /** * @brief Override the ADC resolution configuration diff --git a/cpu/stm32f4/periph/spi.c b/cpu/stm32f4/periph/spi.c deleted file mode 100644 index 89809a90b791..000000000000 --- a/cpu/stm32f4/periph/spi.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * 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. - */ - -/** - * @ingroup cpu_stm32f4 - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Peter Kietzmann - * @author Fabian Nack - * @author Hauke Petersen - * - * @} - */ -#include - -#include "board.h" -#include "cpu.h" -#include "mutex.h" -#include "periph/spi.h" -#include "periph_conf.h" - -#define ENABLE_DEBUG (0) -#include "debug.h" - -/* guard this file in case no SPI device is defined */ -#if SPI_NUMOF - -/** - * @brief Data-structure holding the state for a SPI device - */ -typedef struct { - char(*cb)(char data); -} spi_state_t; - -static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev); - -/** - * @brief Reserve memory for saving the SPI device's state - */ -static spi_state_t spi_config[SPI_NUMOF]; - -/* static bus div mapping */ -static const uint8_t spi_bus_div_map[SPI_NUMOF] = { -#if SPI_0_EN - [SPI_0] = SPI_0_BUS_DIV, -#endif -#if SPI_1_EN - [SPI_1] = SPI_1_BUS_DIV, -#endif -#if SPI_2_EN - [SPI_2] = SPI_2_BUS_DIV, -#endif -}; - -/** - * @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 -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - uint8_t speed_devider; - SPI_TypeDef *spi_port; - - switch (speed) { - case SPI_SPEED_100KHZ: - return -2; /* not possible for stm32f4, APB2 minimum is 328 kHz */ - break; - case SPI_SPEED_400KHZ: - speed_devider = 0x05 + spi_bus_div_map[dev]; /* makes 656 kHz */ - break; - case SPI_SPEED_1MHZ: - speed_devider = 0x04 + spi_bus_div_map[dev]; /* makes 1.3 MHz */ - break; - case SPI_SPEED_5MHZ: - speed_devider = 0x02 + spi_bus_div_map[dev]; /* makes 5.3 MHz */ - break; - case SPI_SPEED_10MHZ: - speed_devider = 0x01 + spi_bus_div_map[dev]; /* makes 10.5 MHz */ - break; - default: - return -1; - } - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - spi_port = SPI_1_DEV; - /* enable clocks */ - SPI_1_CLKEN(); - SPI_1_SCK_PORT_CLKEN(); - SPI_1_MISO_PORT_CLKEN(); - SPI_1_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - spi_port = SPI_2_DEV; - /* enable clocks */ - SPI_2_CLKEN(); - SPI_2_SCK_PORT_CLKEN(); - SPI_2_MISO_PORT_CLKEN(); - SPI_2_MOSI_PORT_CLKEN(); - break; -#endif /* SPI_2_EN */ - default: - return -2; - } - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /**************** SPI-Init *****************/ - spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD);/* Activate the SPI mode (Reset I2SMOD bit in I2SCFGR register) */ - spi_port->CR1 = 0; - spi_port->CR2 = 0; - /* the NSS (chip select) is managed purely by software */ - spi_port->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; - spi_port->CR1 |= (speed_devider << 3); /* Define serial clock baud rate. 001 leads to f_PCLK/4 */ - spi_port->CR1 |= (SPI_CR1_MSTR); /* 1: master configuration */ - spi_port->CR1 |= (conf); - /* enable SPI */ - spi_port->CR1 |= (SPI_CR1_SPE); - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char(*cb)(char data)) -{ - SPI_TypeDef *spi_port; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - /* enable clocks */ - SPI_0_CLKEN(); - SPI_0_SCK_PORT_CLKEN(); - SPI_0_MISO_PORT_CLKEN(); - SPI_0_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_0_IRQ, SPI_IRQ_PRIO); /* set SPI interrupt priority */ - NVIC_EnableIRQ(SPI_0_IRQ); /* set SPI interrupt priority */ - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - spi_port = SPI_1_DEV; - /* enable clocks */ - SPI_1_CLKEN(); - SPI_1_SCK_PORT_CLKEN(); - SPI_1_MISO_PORT_CLKEN(); - SPI_1_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_1_IRQ, SPI_IRQ_PRIO); - NVIC_EnableIRQ(SPI_1_IRQ); - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - spi_port = SPI_2_DEV; - /* enable clocks */ - SPI_2_CLKEN(); - SPI_2_SCK_PORT_CLKEN(); - SPI_2_MISO_PORT_CLKEN(); - SPI_2_MOSI_PORT_CLKEN(); - /* configure interrupt channel */ - NVIC_SetPriority(SPI_2_IRQ, SPI_IRQ_PRIO); - NVIC_EnableIRQ(SPI_2_IRQ); - break; -#endif /* SPI_2_EN */ - default: - return -1; - } - - /* configure sck, miso and mosi pin */ - spi_conf_pins(dev); - - /***************** SPI-Init *****************/ - spi_port->I2SCFGR &= ~(SPI_I2SCFGR_I2SMOD); - spi_port->CR1 = 0; - spi_port->CR2 = 0; - /* enable RXNEIE flag to enable rx buffer not empty interrupt */ - spi_port->CR2 |= (SPI_CR2_RXNEIE); /*1:not masked */ - spi_port->CR1 |= (conf); - /* the NSS (chip select) is managed by software and NSS is low (slave enabled) */ - spi_port->CR1 |= SPI_CR1_SSM; - /* set callback */ - spi_config[dev].cb = cb; - /* enable SPI device */ - spi_port->CR1 |= SPI_CR1_SPE; - return 0; -} - -int spi_conf_pins(spi_t dev) -{ - GPIO_TypeDef *port[3]; - int pin[3], af[3]; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - port[0] = SPI_0_SCK_PORT; - pin[0] = SPI_0_SCK_PIN; - af[0] = SPI_0_SCK_AF; - port[1] = SPI_0_MOSI_PORT; - pin[1] = SPI_0_MOSI_PIN; - af[1] = SPI_0_MOSI_AF; - port[2] = SPI_0_MISO_PORT; - pin[2] = SPI_0_MISO_PIN; - af[2] = SPI_0_MISO_AF; - break; -#endif /* SPI_0_EN */ -#if SPI_1_EN - case SPI_1: - port[0] = SPI_1_SCK_PORT; - pin[0] = SPI_1_SCK_PIN; - af[0] = SPI_1_SCK_AF; - port[1] = SPI_1_MOSI_PORT; - pin[1] = SPI_1_MOSI_PIN; - af[1] = SPI_1_MOSI_AF; - port[2] = SPI_1_MISO_PORT; - pin[2] = SPI_1_MISO_PIN; - af[2] = SPI_1_MISO_AF; - break; -#endif /* SPI_1_EN */ -#if SPI_2_EN - case SPI_2: - port[0] = SPI_2_SCK_PORT; - pin[0] = SPI_2_SCK_PIN; - af[0] = SPI_2_SCK_AF; - port[1] = SPI_2_MOSI_PORT; - pin[1] = SPI_2_MOSI_PIN; - af[1] = SPI_2_MOSI_AF; - port[2] = SPI_2_MISO_PORT; - pin[2] = SPI_2_MISO_PIN; - af[2] = SPI_2_MISO_AF; - break; -#endif /* SPI_2_EN */ - default: - return -1; - } - - /***************** GPIO-Init *****************/ - for (int i = 0; i < 3; i++) { - /* Set GPIOs to AF mode */ - port[i]->MODER &= ~(3 << (2 * pin[i])); - port[i]->MODER |= (2 << (2 * pin[i])); - /* Set speed */ - port[i]->OSPEEDR &= ~(3 << (2 * pin[i])); - port[i]->OSPEEDR |= (3 << (2 * pin[i])); - /* Set to push-pull configuration */ - port[i]->OTYPER &= ~(1 << pin[i]); - /* Configure push-pull resistors */ - port[i]->PUPDR &= ~(3 << (2 * pin[i])); - port[i]->PUPDR |= (2 << (2 * pin[i])); - /* Configure GPIOs for the SPI alternate function */ - int hl = (pin[i] < 8) ? 0 : 1; - port[i]->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4)); - port[i]->AFR[hl] |= (af[i] << ((pin[i] - (hl * 8)) * 4)); - } - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - SPI_TypeDef *spi_port; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi_port = SPI_0_DEV; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi_port = SPI_1_DEV; - break; -#endif -#if SPI_2_EN - case SPI_2: - spi_port = SPI_2_DEV; - break; -#endif - default: - return -1; - } - - while (!(spi_port->SR & SPI_SR_TXE)) {} - spi_port->DR = out; - - while (!(spi_port->SR & SPI_SR_RXNE)) {} - - if (in != NULL) { - *in = spi_port->DR; - } - else { - spi_port->DR; - } - - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_DEV->DR = reset_val; - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_DEV->DR = reset_val; - break; -#endif -#if SPI_2_EN - case SPI_2: - SPI_2_DEV->DR = reset_val; - break; -#endif - } -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_CLKEN(); - break; -#endif -#if SPI_2_EN - case SPI_2: - SPI_2_CLKEN(); - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while (SPI_0_DEV->SR & SPI_SR_BSY) {} - SPI_0_CLKDIS(); - break; -#endif -#if SPI_1_EN - case SPI_1: - while (SPI_1_DEV->SR & SPI_SR_BSY) {} - SPI_1_CLKDIS(); - break; -#endif -#if SPI_2_EN - case SPI_2: - while (SPI_2_DEV->SR & SPI_SR_BSY) {} - SPI_2_CLKDIS(); - break; -#endif - } -} - -static inline void irq_handler_transfer(SPI_TypeDef *spi, spi_t dev) -{ - - if (spi->SR & SPI_SR_RXNE) { - char data; - data = spi->DR; - data = spi_config[dev].cb(data); - spi->DR = data; - } - /* see if a thread with higher priority wants to run now */ - cortexm_isr_end(); -} - -#if SPI_0_EN -void SPI_0_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_0_DEV, SPI_0); -} -#endif - -#if SPI_1_EN -void SPI_1_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_1_DEV, SPI_1); -} -#endif - -#if SPI_2_EN -void SPI_2_IRQ_HANDLER(void) -{ - irq_handler_transfer(SPI_2_DEV, SPI_2); -} -#endif - -#endif /* SPI_NUMOF */ diff --git a/cpu/stm32l1/cpu.c b/cpu/stm32l1/cpu.c index bf092531d642..f0ebc74e6231 100644 --- a/cpu/stm32l1/cpu.c +++ b/cpu/stm32l1/cpu.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "board.h" #include "periph_conf.h" +#include "periph/init.h" /* Check the source to be used for the PLL */ #if defined(CLOCK_HSI) && defined(CLOCK_HSE) @@ -46,6 +47,8 @@ void cpu_init(void) cortexm_init(); /* initialize system clocks */ clk_init(); + /* trigger static peripheral initialization */ + periph_init(); } /** diff --git a/cpu/stm32l1/include/periph_cpu.h b/cpu/stm32l1/include/periph_cpu.h index d8b06ee2a2e3..94880fed64a6 100644 --- a/cpu/stm32l1/include/periph_cpu.h +++ b/cpu/stm32l1/include/periph_cpu.h @@ -89,6 +89,16 @@ typedef struct { uint8_t ev_irqn; /**< event IRQ */ } i2c_conf_t; +/** + * @brief Configure the alternate function for the given pin + * + * @note This is meant for internal use in STM32L1 peripheral drivers only + * + * @param[in] pin pin to configure + * @param[in] af alternate function to use + */ +void gpio_init_af(gpio_t pin, gpio_af_t af); + #ifdef __cplusplus } #endif diff --git a/cpu/stm32l1/periph/spi.c b/cpu/stm32l1/periph/spi.c deleted file mode 100644 index f9e7f40e580f..000000000000 --- a/cpu/stm32l1/periph/spi.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2014 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. - */ - -/** - * @addtogroup driver_periph - * @{ - * - * @file - * @brief Low-level SPI driver implementation - * - * @author Peter Kietzmann - * @author Hauke Petersen - * @author Fabian Nack - * @author Thomas Eichinger - * @author Joakim Nohlgård - * - * @} - */ - -#include "cpu.h" -#include "mutex.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 -#if SPI_2_EN - [SPI_2] = MUTEX_INIT -#endif -}; - -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) -{ - SPI_TypeDef *spi; - - /* power on the SPI device */ - spi_poweron(dev); - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = SPI_0_DEV; - SPI_0_PORT_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - spi = SPI_1_DEV; - SPI_1_PORT_CLKEN(); - break; -#endif - default: - return -1; - } - - /* configure SCK, MISO and MOSI pin */ - spi_conf_pins(dev); - - /* reset SPI configuration registers */ - spi->CR1 = 0; - spi->CR2 = 0; - spi->I2SCFGR = 0; /* this makes sure SPI mode is selected */ - - /* configure bus clock speed */ - switch (speed) { - case SPI_SPEED_100KHZ: - spi->CR1 |= (7 << 3); /* actual clock: 125KHz (lowest possible) */ - break; - case SPI_SPEED_400KHZ: - spi->CR1 |= (5 << 3); /* actual clock: 500KHz */ - break; - case SPI_SPEED_1MHZ: - spi->CR1 |= (4 << 3); /* actual clock: 1MHz */ - break; - case SPI_SPEED_5MHZ: - spi->CR1 |= (2 << 3); /* actual clock: 4MHz */ - break; - case SPI_SPEED_10MHZ: - spi->CR1 |= (1 << 3); /* actual clock 8MHz */ - } - - /* select clock polarity and clock phase */ - spi->CR1 |= conf; - /* select master mode */ - spi->CR1 |= SPI_CR1_MSTR; - /* the NSS (chip select) is managed purely by software */ - spi->CR1 |= SPI_CR1_SSM | SPI_CR1_SSI; - /* enable the SPI device */ - spi->CR1 |= SPI_CR1_SPE; - return 0; -} - -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)) -{ - /* due to issues with the send buffer, the slave mode is not (yet) supported */ - return -1; -} - -int spi_conf_pins(spi_t dev) -{ - GPIO_TypeDef *port; - int pin[3]; /* 3 pins: sck, miso, mosi */ - int af = 0; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - port = SPI_0_PORT; - pin[0] = SPI_0_PIN_SCK; - pin[1] = SPI_0_PIN_MISO; - pin[2] = SPI_0_PIN_MOSI; - af = SPI_0_PIN_AF; - break; -#endif -#if SPI_1_EN - case SPI_1: - port = SPI_1_PORT; - pin[0] = SPI_1_PIN_SCK; - pin[1] = SPI_1_PIN_MISO; - pin[2] = SPI_1_PIN_MOSI; - af = SPI_1_PIN_AF; - break; -#endif - default: - return -1; - } - - /* configure pins for their correct alternate function */ - for (int i = 0; i < 3; i++) { - port->MODER &= ~(3 << (pin[i] * 2)); - port->MODER |= (2 << (pin[i] * 2)); - port->OSPEEDR |= (3 << (pin[i] * 2)); - int hl = (pin[i] < 8) ? 0 : 1; - port->AFR[hl] &= ~(0xf << ((pin[i] - (hl * 8)) * 4)); - port->AFR[hl] |= (af << ((pin[i] - (hl * 8)) * 4)); - } - - return 0; -} - -int spi_acquire(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_lock(&locks[dev]); - return 0; -} - -int spi_release(spi_t dev) -{ - if ((unsigned int)dev >= SPI_NUMOF) { - return -1; - } - mutex_unlock(&locks[dev]); - return 0; -} - -int spi_transfer_byte(spi_t dev, char out, char *in) -{ - char tmp; - SPI_TypeDef *spi = 0; - - switch (dev) { -#if SPI_0_EN - case SPI_0: - spi = SPI_0_DEV; - break; -#endif -#if SPI_1_EN - case SPI_1: - spi = SPI_1_DEV; - break; -#endif - default: - return 0; - } - - /* wait for an eventually previous byte to be readily transferred */ - while(!(spi->SR & SPI_SR_TXE)) {} - /* put next byte into the output register */ - spi->DR = out; - /* wait until the current byte was successfully transferred */ - while(!(spi->SR & SPI_SR_RXNE)) {} - /* read response byte to reset flags */ - tmp = spi->DR; - /* 'return' response byte if wished for */ - if (in) { - *in = tmp; - } - -#if ENABLE_DEBUG - if (in != NULL) { - DEBUG("\nout: %x in: %x \n", out, *in, transferred); - } - else { - DEBUG("\nout: %x in: was nullPointer\n", out, transferred); - } -#endif /*ENABLE_DEBUG */ - - return 1; -} - -void spi_transmission_begin(spi_t dev, char reset_val) -{ - /* slave mode is not (yet) supported */ -} - -void spi_poweron(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - SPI_0_CLKEN(); - break; -#endif -#if SPI_1_EN - case SPI_1: - SPI_1_CLKEN(); - break; -#endif - } -} - -void spi_poweroff(spi_t dev) -{ - switch (dev) { -#if SPI_0_EN - case SPI_0: - while (SPI_0_DEV->SR & SPI_SR_BSY) {} - SPI_0_CLKDIS(); - break; -#endif -#if SPI_1_EN - case SPI_1: - while (SPI_1_DEV->SR & SPI_SR_BSY) {} - SPI_1_CLKDIS(); - break; -#endif - } -} - -#endif /* SPI_NUMOF */ diff --git a/cpu/stm32l1/periph/spi.cold b/cpu/stm32l1/periph/spi.cold new file mode 100644 index 000000000000..f664b6bd4b0d --- /dev/null +++ b/cpu/stm32l1/periph/spi.cold @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2014-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. + */ + +/** + * @addtogroup driver_periph + * @{ + * + * @file + * @brief Low-level SPI driver implementation + * + * @author Peter Kietzmann + * @author Hauke Petersen + * @author Fabian Nack + * @author Thomas Eichinger + * @author Joakim Nohlgård + * + * @} + */ + +#include "cpu.h" +#include "mutex.h" +#include "assert.h" +#include "periph/spi.h" + +/* Remove this ugly guard once we selectively build the periph drivers */ +#ifdef SPI_NUMOF + +/** + * @brief Number of bits to shift the BR value in the CR1 register + */ +#define BR_SHIFT (3U) + +/** + * @brief Allocate one lock per SPI device + */ +static mutex_t locks[SPI_NUMOF]; + +static inline SPI_TypeDef *dev(spi_t bus) +{ + return spi_config[bus].dev; +} + +void spi_init(spi_t bus) +{ + assert(bus < SPI_NUMOF); + + /* initialize device lock */ + mutex_lock(&locks[bus]); + /* trigger pin initialization */ + spi_init_pins(bus); +} + +void spi_init_pins(spi_t bus) +{ + gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); + gpio_init(spi_config[bus].miso_pin, GPIO_IN); + gpio_init(spi_config[bus].sclk_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].mosi_pin, spi_config[bus].af); + gpio_init_af(spi_config[bus].sclk_pin, spi_config[bus].af); +} + +int spi_init_cs(spi_t bus, spi_cs_t cs) +{ + if (bus >= SPI_NUMOF) { + return SPI_NODEV; + } + if (cs == SPI_CS_UNDEF || + (((cs & SPI_HWCS_MASK) == SPI_HWCS_MASK) && (cs & ~(SPI_HWCS_MASK)))) { + return SPI_NOCS; + } + + if (cs == SPI_HWCS_MASK) { + if (spi_config[bus].cs_pin == GPIO_UNDEF) { + return SPI_NOCS; + } + gpio_init(spi_config[bus].cs_pin, GPIO_OUT); + gpio_init_af(spi_config[bus].cs_pin, spi_config[bus].af); + } + else { + gpio_init((gpio_t)cs, GPIO_OUT); + gpio_set((gpio_t)cs); + } + + return SPI_OK; +} + +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) +{ + /* check clock speed for validity */ + if (clk >= 0x0f) { + return SPI_NOCLK; + } + + /* lock bus */ + mutex_lock(&locks[bus]); + /* enable SPI device clock */ + periph_clk_en(spi_config[bus].apbbus, spi_config[bus].rccmask); + /* enable device */ + uint8_t br = spi_divtable[spi_config[bus].apbbus][clk]; + dev(bus)->CR1 = ((br << BR_SHIFT) | mode | SPI_CR1_MSTR); + if (cs != SPI_HWCS_MASK) { + dev(bus)->CR1 |= (SPI_CR1_SSM | SPI_CR1_SSI); + } + + return SPI_OK; +} + +void spi_release(spi_t bus) +{ + /* disable device and release lock */ + dev(bus)->CR1 = 0; + periph_clk_dis(spi_config[bus].apbbus, spi_config[bus].rccmask); + mutex_unlock(&locks[bus]); +} + +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len) +{ + uint8_t *inbuf = (uint8_t *)in; + uint8_t *outbuf = (uint8_t *)out; + + /* make sure at least one input or one output buffer is given */ + assert(outbuf || inbuf); + + /* active the given chip select line */ + dev(bus)->CR1 |= (SPI_CR1_SPE); /* this pulls the HW CS line low */ + if ((cs != SPI_HWCS_MASK) && (cs != SPI_CS_UNDEF)) { + gpio_clear((gpio_t)cs); + } + + /* transfer data, use shortpath if only sending data */ + if (!inbuf) { + for (size_t i = 0; i < len; i++) { + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = outbuf[i]; + } + /* wait until everything is finished and empty the receive buffer */ + while (dev(bus)->SR & SPI_SR_BSY) {} + dev(bus)->DR; + } + else { + for (size_t i = 0; i < len; i++) { + uint8_t tmp = (outbuf) ? outbuf[i] : 0; + while (!(dev(bus)->SR & SPI_SR_TXE)); + dev(bus)->DR = tmp; + while (!(dev(bus)->SR & SPI_SR_RXNE)); + inbuf[i] = dev(bus)->DR; + } + } + + /* release the chip select if not specified differently */ + if ((!cont) && (cs != SPI_CS_UNDEF)) { + dev(bus)->CR1 &= ~(SPI_CR1_SPE); /* pull HW CS line high */ + if (cs != SPI_HWCS_MASK) { + gpio_set((gpio_t)cs); + } + } +} + +#endif /* SPI_NUMOF */ diff --git a/drivers/adt7310/adt7310.c b/drivers/adt7310/adt7310.c index 50c38da6237f..bf65630e8e39 100644 --- a/drivers/adt7310/adt7310.c +++ b/drivers/adt7310/adt7310.c @@ -95,15 +95,9 @@ static int adt7310_read_reg(const adt7310_t *dev, const uint8_t addr, const uint int status = 0; uint8_t command = ADT7310_CMD_READ | (addr << ADT7310_CMD_ADDR_SHIFT); /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); + spi_acquire(dev->spi, dev->cs, SPI_MODE_0, dev->clk); /* Perform the transaction */ - gpio_clear(dev->cs); - - if (spi_transfer_regs(dev->spi, command, NULL, (char *)buf, len) < len) { - status = -1; - } - - gpio_set(dev->cs); + spi_transfer_regs(dev->spi, dev->cs, command, NULL, buf, (size_t)len); /* Release the bus for other threads. */ spi_release(dev->spi); @@ -127,34 +121,28 @@ static int adt7310_write_reg(const adt7310_t *dev, const uint8_t addr, int status = 0; uint8_t command = ADT7310_CMD_WRITE | (addr << ADT7310_CMD_ADDR_SHIFT); /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); + spi_acquire(dev->spi, dev->cs, SPI_MODE_0, dev->clk); /* Perform the transaction */ - gpio_clear(dev->cs); - - if (spi_transfer_regs(dev->spi, command, (char *)buf, NULL, len) < len) { - status = -1; - } - - gpio_set(dev->cs); + spi_transfer_regs(dev->spi, dev->cs, command, buf, NULL, (size_t)len); /* Release the bus for other threads. */ spi_release(dev->spi); return status; } -int adt7310_init(adt7310_t *dev, spi_t spi, gpio_t cs) +int adt7310_init(adt7310_t *dev, spi_t spi, spi_clk_t clk, gpio_t cs) { int status; uint8_t reg = 0; /* write device descriptor */ dev->spi = spi; + dev->clk = clk; dev->cs = cs; dev->initialized = false; dev->high_res = false; /* CS */ - gpio_init(dev->cs, GPIO_OUT); - gpio_set(dev->cs); + spi_init_cs(dev->spi, dev->cs); #if ENABLE_DEBUG for (int i = 0; i < 8; ++i) { diff --git a/drivers/at86rf2xx/at86rf2xx.c b/drivers/at86rf2xx/at86rf2xx.c index 8f28b4f712e3..ebeab759d8a5 100644 --- a/drivers/at86rf2xx/at86rf2xx.c +++ b/drivers/at86rf2xx/at86rf2xx.c @@ -46,8 +46,6 @@ void at86rf2xx_setup(at86rf2xx_t *dev, const at86rf2xx_params_t *params) dev->idle_state = AT86RF2XX_STATE_TRX_OFF; dev->state = AT86RF2XX_STATE_SLEEP; dev->pending_tx = 0; - /* initialise SPI */ - spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, params->spi_speed); } void at86rf2xx_reset(at86rf2xx_t *dev) diff --git a/drivers/at86rf2xx/at86rf2xx_internal.c b/drivers/at86rf2xx/at86rf2xx_internal.c index 2c5a436aa58e..0265ef6f54bf 100644 --- a/drivers/at86rf2xx/at86rf2xx_internal.c +++ b/drivers/at86rf2xx/at86rf2xx_internal.c @@ -28,32 +28,35 @@ #include "at86rf2xx_internal.h" #include "at86rf2xx_registers.h" +#define SPIDEV (dev->params.spi) +#define CSPIN (dev->params.cs_pin) + +static inline void getbus(const at86rf2xx_t *dev) +{ + spi_acquire(SPIDEV, CSPIN, SPI_MODE_0, dev->params.spi_clk); +} + void at86rf2xx_reg_write(const at86rf2xx_t *dev, const uint8_t addr, const uint8_t value) { - spi_acquire(dev->params.spi); - gpio_clear(dev->params.cs_pin); - spi_transfer_reg(dev->params.spi, - AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_WRITE | addr, - value, 0); - gpio_set(dev->params.cs_pin); - spi_release(dev->params.spi); + uint8_t reg = (AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_WRITE | addr); + + getbus(dev); + spi_transfer_reg(SPIDEV, CSPIN, reg, value); + spi_release(SPIDEV); } uint8_t at86rf2xx_reg_read(const at86rf2xx_t *dev, const uint8_t addr) { - char value; + uint8_t reg = (AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_READ | addr); + uint8_t value; - spi_acquire(dev->params.spi); - gpio_clear(dev->params.cs_pin); - spi_transfer_reg(dev->params.spi, - AT86RF2XX_ACCESS_REG | AT86RF2XX_ACCESS_READ | addr, - 0, &value); - gpio_set(dev->params.cs_pin); - spi_release(dev->params.spi); + getbus(dev); + value = spi_transfer_reg(SPIDEV, CSPIN, reg, 0); + spi_release(SPIDEV); - return (uint8_t)value; + return value; } void at86rf2xx_sram_read(const at86rf2xx_t *dev, @@ -61,14 +64,13 @@ void at86rf2xx_sram_read(const at86rf2xx_t *dev, uint8_t *data, const size_t len) { - spi_acquire(dev->params.spi); - gpio_clear(dev->params.cs_pin); - spi_transfer_reg(dev->params.spi, - AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_READ, - (char)offset, NULL); - spi_transfer_bytes(dev->params.spi, NULL, (char *)data, len); - gpio_set(dev->params.cs_pin); - spi_release(dev->params.spi); + uint8_t reg = (AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_READ); + + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg); + spi_transfer_byte(SPIDEV, CSPIN, true, offset); + spi_transfer_bytes(SPIDEV, CSPIN, false, NULL, data, len); + spi_release(SPIDEV); } void at86rf2xx_sram_write(const at86rf2xx_t *dev, @@ -76,36 +78,35 @@ void at86rf2xx_sram_write(const at86rf2xx_t *dev, const uint8_t *data, const size_t len) { - spi_acquire(dev->params.spi); - gpio_clear(dev->params.cs_pin); - spi_transfer_reg(dev->params.spi, - AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_WRITE, - (char)offset, NULL); - spi_transfer_bytes(dev->params.spi, (char *)data, NULL, len); - gpio_set(dev->params.cs_pin); - spi_release(dev->params.spi); + uint8_t reg = (AT86RF2XX_ACCESS_SRAM | AT86RF2XX_ACCESS_WRITE); + + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg); + spi_transfer_byte(SPIDEV, CSPIN, true, offset); + spi_transfer_bytes(SPIDEV, CSPIN, false, data, NULL, len); + spi_release(SPIDEV); } void at86rf2xx_fb_start(const at86rf2xx_t *dev) { - spi_acquire(dev->params.spi); - gpio_clear(dev->params.cs_pin); - spi_transfer_byte(dev->params.spi, - AT86RF2XX_ACCESS_FB | AT86RF2XX_ACCESS_READ, - NULL); + uint8_t reg = AT86RF2XX_ACCESS_FB | AT86RF2XX_ACCESS_READ; + + getbus(dev); + spi_transfer_byte(SPIDEV, CSPIN, true, reg); } void at86rf2xx_fb_read(const at86rf2xx_t *dev, uint8_t *data, const size_t len) { - spi_transfer_bytes(dev->params.spi, NULL, (char *)data, len); + spi_transfer_bytes(SPIDEV, CSPIN, true, NULL, data, len); } void at86rf2xx_fb_stop(const at86rf2xx_t *dev) { - gpio_set(dev->params.cs_pin); - spi_release(dev->params.spi); + /* transfer one byte (which we ignore) to release the chip select */ + spi_transfer_byte(SPIDEV, CSPIN, false, 1); + spi_release(SPIDEV); } uint8_t at86rf2xx_get_status(const at86rf2xx_t *dev) diff --git a/drivers/at86rf2xx/at86rf2xx_netdev.c b/drivers/at86rf2xx/at86rf2xx_netdev.c index 56c6d9376c7c..4476ea4891e3 100644 --- a/drivers/at86rf2xx/at86rf2xx_netdev.c +++ b/drivers/at86rf2xx/at86rf2xx_netdev.c @@ -70,8 +70,7 @@ static int _init(netdev2_t *netdev) at86rf2xx_t *dev = (at86rf2xx_t *)netdev; /* initialise GPIOs */ - gpio_init(dev->params.cs_pin, GPIO_OUT); - gpio_set(dev->params.cs_pin); + spi_init_cs(dev->params.spi, dev->params.cs_pin); gpio_init(dev->params.sleep_pin, GPIO_OUT); gpio_clear(dev->params.sleep_pin); gpio_init(dev->params.reset_pin, GPIO_OUT); diff --git a/drivers/at86rf2xx/include/at86rf2xx_params.h b/drivers/at86rf2xx/include/at86rf2xx_params.h index 8dd9a3156825..fad6a8e3b5e9 100644 --- a/drivers/at86rf2xx/include/at86rf2xx_params.h +++ b/drivers/at86rf2xx/include/at86rf2xx_params.h @@ -32,10 +32,10 @@ extern "C" { * @{ */ #ifndef AT86RF2XX_PARAM_SPI -#define AT86RF2XX_PARAM_SPI (SPI_0) +#define AT86RF2XX_PARAM_SPI (SPI_DEV(0)) #endif -#ifndef AT86RF2XX_PARAM_SPI_SPEED -#define AT86RF2XX_PARAM_SPI_SPEED (SPI_SPEED_5MHZ) +#ifndef AT86RF2XX_PARAM_SPI_CLK +#define AT86RF2XX_PARAM_SPI_CLK (SPI_CLK_5MHZ) #endif #ifndef AT86RF2XX_PARAM_CS #define AT86RF2XX_PARAM_CS (GPIO_PIN(0, 0)) @@ -51,7 +51,7 @@ extern "C" { #endif #define AT86RF2XX_PARAMS_DEFAULT {.spi = AT86RF2XX_PARAM_SPI, \ - .spi_speed = AT86RF2XX_PARAM_SPI_SPEED, \ + .spi_clk = AT86RF2XX_PARAM_SPI_CLK, \ .cs_pin = AT86RF2XX_PARAM_CS, \ .int_pin = AT86RF2XX_PARAM_INT, \ .sleep_pin = AT86RF2XX_PARAM_SLEEP, \ diff --git a/drivers/cc110x/cc110x-spi.c b/drivers/cc110x/cc110x-spi.c index da1ee16aa814..5a0c4efb10fd 100644 --- a/drivers/cc110x/cc110x-spi.c +++ b/drivers/cc110x/cc110x-spi.c @@ -35,10 +35,18 @@ #include "xtimer.h" #include "irq.h" +#define SPI_CLK SPI_CLK_5MHZ +#define SPI_MODE SPI_MODE_0 + /********************************************************************** * CC110x spi access **********************************************************************/ +static inline void lock(cc110x_t *dev) +{ + spi_acquire(dev->params.spi, dev->params.cs, SPI_MODE, SPI_CLK); +} + void cc110x_cs(cc110x_t *dev) { volatile int retry_count = 0; @@ -68,17 +76,18 @@ void cc110x_cs(cc110x_t *dev) } /* Switch MISO/GDO1 to spi mode */ #ifndef GPIO_READS_SPI_PINS - spi_conf_pins(dev->params.spi); + spi_init_pins(dev->params.spi); #endif } void cc110x_writeburst_reg(cc110x_t *dev, uint8_t addr, const char *src, uint8_t count) { unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); - spi_transfer_regs(dev->params.spi, addr | CC110X_WRITE_BURST, (char *)src, 0, count); + spi_transfer_regs(dev->params.spi, SPI_CS_UNDEF, + (addr | CC110X_WRITE_BURST), src, NULL, count); gpio_set(dev->params.cs); irq_restore(cpsr); spi_release(dev->params.spi); @@ -88,12 +97,14 @@ void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t cou { int i = 0; unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); - spi_transfer_byte(dev->params.spi, addr | CC110X_READ_BURST, 0); + spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, false, + (addr | CC110X_READ_BURST)); while (i < count) { - spi_transfer_byte(dev->params.spi, CC110X_NOBYTE, &buffer[i]); + buffer[i] = (char)spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, + false, CC110X_NOBYTE); i++; } gpio_set(dev->params.cs); @@ -104,10 +115,10 @@ void cc110x_readburst_reg(cc110x_t *dev, uint8_t addr, char *buffer, uint8_t cou void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value) { unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); - spi_transfer_reg(dev->params.spi, addr, value, 0); + spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, addr, value); gpio_set(dev->params.cs); irq_restore(cpsr); spi_release(dev->params.spi); @@ -115,26 +126,28 @@ void cc110x_write_reg(cc110x_t *dev, uint8_t addr, uint8_t value) uint8_t cc110x_read_reg(cc110x_t *dev, uint8_t addr) { - char result; + uint8_t result; unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); - spi_transfer_reg(dev->params.spi, addr | CC110X_READ_SINGLE, CC110X_NOBYTE, &result); + result = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, + (addr | CC110X_READ_SINGLE), CC110X_NOBYTE); gpio_set(dev->params.cs); irq_restore(cpsr); spi_release(dev->params.spi); - return (uint8_t) result; + return result; } uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr) { - char result; + uint8_t result; unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); - spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result); + result = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, + (addr | CC110X_READ_BURST), CC110X_NOBYTE); gpio_set(dev->params.cs); irq_restore(cpsr); spi_release(dev->params.spi); @@ -143,19 +156,21 @@ uint8_t cc110x_read_status(cc110x_t *dev, uint8_t addr) uint8_t cc110x_get_reg_robust(cc110x_t *dev, uint8_t addr) { - char result, result2; + uint8_t res1, res2; unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); do { - spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result); - spi_transfer_reg(dev->params.spi, addr | CC110X_READ_BURST, CC110X_NOBYTE, &result2); - } while (result != result2); + res1 = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, + (addr | CC110X_READ_BURST), CC110X_NOBYTE); + res2 = spi_transfer_reg(dev->params.spi, SPI_CS_UNDEF, + (addr | CC110X_READ_BURST), CC110X_NOBYTE); + } while (res1 != res2); gpio_set(dev->params.cs); irq_restore(cpsr); spi_release(dev->params.spi); - return (uint8_t) result; + return res1; } uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c) @@ -166,14 +181,14 @@ uint8_t cc110x_strobe(cc110x_t *dev, uint8_t c) } #endif - char result; + uint8_t result; unsigned int cpsr; - spi_acquire(dev->params.spi); + lock(dev); cpsr = irq_disable(); cc110x_cs(dev); - spi_transfer_byte(dev->params.spi, c, &result); + result = spi_transfer_byte(dev->params.spi, SPI_CS_UNDEF, false, c); gpio_set(dev->params.cs); irq_restore(cpsr); spi_release(dev->params.spi); - return (uint8_t) result; + return result; } diff --git a/drivers/cc110x/cc110x.c b/drivers/cc110x/cc110x.c index 778a1035979a..0286ed5b04e5 100644 --- a/drivers/cc110x/cc110x.c +++ b/drivers/cc110x/cc110x.c @@ -55,17 +55,11 @@ int cc110x_setup(cc110x_t *dev, const cc110x_params_t *params) dev->params = *params; /* Configure chip-select */ - gpio_init(dev->params.cs, GPIO_OUT); - gpio_set(dev->params.cs); + spi_init_cs(dev->params.spi, dev->params.cs); /* Configure GDO1 */ gpio_init(dev->params.gdo1, GPIO_IN); - /* Configure SPI */ - spi_acquire(dev->params.spi); - spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ); - spi_release(dev->params.spi); - #ifndef CC110X_DONT_RESET /* reset device*/ _power_up_reset(dev); diff --git a/drivers/cc2420/cc2420.c b/drivers/cc2420/cc2420.c index abe8cde5275f..24d8ef2a8b11 100644 --- a/drivers/cc2420/cc2420.c +++ b/drivers/cc2420/cc2420.c @@ -42,7 +42,6 @@ void cc2420_setup(cc2420_t * dev, const cc2420_params_t *params) dev->state = CC2420_STATE_IDLE; /* reset device descriptor fields */ dev->options = 0; - spi_init_master(dev->params.spi, SPI_CONF_FIRST_RISING, dev->params.spi_clk); } int cc2420_init(cc2420_t *dev) diff --git a/drivers/cc2420/cc2420_internal.c b/drivers/cc2420/cc2420_internal.c index 01ab024f2967..dea3f04818a0 100644 --- a/drivers/cc2420/cc2420_internal.c +++ b/drivers/cc2420/cc2420_internal.c @@ -27,15 +27,19 @@ #include "cc2420_internal.h" #include "cc2420_registers.h" +#define SPI_BUS (dev->params.spi) +#define SPI_CS (dev->params.pin_cs) +#define SPI_MODE (SPI_MODE_0) +#define SPI_CLK (dev->params.spi_clk) + + uint8_t cc2420_strobe(const cc2420_t *dev, const uint8_t command) { - char res; + uint8_t res; - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_byte(dev->params.spi, (char)command, (char *)&res); - gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + res = spi_transfer_byte(SPI_BUS, SPI_CS, false, command); + spi_release(SPI_BUS); return res; } @@ -46,24 +50,18 @@ void cc2420_reg_write(const cc2420_t *dev, { uint16_t tmp = byteorder_htons(value).u16; - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_regs(dev->params.spi, CC2420_REG_WRITE | addr, - (char *)&tmp, NULL, 2); - gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + spi_transfer_regs(SPI_BUS, SPI_CS, (CC2420_REG_WRITE | addr), &tmp, NULL, 2); + spi_release(SPI_BUS); } uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr) { network_uint16_t tmp; - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_regs(dev->params.spi, CC2420_REG_READ | addr, - NULL, (char *)&tmp, 2); - gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + spi_transfer_regs(SPI_BUS, SPI_CS, (CC2420_REG_READ | addr),NULL, &tmp, 2); + spi_release(SPI_BUS); return byteorder_ntohs(tmp); } @@ -71,49 +69,40 @@ uint16_t cc2420_reg_read(const cc2420_t *dev, const uint8_t addr) void cc2420_ram_read(const cc2420_t *dev, const uint16_t addr, uint8_t *data, const size_t len) { - char tmp[] = { (CC2420_RAM | (addr & 0x7f)), - (CC2420_RAM_READ | ((addr >> 1) & 0xc0)) }; + uint8_t tmp[] = { (CC2420_RAM | (addr & 0x7f)), + (CC2420_RAM_READ | ((addr >> 1) & 0xc0)) }; - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_bytes(dev->params.spi, tmp, NULL, 2); - spi_transfer_bytes(dev->params.spi, NULL, (char*)data, len); - gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + spi_transfer_bytes(SPI_BUS, SPI_CS, true, tmp, NULL, 2); + spi_transfer_bytes(SPI_BUS, SPI_CS, false, NULL, data, len); + spi_release(SPI_BUS); } void cc2420_ram_write(const cc2420_t *dev, const uint16_t addr, const uint8_t *data, const size_t len) { - char tmp[] = { (CC2420_RAM | (addr & 0x7f)), - (CC2420_RAM_WRITE | ((addr >> 1) & 0xc0)) }; + uint8_t tmp[] = { (CC2420_RAM | (addr & 0x7f)), + (CC2420_RAM_WRITE | ((addr >> 1) & 0xc0)) }; - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_bytes(dev->params.spi, tmp, NULL, 2); - spi_transfer_bytes(dev->params.spi, (char*)data, NULL, len); - gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + spi_transfer_bytes(SPI_BUS, SPI_CS, true, tmp, NULL, 2); + spi_transfer_bytes(SPI_BUS, SPI_CS, false, data, NULL, len); + spi_release(SPI_BUS); } void cc2420_fifo_read(const cc2420_t *dev, uint8_t *data, const size_t len) { - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_regs(dev->params.spi, CC2420_FIFO_READ, - NULL, (char *)data, len); - gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + spi_transfer_regs(SPI_BUS, SPI_CS, CC2420_FIFO_READ, NULL, data, len); + spi_release(SPI_BUS); } void cc2420_fifo_write(const cc2420_t *dev, uint8_t *data, const size_t len) { - spi_acquire(dev->params.spi); - gpio_clear(dev->params.pin_cs); - spi_transfer_regs(dev->params.spi, CC2420_FIFO_WRITE, - (char *)data, NULL, len); + spi_acquire(SPI_BUS, SPI_CS, SPI_MODE, SPI_CLK); + spi_transfer_regs(SPI_BUS, SPI_CS, CC2420_FIFO_WRITE, data, NULL, len); gpio_set(dev->params.pin_cs); - spi_release(dev->params.spi); + spi_release(SPI_BUS); } uint8_t cc2420_status(cc2420_t *dev) diff --git a/drivers/cc2420/cc2420_netdev.c b/drivers/cc2420/cc2420_netdev.c index cfdd054b74fc..c3bf61e9187c 100644 --- a/drivers/cc2420/cc2420_netdev.c +++ b/drivers/cc2420/cc2420_netdev.c @@ -116,8 +116,7 @@ static int _init(netdev2_t *netdev) gpio_init_int(dev->params.pin_fifop, GPIO_IN, GPIO_RISING, _irq_handler, dev); /* initialize the chip select line and the SPI bus */ - gpio_init(dev->params.pin_cs, GPIO_OUT); - gpio_set(dev->params.pin_cs); + spi_init_cs(dev->params.spi, dev->params.pin_cs); /* power on and toggle reset */ gpio_set(dev->params.pin_vrefen); diff --git a/drivers/cc2420/include/cc2420_params.h b/drivers/cc2420/include/cc2420_params.h index 77d901aa5aef..9687c0cdd8f1 100644 --- a/drivers/cc2420/include/cc2420_params.h +++ b/drivers/cc2420/include/cc2420_params.h @@ -30,10 +30,10 @@ extern "C" { * @{ */ #ifndef CC2420_PARAM_SPI -#define CC2420_PARAM_SPI (SPI_0) +#define CC2420_PARAM_SPI (SPI_DEV(0)) #endif #ifndef CC2420_PARAM_SPI_CLK -#define CC2420_PARAM_SPI_CLK (SPI_SPEED_5MHZ) +#define CC2420_PARAM_SPI_CLK (SPI_CLK_5MHZ) #endif #ifndef CC2420_PARAM_CS #define CC2420_PARAM_CS (GPIO_PIN(0, 0)) diff --git a/drivers/enc28j60/enc28j60.c b/drivers/enc28j60/enc28j60.c index 848d8ad3cdc0..ee8d0ca8a0c6 100644 --- a/drivers/enc28j60/enc28j60.c +++ b/drivers/enc28j60/enc28j60.c @@ -51,7 +51,7 @@ * The SPI speed is set to a fixed value, as it must be > 8MHz (see the devices * errata sheet). */ -#define SPI_SPEED SPI_SPEED_10MHZ +#define SPI_CLK SPI_CLK_10MHZ /** * @brief The devices build-in buffer size @@ -82,61 +82,79 @@ static void switch_bank(enc28j60_t *dev, int8_t bank) return; } /* clear old value */ - gpio_clear(dev->cs_pin); - spi_transfer_reg(dev->spi, CMD_BFC | REG_ECON1, 0x03, 0); - gpio_set(dev->cs_pin); + spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFC | REG_ECON1), 0x03); /* set new value */ - gpio_clear(dev->cs_pin); - spi_transfer_reg(dev->spi, CMD_BFS | REG_ECON1, bank, 0); - gpio_set(dev->cs_pin); + spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFS | REG_ECON1), bank); /* remember active bank */ dev->bank = bank; } static uint8_t cmd_rcr(enc28j60_t *dev, uint8_t reg, int8_t bank) { - char res; + uint8_t res; + + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); switch_bank(dev, bank); - gpio_clear(dev->cs_pin); - spi_transfer_reg(dev->spi, CMD_RCR | reg, 0, &res); - gpio_set(dev->cs_pin); - return (uint8_t)res; + res = spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_RCR | reg), 0); + + /* finish SPI transaction */ + spi_release(dev->spi); + + return res; } static uint8_t cmd_rcr_miimac(enc28j60_t *dev, uint8_t reg, int8_t bank) { char res[2]; + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); + switch_bank(dev, bank); - gpio_clear(dev->cs_pin); - spi_transfer_regs(dev->spi, CMD_RCR | reg, NULL, res, 2); - gpio_set(dev->cs_pin); + spi_transfer_regs(dev->spi, dev->cs_pin, (CMD_RCR | reg), NULL, res, 2); + + /* finish SPI transaction */ + spi_release(dev->spi); + return (uint8_t)res[1]; } static void cmd_wcr(enc28j60_t *dev, uint8_t reg, int8_t bank, uint8_t value) { + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); + switch_bank(dev, bank); - gpio_clear(dev->cs_pin); - spi_transfer_reg(dev->spi, CMD_WCR | reg, (char)value, 0); - gpio_set(dev->cs_pin); + spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_WCR | reg), value); + + /* finish SPI transaction */ + spi_release(dev->spi); } static void cmd_bfs(enc28j60_t *dev, uint8_t reg, int8_t bank, uint8_t mask) { + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); + switch_bank(dev, bank); - gpio_clear(dev->cs_pin); - spi_transfer_reg(dev->spi, CMD_BFS | reg, mask, 0); - gpio_set(dev->cs_pin); + spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFS | reg), mask); + + /* finish SPI transaction */ + spi_release(dev->spi); } static void cmd_bfc(enc28j60_t *dev, uint8_t reg, int8_t bank, uint8_t mask) { + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); + switch_bank(dev, bank); - gpio_clear(dev->cs_pin); - spi_transfer_reg(dev->spi, CMD_BFC | reg, mask, 0); - gpio_set(dev->cs_pin); + spi_transfer_reg(dev->spi, dev->cs_pin, (CMD_BFC | reg), mask); + + /* finish SPI transaction */ + spi_release(dev->spi); } static uint16_t cmd_r_addr(enc28j60_t *dev, uint8_t addr) @@ -178,16 +196,22 @@ static void cmd_w_phy(enc28j60_t *dev, uint8_t reg, uint16_t val) static void cmd_rbm(enc28j60_t *dev, uint8_t *data, size_t len) { - gpio_clear(dev->cs_pin); - spi_transfer_regs(dev->spi, CMD_RBM, NULL, (char *)data, len); - gpio_set(dev->cs_pin); + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); + /* transfer data */ + spi_transfer_regs(dev->spi, dev->cs_pin, CMD_RBM, NULL, data, len); + /* finish SPI transaction */ + spi_release(dev->spi); } static void cmd_wbm(enc28j60_t *dev, uint8_t *data, size_t len) { - gpio_clear(dev->cs_pin); - spi_transfer_regs(dev->spi, CMD_WBM, (char *)data, NULL, len); - gpio_set(dev->cs_pin); + /* start transaction */ + spi_acquire(dev->spi, dev->cs_pin, SPI_MODE_0, SPI_CLK); + /* transfer data */ + spi_transfer_regs(dev->spi, dev->cs_pin, CMD_WBM, data, NULL, len); + /* finish SPI transaction */ + spi_release(dev->spi); } static void mac_get(enc28j60_t *dev, uint8_t *mac) @@ -296,14 +320,11 @@ static int nd_init(netdev2_t *netdev) /* setup the low-level interfaces */ gpio_init(dev->reset_pin, GPIO_OUT); gpio_clear(dev->reset_pin); /* this puts the device into reset state */ - gpio_init(dev->cs_pin, GPIO_OUT); - gpio_set(dev->cs_pin); - gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, on_int, (void *)dev); - res = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED); - if (res < 0) { - DEBUG("[enc28j60] init: error initializing SPI bus [%i]\n", res); + if (spi_init_cs(dev->spi, dev->cs_pin) != SPI_OK) { + DEBUG("[enc28j60] init: error initializing the CS pin [%i]\n", res); return -1; } + gpio_init_int(dev->int_pin, GPIO_IN, GPIO_FALLING, on_int, (void *)dev); /* wait at least 1ms and then release device from reset state */ xtimer_usleep(DELAY_RESET); diff --git a/drivers/enc28j60/include/enc28j60_params.h b/drivers/enc28j60/include/enc28j60_params.h index 6546ae448111..5266440217c5 100644 --- a/drivers/enc28j60/include/enc28j60_params.h +++ b/drivers/enc28j60/include/enc28j60_params.h @@ -30,7 +30,7 @@ extern "C" { * @{ */ #ifndef ENC28J60_PARAM_SPI -#define ENC28J60_PARAM_SPI (SPI_0) +#define ENC28J60_PARAM_SPI (SPI_DEV(0)) #endif #ifndef ENC28J60_PARAM_CS #define ENC28J60_PARAM_CS (GPIO_PIN(0, 0)) diff --git a/drivers/encx24j600/encx24j600.c b/drivers/encx24j600/encx24j600.c index 96542bdeb2c6..d46fa63d2b74 100644 --- a/drivers/encx24j600/encx24j600.c +++ b/drivers/encx24j600/encx24j600.c @@ -37,18 +37,19 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#define ENCX24J600_SPI_SPEED SPI_SPEED_1MHZ +#define SPI_CLK SPI_CLK_1MHZ +#define SPI_MODE SPI_MODE_0 -#define ENCX24J600_INIT_DELAY 100000U +#define ENCX24J600_INIT_DELAY (100000U) -#define ENC_BUFFER_START 0x0000 -#define ENC_BUFFER_SIZE 0x6000 -#define ENC_BUFFER_END 0x5FFF -#define RX_BUFFER_START (0x5340) /* Default value */ -#define RX_BUFFER_END (ENC_BUFFER_END) -#define TX_BUFFER_LEN (0x2000) -#define TX_BUFFER_END (RX_BUFFER_START) -#define TX_BUFFER_START (TX_BUFFER_END - TX_BUFFER_LEN) +#define ENC_BUFFER_START (0x0000) +#define ENC_BUFFER_SIZE (0x6000) +#define ENC_BUFFER_END (0x5FFF) +#define RX_BUFFER_START (0x5340) /* Default value */ +#define RX_BUFFER_END (ENC_BUFFER_END) +#define TX_BUFFER_LEN (0x2000) +#define TX_BUFFER_END (RX_BUFFER_START) +#define TX_BUFFER_START (TX_BUFFER_END - TX_BUFFER_LEN) static void cmd(encx24j600_t *dev, char cmd); static void reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value); @@ -75,11 +76,11 @@ const static netdev2_driver_t netdev2_driver_encx24j600 = { }; static inline void lock(encx24j600_t *dev) { - mutex_lock(&dev->mutex); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); } static inline void unlock(encx24j600_t *dev) { - mutex_unlock(&dev->mutex); + spi_release(dev->spi); } void encx24j600_setup(encx24j600_t *dev, const encx24j600_params_t *params) @@ -89,8 +90,6 @@ void encx24j600_setup(encx24j600_t *dev, const encx24j600_params_t *params) dev->cs = params->cs_pin; dev->int_pin = params->int_pin; dev->rx_next_ptr = RX_BUFFER_START; - - mutex_init(&dev->mutex); } static void encx24j600_isr(void *arg) @@ -147,11 +146,7 @@ static void _isr(netdev2_t *netdev) static inline void enc_spi_transfer(encx24j600_t *dev, char *out, char *in, int len) { - spi_acquire(dev->spi); - gpio_clear(dev->cs); - spi_transfer_bytes(dev->spi, out, in, len); - gpio_set(dev->cs); - spi_release(dev->spi); + spi_transfer_bytes(dev->spi, dev->cs, false, out, in, len); } static inline uint16_t reg_get(encx24j600_t *dev, uint8_t reg) @@ -170,20 +165,12 @@ static void phy_reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value) { } static void cmd(encx24j600_t *dev, char cmd) { - spi_acquire(dev->spi); - gpio_clear(dev->cs); - spi_transfer_byte(dev->spi, cmd, NULL); - gpio_set(dev->cs); - spi_release(dev->spi); + spi_transfer_byte(dev->spi, dev->cs, false, (uint8_t)cmd); } static void cmdn(encx24j600_t *dev, uint8_t cmd, char *out, char *in, int len) { - spi_acquire(dev->spi); - gpio_clear(dev->cs); - spi_transfer_byte(dev->spi, cmd, NULL); - spi_transfer_bytes(dev->spi, out, in, len); - gpio_set(dev->cs); - spi_release(dev->spi); + spi_transfer_byte(dev->spi, dev->cs, true, cmd); + spi_transfer_bytes(dev->spi, dev->cs, false, out, in, len); } static void reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value) @@ -249,13 +236,10 @@ static int _init(netdev2_t *encdev) DEBUG("encx24j600: starting initialization...\n"); /* setup IO */ - gpio_init(dev->cs, GPIO_OUT); - gpio_set(dev->cs); - gpio_init_int(dev->int_pin, GPIO_IN_PU, GPIO_FALLING, encx24j600_isr, (void*)dev); - - if (spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, ENCX24J600_SPI_SPEED) < 0) { + if (spi_init_cs(dev->spi, dev->cs) != SPI_OK) { return -1; } + gpio_init_int(dev->int_pin, GPIO_IN_PU, GPIO_FALLING, encx24j600_isr, (void*)dev); lock(dev); diff --git a/drivers/include/adt7310.h b/drivers/include/adt7310.h index 2cf37fb190a0..4ba673b6fb2f 100644 --- a/drivers/include/adt7310.h +++ b/drivers/include/adt7310.h @@ -65,6 +65,7 @@ extern "C" */ typedef struct { spi_t spi; /**< SPI bus the sensor is connected to */ + spi_clk_t clk; /**< SPI bus clock speed */ gpio_t cs; /**< CS pin GPIO handle */ bool initialized; /**< sensor status, true if sensor is initialized */ bool high_res; /**< Sensor resolution, true if configured to 16 bit resolution */ @@ -119,12 +120,13 @@ int adt7310_set_config(adt7310_t *dev, uint8_t config); * * @param[in] dev pointer to sensor device descriptor * @param[in] spi SPI bus the sensor is connected to + * @param[in] clk SPI bus speed * @param[in] cs GPIO pin the chip select signal is connected to * * @return 0 on success * @return <0 on error */ -int adt7310_init(adt7310_t *dev, spi_t spi, gpio_t cs); +int adt7310_init(adt7310_t *dev, spi_t spi, spi_clk_t clk, gpio_t cs); /** * @brief Read raw temperature register value diff --git a/drivers/include/at86rf2xx.h b/drivers/include/at86rf2xx.h index 74a963083667..a2e49b9e1d81 100644 --- a/drivers/include/at86rf2xx.h +++ b/drivers/include/at86rf2xx.h @@ -137,8 +137,8 @@ extern "C" { */ typedef struct at86rf2xx_params { spi_t spi; /**< SPI bus the device is connected to */ - spi_speed_t spi_speed; /**< SPI speed to use */ - gpio_t cs_pin; /**< GPIO pin connected to chip select */ + spi_clk_t spi_clk; /**< SPI clock speed to use */ + spi_cs_t cs_pin; /**< GPIO pin connected to chip select */ gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */ gpio_t sleep_pin; /**< GPIO pin connected to the sleep pin */ gpio_t reset_pin; /**< GPIO pin connected to the reset pin */ diff --git a/drivers/include/cc2420.h b/drivers/include/cc2420.h index c10d0cf0a51d..ab4758054e99 100644 --- a/drivers/include/cc2420.h +++ b/drivers/include/cc2420.h @@ -74,7 +74,7 @@ enum { */ typedef struct cc2420_params { spi_t spi; /**< SPI bus the device is connected to */ - spi_speed_t spi_clk; /**< SPI speed to use */ + spi_clk_t spi_clk; /**< SPI speed to use */ gpio_t pin_cs; /**< pin connected to chip select */ gpio_t pin_fifo; /**< pin connected to the FIFO interrupt pin */ gpio_t pin_fifop; /**< pin connected to the FIFOP interrupt pin */ diff --git a/drivers/include/encx24j600.h b/drivers/include/encx24j600.h index 683b6c1efc0c..a4ab05c40e77 100644 --- a/drivers/include/encx24j600.h +++ b/drivers/include/encx24j600.h @@ -41,7 +41,6 @@ typedef struct { gpio_t cs; /**< SPI chip select pin */ gpio_t int_pin; /**< SPI interrupt pin */ uint16_t rx_next_ptr; /**< ptr to next packet whithin devices memory */ - mutex_t mutex; /**< mutex used to lock device access */ } encx24j600_t; /** diff --git a/drivers/include/kw2xrf.h b/drivers/include/kw2xrf.h index a90fc43a44fe..c7682ba1b7c5 100644 --- a/drivers/include/kw2xrf.h +++ b/drivers/include/kw2xrf.h @@ -130,14 +130,14 @@ typedef struct { * @brief Initialize the given KW2XRF device * @param[out] dev device descriptor * @param[in] spi SPI bus the device is connected to - * @param[in] spi_speed SPI speed to use + * @param[in] spi_clk SPI bus clock speed to use * @param[in] cs_pin GPIO pin connected to chip select * @param[in] int_pin GPIO pin connected to the interrupt pin * * @return 0 on success * @return <0 on error */ -int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed, +int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk, gpio_t cs_pin, gpio_t int_pin); /** @@ -145,7 +145,7 @@ int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed, */ typedef struct kw2xrf_params { spi_t spi; /**< SPI bus the device is connected to */ - spi_speed_t spi_speed; /**< SPI speed to use */ + spi_clk_t spi_speed; /**< SPI speed to use */ gpio_t cs_pin; /**< GPIO pin connected to chip select */ gpio_t int_pin; /**< GPIO pin connected to the interrupt pin */ } kw2xrf_params_t; diff --git a/drivers/include/lis3dh.h b/drivers/include/lis3dh.h index ec4bfb8298c8..a0015fdc7d86 100644 --- a/drivers/include/lis3dh.h +++ b/drivers/include/lis3dh.h @@ -677,10 +677,11 @@ typedef enum { /** @} */ /** - * @brief Device descriptor for LIS3DH sensors + * @brief Configuration parameters for LIS3DH devices */ typedef struct { spi_t spi; /**< SPI device the sensor is connected to */ + spi_clk_t clk; /**< designated clock speed of the SPI bus */ gpio_t cs; /**< Chip select pin */ gpio_t int1; /**< INT1 pin */ gpio_t int2; /**< INT2 (DRDY) pin */ @@ -688,8 +689,12 @@ typedef struct { uint8_t odr; /**< Default sensor ODR setting: LIS3DH_ODR_xxxHz */ } lis3dh_params_t; +/** + * @brief Device descriptor for LIS3DH sensors + */ typedef struct { spi_t spi; /**< SPI device the sensor is connected to */ + spi_clk_t clk; /**< clock speed of the SPI bus */ gpio_t cs; /**< Chip select pin */ int16_t scale; /**< Current scale setting of the sensor */ } lis3dh_t; @@ -710,13 +715,15 @@ typedef struct __attribute__((packed)) * * @param[in] dev Device descriptor of sensor to initialize * @param[in] spi SPI bus the accelerometer is connected to + * @param[in] clk SPI bus speed * @param[in] cs_pin GPIO connected to the chip select pin of the accelerometer * @param[in] scale Initial scale setting of the sensor * * @return 0 on success * @return -1 on error */ -int lis3dh_init(lis3dh_t *dev, spi_t spi, gpio_t cs_pin, uint8_t scale); +int lis3dh_init(lis3dh_t *dev, spi_t spi, spi_clk_t clk, + gpio_t cs_pin, uint8_t scale); /** * @brief Read 3D acceleration data from the accelerometer diff --git a/drivers/include/nvram-spi.h b/drivers/include/nvram-spi.h index c03a163106cc..c064d93e228b 100644 --- a/drivers/include/nvram-spi.h +++ b/drivers/include/nvram-spi.h @@ -38,6 +38,8 @@ extern "C" { typedef struct nvram_spi_params { /** @brief RIOT SPI device */ spi_t spi; + /** @brief SPI clock speed */ + spi_clk_t clk; /** @brief Chip select pin */ gpio_t cs; /** @brief Number of address bytes following each read/write command. */ diff --git a/drivers/include/periph/init.h b/drivers/include/periph/init.h new file mode 100644 index 000000000000..3e74d35ba76e --- /dev/null +++ b/drivers/include/periph/init.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 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. + */ + +/** + * @defgroup drivers_periph_init Common peripheral initialization + * @ingroup drivers_periph + * @brief Common static peripheral driver initialization + * + * This interface provides a central hook for any static peripheral + * initialization that might be needed. Typical drivers that need this are + * shared peripherals like SPI and I2C. + * + * @{ + * @file + * @brief Common peripheral driver initialization interface + * + * @author Hauke Petersen + */ + +#ifndef PERIPH_INIT_H +#define PERIPH_INIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Common peripheral initialization function + * + * This function should call all needed static initialization functions for + * configured peripheral drivers like SPI or I2C. This function SHOULD be called + * early in the boot process, e.g. before the actual kernel initialization is + * started. + */ +void periph_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_INIT_H */ +/** @} */ diff --git a/drivers/include/periph/spi.h b/drivers/include/periph/spi.h index 64888141edda..adbc2bf85e8a 100644 --- a/drivers/include/periph/spi.h +++ b/drivers/include/periph/spi.h @@ -1,9 +1,9 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-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. */ /** @@ -11,258 +11,316 @@ * @ingroup drivers_periph * @brief Low-level SPI peripheral driver * - * The current design of this interface targets implementations that use the SPI in blocking mode. - * - * TODO: add means for asynchronous SPI usage + * This interface defines an abstraction for using a CPU's hardware SPI units. + * The interface only supports SPI master mode. + * + * As SPI buses can have multiple devices connected to them they are to be + * considered as shared resources. To reflect this, the SPI interface is based + * on a transaction model. This requires that the bus needs to be acquired + * before usage and released afterwards, using the `spi_acquire()` and the + * `spi_release()` functions. + * + * This interface supports both software and hardware chip select lines. This is + * reflected by the cpi_cs_t type, which overloads the gpio_t type with platform + * specific values for defining platform dependent hardware chip select lines. + * + * Some devices have however very uncommon requirements on the usage and the + * timings of their chip select line. For those cases this interface allows to + * manage the chip select line manually from the user code (e.g. by calling + * gpio_set/clear explicitly) while deactivating the SPI driver internal chip + * select handling by passing @ref GPIO_UNDEF as CS parameter. + * + * In the time, when the SPI bus is not used, the SPI unit should be in + * low-power mode to save energy. + * + * The SPI unit's initialization is split into 3 parts: + * 1. `spi_init()` should be called once for each SPI unit defined by a board + * during system initialization. + * 2. `spi_init_cs()` should be called during device driver initialization, as + * each chip select pin/line is used uniquely by a specific device, i.e. chip + * select lines are no shared resource. + * 3. `spi_aquire()` needs to be called for each new transaction. This function + * configures the bus with specific parameters (clock, mode) for the duration + * of that transaction. * * @{ * @file - * @brief Low-level SPI peripheral driver interface definitions + * @brief Low-level SPI peripheral driver interface definition * * @author Hauke Petersen */ -#ifndef SPI_H -#define SPI_H +#ifndef PERIPH_SPI_H +#define PERIPH_SPI_H +#include +#include #include +#include #include "periph_cpu.h" #include "periph_conf.h" +#include "periph/gpio.h" #ifdef __cplusplus extern "C" { #endif -/* add guard for the case that no SPI device is defined */ -#if SPI_NUMOF +/** + * @brief Default SPI device access macro + */ +#ifndef SPI_DEV +#define SPI_DEV(x) (x) +#endif /** - * @brief Definition available SPI devices + * @brief Define global value for undefined SPI device */ -typedef enum { -#if SPI_0_EN - SPI_0 = 0, /**< SPI device 0 */ +#ifndef SPI_UNDEF +#define SPI_UNDEF (UINT_MAX) #endif -#if SPI_1_EN - SPI_1, /**< SPI device 1 */ + +/** + * @brief Define value for unused CS line + */ +#ifndef SPI_CS_UNDEF +#define SPI_CS_UNDEF (GPIO_UNDEF) #endif -#if SPI_2_EN - SPI_2, /**< SPI device 2 */ + +/** + * @brief Default SPI hardware chip select access macro + * + * Per default, we map all hardware chip select lines to be not defined. If an + * implementation makes use of HW chip select lines, this value needs to be + * overridden by the corresponding CPU. + */ +#ifndef SPI_HWCS +#define SPI_HWCS(x) (SPI_CS_UNDEF) #endif -#if SPI_3_EN - SPI_3, /**< SPI device 3 */ + +/** + * @brief Default type for SPI devices + */ +#ifndef HAVE_SPI_T +typedef unsigned int spi_t; #endif -} spi_t; /** - * @brief The SPI mode is defined by the four possible combinations of clock polarity and - * clock phase. - * @{ + * @brief Chip select pin type overlaps with gpio_t so it can be casted to + * this */ -#ifndef HAVE_SPI_CONF_T -typedef enum { - /** - * The first data bit is sampled by the receiver on the first SCK edge. The - * first edge of SCK is rising. This is sometimes also referred to as SPI - * mode 0, or (CPOL=0, CPHA=0). - */ - SPI_CONF_FIRST_RISING = 0, - /** - * The first data bit is sampled by the receiver on the second SCK edge. The - * first edge of SCK is rising, i.e. the sampling edge is falling. This is - * sometimes also referred to as SPI mode 1, or (CPOL=0, CPHA=1). - */ - SPI_CONF_SECOND_RISING = 1, - /** - * The first data bit is sampled by the receiver on the first SCK edge. The - * first edge of SCK is falling. This is sometimes also referred to as SPI - * mode 2, or (CPOL=1, CPHA=0). - */ - SPI_CONF_FIRST_FALLING = 2, - /** - * The first data bit is sampled by the receiver on the second SCK edge. The - * first edge of SCK is falling, i.e. the sampling edge is rising. This is - * sometimes also referred to as SPI mode 3, or (CPOL=1, CPHA=1). - */ - SPI_CONF_SECOND_FALLING = 3 -} spi_conf_t; +#ifndef HAVE_SPI_CS_T +typedef gpio_t spi_cs_t; #endif -/** @} */ /** - * @brief Define a set of pre-defined SPI clock speeds. - * - * The actual speed of the bus can vary to some extend, as the combination of CPU clock and - * available prescale values on certain platforms may not make the exact values possible. - * - * @{ + * @brief Status codes used by the SPI driver interface + */ +enum { + SPI_OK = 0, /**< everything went as planned */ + SPI_NODEV = -1, /**< invalid SPI bus specified */ + SPI_NOCS = -2, /**< invalid chip select line specified */ + SPI_NOMODE = -3, /**< selected mode is not supported */ + SPI_NOCLK = -4 /**< selected clock value is not supported */ +}; + +/** + * @brief Available SPI modes, defining the configuration of clock polarity + * and clock phase + * + * RIOT is using the mode numbers as commonly defined by most vendors + * (https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Mode_numbers): + * + * - MODE_0: CPOL=0, CPHA=0 - The first data bit is sampled by the receiver on + * the first SCK rising SCK edge (this mode is used most often). + * - MODE_1: CPOL=0, CPHA=1 - The first data bit is sampled by the receiver on + * the second rising SCK edge. + * - MODE_2: CPOL=1, CPHA=0 - The first data bit is sampled by the receiver on + * the first falling SCK edge. + * - MODE_3: CPOL=1, CPHA=1 - The first data bit is sampled by the receiver on + * the second falling SCK edge. */ -#ifndef HAVE_SPI_SPEED_T +#ifndef HAVE_SPI_MODE_T typedef enum { - SPI_SPEED_100KHZ = 0, /**< drive the SPI bus with 100KHz */ - SPI_SPEED_400KHZ, /**< drive the SPI bus with 400KHz */ - SPI_SPEED_1MHZ, /**< drive the SPI bus with 1MHz */ - SPI_SPEED_5MHZ, /**< drive the SPI bus with 5MHz */ - SPI_SPEED_10MHZ /**< drive the SPI bus with 10MHz */ -} spi_speed_t; + SPI_MODE_0 = 0, /**< CPOL=0, CPHA=0 */ + SPI_MODE_1, /**< CPOL=0, CPHA=1 */ + SPI_MODE_2, /**< CPOL=1, CPHA=0 */ + SPI_MODE_3 /**< CPOL=1, CPHA=1 */ +} spi_mode_t; #endif -/** @} */ /** - * @brief Initialize the given SPI device to work in master mode - * - * In master mode the SPI device is configured to control the SPI bus. This means the device - * will start and end all communication on the bus and control the CLK line. For transferring - * data on the bus the below defined transfer functions should be used. - * - * @param[in] dev SPI device to initialize - * @param[in] conf Mode of clock phase and clock polarity - * @param[in] speed desired clock speed for driving the SPI bus + * @brief Available SPI clock speeds * - * @return 0 on success - * @return -1 on unavailable speed value - * @return -2 on other errors + * The actual speed of the bus can vary to some extend, as the combination of + * CPU clock and available prescaler values on certain platforms may not make + * the exact values possible. */ -int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed); +#ifndef HAVE_SPI_CLK_T +typedef enum { + SPI_CLK_100KHZ = 0, /**< drive the SPI bus with 100KHz */ + SPI_CLK_400KHZ, /**< drive the SPI bus with 400KHz */ + SPI_CLK_1MHZ, /**< drive the SPI bus with 1MHz */ + SPI_CLK_5MHZ, /**< drive the SPI bus with 5MHz */ + SPI_CLK_10MHZ /**< drive the SPI bus with 10MHz */ +} spi_clk_t; +#endif /** - * @brief Initialize the given SPI device to work in slave mode + * @brief Basic initialization of the given SPI bus * - * In slave mode the SPI device is purely reacting to the bus. Transaction will be started and - * ended by a connected SPI master. When a byte is received, the callback is called in interrupt - * context with this byte as argument. The return byte of the callback is transferred to the - * master in the next transmission cycle. This interface enables easy implementation of a register - * based access paradigm for the SPI slave. + * This function does the basic initialization including pin configuration for + * MISO, MOSI, and CLK pins. After initialization, the given device should be + * in power down state. * - * @param[in] dev The SPI device to initialize as SPI slave - * @param[in] conf Mode of clock phase and polarity - * @param[in] cb callback called every time a byte was received + * This function is intended to be called by the board initialization code + * during system startup to prepare the (shared) SPI device for further usage. + * It uses the board specific initialization parameters as defined in the + * board's `periph_conf.h`. * - * @return 0 on success - * @return -1 on error - */ -int spi_init_slave(spi_t dev, spi_conf_t conf, char (*cb)(char data)); - -/** - * @brief Configure SCK, MISO and MOSI pins for the given SPI device + * Errors (e.g. invalid @p bus parameter) are not signaled through a return + * value, but should be signaled using the assert() function internally. * - * @param[in] dev SPI device to use + * @note This function MUST not be called more than once per bus! * - * @return 0 on success - * @return -1 on error + * @param[in] bus SPI device to initialize */ -int spi_conf_pins(spi_t dev); +void spi_init(spi_t bus); /** - * @brief Get mutually exclusive access to the given SPI bus + * @brief Initialize the used SPI bus pins, i.e. MISO, MOSI, and CLK + * * - * In case the SPI device is busy, this function will block until the bus is free again. + * After calling spi_init, the pins must be initialized (i.e. spi_init is + * calling) this function internally. In normal cases, this function will not be + * used. But there are some devices (e.g. CC110x), that use SPI bus lines also + * for other purposes and need the option to dynamically re-configure one or + * more of the used pins. So they can take control over certain pins and return + * control back to the SPI driver using this function. * - * @param[in] dev SPI device to access + * The pins used are configured in the board's periph_conf.h. * - * @return 0 on success - * @return -1 on error + * @param[in] bus SPI device the pins are configure for */ -int spi_acquire(spi_t dev); +void spi_init_pins(spi_t bus); /** - * @brief Release the given SPI device to be used by others + * @brief Initialize the given chip select pin * - * @param[in] dev SPI device to release + * The chip select can be any generic GPIO pin (e.g. GPIO_PIN(x,y)), or it can + * be a hardware chip select line. The existence and number of of hardware chip + * select lines depends on the underlying platform and the actual pins used for + * hardware chip select lines are defined in the board's `periph_conf.h`. * - * @return 0 on success - * @return -1 on error - */ -int spi_release(spi_t dev); - -/** - * @brief Transfer one byte on the given SPI bus + * Define the used chip select line using the @ref SPI_HWCS(x) macro for + * hardware chip select line `x` or the GPIO_PIN(x,y) macro for using any + * GPIO pin for manual chip select. * - * @param[in] dev SPI device to use - * @param[in] out Byte to send out, set NULL if only receiving - * @param[out] in Byte to read, set NULL if only sending + * @param[in] bus SPI device that is used with the given CS line + * @param[in] cs chip select pin to initialize * - * @return Number of bytes that were transfered - * @return -1 on error + * @return SPI_OK on success + * @return SPI_NODEV on invalid device + * @return SPI_NOCS on invalid CS pin/line */ -int spi_transfer_byte(spi_t dev, char out, char *in); +int spi_init_cs(spi_t bus, spi_cs_t cs); /** - * @brief Transfer a number bytes on the given SPI bus + * @brief Start a new SPI transaction + * + * Starting a new SPI transaction will get exclusive access to the SPI bus + * and configure it according to the given values. If another SPI transaction + * is active when this function is called, this function will block until the + * other transaction is complete (spi_relase was called). + * + * @note This function expects the @p bus and the @p cs parameters to be + * valid (they are checked in spi_init and spi_init_cs before) * - * @param[in] dev SPI device to use - * @param[in] out Array of bytes to send, set NULL if only receiving - * @param[out] in Buffer to receive bytes to, set NULL if only sending - * @param[in] length Number of bytes to transfer + * @param[in] bus SPI device to access + * @param[in] cs chip select pin/line to use, set to SPI_CS_UNDEF if chip + * select should not be handled by the SPI driver + * @param[in] mode mode to use for the new transaction + * @param[in] clk bus clock speed to use for the transaction * - * @return Number of bytes that were transfered - * @return -1 on error + * @return SPI_OK on success + * @return SPI_NOMODE if given mode is not supported + * @return SPI_NOCLK if given clock speed is not supported */ -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length); +int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk); /** - * @brief Transfer one byte to/from a given register address + * @brief Finish an ongoing SPI transaction by releasing the given SPI bus * - * This function is a shortcut function for easier handling of register based SPI devices. As - * many SPI devices use a register based addressing scheme, this function is a convenient short- - * cut for interfacing with such devices. + * After release, the given SPI bus should be fully powered down until acquired + * again. * - * @param[in] dev SPI device to use - * @param[in] reg Register address to transfer data to/from - * @param[in] out Byte to send, set NULL if only receiving data - * @param[out] in Byte to read, set NULL if only sending - * - * @return Number of bytes that were transfered - * @return -1 on error + * @param[in] bus SPI device to release */ -int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in); +void spi_release(spi_t bus); /** - * @brief Transfer a number of bytes from/to a given register address - * - * This function is a shortcut function for easier handling of register based SPI devices. As - * many SPI devices use a register based addressing scheme, this function is a convenient short- - * cut for interfacing with such devices. + * @brief Transfer one byte on the given SPI bus * - * @param[in] dev SPI device to use - * @param[in] reg Register address to transfer data to/from - * @param[in] out Byte array to send data from, set NULL if only receiving - * @param[out] in Byte buffer to read into, set NULL if only sending - * @param[in] length Number of bytes to transfer + * @param[in] bus SPI device to use + * @param[in] cs chip select pin/line to use, set to SPI_CS_UNDEF if chip + * select should not be handled by the SPI driver + * @param[in] cont if true, keep device selected after transfer + * @param[in] out byte to send out, set NULL if only receiving * - * @return Number of bytes that were transfered - * @return -1 on error + * @return the received byte */ -int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length); +uint8_t spi_transfer_byte(spi_t bus, spi_cs_t cs, bool cont, uint8_t out); /** - * @brief Tell the SPI driver that a new transaction was started. Call only when SPI in slave mode! - * - * @param[in] dev SPI device that is active - * @param[in] reset_val The byte that is send to the master as first byte + * @brief Transfer a number bytes using the given SPI bus + * + * @param[in] bus SPI device to use + * @param[in] cs chip select pin/line to use, set to SPI_CS_UNDEF if chip + * select should not be handled by the SPI driver + * @param[in] cont if true, keep device selected after transfer + * @param[in] out buffer to send data from, set NULL if only receiving + * @param[out] in buffer to read into, set NULL if only sending + * @param[in] len number of bytes to transfer */ -void spi_transmission_begin(spi_t dev, char reset_val); +void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont, + const void *out, void *in, size_t len); /** - * @brief Power on the given SPI device + * @brief Transfer one byte to/from a given register address + * + * This function is a shortcut function for easier handling of SPI devices that + * implement a register based access scheme. + * + * @param[in] bus SPI device to use + * @param[in] cs chip select pin/line to use, set to SPI_CS_UNDEF if chip + * select should not be handled by the SPI driver + * @param[in] reg register address to transfer data to/from + * @param[in] out byte to send, set NULL if only receiving data * - * @param[in] dev SPI device to power on + * @return value that was read from the given register address */ -void spi_poweron(spi_t dev); +uint8_t spi_transfer_reg(spi_t bus, spi_cs_t cs, uint8_t reg, uint8_t out); /** - * @brief Power off the given SPI device - * - * @param[in] dev SPI device to power off + * @brief Transfer a number of bytes to/from a given register address + * + * This function is a shortcut function for easier handling of SPI devices that + * implement a register based access scheme. + * + * @param[in] bus SPI device to use + * @param[in] cs chip select pin/line to use, set to SPI_CS_UNDEF if chip + * select should not be handled by the SPI driver + * @param[in] reg register address to transfer data to/from + * @param[in] out buffer to send data from, set NULL if only receiving + * @param[out] in buffer to read into, set NULL if only sending + * @param[in] len number of bytes to transfer */ -void spi_poweroff(spi_t dev); - -#endif /* SPI_NUMOF */ +void spi_transfer_regs(spi_t bus, spi_cs_t cs, uint8_t reg, + const void *out, void *in, size_t len); #ifdef __cplusplus } #endif -#endif /* SPI_H */ +#endif /* PERIPH_SPI_H */ /** @} */ diff --git a/drivers/include/sdcard_spi.h b/drivers/include/sdcard_spi.h index 87758921285d..0d19a56d1bd0 100644 --- a/drivers/include/sdcard_spi.h +++ b/drivers/include/sdcard_spi.h @@ -185,13 +185,14 @@ typedef struct { * @brief Device descriptor for sdcard_spi */ struct { - sdcard_spi_params_t params; /**< parameters for pin and spi config */ - bool use_block_addr; /**< true if block adressing (vs. byte adressing) is used */ - bool init_done; /**< set to true once the init procedure completed sucessfully */ - sd_version_t card_type; /**< version of SD-card */ - int csd_structure; /**< version of the CSD register structure */ - cid_t cid; /**< CID register */ - csd_t csd; /**< CSD register */ + sdcard_spi_params_t params; /**< parameters for pin and spi config */ + spi_clk_t spi_clk; /**< active SPI clock speed */ + bool use_block_addr; /**< true if block adressing (vs. byte adressing) is used */ + bool init_done; /**< set to true once the init procedure completed sucessfully */ + sd_version_t card_type; /**< version of SD-card */ + int csd_structure; /**< version of the CSD register structure */ + cid_t cid; /**< CID register */ + csd_t csd; /**< CSD register */ } typedef sdcard_spi_t; /** diff --git a/drivers/include/w5100.h b/drivers/include/w5100.h index 9cd72076c9dd..75447a08f695 100644 --- a/drivers/include/w5100.h +++ b/drivers/include/w5100.h @@ -56,7 +56,7 @@ enum { */ typedef struct { spi_t spi; /**< SPI bus used */ - spi_speed_t spi_speed; /**< clock speed used on the selected SPI bus */ + spi_clk_t clk; /**< clock speed used on the selected SPI bus */ gpio_t cs; /**< pin connected to the chip select line */ gpio_t evt; /**< pin connected to the INT line */ } w5100_params_t; diff --git a/drivers/kw2xrf/include/kw2xrf_spi.h b/drivers/kw2xrf/include/kw2xrf_spi.h index 3368ed21ee4b..a973a5510f1c 100644 --- a/drivers/kw2xrf/include/kw2xrf_spi.h +++ b/drivers/kw2xrf/include/kw2xrf_spi.h @@ -30,14 +30,13 @@ extern "C" { /** * @brief SPI interface initialization * @param[in] spi SPI bus the device is connected to - * @param[in] spi_speed SPI speed to use + * @param[in] spi_clk SPI clock speed to use * @param[in] cs_pin GPIO pin connected to chip select * * @return 0 on success * @return -1 on error */ -int kw2xrf_spi_init(spi_t spi, spi_speed_t spi_speed, - gpio_t cs_pin); +int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin); /** * @brief Writes a byte to the kw2xrf register. diff --git a/drivers/kw2xrf/kw2xrf.c b/drivers/kw2xrf/kw2xrf.c index ebb4dff1e631..fd2b41d9b7ff 100644 --- a/drivers/kw2xrf/kw2xrf.c +++ b/drivers/kw2xrf/kw2xrf.c @@ -383,7 +383,7 @@ int kw2xrf_set_addr_long(kw2xrf_t *dev, uint64_t addr) return sizeof(uint64_t); } -int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed, +int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_clk_t spi_clk, gpio_t cs_pin, gpio_t int_pin) { uint8_t reg = 0; @@ -405,7 +405,7 @@ int kw2xrf_init(kw2xrf_t *dev, spi_t spi, spi_speed_t spi_speed, return -ENODEV; } - kw2xrf_spi_init(spi, spi_speed, cs_pin); + kw2xrf_spi_init(spi, spi_clk, cs_pin); if (kw2xrf_on(dev) != 0) { core_panic(PANIC_GENERAL_ERROR, "Could not start MKW2XD radio transceiver"); diff --git a/drivers/kw2xrf/kw2xrf_spi.c b/drivers/kw2xrf/kw2xrf_spi.c index 8a9bc9e4f58f..f129925dccc0 100644 --- a/drivers/kw2xrf/kw2xrf_spi.c +++ b/drivers/kw2xrf/kw2xrf_spi.c @@ -27,49 +27,36 @@ #define ENABLE_DEBUG (0) #include "debug.h" -#define KW2XRF_IBUF_LENGTH 9 +#define SPI_MODE (SPI_MODE_0) +#define KW2XRF_IBUF_LENGTH (9) static uint8_t ibuf[KW2XRF_IBUF_LENGTH]; /** Set up in kw2xrf_spi_init during initialization */ -static gpio_t kw2xrf_cs_pin; static spi_t kw2xrf_spi; +static spi_clk_t kw2xrf_clk; +static spi_cs_t kw2xrf_cs_pin; -void kw2xrf_spi_transfer_head(void) +static inline void kw2xrf_spi_transfer_head(void) { -#if KW2XRF_SHARED_SPI - spi_acquire(kw2xrf_spi); - gpio_clear(kw2xrf_cs_pin); -#endif + spi_acquire(kw2xrf_spi, kw2xrf_cs_pin, SPI_MODE, kw2xrf_clk); } -void kw2xrf_spi_transfer_tail(void) +static inline void kw2xrf_spi_transfer_tail(void) { -#if KW2XRF_SHARED_SPI - gpio_set(kw2xrf_cs_pin); spi_release(kw2xrf_spi); -#endif } -int kw2xrf_spi_init(spi_t spi, spi_speed_t spi_speed, - gpio_t cs_pin) +int kw2xrf_spi_init(spi_t spi, spi_clk_t spi_clk, spi_cs_t cs_pin) { int res; - kw2xrf_cs_pin = cs_pin; /**< for later reference */ kw2xrf_spi = spi; + kw2xrf_clk = spi_clk; + kw2xrf_cs_pin = cs_pin; /**< for later reference */ -#if KW2XRF_SHARED_SPI - spi_acquire(kw2xrf_spi); -#endif - res = spi_init_master(kw2xrf_spi, SPI_CONF_FIRST_RISING, spi_speed); -#if KW2XRF_SHARED_SPI - spi_release(kw2xrf_spi); - gpio_init(kw2xrf_cs_pin, GPIO_OUT); - gpio_set(kw2xrf_cs_pin); -#endif - - if (res < 0) { - DEBUG("kw2xrf_spi_init: error initializing SPI_%i device (code %i)\n", + res = spi_init_cs(kw2xrf_spi, kw2xrf_cs_pin); + if (res != SPI_OK) { + DEBUG("kw2xrf_spi_init: error initializing SPI_DEV(%i) (code %i)\n", kw2xrf_spi, res); return -1; } @@ -80,7 +67,7 @@ int kw2xrf_spi_init(spi_t spi, spi_speed_t spi_speed, void kw2xrf_write_dreg(uint8_t addr, uint8_t value) { kw2xrf_spi_transfer_head(); - spi_transfer_reg(kw2xrf_spi, addr, value, NULL); + spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin, addr, value); kw2xrf_spi_transfer_tail(); return; } @@ -89,8 +76,8 @@ uint8_t kw2xrf_read_dreg(uint8_t addr) { uint8_t value; kw2xrf_spi_transfer_head(); - spi_transfer_reg(kw2xrf_spi, (addr | MKW2XDRF_REG_READ), - 0x0, (char *)&value); + value = spi_transfer_reg(kw2xrf_spi, kw2xrf_cs_pin, + (addr | MKW2XDRF_REG_READ), 0x0); kw2xrf_spi_transfer_tail(); return value; } @@ -108,8 +95,8 @@ void kw2xrf_write_iregs(uint8_t addr, uint8_t *buf, uint8_t length) } kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, MKW2XDM_IAR_INDEX, - (char *)ibuf, NULL, length + 1); + spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDM_IAR_INDEX, + ibuf, NULL, length + 1); kw2xrf_spi_transfer_tail(); return; @@ -124,8 +111,9 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length) ibuf[0] = addr; kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ, - (char *)ibuf, (char *)ibuf, length + 1); + spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, + MKW2XDM_IAR_INDEX | MKW2XDRF_REG_READ, + ibuf, ibuf, length + 1); kw2xrf_spi_transfer_tail(); for (uint8_t i = 0; i < length; i++) { @@ -138,16 +126,15 @@ void kw2xrf_read_iregs(uint8_t addr, uint8_t *buf, uint8_t length) void kw2xrf_write_fifo(uint8_t *data, uint8_t length) { kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, MKW2XDRF_BUF_WRITE, - (char *)data, NULL, length); + spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_WRITE, + data, NULL, length); kw2xrf_spi_transfer_tail(); } void kw2xrf_read_fifo(uint8_t *data, uint8_t length) { kw2xrf_spi_transfer_head(); - spi_transfer_regs(kw2xrf_spi, MKW2XDRF_BUF_READ, NULL, - (char *)data, length); + spi_transfer_regs(kw2xrf_spi, kw2xrf_cs_pin, MKW2XDRF_BUF_READ, + NULL, data, length); kw2xrf_spi_transfer_tail(); } -/** @} */ diff --git a/drivers/lis3dh/include/lis3dh_params.h b/drivers/lis3dh/include/lis3dh_params.h index 77c47fae5adc..8d0159fe5618 100644 --- a/drivers/lis3dh/include/lis3dh_params.h +++ b/drivers/lis3dh/include/lis3dh_params.h @@ -32,7 +32,7 @@ extern "C" { * @{ */ #ifndef LIS3DH_PARAM_SPI -#define LIS3DH_PARAM_SPI (SPI_0) +#define LIS3DH_PARAM_SPI (SPI_DEV(0)) #endif #ifndef LIS3DH_PARAM_CS #define LIS3DH_PARAM_CS (GPIO_PIN(0, 0)) diff --git a/drivers/lis3dh/lis3dh.c b/drivers/lis3dh/lis3dh.c index fae0064e0e6c..808687bae1e0 100644 --- a/drivers/lis3dh/lis3dh.c +++ b/drivers/lis3dh/lis3dh.c @@ -1,54 +1,59 @@ /* * Copyright (C) 2015 Eistec AB + * 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. */ -#include -#include -#include "periph/gpio.h" -#include "periph/spi.h" -#include "lis3dh.h" - /** * @ingroup drivers_lis3dh * @{ * * @file - * @brief Implementation of LIS3DH SPI driver + * @brief Implementation of LIS3DH SPI driver * - * @author Joakim Nohlgård + * @author Joakim Nohlgård + * @author Hauke Petersen */ +#include +#include +#include "periph/gpio.h" +#include "periph/spi.h" +#include "lis3dh.h" -static inline int lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t mask, - const uint8_t values); -static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t value); -static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t len, - uint8_t *buf); +#define SPI_MODE SPI_MODE_0 +static inline int lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg, + const uint8_t mask, const uint8_t values); +static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, + const uint8_t value); +static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, + const uint8_t len, uint8_t *buf); -int lis3dh_init(lis3dh_t *dev, spi_t spi, gpio_t cs_pin, uint8_t scale) +int lis3dh_init(lis3dh_t *dev, spi_t spi, spi_clk_t clk, + gpio_t cs_pin, uint8_t scale) { - uint8_t in; + uint8_t test; dev->spi = spi; + dev->clk = clk; dev->cs = cs_pin; dev->scale = 0; - /* CS */ - gpio_init(dev->cs, GPIO_OUT); - gpio_set(dev->cs); - - if (lis3dh_read_regs(dev, LIS3DH_REG_WHO_AM_I, 1, &in) < 0) { - /* Communication error */ + /* initialize the chip select line */ + if (spi_init_cs(dev->spi, dev->cs) != SPI_OK) { return -1; } - if (in != LIS3DH_WHO_AM_I_RESPONSE) { - /* Chip is not responding correctly */ + /* test connection to the device */ + spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk); + test = spi_transfer_reg(dev->spi, dev->cs, LIS3DH_REG_WHO_AM_I, 0); + spi_release(dev->spi); + if (test != LIS3DH_WHO_AM_I_RESPONSE) { + /* chip is not responding correctly */ return -1; } @@ -78,23 +83,14 @@ int lis3dh_read_xyz(const lis3dh_t *dev, lis3dh_data_t *acc_data) { uint8_t i; /* Set READ MULTIPLE mode */ - static const uint8_t addr = (LIS3DH_REG_OUT_X_L | LIS3DH_SPI_READ_MASK | LIS3DH_SPI_MULTI_MASK); + static const uint8_t addr = (LIS3DH_REG_OUT_X_L | LIS3DH_SPI_READ_MASK | + LIS3DH_SPI_MULTI_MASK); /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); + spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk); /* Perform the transaction */ - gpio_clear(dev->cs); - - if (spi_transfer_regs(dev->spi, addr, NULL, (char *)acc_data, - sizeof(lis3dh_data_t)) != sizeof(lis3dh_data_t)) { - /* Transfer error */ - gpio_set(dev->cs); - /* Release the bus for other threads. */ - spi_release(dev->spi); - return -1; - } - - gpio_set(dev->cs); + spi_transfer_regs(dev->spi, dev->cs, addr, + NULL, acc_data, sizeof(lis3dh_data_t)); /* Release the bus for other threads. */ spi_release(dev->spi); @@ -111,29 +107,35 @@ int lis3dh_read_xyz(const lis3dh_t *dev, lis3dh_data_t *acc_data) int lis3dh_read_aux_adc1(const lis3dh_t *dev, int16_t *out) { - return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC1_L, LIS3DH_ADC_DATA_SIZE, (uint8_t *)out); + return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC1_L, + LIS3DH_ADC_DATA_SIZE, (uint8_t *)out); } int lis3dh_read_aux_adc2(const lis3dh_t *dev, int16_t *out) { - return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC2_L, LIS3DH_ADC_DATA_SIZE, (uint8_t *)out); + return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC2_L, + LIS3DH_ADC_DATA_SIZE, (uint8_t *)out); } int lis3dh_read_aux_adc3(const lis3dh_t *dev, int16_t *out) { - return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC3_L, LIS3DH_ADC_DATA_SIZE, (uint8_t *)out); + return lis3dh_read_regs(dev, LIS3DH_REG_OUT_AUX_ADC3_L, + LIS3DH_ADC_DATA_SIZE, (uint8_t *)out); } -int lis3dh_set_aux_adc(lis3dh_t *dev, const uint8_t enable, const uint8_t temperature) +int lis3dh_set_aux_adc(lis3dh_t *dev, const uint8_t enable, + const uint8_t temperature) { - return lis3dh_write_bits(dev, LIS3DH_REG_TEMP_CFG_REG, LIS3DH_TEMP_CFG_REG_ADC_PD_MASK, + return lis3dh_write_bits(dev, LIS3DH_REG_TEMP_CFG_REG, + LIS3DH_TEMP_CFG_REG_ADC_PD_MASK, (enable ? LIS3DH_TEMP_CFG_REG_ADC_PD_MASK : 0) | (temperature ? LIS3DH_TEMP_CFG_REG_TEMP_EN_MASK : 0)); } int lis3dh_set_axes(lis3dh_t *dev, const uint8_t axes) { - return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG1, LIS3DH_CTRL_REG1_XYZEN_MASK, axes); + return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG1, + LIS3DH_CTRL_REG1_XYZEN_MASK, axes); } int lis3dh_set_fifo(lis3dh_t *dev, const uint8_t mode, const uint8_t watermark) @@ -190,8 +192,8 @@ int lis3dh_set_scale(lis3dh_t *dev, const uint8_t scale) default: return -1; } - return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG4, LIS3DH_CTRL_REG4_FS_MASK, - scale_reg); + return lis3dh_write_bits(dev, LIS3DH_REG_CTRL_REG4, + LIS3DH_CTRL_REG4_FS_MASK, scale_reg); } int lis3dh_set_int1(lis3dh_t *dev, const uint8_t mode) @@ -218,31 +220,23 @@ int lis3dh_get_fifo_level(lis3dh_t *dev) * @param[in] dev Device descriptor * @param[in] reg The source register starting address * @param[in] len Number of bytes to read - * @param[out] buf The values of the source registers will be written here + * @param[out] buf The values of the source registers will be written + * here * * @return 0 on success * @return -1 on error */ -static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t len, - uint8_t *buf) +static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, + const uint8_t len, uint8_t *buf) { /* Set READ MULTIPLE mode */ - uint8_t addr = (reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_READ_MASK | LIS3DH_SPI_MULTI_MASK; + uint8_t addr = (reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_READ_MASK | + LIS3DH_SPI_MULTI_MASK; /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); + spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk); /* Perform the transaction */ - gpio_clear(dev->cs); - - if (spi_transfer_regs(dev->spi, addr, NULL, (char *)buf, len) < 0) { - /* Transfer error */ - gpio_set(dev->cs); - /* Release the bus for other threads. */ - spi_release(dev->spi); - return -1; - } - - gpio_set(dev->cs); + spi_transfer_regs(dev->spi, dev->cs, addr, NULL, buf, (size_t)len); /* Release the bus for other threads. */ spi_release(dev->spi); @@ -258,27 +252,20 @@ static int lis3dh_read_regs(const lis3dh_t *dev, const lis3dh_reg_t reg, const u * @return 0 on success * @return -1 on error */ -static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t value) +static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, + const uint8_t value) { /* Set WRITE SINGLE mode */ - uint8_t addr = (reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_WRITE_MASK | LIS3DH_SPI_SINGLE_MASK; + uint8_t addr = ((reg & LIS3DH_SPI_ADDRESS_MASK) | LIS3DH_SPI_WRITE_MASK | + LIS3DH_SPI_SINGLE_MASK); /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); + spi_acquire(dev->spi, dev->cs, SPI_MODE, dev->clk); /* Perform the transaction */ - gpio_clear(dev->cs); - - if (spi_transfer_reg(dev->spi, addr, value, NULL) < 0) { - /* Transfer error */ - gpio_set(dev->cs); - /* Release the bus for other threads. */ - spi_release(dev->spi); - return -1; - } - - gpio_set(dev->cs); + spi_transfer_reg(dev->spi, dev->cs, addr, value); /* Release the bus for other threads. */ spi_release(dev->spi); + return 0; } @@ -292,9 +279,8 @@ static int lis3dh_write_reg(const lis3dh_t *dev, const lis3dh_reg_t reg, const u * @return 0 on success * @return -1 on error */ -static inline int -lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg, const uint8_t mask, - const uint8_t values) +static inline int lis3dh_write_bits(const lis3dh_t *dev, const lis3dh_reg_t reg, + const uint8_t mask, const uint8_t values) { uint8_t tmp; diff --git a/drivers/nrf24l01p/nrf24l01p.c b/drivers/nrf24l01p/nrf24l01p.c index d82a5a1b0ec9..344a381b7abe 100644 --- a/drivers/nrf24l01p/nrf24l01p.c +++ b/drivers/nrf24l01p/nrf24l01p.c @@ -31,43 +31,34 @@ #define DELAY_AFTER_FUNC_TICKS (xtimer_ticks_from_usec(DELAY_AFTER_FUNC_US)) #define DELAY_CHANGE_TXRX_TICKS (xtimer_ticks_from_usec(DELAY_CHANGE_TXRX_US)) +#define SPI_MODE SPI_MODE_0 +#define SPI_CLK SPI_CLK_400KHZ + int nrf24l01p_read_reg(nrf24l01p_t *dev, char reg, char *answer) { - int status; - /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_reg(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & reg)), CMD_NOP, answer); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + *answer = (char)spi_transfer_reg(dev->spi, dev->cs, + (CMD_R_REGISTER | (REGISTER_MASK & reg)), + CMD_NOP); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - - return (status < 0) ? status : 0; + return 0; } int nrf24l01p_write_reg(nrf24l01p_t *dev, char reg, char write) { - int status; - char reg_content; - /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_reg(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & reg)), write, ®_content); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_reg(dev->spi, dev->cs, + (CMD_W_REGISTER | (REGISTER_MASK & reg)), (uint8_t)write); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - - return (status < 0) ? status : 0; + return 0; } @@ -87,22 +78,17 @@ int nrf24l01p_init(nrf24l01p_t *dev, spi_t spi, gpio_t ce, gpio_t cs, gpio_t irq gpio_init(dev->ce, GPIO_OUT); /* Init CS pin */ - gpio_init(dev->cs, GPIO_OUT); - gpio_set(dev->cs); + spi_init_cs(dev->spi, dev->cs); /* Init IRQ pin */ gpio_init_int(dev->irq, GPIO_IN_PU, GPIO_FALLING, nrf24l01p_rx_cb, dev); - - /* Init SPI */ - spi_poweron(dev->spi); - spi_acquire(dev->spi); - status = spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, SPI_SPEED_400KHZ); - spi_release(dev->spi); - - if (status < 0) { - return status; + /* Test the SPI connection */ + if (spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK) != SPI_OK) { + DEBUG("error: unable to acquire SPI bus with given params\n"); + return -1; } + spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); @@ -237,20 +223,14 @@ void nrf24l01p_transmit(nrf24l01p_t *dev) int nrf24l01p_read_payload(nrf24l01p_t *dev, char *answer, unsigned int size) { - int status; - /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, CMD_R_RX_PAYLOAD, 0, answer, size); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, CMD_R_RX_PAYLOAD, NULL, answer, size); xtimer_spin(DELAY_AFTER_FUNC_TICKS); /* Release the bus for other threads. */ spi_release(dev->spi); - return status; + return 0; } void nrf24l01p_register(nrf24l01p_t *dev, unsigned int *pid) @@ -288,23 +268,16 @@ void nrf24l01p_stop(nrf24l01p_t *dev) int nrf24l01p_preload(nrf24l01p_t *dev, char *data, unsigned int size) { - int status; - size = (size <= 32) ? size : 32; /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, CMD_W_TX_PAYLOAD, data, NULL, size); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, CMD_W_TX_PAYLOAD, data, NULL, size); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - - return status; + return 0; } @@ -395,27 +368,21 @@ int nrf24l01p_set_payload_width(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char int nrf24l01p_set_tx_address(nrf24l01p_t *dev, char *saddr, unsigned int length) { - int status; - /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), saddr, NULL, length); /* address width is 5 byte */ - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, + (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), + saddr, NULL, length); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - return (status < 0) ? status : length; + return (int)length; } int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int length) { - int status; - char buf[length]; if (length <= INITIAL_ADDRESS_WIDTH) { @@ -429,44 +396,32 @@ int nrf24l01p_set_tx_address_long(nrf24l01p_t *dev, uint64_t saddr, unsigned int } /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), buf, NULL, length); /* address width is 5 byte */ - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, + (CMD_W_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), + buf, NULL, length); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - - return (status < 0) ? status : length; + return (int)length; } uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev) { - int status; uint64_t saddr_64 = 0; char addr_array[INITIAL_ADDRESS_WIDTH]; /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */ - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, + (CMD_R_REGISTER | (REGISTER_MASK & REG_TX_ADDR)), + NULL, addr_array, INITIAL_ADDRESS_WIDTH); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - if (status < 0) { - return -1; - } - - xtimer_spin(DELAY_AFTER_FUNC_TICKS); - for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) { saddr_64 |= (((uint64_t) addr_array[i]) << (8 * (INITIAL_ADDRESS_WIDTH - i - 1))); } @@ -477,7 +432,6 @@ uint64_t nrf24l01p_get_tx_address_long(nrf24l01p_t *dev) int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *saddr, unsigned int length) { - int status; char pipe_addr; switch (pipe) { @@ -510,12 +464,10 @@ int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *s } /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, (CMD_W_REGISTER | (REGISTER_MASK & pipe_addr)), saddr, NULL, length); /* address width is 5 byte */ - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, + (CMD_W_REGISTER | (REGISTER_MASK & pipe_addr)), + saddr, NULL, length); /* Release the bus for other threads. */ spi_release(dev->spi); @@ -523,7 +475,7 @@ int nrf24l01p_set_rx_address(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, char *s /* Enable this pipe */ nrf24l01p_enable_pipe(dev, pipe); - return (status < 0) ? status : length; + return (int)length; } int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, uint64_t saddr, unsigned int length) @@ -546,7 +498,6 @@ int nrf24l01p_set_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe, ui uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pipe) { - int status; char pipe_addr; uint64_t saddr_64 = 0; @@ -582,19 +533,13 @@ uint64_t nrf24l01p_get_rx_address_long(nrf24l01p_t *dev, nrf24l01p_rx_pipe_t pip } /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_regs(dev->spi, (CMD_R_REGISTER | (REGISTER_MASK & pipe_addr)), 0, addr_array, INITIAL_ADDRESS_WIDTH); /* address width is 5 byte */ - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_regs(dev->spi, dev->cs, + (CMD_R_REGISTER | (REGISTER_MASK & pipe_addr)), + NULL, addr_array, INITIAL_ADDRESS_WIDTH); /* Release the bus for other threads. */ spi_release(dev->spi); - if (status < 0) { - return -1; - } - xtimer_spin(DELAY_AFTER_FUNC_TICKS); for (int i = 0; i < INITIAL_ADDRESS_WIDTH; i++) { @@ -635,14 +580,11 @@ int nrf24l01p_set_datarate(nrf24l01p_t *dev, nrf24l01p_dr_t dr) int nrf24l01p_get_status(nrf24l01p_t *dev) { - char status; + uint8_t status; + /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - spi_transfer_byte(dev->spi, CMD_NOP, &status); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + status = spi_transfer_byte(dev->spi, dev->cs, false, CMD_NOP); /* Release the bus for other threads. */ spi_release(dev->spi); @@ -971,42 +913,28 @@ int nrf24l01p_disable_all_auto_ack(nrf24l01p_t *dev) int nrf24l01p_flush_tx_fifo(nrf24l01p_t *dev) { - int status; - char reg_content; - /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_byte(dev->spi, CMD_FLUSH_TX, ®_content); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_byte(dev->spi, dev->cs, false, CMD_FLUSH_TX); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - return (status < 0) ? status : 0; + return 0; } int nrf24l01p_flush_rx_fifo(nrf24l01p_t *dev) { - int status; - char reg_content; - /* Acquire exclusive access to the bus. */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - status = spi_transfer_byte(dev->spi, CMD_FLUSH_RX, ®_content); - xtimer_spin(DELAY_CS_TOGGLE_TICKS); - gpio_set(dev->cs); + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); + spi_transfer_byte(dev->spi, dev->cs, false, CMD_FLUSH_RX); /* Release the bus for other threads. */ spi_release(dev->spi); xtimer_spin(DELAY_AFTER_FUNC_TICKS); - return (status < 0) ? status : 0; + return 0; } void nrf24l01p_rx_cb(void *arg) diff --git a/drivers/nvram_spi/nvram-spi.c b/drivers/nvram_spi/nvram-spi.c index 9ed5ee664d95..6cba3f4fbce1 100644 --- a/drivers/nvram_spi/nvram-spi.c +++ b/drivers/nvram_spi/nvram-spi.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Eistec AB + * 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 @@ -27,6 +28,7 @@ * - Cypress/Ramtron FM25L04B. * * @author Joakim Nohlgård + * @author Hauke Petersen */ typedef enum { @@ -114,8 +116,9 @@ int nvram_spi_init(nvram_t *dev, nvram_spi_params_t *spi_params, size_t size) } dev->extra = spi_params; - gpio_init(spi_params->cs, GPIO_OUT); - gpio_set(spi_params->cs); + if (spi_init_cs(spi_params->spi, spi_params->cs) != SPI_OK) { + return -1; + } return 0; } @@ -123,54 +126,37 @@ int nvram_spi_init(nvram_t *dev, nvram_spi_params_t *spi_params, size_t size) static int nvram_spi_write(nvram_t *dev, const uint8_t *src, uint32_t dst, size_t len) { nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; - int status; union { uint32_t u32; char c[4]; } addr; + /* Address is expected by the device as big-endian, i.e. network byte order, * we utilize the network byte order macros here. */ addr.u32 = HTONL(dst); - /* Acquire exclusive bus access */ - spi_acquire(spi_dev->spi); - /* Assert CS */ - gpio_clear(spi_dev->cs); + + /* Acquire exclusive bus access while configuring clock and mode */ + spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk); /* Enable writes */ - status = spi_transfer_byte(spi_dev->spi, NVRAM_SPI_CMD_WREN, NULL); - if (status < 0) - { - return status; - } - /* Release CS */ - gpio_set(spi_dev->cs); + spi_transfer_byte(spi_dev->spi, spi_dev->cs, false, NVRAM_SPI_CMD_WREN); + /* Make sure we have a minimum gap between transfers */ xtimer_spin(NVRAM_SPI_CS_TOGGLE_TICKS); - /* Re-assert CS */ - gpio_clear(spi_dev->cs); /* Write command and address */ - status = spi_transfer_regs(spi_dev->spi, NVRAM_SPI_CMD_WRITE, + spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, NVRAM_SPI_CMD_WRITE); + spi_transfer_bytes(spi_dev->spi, spi_dev->cs, true, &addr.c[sizeof(addr.c) - spi_dev->address_count], NULL, spi_dev->address_count); - if (status < 0) - { - return status; - } - /* Keep holding CS and write data */ - status = spi_transfer_bytes(spi_dev->spi, (char *)src, NULL, len); - if (status < 0) - { - return status; - } - /* Release CS */ - gpio_set(spi_dev->cs); + /* Write data (we still hold the CS line low in between) */ + spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, src, NULL, len); /* Release exclusive bus access */ spi_release(spi_dev->spi); - return status; + + return (int)len; } static int nvram_spi_read(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len) { nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; - int status; union { uint32_t u32; char c[4]; @@ -178,40 +164,31 @@ static int nvram_spi_read(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len) /* Address is expected by the device as big-endian, i.e. network byte order, * we utilize the network byte order macros here. */ addr.u32 = HTONL(src); - /* Acquire exclusive bus access */ - spi_acquire(spi_dev->spi); - /* Assert CS */ - gpio_clear(spi_dev->cs); + + /* Acquire exclusive bus access while configuring clock and mode */ + spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk); /* Write command and address */ - status = spi_transfer_regs(spi_dev->spi, NVRAM_SPI_CMD_READ, + spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, NVRAM_SPI_CMD_READ); + spi_transfer_bytes(spi_dev->spi, spi_dev->cs, true, &addr.c[sizeof(addr.c) - spi_dev->address_count], NULL, spi_dev->address_count); - if (status < 0) - { - return status; - } - /* Keep holding CS and read data */ - status = spi_transfer_bytes(spi_dev->spi, NULL, (char *)dst, len); - if (status < 0) - { - return status; - } - /* Release CS */ - gpio_set(spi_dev->cs); + /* Read data (while still holding the CS line active) */ + spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, NULL, dst, len); /* Release exclusive bus access */ spi_release(spi_dev->spi); + /* status contains the number of bytes actually read from the SPI bus. */ - return status; + return (int)len; } static int nvram_spi_write_9bit_addr(nvram_t *dev, const uint8_t *src, uint32_t dst, size_t len) { nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; - int status; uint8_t cmd; uint8_t addr; cmd = NVRAM_SPI_CMD_WRITE; + /* The upper address bit is mixed into the command byte on certain devices, * probably just to save a byte in the SPI transfer protocol. */ if (dst > 0xff) { @@ -219,42 +196,30 @@ static int nvram_spi_write_9bit_addr(nvram_t *dev, const uint8_t *src, uint32_t } /* LSB of address */ addr = (dst & 0xff); - spi_acquire(spi_dev->spi); - gpio_clear(spi_dev->cs); + + spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk); /* Enable writes */ - status = spi_transfer_byte(spi_dev->spi, NVRAM_SPI_CMD_WREN, NULL); - if (status < 0) - { - return status; - } - gpio_set(spi_dev->cs); + spi_transfer_byte(spi_dev->spi, spi_dev->cs, false, NVRAM_SPI_CMD_WREN); + /* Insert needed delay between transactions */ xtimer_spin(NVRAM_SPI_CS_TOGGLE_TICKS); - gpio_clear(spi_dev->cs); /* Write command and address */ - status = spi_transfer_reg(spi_dev->spi, cmd, addr, NULL); - if (status < 0) - { - return status; - } + spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, cmd); + spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, addr); /* Keep holding CS and write data */ - status = spi_transfer_bytes(spi_dev->spi, (char *)src, NULL, len); - if (status < 0) - { - return status; - } - gpio_set(spi_dev->cs); + spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, src, NULL, len); spi_release(spi_dev->spi); + /* status contains the number of bytes actually written to the SPI bus. */ - return status; + return (int)len; } static int nvram_spi_read_9bit_addr(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len) { nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; - int status; uint8_t cmd; uint8_t addr; cmd = NVRAM_SPI_CMD_READ; + /* The upper address bit is mixed into the command byte on certain devices, * probably just to save a byte in the SPI transfer protocol. */ if (src > 0xff) { @@ -262,24 +227,17 @@ static int nvram_spi_read_9bit_addr(nvram_t *dev, uint8_t *dst, uint32_t src, si } /* LSB of address */ addr = (src & 0xff); - spi_acquire(spi_dev->spi); - gpio_clear(spi_dev->cs); + + spi_acquire(spi_dev->spi, spi_dev->cs, SPI_MODE_0, spi_dev->clk); /* Write command and address */ - status = spi_transfer_reg(spi_dev->spi, (char)cmd, addr, NULL); - if (status < 0) - { - return status; - } + spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, cmd); + spi_transfer_byte(spi_dev->spi, spi_dev->cs, true, addr); /* Keep holding CS and read data */ - status = spi_transfer_bytes(spi_dev->spi, NULL, (char *)dst, len); - if (status < 0) - { - return status; - } - gpio_set(spi_dev->cs); + spi_transfer_bytes(spi_dev->spi, spi_dev->cs, false, NULL, dst, len); spi_release(spi_dev->spi); + /* status contains the number of bytes actually read from the SPI bus. */ - return status; + return (int)len; } /** @} */ diff --git a/drivers/pcd8544/pcd8544.c b/drivers/pcd8544/pcd8544.c index 208af5660f8a..daa643b446cb 100644 --- a/drivers/pcd8544/pcd8544.c +++ b/drivers/pcd8544/pcd8544.c @@ -32,6 +32,9 @@ #define ASCII_MAX 0x7e /**< end of ASCII table */ #define CHAR_WIDTH (6U) /**< pixel width of a single character */ +#define SPI_CLK (SPI_CLK_1MHZ) +#define SPI_MODE (SPI_MODE_0) + static const uint8_t _ascii[][5] = { {0x00, 0x00, 0x00, 0x00, 0x00},/* 20 SPACE*/ {0x00, 0x00, 0x5f, 0x00, 0x00},/* 21 ! */ @@ -196,17 +199,22 @@ static const char _riot[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; +static inline void lock(pcd8544_t *dev) +{ + spi_acquire(dev->spi, dev->cs, SPI_MODE, SPI_CLK); +} + +static inline void done(pcd8544_t *dev) +{ + spi_release(dev->spi); +} static void _write(pcd8544_t *dev, uint8_t is_data, char data) { /* set command or data mode */ gpio_write(dev->mode, is_data); /* write byte to LCD */ - spi_acquire(dev->spi); - gpio_clear(dev->cs); - spi_transfer_byte(dev->spi, data, 0); - gpio_set(dev->cs); - spi_release(dev->spi); + spi_transfer_bytes(dev->spi, dev->cs, false, (uint8_t *)&data, NULL, 1); } static inline void _set_x(pcd8544_t *dev, uint8_t x) @@ -231,15 +239,13 @@ int pcd8544_init(pcd8544_t *dev, spi_t spi, gpio_t cs, gpio_t reset, gpio_t mode DEBUG("done setting dev members\n"); /* initialze pins */ - gpio_init(cs, GPIO_OUT); gpio_init(reset, GPIO_OUT); gpio_init(mode, GPIO_OUT); DEBUG("done with gpios\n"); /* clear CS line */ - gpio_set(cs); DEBUG("done clearing CS line\n"); /* initialize SPI */ - spi_init_master(spi, SPI_CONF_FIRST_RISING, SPI_SPEED_1MHZ); + spi_init_cs(spi, (spi_cs_t)cs); DEBUG("done initializing SPI master\n"); /* reset display */ gpio_clear(reset); @@ -253,8 +259,10 @@ int pcd8544_init(pcd8544_t *dev, spi_t spi, gpio_t cs, gpio_t reset, gpio_t mode pcd8544_set_bias(dev, PCD8544_DEFAULT_BIAS); pcd8544_set_tempcoef(dev, PCD8544_DEFAULT_TEMPCOEF); /* enable display */ + lock(dev); _write(dev, MODE_CMD, CMD_ENABLE_H); _write(dev, MODE_CMD, CMD_MODE_NORMAL); + done(dev); return 0; } @@ -263,9 +271,11 @@ void pcd8544_set_contrast(pcd8544_t *dev, uint8_t contrast) if (contrast > CONTRAST_MAX) { contrast = CONTRAST_MAX; } + lock(dev); _write(dev, MODE_CMD, CMD_EXTENDED); _write(dev, MODE_CMD, (CMD_EXT_CONTRAST | contrast)); _write(dev, MODE_CMD, CMD_ENABLE_H); + done(dev); } void pcd8544_set_tempcoef(pcd8544_t *dev, uint8_t coef) @@ -273,9 +283,11 @@ void pcd8544_set_tempcoef(pcd8544_t *dev, uint8_t coef) if (coef > TEMP_MAX) { coef = TEMP_MAX; } + lock(dev); _write(dev, MODE_CMD, CMD_EXTENDED); _write(dev, MODE_CMD, (CMD_EXT_TEMP | coef)); _write(dev, MODE_CMD, CMD_ENABLE_H); + done(dev); } void pcd8544_set_bias(pcd8544_t *dev, uint8_t bias) @@ -283,9 +295,11 @@ void pcd8544_set_bias(pcd8544_t *dev, uint8_t bias) if (bias > BIAS_MAX) { bias = BIAS_MAX; } + lock(dev); _write(dev, MODE_CMD, CMD_EXTENDED); _write(dev, MODE_CMD, (CMD_EXT_BIAS | bias)); _write(dev, MODE_CMD, CMD_ENABLE_H); + done(dev); } void pcd8544_riot(pcd8544_t *dev) @@ -296,12 +310,14 @@ void pcd8544_riot(pcd8544_t *dev) void pcd8544_write_img(pcd8544_t *dev, const char img[]) { /* set initial position */ + lock(dev); _set_x(dev, 0); _set_y(dev, 0); /* write image data to display */ for (int i = 0; i < (PCD8544_RES_X * PCD8544_RES_Y / 8); i++) { _write(dev, MODE_DTA, img[i]); } + done(dev); } void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c) @@ -311,6 +327,7 @@ void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c) return ; } /* set position */ + lock(dev); _set_x(dev, x * CHAR_WIDTH); _set_y(dev, y); /* write char */ @@ -318,6 +335,7 @@ void pcd8544_write_c(pcd8544_t *dev, uint8_t x, uint8_t y, char c) _write(dev, MODE_DTA, _ascii[c - ASCII_MIN][i]); } _write(dev, MODE_DTA, 0x00); + done(dev); } void pcd8544_write_s(pcd8544_t *dev, uint8_t x, uint8_t y, const char *s) @@ -329,15 +347,18 @@ void pcd8544_write_s(pcd8544_t *dev, uint8_t x, uint8_t y, const char *s) void pcd8544_clear(pcd8544_t *dev) { + lock(dev); _set_x(dev, 0); _set_y(dev, 0); for (int i = 0; i < PCD8544_RES_X * PCD8544_ROWS; i++) { _write(dev, MODE_DTA, 0x00); } + done(dev); } void pcd8544_invert(pcd8544_t *dev) { + lock(dev); if (dev->inverted) { _write(dev, MODE_CMD, CMD_MODE_NORMAL); } @@ -345,6 +366,7 @@ void pcd8544_invert(pcd8544_t *dev) _write(dev, MODE_CMD, CMD_MODE_INVERSE); } dev->inverted ^= 0x01; + done(dev); } int pcd8544_is_inverted(pcd8544_t *dev) @@ -354,10 +376,14 @@ int pcd8544_is_inverted(pcd8544_t *dev) void pcd8544_poweron(pcd8544_t *dev) { + lock(dev); _write(dev, MODE_CMD, CMD_ENABLE_H); + done(dev); } void pcd8544_poweroff(pcd8544_t *dev) { + lock(dev); _write(dev, MODE_CMD, CMD_DISABLE); + done(dev); } diff --git a/drivers/periph_common/init.c b/drivers/periph_common/init.c new file mode 100644 index 000000000000..3c13f15120d5 --- /dev/null +++ b/drivers/periph_common/init.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 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 drivers_periph_init + * @{ + * + * @file + * @brief Common static peripheral driver initialization implementation + * + * @author Hauke Petersen + * + * @} + */ + +#include "periph/spi.h" + +void periph_init(void) +{ + /* initialize configured SPI devices */ +#ifdef SPI_NUMOF + for (unsigned i = 0; i < SPI_NUMOF; i++) { + spi_init(SPI_DEV(i)); + } +#endif +} diff --git a/drivers/periph_common/spi.c b/drivers/periph_common/spi.c index ec0747ef1420..bc15a3016cce 100644 --- a/drivers/periph_common/spi.c +++ b/drivers/periph_common/spi.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015 Kaspar Schleiser + * 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 @@ -14,6 +15,7 @@ * @brief common SPI function fallback implementations * * @author Kaspar Schleiser + * @author Hauke Petersen * * @} */ @@ -22,76 +24,49 @@ #include "board.h" #include "cpu.h" #include "periph/spi.h" -#include "periph_cpu.h" -#if SPI_NUMOF +#ifdef SPI_NUMOF -#ifdef PERIPH_SPI_NEEDS_TRANSFER_BYTES -int spi_transfer_bytes(spi_t dev, char *out, char *in, unsigned int length) +#ifdef PERIPH_SPI_NEEDS_INIT_CS +int spi_init_cs(spi_t bus, spi_cs_t cs) { - int trans_ret; - unsigned trans_bytes = 0; - char in_temp; - - for (trans_bytes = 0; trans_bytes < length; trans_bytes++) { - if (out != NULL) { - trans_ret = spi_transfer_byte(dev, out[trans_bytes], &in_temp); - } - else { - trans_ret = spi_transfer_byte(dev, 0, &in_temp); - } - if (trans_ret < 0) { - return -1; - } - if (in != NULL) { - in[trans_bytes] = in_temp; - } + if (bus >= SPI_NUMOF) { + return SPI_NODEV; + } + if ((cs == SPI_CS_UNDEF) || (cs == GPIO_UNDEF)) { + return SPI_NOCS; } - return trans_bytes; + gpio_init((gpio_t)cs, GPIO_OUT); + gpio_set((gpio_t)cs); + + return SPI_OK; } #endif #ifdef PERIPH_SPI_NEEDS_TRANSFER_BYTE -int spi_transfer_byte(spi_t dev, char out, char *in) +uint8_t spi_transfer_byte(spi_t bus, spi_cs_t cs, bool cont, uint8_t out) { - return spi_transfer_bytes(dev, &out, in, 1); + uint8_t in; + spi_transfer_bytes(bus, cs, cont, &out, &in, 1); + return in; } #endif #ifdef PERIPH_SPI_NEEDS_TRANSFER_REG -int spi_transfer_reg(spi_t dev, uint8_t reg, char out, char *in) +uint8_t spi_transfer_reg(spi_t bus, spi_cs_t cs, uint8_t reg, uint8_t out) { - int trans_ret; - - trans_ret = spi_transfer_byte(dev, reg, in); - if (trans_ret < 0) { - return -1; - } - trans_ret = spi_transfer_byte(dev, out, in); - if (trans_ret < 0) { - return -1; - } - - return 1; + spi_transfer_bytes(bus, cs, true, ®, NULL, 1); + return spi_transfer_byte(bus, cs, false, out); } #endif #ifdef PERIPH_SPI_NEEDS_TRANSFER_REGS -int spi_transfer_regs(spi_t dev, uint8_t reg, char *out, char *in, unsigned int length) +void spi_transfer_regs(spi_t bus, spi_cs_t cs, + uint8_t reg, const void *out, void *in, size_t len) { - int trans_ret; - - trans_ret = spi_transfer_byte(dev, reg, in); - if (trans_ret < 0) { - return -1; - } - trans_ret = spi_transfer_bytes(dev, out, in, length); - if (trans_ret < 0) { - return -1; - } - - return trans_ret; + spi_transfer_bytes(bus, cs, true, ®, NULL, 1); + spi_transfer_bytes(bus, cs, false, out, in, len); } #endif diff --git a/drivers/sdcard_spi/include/sdcard_spi_internal.h b/drivers/sdcard_spi/include/sdcard_spi_internal.h index 5ca30cfd205e..dfc428891c8b 100644 --- a/drivers/sdcard_spi/include/sdcard_spi_internal.h +++ b/drivers/sdcard_spi/include/sdcard_spi_internal.h @@ -139,13 +139,13 @@ extern "C" { /* memory capacity in bytes = (C_SIZE+1) * SD_CSD_V2_C_SIZE_BLOCK_MULT * BLOCK_LEN */ #define SD_CSD_V2_C_SIZE_BLOCK_MULT 1024 -#define SD_CARD_SPI_MODE SPI_CONF_FIRST_RISING +#define SD_CARD_SPI_MODE SPI_MODE_0 /* this speed setting is only used while the init procedure is performed */ -#define SD_CARD_SPI_SPEED_PREINIT SPI_SPEED_400KHZ +#define SD_CARD_SPI_SPEED_PREINIT SPI_CLK_400KHZ /* after init procedure is finished the driver auto sets the card to this speed */ -#define SD_CARD_SPI_SPEED_POSTINIT SPI_SPEED_10MHZ +#define SD_CARD_SPI_SPEED_POSTINIT SPI_CLK_10MHZ #define SD_CARD_DUMMY_BYTE 0xFF diff --git a/drivers/sdcard_spi/include/sdcard_spi_params.h b/drivers/sdcard_spi/include/sdcard_spi_params.h index 0f46304054ff..36a07e1c5572 100644 --- a/drivers/sdcard_spi/include/sdcard_spi_params.h +++ b/drivers/sdcard_spi/include/sdcard_spi_params.h @@ -30,7 +30,7 @@ extern "C" { * @{ */ #ifndef SDCARD_SPI_PARAM_SPI -#define SDCARD_SPI_PARAM_SPI (SPI_0) +#define SDCARD_SPI_PARAM_SPI (SPI_DEV(0)) #endif #ifndef SDCARD_SPI_PARAM_CS #define SDCARD_SPI_PARAM_CS (GPIO_PIN(2,4)) diff --git a/drivers/sdcard_spi/sdcard_spi.c b/drivers/sdcard_spi/sdcard_spi.c index ceeff4d20445..d61c3c0e9bee 100644 --- a/drivers/sdcard_spi/sdcard_spi.c +++ b/drivers/sdcard_spi/sdcard_spi.c @@ -65,6 +65,7 @@ int sdcard_spi_init(sdcard_spi_t *card, const sdcard_spi_params_t *params) { sd_init_fsm_state_t state = SD_INIT_START; memcpy(&card->params, params, sizeof(sdcard_spi_params_t)); + card->spi_clk = SD_CARD_SPI_SPEED_PREINIT; do { state = _init_sd_fsm_step(card, state); @@ -88,7 +89,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta if ((gpio_init(card->params.mosi, GPIO_OUT) == 0) && (gpio_init(card->params.clk, GPIO_OUT) == 0) && (gpio_init(card->params.cs, GPIO_OUT) == 0) && - (gpio_init(card->params.miso, GPIO_IN) == 0) && + (gpio_init(card->params.miso, GPIO_IN_PU) == 0) && ( (card->params.power == GPIO_UNDEF) || (gpio_init(card->params.power, GPIO_OUT) == 0)) ) { @@ -125,43 +126,37 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta DEBUG("SD_INIT_SEND_CMD0\n"); gpio_clear(card->params.mosi); - gpio_clear(card->params.cs); /* select sdcard for cmd0 */ /* use soft-spi to perform init command to allow use of internal pull-ups on miso */ _dyn_spi_rxtx_byte = &_sw_spi_rxtx_byte; - _select_card_spi(card); + /* select sdcard for cmd0 */ + gpio_clear(card->params.cs); char cmd0_r1 = sdcard_spi_send_cmd(card, SD_CMD_0, SD_CMD_NO_ARG, INIT_CMD0_RETRY_CNT); + gpio_set(card->params.cs); + if (R1_VALID(cmd0_r1) && !R1_ERROR(cmd0_r1) && R1_IDLE_BIT_SET(cmd0_r1)) { DEBUG("CMD0: [OK]\n"); - _unselect_card_spi(card); - - if (spi_init_master(card->params.spi_dev, SD_CARD_SPI_MODE, - SD_CARD_SPI_SPEED_PREINIT) == 0) { - DEBUG("spi_init_master(): [OK]\n"); - - /* switch to hw spi since sd card is now in real spi mode */ - _dyn_spi_rxtx_byte = &_hw_spi_rxtx_byte; - return SD_INIT_ENABLE_CRC; - } - DEBUG("spi_init_master(): [ERROR]\n"); - return SD_INIT_CARD_UNKNOWN; + /* give control over SPI pins back to HW SPI device */ + spi_init_pins(card->params.spi_dev); + /* switch to HW SPI since SD card is now in real SPI mode */ + _dyn_spi_rxtx_byte = &_hw_spi_rxtx_byte; + return SD_INIT_ENABLE_CRC; } - _unselect_card_spi(card); return SD_INIT_CARD_UNKNOWN; case SD_INIT_ENABLE_CRC: DEBUG("SD_INIT_ENABLE_CRC\n"); _select_card_spi(card); char r1 = sdcard_spi_send_cmd(card, SD_CMD_59, SD_CMD_59_ARG_EN, INIT_CMD_RETRY_CNT); + _unselect_card_spi(card); + if (R1_VALID(r1) && !R1_ERROR(r1)) { DEBUG("CMD59: [OK]\n"); - _unselect_card_spi(card); return SD_INIT_SEND_CMD8; } - _unselect_card_spi(card); return SD_INIT_CARD_UNKNOWN; case SD_INIT_SEND_CMD8: @@ -327,15 +322,9 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta case SD_INIT_SET_MAX_SPI_SPEED: DEBUG("SD_INIT_SET_MAX_SPI_SPEED\n"); - if (spi_init_master(card->params.spi_dev, SD_CARD_SPI_MODE, - SD_CARD_SPI_SPEED_POSTINIT) == 0) { - DEBUG("SD_INIT_SET_MAX_SPI_SPEED: [OK]\n"); - return SD_INIT_FINISH; - } - else { - DEBUG("SD_INIT_SET_MAX_SPI_SPEED: [ERROR]\n"); - return SD_INIT_CARD_UNKNOWN; - } + card->spi_clk = SD_CARD_SPI_SPEED_POSTINIT; + DEBUG("SD_INIT_SET_MAX_SPI_SPEED: [OK]\n"); + return SD_INIT_FINISH; default: DEBUG("SD-INIT-FSM REACHED INVALID STATE!\n"); @@ -350,18 +339,14 @@ static inline bool _wait_for_token(sdcard_spi_t *card, char token, int32_t max_r do { char read_byte = 0; - if (spi_transfer_byte(card->params.spi_dev, SD_CARD_DUMMY_BYTE, &read_byte) == 1) { - if (read_byte == token) { - DEBUG("_wait_for_token: [MATCH]\n"); - return true; - } - else { - DEBUG("_wait_for_token: [NO MATCH] (0x%02x)\n", read_byte); - } + read_byte = spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, + SD_CARD_DUMMY_BYTE); + if (read_byte == token) { + DEBUG("_wait_for_token: [MATCH]\n"); + return true; } else { - DEBUG("spi_transfer_byte: [FAILED]\n"); - return false; + DEBUG("_wait_for_token: [NO MATCH] (0x%02x)\n", read_byte); } tried++; @@ -557,7 +542,8 @@ static inline char _wait_for_r1(sdcard_spi_t *card, int32_t max_retries) void _select_card_spi(sdcard_spi_t *card) { - spi_acquire(card->params.spi_dev); + spi_acquire(card->params.spi_dev, GPIO_UNDEF, + SD_CARD_SPI_MODE, card->spi_clk); gpio_clear(card->params.cs); } @@ -587,7 +573,8 @@ static inline int _sw_spi_rxtx_byte(sdcard_spi_t *card, char out, char *in){ } static inline int _hw_spi_rxtx_byte(sdcard_spi_t *card, char out, char *in){ - return spi_transfer_byte(card->params.spi_dev, out, in); + *in = spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, out); + return 1; } static inline int _transfer_bytes(sdcard_spi_t *card, char *out, char *in, unsigned int length){ @@ -720,66 +707,54 @@ int sdcard_spi_read_blocks(sdcard_spi_t *card, int blockaddr, char *data, int bl static sd_rw_response_t _write_data_packet(sdcard_spi_t *card, char token, char *data, int size) { - if (spi_transfer_byte(card->params.spi_dev, token, 0) == 1) { + spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, token); - if (_transfer_bytes(card, data, 0, size) == size) { + if (_transfer_bytes(card, data, 0, size) == size) { - uint16_t data__crc_16 = _crc_16(data, size); - char crc[sizeof(uint16_t)] = { data__crc_16 >> 8, data__crc_16 & 0xFF }; + uint16_t data__crc_16 = _crc_16(data, size); + char crc[sizeof(uint16_t)] = { data__crc_16 >> 8, data__crc_16 & 0xFF }; - if (_transfer_bytes(card, crc, 0, sizeof(crc)) == sizeof(crc)) { + if (_transfer_bytes(card, crc, 0, sizeof(crc)) == sizeof(crc)) { - char data_response; - - if (spi_transfer_byte(card->params.spi_dev, SD_CARD_DUMMY_BYTE, - &data_response) == 1) { - - DEBUG("_write_data_packet: DATA_RESPONSE: 0x%02x\n", data_response); + char data_response; - if (DATA_RESPONSE_IS_VALID(data_response)) { + data_response = (char)spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, + true, SD_CARD_DUMMY_BYTE); - if (DATA_RESPONSE_ACCEPTED(data_response)) { - DEBUG("_write_data_packet: DATA_RESPONSE: [OK]\n"); - return SD_RW_OK; - } - else { + DEBUG("_write_data_packet: DATA_RESPONSE: 0x%02x\n", data_response); - if (DATA_RESPONSE_WRITE_ERR(data_response)) { - DEBUG("_write_data_packet: DATA_RESPONSE: [WRITE_ERROR]\n"); - } + if (DATA_RESPONSE_IS_VALID(data_response)) { - if (DATA_RESPONSE_CRC_ERR(data_response)) { - DEBUG("_write_data_packet: DATA_RESPONSE: [CRC_ERROR]\n"); - } - return SD_RW_WRITE_ERROR; - } + if (DATA_RESPONSE_ACCEPTED(data_response)) { + DEBUG("_write_data_packet: DATA_RESPONSE: [OK]\n"); + return SD_RW_OK; + } + else { + if (DATA_RESPONSE_WRITE_ERR(data_response)) { + DEBUG("_write_data_packet: DATA_RESPONSE: [WRITE_ERROR]\n"); } - else { - DEBUG("_write_data_packet: DATA_RESPONSE invalid\n"); - return SD_RW_RX_TX_ERROR; - } - + if (DATA_RESPONSE_CRC_ERR(data_response)) { + DEBUG("_write_data_packet: DATA_RESPONSE: [CRC_ERROR]\n"); + } + return SD_RW_WRITE_ERROR; } - else { - DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting data response)\n"); - return SD_RW_RX_TX_ERROR; - } + } else { - DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting CRC16)\n"); + DEBUG("_write_data_packet: DATA_RESPONSE invalid\n"); return SD_RW_RX_TX_ERROR; } + } else { - DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting payload)\n"); + DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting CRC16)\n"); return SD_RW_RX_TX_ERROR; } - } else { - DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting token)\n"); + DEBUG("_write_data_packet: [RX_TX_ERROR] (while transmitting payload)\n"); return SD_RW_RX_TX_ERROR; } } @@ -823,16 +798,10 @@ static inline int _write_blocks(sdcard_spi_t *card, char cmd_idx, int bladdr, ch /* if this is a multi-block write it is needed to issue a stop command*/ if (cmd_idx == SD_CMD_25) { - char data_response; - if (spi_transfer_byte(card->params.spi_dev, SD_DATA_TOKEN_CMD_25_STOP, - &data_response) == 1) { - DEBUG("_write_blocks: write multi (%d) blocks: [OK]\n", nbl); - } - else { - DEBUG("_write_blocks: spi_transfer_byte: [FAILED] (SD_DATA_TOKEN_CMD_25_STOP)\n"); - _unselect_card_spi(card); - *state = SD_RW_RX_TX_ERROR; - } + spi_transfer_byte(card->params.spi_dev, GPIO_UNDEF, true, + SD_DATA_TOKEN_CMD_25_STOP); + DEBUG("_write_blocks: write multi (%d) blocks: [OK]\n", nbl); + _send_dummy_byte(card); //sd card needs dummy byte before we can wait for not-busy state if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_CNT)) { _unselect_card_spi(card); diff --git a/drivers/w5100/include/w5100_params.h b/drivers/w5100/include/w5100_params.h index 315bfd5b681f..10ea7fb903a3 100644 --- a/drivers/w5100/include/w5100_params.h +++ b/drivers/w5100/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(0, 0)) @@ -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/drivers/w5100/w5100.c b/drivers/w5100/w5100.c index af958da9e8b2..443d61883f2b 100644 --- a/drivers/w5100/w5100.c +++ b/drivers/w5100/w5100.c @@ -35,7 +35,7 @@ #include "debug.h" -#define SPI_CONF SPI_CONF_FIRST_RISING +#define SPI_CONF SPI_MODE_0 #define RMSR_DEFAULT_VALUE (0x55) #define S0_MEMSIZE (0x2000) @@ -48,25 +48,26 @@ static const netdev2_driver_t netdev2_driver_w5100; static inline void send_addr(w5100_t *dev, uint16_t addr) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - spi_transfer_byte(dev->p.spi, (addr >> 8), NULL); - spi_transfer_byte(dev->p.spi, (addr & 0xff), NULL); + spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr >> 8)); + spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr & 0xff)); #else - spi_transfer_byte(dev->p.spi, (addr & 0xff), NULL); - spi_transfer_byte(dev->p.spi, (addr >> 8), NULL); + spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr & 0xff)); + spi_transfer_byte(dev->p.spi, dev->p.cs, true, (addr >> 8)); #endif } static uint8_t rreg(w5100_t *dev, uint16_t reg) { - uint8_t data; - - gpio_clear(dev->p.cs); - spi_transfer_byte(dev->p.spi, CMD_READ, NULL); + spi_transfer_byte(dev->p.spi, dev->p.cs, true, CMD_READ); send_addr(dev, reg++); - spi_transfer_byte(dev->p.spi, 0, (char *)&data); - gpio_set(dev->p.cs); + return spi_transfer_byte(dev->p.spi, dev->p.cs, false, 0); +} - return data; +static void wreg(w5100_t *dev, uint16_t reg, uint8_t data) +{ + spi_transfer_byte(dev->p.spi, dev->p.cs, true, CMD_WRITE); + send_addr(dev, reg); + spi_transfer_byte(dev->p.spi, dev->p.cs, false, data); } static uint16_t raddr(w5100_t *dev, uint16_t addr_high, uint16_t addr_low) @@ -76,6 +77,13 @@ static uint16_t raddr(w5100_t *dev, uint16_t addr_high, uint16_t addr_low) return res; } +static void waddr(w5100_t *dev, + uint16_t addr_high, uint16_t addr_low, uint16_t val) +{ + wreg(dev, addr_high, (uint8_t)(val >> 8)); + wreg(dev, addr_low, (uint8_t)(val & 0xff)); +} + static void rchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len) { /* reading a chunk must be split in multiple single byte reads, as the @@ -85,22 +93,6 @@ static void rchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len) } } -static void wreg(w5100_t *dev, uint16_t reg, uint8_t data) -{ - gpio_clear(dev->p.cs); - spi_transfer_byte(dev->p.spi, CMD_WRITE, NULL); - send_addr(dev, reg); - spi_transfer_byte(dev->p.spi, data, NULL); - gpio_set(dev->p.cs); -} - -static void waddr(w5100_t *dev, - uint16_t addr_high, uint16_t addr_low, uint16_t val) -{ - wreg(dev, addr_high, (uint8_t)(val >> 8)); - wreg(dev, addr_low, (uint8_t)(val & 0xff)); -} - static void wchunk(w5100_t *dev, uint16_t addr, uint8_t *data, size_t len) { /* writing a chunk must be split in multiple single byte writes, as the @@ -129,11 +121,8 @@ void w5100_setup(w5100_t *dev, const w5100_params_t *params) /* initialize the device descriptor */ memcpy(&dev->p, params, sizeof(w5100_params_t)); - /* initialize pins and SPI */ - gpio_init(dev->p.cs, GPIO_OUT); - gpio_set(dev->p.cs); - spi_init_master(dev->p.spi, SPI_CONF, dev->p.spi_speed); - + /* initialize the chip select pin and the external interrupt pin */ + spi_init_cs(dev->p.spi, dev->p.cs); gpio_init_int(dev->p.evt, GPIO_IN, GPIO_FALLING, extint, dev); } @@ -143,9 +132,13 @@ static int init(netdev2_t *netdev) uint8_t tmp; uint8_t hwaddr[ETHERNET_ADDR_LEN]; + /* get access to the SPI bus for the duration of this function */ + spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk); + /* test the SPI connection by reading the value of the RMSR register */ tmp = rreg(dev, REG_TMSR); if (tmp != RMSR_DEFAULT_VALUE) { + spi_release(dev->p.spi); LOG_ERROR("[w5100] error: no SPI connection\n"); return W5100_ERR_BUS; } @@ -180,6 +173,9 @@ static int init(netdev2_t *netdev) /* start receiving packets */ wreg(dev, S0_CR, CR_RECV); + /* release the SPI bus again */ + spi_release(dev->p.spi); + return 0; } @@ -203,6 +199,9 @@ static int send(netdev2_t *netdev, const struct iovec *vector, unsigned count) w5100_t *dev = (w5100_t *)netdev; int sum = 0; + /* get access to the SPI bus for the duration of this function */ + spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk); + uint16_t pos = raddr(dev, S0_TX_WR0, S0_TX_WR1); /* the register is only set correctly after the first send pkt, so we need @@ -211,7 +210,7 @@ static int send(netdev2_t *netdev, const struct iovec *vector, unsigned count) pos = S0_TX_BASE; } - for (int i = 0; i < count; i++) { + for (unsigned i = 0; i < count; i++) { pos = tx_upload(dev, pos, vector[i].iov_base, vector[i].iov_len); sum += vector[i].iov_len; } @@ -225,15 +224,22 @@ static int send(netdev2_t *netdev, const struct iovec *vector, unsigned count) DEBUG("[w5100] send: transferred %i byte (at 0x%04x)\n", sum, (int)pos); + /* release the SPI bus again */ + spi_release(dev->p.spi); + return sum; } static int recv(netdev2_t *netdev, void *buf, size_t len, void *info) { + (void)info; w5100_t *dev = (w5100_t *)netdev; uint8_t *in_buf = (uint8_t *)buf; int n = 0; + /* get access to the SPI bus for the duration of this function */ + spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk); + uint16_t num = raddr(dev, S0_RX_RSR0, S0_RX_RSR1); if (num > 0) { @@ -267,16 +273,23 @@ static int recv(netdev2_t *netdev, void *buf, size_t len, void *info) } } + /* release the SPI bus again */ + spi_release(dev->p.spi); + return n; } static void isr(netdev2_t *netdev) { + uint8_t ir; w5100_t *dev = (w5100_t *)netdev; /* we only react on RX events, and if we see one, we read from the RX buffer * until it is empty */ - while (rreg(dev, S0_IR) & IR_RECV) { + spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk); + ir = rreg(dev, S0_IR); + spi_release(dev->p.spi); + while (ir & IR_RECV) { DEBUG("[w5100] netdev2 RX complete\n"); netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE); } @@ -290,7 +303,9 @@ static int get(netdev2_t *netdev, netopt_t opt, void *value, size_t max_len) switch (opt) { case NETOPT_ADDRESS: assert(max_len >= ETHERNET_ADDR_LEN); + spi_acquire(dev->p.spi, dev->p.cs, SPI_CONF, dev->p.clk); rchunk(dev, REG_SHAR0, value, ETHERNET_ADDR_LEN); + spi_release(dev->p.spi); res = ETHERNET_ADDR_LEN; break; default: diff --git a/pkg/u8g2/README.md b/pkg/u8g2/README.md index f8d77777cc65..8eaae174aba5 100644 --- a/pkg/u8g2/README.md +++ b/pkg/u8g2/README.md @@ -46,7 +46,7 @@ uint32_t bitmap = ( u8g2_Setup_ssd1306_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_riotos_hw_spi, u8x8_gpio_and_delay_riotos); u8g2_SetPins(&u8g2, pins, bitmap); -u8g2_SetDevice(&u8g2, SPI_0); +u8g2_SetDevice(&u8g2, SPI_DEV(0)); ``` ## Virtual displays diff --git a/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch b/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch index 1eb0aec881d6..54cf0184767d 100644 --- a/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch +++ b/pkg/u8g2/patches/0001-u8g2-add-riot-os-makefiles.patch @@ -1,7 +1,7 @@ -From e9c737b4cbfcc460c0274428ece41d6654c82f90 Mon Sep 17 00:00:00 2001 +From a2a2cfb145902cb36cbe82bdaf68d97686bb9724 Mon Sep 17 00:00:00 2001 From: Bas Stottelaar Date: Tue, 24 May 2016 20:17:39 +0200 -Subject: [PATCH 1/2] u8g2: add riot-os makefiles. +Subject: [PATCH 1/3] u8g2: add riot-os makefiles. --- Makefile | 22 ++++++++++++++++++++++ @@ -72,5 +72,5 @@ index 0000000..32e7913 + +include $(RIOTBASE)/Makefile.base -- -2.8.1 +1.9.1 diff --git a/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch b/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch index 208b30def7e9..7f938b8b3a77 100644 --- a/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch +++ b/pkg/u8g2/patches/0002-u8g2-add-riot-os-interface.patch @@ -1,7 +1,7 @@ -From 68fcbaf8eb8b2e2c1abe319fb74f75f0a75c330e Mon Sep 17 00:00:00 2001 +From 5acedd785fd31b43171c6855ecd5323bfd31c9e2 Mon Sep 17 00:00:00 2001 From: Bas Stottelaar Date: Wed, 22 Jun 2016 18:04:31 +0200 -Subject: [PATCH 2/2] u8g2: add riot-os interface. +Subject: [PATCH 2/3] u8g2: add riot-os interface. --- csrc/u8g2.h | 4 +- @@ -17,21 +17,21 @@ index b65c9f1..bd8c485 100644 @@ -362,6 +362,9 @@ void u8g2_ClearDisplay(u8g2_t *u8g2); #define u8g2_SetMenuDownPin(u8g2, val) u8x8_SetMenuDownPin(u8g2_GetU8x8(u8g2), (val)) #endif - + +#define u8g2_SetPins(u8x8,pins,pins_enabled) u8x8_SetPins(u8g2_GetU8x8(&u8g2), pins, pins_enabled) +#define u8g2_SetDevice(u8x8,device) u8x8_SetDevice(u8g2_GetU8x8(&u8g2), device) + /*==========================================*/ /* u8g2_setup.c */ - + @@ -1663,4 +1666,3 @@ extern const uint8_t u8g2_font_px437wyse700b_mn[] U8G2_FONT_SECTION("u8g2_font_p - - + + #endif - diff --git a/csrc/u8g2_riotos.c b/csrc/u8g2_riotos.c new file mode 100644 -index 0000000..7106e07 +index 0000000..e0c042c --- /dev/null +++ b/csrc/u8g2_riotos.c @@ -0,0 +1,163 @@ @@ -205,27 +205,27 @@ index dd74869..7c45b6a 100644 @@ -107,6 +107,8 @@ #include #include - + +#include "periph/gpio.h" + #if defined(__GNUC__) && defined(__AVR__) #include - #endif + #endif @@ -154,9 +156,9 @@ extern "C" { - # define u8x8_pgm_read(adr) (*(const uint8_t *)(adr)) + # define u8x8_pgm_read(adr) (*(const uint8_t *)(adr)) #endif - + -#ifdef ARDUINO -#define U8X8_USE_PINS -#endif +//#ifdef ARDUINO +//#define U8X8_USE_PINS +//#endif - + /*==========================================*/ /* U8X8 typedefs and data structures */ @@ -316,6 +318,10 @@ struct u8x8_struct - #ifdef U8X8_USE_PINS + #ifdef U8X8_USE_PINS uint8_t pins[U8X8_PIN_CNT]; /* defines a pinlist: Mainly a list of pins for the Arduino Envionment, use U8X8_PIN_xxx to access */ #endif + @@ -233,27 +233,27 @@ index dd74869..7c45b6a 100644 + uint32_t pins_enabled; + uint32_t dev; }; - + #define u8x8_GetCols(u8x8) ((u8x8)->display_info->tile_width) @@ -337,6 +343,8 @@ struct u8x8_struct #define u8x8_SetMenuDownPin(u8x8, val) u8x8_SetPin((u8x8),U8X8_PIN_MENU_DOWN,(val)) #endif - + +#define u8x8_SetPins(u8x8,pins,pins_enabled) {(u8x8)->pins = (pins); (u8x8)->pins_enabled = (pins_enabled);} +#define u8x8_SetDevice(u8x8,device) ((u8x8)->dev = device) - + /*==========================================*/ - + @@ -818,6 +826,9 @@ extern const uint8_t u8x8_font_pxplustandynewtv_u[] U8X8_FONT_SECTION("u8x8_font - + /* end font list */ - + +extern uint8_t u8x8_byte_riotos_hw_spi(u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, void *arg_ptr); +extern uint8_t u8x8_gpio_and_delay_riotos(u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, void *arg_ptr); +extern uint8_t u8x8_byte_riotos_hw_i2c(u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, void *arg_ptr); - + #ifdef __cplusplus } --- -2.8.1 +-- +1.9.1 diff --git a/pkg/u8g2/patches/0003-u8g2-adapted-RIOT-interface-to-SPI-changes.patch b/pkg/u8g2/patches/0003-u8g2-adapted-RIOT-interface-to-SPI-changes.patch new file mode 100644 index 000000000000..1d9786191dd5 --- /dev/null +++ b/pkg/u8g2/patches/0003-u8g2-adapted-RIOT-interface-to-SPI-changes.patch @@ -0,0 +1,89 @@ +From 51897f66e18e291c3f3d528a0678eb195341d18d Mon Sep 17 00:00:00 2001 +From: Hauke Petersen +Date: Wed, 25 Jan 2017 12:29:36 +0100 +Subject: [PATCH 3/3] u8g2: adapted RIOT interface to SPI changes + +--- + csrc/u8g2_riotos.c | 33 +++++++++++++++++---------------- + 1 file changed, 17 insertions(+), 16 deletions(-) + +diff --git a/csrc/u8g2_riotos.c b/csrc/u8g2_riotos.c +index e0c042c..bd06ccb 100644 +--- a/csrc/u8g2_riotos.c ++++ b/csrc/u8g2_riotos.c +@@ -8,29 +8,29 @@ + + #include + +-#if SPI_NUMOF +-static spi_speed_t u8x8_pulse_width_to_spi_speed(uint32_t pulse_width) ++#ifdef SPI_NUMOF ++static spi_clk_t u8x8_pulse_width_to_spi_speed(uint32_t pulse_width) + { + uint32_t cycle_time = 2 * pulse_width; + + if (cycle_time < 100) { +- return SPI_SPEED_10MHZ; ++ return SPI_CLK_10MHZ; + } else if (cycle_time < 200) { +- return SPI_SPEED_5MHZ; ++ return SPI_CLK_5MHZ; + } else if (cycle_time < 1000) { +- return SPI_SPEED_1MHZ; ++ return SPI_CLK_1MHZ; + } else if (cycle_time < 2500) { +- return SPI_SPEED_400KHZ; ++ return SPI_CLK_400KHZ; + } + +- return SPI_SPEED_100KHZ; ++ return SPI_CLK_100KHZ; + } + #endif /* SPI_NUMOF */ + +-#if SPI_NUMOF +-static spi_speed_t u8x8_spi_mode_to_spi_conf(uint32_t spi_mode) ++#ifdef SPI_NUMOF ++static spi_mode_t u8x8_spi_mode_to_spi_conf(uint32_t spi_mode) + { +- return (spi_speed_t) spi_mode; ++ return (spi_mode_t) spi_mode; + } + #endif /* SPI_NUMOF */ + +@@ -90,25 +90,26 @@ uint8_t u8x8_gpio_and_delay_riotos(u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, v + return 1; + } + +-#if SPI_NUMOF ++#ifdef SPI_NUMOF + uint8_t u8x8_byte_riotos_hw_spi(u8x8_t *u8g2, uint8_t msg, uint8_t arg_int, void *arg_ptr) + { + spi_t dev = (spi_t) u8g2->dev; + + switch (msg) { + case U8X8_MSG_BYTE_SEND: +- spi_transfer_bytes(dev, (char *) arg_ptr, NULL, arg_int); ++ spi_transfer_bytes(dev, GPIO_UNDEF, true, ++ arg_ptr, NULL, (size_t)arg_int); + break; + case U8X8_MSG_BYTE_INIT: +- spi_init_master(dev, +- u8x8_spi_mode_to_spi_conf(u8g2->display_info->spi_mode), +- u8x8_pulse_width_to_spi_speed(u8g2->display_info->sck_pulse_width_ns)); ++ spi_init_pins(dev); + break; + case U8X8_MSG_BYTE_SET_DC: + u8x8_gpio_SetDC(u8g2, arg_int); + break; + case U8X8_MSG_BYTE_START_TRANSFER: +- spi_acquire(dev); ++ spi_acquire(dev, GPIO_UNDEF, ++ u8x8_spi_mode_to_spi_conf(u8g2->display_info->spi_mode), ++ u8x8_pulse_width_to_spi_speed(u8g2->display_info->sck_pulse_width_ns)); + + u8x8_gpio_SetCS(u8g2, u8g2->display_info->chip_enable_level); + u8g2->gpio_and_delay_cb(u8g2, U8X8_MSG_DELAY_NANO, u8g2->display_info->post_chip_enable_wait_ns, NULL); +-- +1.9.1 + diff --git a/sys/auto_init/saul/auto_init_lis3dh.c b/sys/auto_init/saul/auto_init_lis3dh.c index 46e2285cc93f..4890069e411f 100644 --- a/sys/auto_init/saul/auto_init_lis3dh.c +++ b/sys/auto_init/saul/auto_init_lis3dh.c @@ -55,7 +55,7 @@ void auto_init_lis3dh(void) LOG_DEBUG("[auto_init_saul] initializing lis3dh #%u\n", i); - res = lis3dh_init(&lis3dh_devs[i], p->spi, p->cs, p->scale); + res = lis3dh_init(&lis3dh_devs[i], p->spi, p->clk, p->cs, p->scale); if (res < 0) { LOG_ERROR("[auto_init_saul] error initializing lis3dh #%u\n", i); continue; diff --git a/sys/auto_init/storage/auto_init_sdcard_spi.c b/sys/auto_init/storage/auto_init_sdcard_spi.c index 8c7dc3c25f0a..5c8fd1a86c62 100644 --- a/sys/auto_init/storage/auto_init_sdcard_spi.c +++ b/sys/auto_init/storage/auto_init_sdcard_spi.c @@ -18,6 +18,7 @@ #ifdef MODULE_SDCARD_SPI +#include "log.h" #include "sdcard_spi.h" #include "sdcard_spi_params.h" @@ -40,11 +41,12 @@ sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM]; void auto_init_sdcard_spi(void) { - for (int i = 0; i < SDCARD_SPI_NUM; i++) { - DEBUG("sdcard_spi_auto_init(): initializing device [%i]...\n", i); - int resu = sdcard_spi_init(&sdcard_spi_devs[i], &sdcard_spi_params[i]); - if(resu != 0){ - DEBUG("error initializing device [%i]\n", i); + for (unsigned i = 0; i < SDCARD_SPI_NUM; i++) { + LOG_DEBUG("[auto_init_storage] initializing sdcard_spi #%u\n", i); + + if (sdcard_spi_init(&sdcard_spi_devs[i], &sdcard_spi_params[i]) != + SDCARD_SPI_OK) { + LOG_ERROR("[auto_init_storage] error initializing sdcard_spi #%u\n", i); } } } diff --git a/tests/driver_adt7310/Makefile b/tests/driver_adt7310/Makefile index bf177ad98a8b..a5403ff15a55 100644 --- a/tests/driver_adt7310/Makefile +++ b/tests/driver_adt7310/Makefile @@ -9,7 +9,7 @@ USEMODULE += adt7310 USEMODULE += xtimer # set default device parameters in case they are undefined -TEST_ADT7310_SPI ?= SPI_0 +TEST_ADT7310_SPI ?= SPI_DEV\(0\) TEST_ADT7310_CS ?= GPIO_PIN\(0,0\) # export parameters diff --git a/tests/driver_adt7310/main.c b/tests/driver_adt7310/main.c index c9eef6cb1fdf..bf4b0f055bc2 100644 --- a/tests/driver_adt7310/main.c +++ b/tests/driver_adt7310/main.c @@ -36,7 +36,7 @@ #endif #define SPI_CONF (SPI_CONF_SECOND_FALLING) -#define SPI_SPEED (SPI_SPEED_10MHZ) +#define SPI_CLK (SPI_CLK_10MHZ) #define SLEEP_CONT (100 * 1000U) #define SLEEP_1SPS (1000 * 1000U) @@ -89,17 +89,9 @@ int main(void) adt7310_t dev; puts("ADT7310 temperature driver test application\n"); - printf("Initializing SPI_%i... ", TEST_ADT7310_SPI); - if (spi_init_master(TEST_ADT7310_SPI, SPI_CONF, SPI_SPEED) == 0) { - puts("[OK]"); - } - else { - puts("[Failed]\n"); - return 1; - } puts("Initializing ADT7310 sensor... "); - if (adt7310_init(&dev, TEST_ADT7310_SPI, TEST_ADT7310_CS) == 0) { + if (adt7310_init(&dev, TEST_ADT7310_SPI, SPI_CLK, TEST_ADT7310_CS) == 0) { puts("[OK]"); } else { diff --git a/tests/driver_enc28j60/Makefile b/tests/driver_enc28j60/Makefile index a243bf222ee4..ae89bc8b3e80 100644 --- a/tests/driver_enc28j60/Makefile +++ b/tests/driver_enc28j60/Makefile @@ -4,7 +4,7 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_spi periph_gpio BOARD_INSUFFICIENT_MEMORY := msb-430h nucleo-f334 stm32f0discovery telosb \ - weio z1 + weio z1 msb-430 USEMODULE += gnrc_netdev2 USEMODULE += gnrc_netdev_default @@ -18,14 +18,14 @@ USEMODULE += ps # set board specific peripheral configurations ifneq (,$(filter stm32f4discovery,$(BOARD))) - ENC_SPI ?= SPI_1 + ENC_SPI ?= SPI_DEV\(1\) ENC_CS ?= GPIO_PIN\(PORT_B,12\) ENC_INT ?= GPIO_PIN\(PORT_B,11\) ENC_RST ?= GPIO_PIN\(PORT_B,10\) endif # fallback: set SPI bus and pins to default values -ENC_SPI ?= SPI_0 +ENC_SPI ?= SPI_DEV\(0\) ENC_CS ?= GPIO_PIN\(0,0\) ENC_INT ?= GPIO_PIN\(0,1\) ENC_RST ?= GPIO_PIN\(0,2\) diff --git a/tests/driver_encx24j600/Makefile b/tests/driver_encx24j600/Makefile index 5fee1398157e..df2eac0808ad 100644 --- a/tests/driver_encx24j600/Makefile +++ b/tests/driver_encx24j600/Makefile @@ -3,7 +3,7 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_spi periph_gpio -BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1 +BOARD_INSUFFICIENT_MEMORY := msb-430 msb-430h stm32f0discovery telosb weio z1 USEMODULE += gnrc_netdev2 USEMODULE += gnrc_netdev_default @@ -22,13 +22,13 @@ CFLAGS += -DGNRC_PKTBUF_SIZE=2048 ifneq (,$(filter nucleo-f334,$(BOARD))) # these settings are probably valid for PoEll-i on most nucelo boards, but # tested only on nucleo-f334 - ENC_SPI ?= SPI_0 + ENC_SPI ?= SPI_DEV\(0\) ENC_CS ?= GPIO_PIN\(PORT_C,10\) ENC_INT ?= GPIO_PIN\(PORT_D,2\) endif # fallback: set SPI bus and pins to default values -ENC_SPI ?= SPI_0 +ENC_SPI ?= SPI_DEV\(0\) ENC_CS ?= GPIO_PIN\(0,0\) ENC_INT ?= GPIO_PIN\(0,1\) # export SPI and pins diff --git a/tests/driver_kw2xrf/Makefile b/tests/driver_kw2xrf/Makefile index e52d829856ea..936b69c279b7 100644 --- a/tests/driver_kw2xrf/Makefile +++ b/tests/driver_kw2xrf/Makefile @@ -26,8 +26,8 @@ ifneq (true,$(USE_BOARD_PARAMETERS)) # set default device parameters in case they are undefined DRIVER ?= kw2xrf KW2XRF_SHARED_SPI ?= 1 - KWRF_SPI ?= SPI_0 - KWRF_SPI_SPEED ?= SPI_SPEED_5MHZ + KWRF_SPI ?= SPI_DEV\(0\) + KWRF_SPI_SPEED ?= SPI_CLK_5MHZ KWRF_CS ?= GPIO_PIN\(0,0\) KWRF_INT ?= GPIO_PIN\(0,1\) diff --git a/tests/driver_kw2xrf/kw2xrf_params.h b/tests/driver_kw2xrf/kw2xrf_params.h index 7251fd59a012..0ff9db424562 100644 --- a/tests/driver_kw2xrf/kw2xrf_params.h +++ b/tests/driver_kw2xrf/kw2xrf_params.h @@ -40,7 +40,7 @@ extern "C" { #error "Interrupt pin not defined" #endif #ifndef KWRF_SPI_SPEED -#define KWRF_SPI_SPEED (SPI_SPEED_10MHZ) +#define KWRF_SPI_SPEED (SPI_CLK_10MHZ) #endif /**@}*/ diff --git a/tests/driver_lis3dh/Makefile b/tests/driver_lis3dh/Makefile index 2097649d77be..5e10cf99f28f 100644 --- a/tests/driver_lis3dh/Makefile +++ b/tests/driver_lis3dh/Makefile @@ -7,7 +7,7 @@ USEMODULE += lis3dh USEMODULE += xtimer # set default device parameters in case they are undefined -TEST_LIS3DH_SPI ?= SPI_0 +TEST_LIS3DH_SPI ?= SPI_DEV\(0\) TEST_LIS3DH_CS ?= GPIO_PIN\(0,0\) TEST_LIS3DH_INT1 ?= GPIO_PIN\(0,1\) TEST_LIS3DH_INT2 ?= GPIO_PIN\(0,2\) diff --git a/tests/driver_lis3dh/main.c b/tests/driver_lis3dh/main.c index 2fea3559cdbc..6dfb770a2d38 100644 --- a/tests/driver_lis3dh/main.c +++ b/tests/driver_lis3dh/main.c @@ -61,7 +61,7 @@ #define ODR LIS3DH_ODR_100Hz #define SLEEP (100 * 1000U) #define SPI_CONF (SPI_CONF_SECOND_FALLING) -#define SPI_SPEED (SPI_SPEED_10MHZ) +#define SPI_CLK (SPI_CLK_10MHZ) #define WATERMARK_LEVEL 16 @@ -79,17 +79,9 @@ int main(void) lis3dh_data_t acc_data; puts("LIS3DH accelerometer driver test application\n"); - printf("Initializing SPI_%i... ", TEST_LIS3DH_SPI); - if (spi_init_master(TEST_LIS3DH_SPI, SPI_CONF, SPI_SPEED) == 0) { - puts("[OK]"); - } - else { - puts("[Failed]\n"); - return 1; - } puts("Initializing LIS3DH sensor... "); - if (lis3dh_init(&dev, TEST_LIS3DH_SPI, TEST_LIS3DH_CS, SCALE) == 0) { + if (lis3dh_init(&dev, TEST_LIS3DH_SPI, SPI_CLK, TEST_LIS3DH_CS, SCALE) == 0) { puts("[OK]"); } else { diff --git a/tests/driver_nrf24l01p_lowlevel/Makefile b/tests/driver_nrf24l01p_lowlevel/Makefile index 8df69ec9158b..6936803e44e8 100644 --- a/tests/driver_nrf24l01p_lowlevel/Makefile +++ b/tests/driver_nrf24l01p_lowlevel/Makefile @@ -10,7 +10,7 @@ USEMODULE += xtimer USEMODULE += nrf24l01p # set default device parameters in case they are undefined -SPI_PORT ?= SPI_0 +SPI_PORT ?= SPI_DEV\(0\) CE_PIN ?= GPIO_PIN\(0,0\) CS_PIN ?= GPIO_PIN\(0,1\) IRQ_PIN ?= GPIO_PIN\(0,2\) diff --git a/tests/driver_nrf24l01p_lowlevel/main.c b/tests/driver_nrf24l01p_lowlevel/main.c index e16fd6b0084c..7d4e5b168ec1 100644 --- a/tests/driver_nrf24l01p_lowlevel/main.c +++ b/tests/driver_nrf24l01p_lowlevel/main.c @@ -85,34 +85,26 @@ void print_register(char reg, int num_bytes) { char buf_return[num_bytes]; - int ret; + spi_transfer_regs(SPI_PORT, CS_PIN, + (CMD_R_REGISTER | (REGISTER_MASK & reg)), + NULL, (uint8_t *)buf_return, num_bytes); - gpio_clear(CS_PIN); - xtimer_usleep(1); - ret = spi_transfer_regs(SPI_PORT, (CMD_R_REGISTER | (REGISTER_MASK & reg)), 0, buf_return, num_bytes); - gpio_set(CS_PIN); + if (num_bytes < 2) { + printf("0x%x returned: ", reg); - if (ret < 0) { - printf("Error in read access\n"); + for (int i = 0; i < num_bytes; i++) { + prtbin(buf_return[i]); + } } else { - if (num_bytes < 2) { - printf("0x%x returned: ", reg); + printf("0x%x returned: ", reg); - for (int i = 0; i < num_bytes; i++) { - prtbin(buf_return[i]); - } + for (int i = 0; i < num_bytes; i++) { + printf("%x ", buf_return[i]); } - else { - printf("0x%x returned: ", reg); - - for (int i = 0; i < num_bytes; i++) { - printf("%x ", buf_return[i]); - } - printf("\n\n"); - } + printf("\n\n"); } } @@ -266,6 +258,7 @@ int cmd_print_regs(int argc, char **argv) printf("################## Print Registers ###################\n"); + spi_acquire(SPI_PORT, CS_PIN, SPI_MODE_0, SPI_CLK_400KHZ); puts("REG_CONFIG: "); print_register(REG_CONFIG, 1); @@ -315,6 +308,8 @@ int cmd_print_regs(int argc, char **argv) puts("REG_FEATURE: "); print_register(REG_FEATURE, 1); + spi_release(SPI_PORT); + return 0; } diff --git a/tests/driver_nvram_spi/Makefile b/tests/driver_nvram_spi/Makefile index 083fcf303ceb..de928f30a401 100644 --- a/tests/driver_nvram_spi/Makefile +++ b/tests/driver_nvram_spi/Makefile @@ -7,7 +7,7 @@ USEMODULE += nvram_spi USEMODULE += xtimer # set default device parameters in case they are undefined -TEST_NVRAM_SPI_DEV ?= SPI_0 +TEST_NVRAM_SPI_DEV ?= SPI_DEV\(0\) TEST_NVRAM_SPI_CS ?= GPIO_PIN\(0,0\) TEST_NVRAM_SPI_SIZE ?= 64 TEST_NVRAM_SPI_ADDRESS_COUNT ?= 1 diff --git a/tests/driver_nvram_spi/main.c b/tests/driver_nvram_spi/main.c index c4e701967185..a517784068ce 100644 --- a/tests/driver_nvram_spi/main.c +++ b/tests/driver_nvram_spi/main.c @@ -40,16 +40,16 @@ #error "TEST_NVRAM_SPI_ADDRESS_COUNT not defined" #endif -#ifdef TEST_NVRAM_SPI_CONF -#define SPI_CONF (TEST_NVRAM_SPI_CONF) +#ifdef TEST_NVRAM_SPI_MODE +#define SPI_MODE (TEST_NVRAM_SPI_MODE) #else -#define SPI_CONF (SPI_CONF_FIRST_RISING) +#define SPI_MODE (SPI_MODE_0) #endif #ifdef TEST_NVRAM_SPI_SPEED -#define SPI_SPEED (TEST_NVRAM_SPI_SPEED) +#define SPI_CLK (TEST_NVRAM_SPI_SPEED) #else -#define SPI_SPEED (SPI_SPEED_10MHZ) +#define SPI_CLK (SPI_CLK_10MHZ) #endif /* This will only work on small memories. Modify if you need to test NVRAM @@ -114,6 +114,7 @@ int main(void) uint32_t i; nvram_spi_params_t spi_params = { .spi = TEST_NVRAM_SPI_DEV, + .clk = SPI_CLK, .cs = TEST_NVRAM_SPI_CS, .address_count = TEST_NVRAM_SPI_ADDRESS_COUNT, }; @@ -121,14 +122,6 @@ int main(void) uint32_t start_delay = 10; puts("NVRAM SPI test application starting..."); - printf("Initializing SPI_%i... ", TEST_NVRAM_SPI_DEV); - if (spi_init_master(TEST_NVRAM_SPI_DEV, SPI_CONF, SPI_SPEED_10MHZ) == 0) { - puts("[OK]"); - } - else { - puts("[Failed]\n"); - return 1; - } puts("Initializing NVRAM SPI device descriptor... "); if (nvram_spi_init(&dev, &spi_params, TEST_NVRAM_SPI_SIZE) == 0) { diff --git a/tests/driver_pcd8544/Makefile b/tests/driver_pcd8544/Makefile index 32a7c7f2864f..0504804716b0 100644 --- a/tests/driver_pcd8544/Makefile +++ b/tests/driver_pcd8544/Makefile @@ -7,7 +7,7 @@ USEMODULE += shell USEMODULE += pcd8544 # set default device parameters in case they are undefined -TEST_PCD8544_SPI ?= SPI_0 +TEST_PCD8544_SPI ?= SPI_DEV\(0\) TEST_PCD8544_CS ?= GPIO_PIN\(0,0\) TEST_PCD8544_RESET ?= GPIO_PIN\(0,1\) TEST_PCD8544_MODE ?= GPIO_PIN\(0,2\) diff --git a/tests/emb6/Makefile b/tests/emb6/Makefile index d958a2a6e440..bc3832ba8d1b 100644 --- a/tests/emb6/Makefile +++ b/tests/emb6/Makefile @@ -7,7 +7,8 @@ FEATURES_REQUIRED = periph_gpio periph_spi # for at86rf231 RIOTBASE ?= $(CURDIR)/../.. -BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1 +BOARD_INSUFFICIENT_MEMORY := msb-430h stm32f0discovery telosb weio z1 \ + wsn430-v1_3b wsn430-v1_4 USEPKG += emb6 diff --git a/tests/lwip/Makefile b/tests/lwip/Makefile index 38c10c2841ca..668918293741 100644 --- a/tests/lwip/Makefile +++ b/tests/lwip/Makefile @@ -6,10 +6,10 @@ include ../Makefile.tests_common RIOTBASE ?= $(CURDIR)/../.. BOARD_BLACKLIST := arduino-mega2560 msb-430h telosb waspmote-pro z1 arduino-uno \ - arduino-duemilanove + arduino-duemilanove msb-430 wsn430-v1_4 wsn430-v1_3b BOARD_INSUFFICIENT_MEMORY := airfy-beacon arduino-mega2560 msb-430h nrf6310 \ nucleo-f334 pca10005 stm32f0discovery telosb \ - weio yunjia-nrf51822 z1 nucleo-f030 + weio yunjia-nrf51822 z1 nucleo-f030 nucleo-f072 # including lwip_ipv6_mld would currently break this test on at86rf2xx radios USEMODULE += lwip lwip_ipv6_autoconfig lwip_conn_ip lwip_netdev2 diff --git a/tests/periph_spi/Makefile b/tests/periph_spi/Makefile index 7f3aae67c4c8..70ea31308788 100644 --- a/tests/periph_spi/Makefile +++ b/tests/periph_spi/Makefile @@ -3,6 +3,7 @@ include ../Makefile.tests_common FEATURES_REQUIRED = periph_spi +USEMODULE += xtimer USEMODULE += shell USEMODULE += shell_commands diff --git a/tests/periph_spi/main.c b/tests/periph_spi/main.c index b251ef946bf1..6bf46d92f198 100644 --- a/tests/periph_spi/main.c +++ b/tests/periph_spi/main.c @@ -24,307 +24,402 @@ #include #include -#include "board.h" +#include "xtimer.h" #include "shell.h" #include "periph/spi.h" -#include "periph/gpio.h" - -enum { - READ = 0, - WRITE, - INIT -} rw; - -static int spi_dev = -1; -static gpio_t spi_cs = -1; -static int spi_mode_int = -1; -static spi_conf_t spi_mode = -1; -static int spi_speed_int = -1; -static spi_speed_t spi_speed = -1; - -/* 0 for slave, 1 for master, -1 for not initialized */ -static int spi_master = -1; -static int port = -1; -static int pin = -1; - -static char buffer[256]; /* temporary buffer */ -static char rx_buffer[256]; /* global receive buffer */ -static int rx_counter = 0; - -static volatile int state; -static char* mem = "Hello Master! abcdefghijklmnopqrstuvwxyz 0123456789 " - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -int parse_spi_dev(int argc, char **argv) -{ - /* reset default values */ - spi_dev = SPI_0; - spi_mode = SPI_CONF_FIRST_RISING; - spi_speed = SPI_SPEED_1MHZ; - - if (argc < 4) { - printf("usage: %s [mode [speed]]\n", argv[0]); - puts(" DEV is the SPI device to use:"); - for (int i = 0; i < SPI_NUMOF; i++) { - printf(" %i - SPI_%i\n", i, i); - } - puts(" cs port: port to use as the chip select line"); - puts(" cs pin: pin to use on th given port as cs line"); - puts(" mode: must be one of the following options (* marks " - "default value):"); - puts(" *0 - POL:0, PHASE:0 - ON FIRST RISING EDGE"); - puts(" 1 - POL:0, PHASE:1 - ON SECOND RISING EDGE"); - puts(" 2 - POL:1, PHASE:0 - ON FIRST FALLING EDGE"); - puts(" 3 - POL:1, PHASE:1 - on second falling edge"); - puts(" speed: must be one of the following options (only used " - "in master mode):"); - puts(" 0 - 100 KHz"); - puts(" 1 - 400 KHz"); - puts(" *2 - 1 MHz"); - puts(" 3 - 5 MHz"); - puts(" 4 - 10 MHz\n"); - return -4; - } - spi_dev = atoi(argv[1]); - if (spi_dev < 0 || spi_dev >= SPI_NUMOF) { - puts("error: invalid DEV value given"); - return -1; - } - port = atoi(argv[2]); - pin = atoi(argv[3]); - spi_cs = GPIO_PIN(port,pin); - if (argc >= 5) { - spi_mode_int = argv[4][0] - '0'; - if (spi_mode_int < 0 || spi_mode_int > 3) { - puts("error: invalid MODE value given"); - return -2; - } else { - switch (spi_mode_int) { - case 0: - spi_mode = SPI_CONF_FIRST_RISING; - break; - case 1: - spi_mode = SPI_CONF_SECOND_RISING; - break; - case 2: - spi_mode = SPI_CONF_FIRST_FALLING; - break; - case 3: - spi_mode = SPI_CONF_SECOND_FALLING; - break; - } - } - } - if (argc >= 6) { - spi_speed_int = argv[5][0] - '0'; - if (spi_speed_int < 0 || spi_speed_int > 4) { - puts("error: invalid SPEED value given"); - return -3; - } else { - switch (spi_speed_int) { - case 0: - spi_speed = SPI_SPEED_100KHZ; - break; - case 1: - spi_speed = SPI_SPEED_400KHZ; - break; - case 2: - spi_speed = SPI_SPEED_1MHZ; - break; - case 3: - spi_speed = SPI_SPEED_5MHZ; - break; - case 4: - spi_speed = SPI_SPEED_10MHZ; - break; - } - } - } - return 0; -} -void print_bytes(char* title, char* chars, int length) +/** + * @brief Some parameters used for benchmarking + */ +#define BENCH_REDOS (1000) +#define BENCH_SMALL (2) +#define BENCH_LARGE (100) +#define BENCH_PAYLOAD ('b') +#define BENCH_REGADDR (0x23) + +#define BUF_SIZE (512U) + +/** + * @brief Benchmark buffers + */ +static uint8_t bench_wbuf[BENCH_LARGE]; +static uint8_t bench_rbuf[BENCH_LARGE]; + +/** + * @brief Generic buffer used for receiving + */ +static uint8_t buf[BUF_SIZE]; + +static struct { + spi_t dev; + spi_mode_t mode; + spi_clk_t clk; + spi_cs_t cs; +} spiconf; + +void print_bytes(char* title, uint8_t* data, size_t len) { - printf("%4s", title); - for (int i = 0; i < length; i++) { - printf(" %2i ", i); + printf("%4s\n", title); + for (size_t i = 0; i < len; i++) { + printf(" %2i ", (int)i); } - printf("\n "); - for (int i = 0; i < length; i++) { - printf(" 0x%02x", (int)chars[i]); + printf("\n "); + for (size_t i = 0; i < len; i++) { + printf(" 0x%02x", (int)data[i]); } - printf("\n "); - for (int i = 0; i < length; i++) { - if (chars[i] < ' ' || chars[i] > '~') { + printf("\n "); + for (size_t i = 0; i < len; i++) { + if (data[i] < ' ' || data[i] > '~') { printf(" ?? "); } else { - printf(" %c ", chars[i]); + printf(" %c ", (char)data[i]); } } printf("\n\n"); } -void slave_on_cs(void *arg) +int cmd_init(int argc, char **argv) { - (void)arg; + int dev, mode, clk, port, pin, tmp; - spi_transmission_begin(spi_dev, 'F'); - state = 0; - rw = INIT; -} + if (argc < 5) { + printf("usage: %s \n", argv[0]); + puts("\tdev:"); + for (int i = 0; i < (int)SPI_NUMOF; i++) { + printf("\t\t%i: SPI_DEV(%i)\n", i, i); + } + puts("\tmode:"); + puts("\t\t0: POL:0, PHASE:0 - on first rising edge"); + puts("\t\t1: POL:0, PHASE:1 - on second rising edge"); + puts("\t\t2: POL:1, PHASE:0 - on first falling edge"); + puts("\t\t3: POL:1, PHASE:1 - on second falling edge"); + puts("\tclk:"); + puts("\t\t0: 100 KHz"); + puts("\t\t1: 400 KHz"); + puts("\t\t2: 1 MHz"); + puts("\t\t3: 5 MHz"); + puts("\t\t4: 10 MHz"); + puts("\tcs port:"); + puts("\t\tPort of the CS pin, set to -1 for hardware chip select"); + puts("\tcs pin:"); + puts("\t\tPin used for chip select. If hardware chip select is enabled,\n" + "\t\tthis value specifies the internal HWCS line"); + return 1; + } -char slave_on_data(char data) -{ - rx_buffer[rx_counter] = data; - rx_counter++; - if (rx_counter >= 256) { - rx_counter = 0; - } - - switch (rw) { - case READ: - return mem[state++]; - case WRITE: - mem[state++] = data; - return 'o'; - case INIT: - if (data == ' ') { - rw = READ; - return mem[state++]; - } else if (data & 0x80) { - rw = WRITE; - state = (data & 0x7f); - return 'W'; - } else { - rw = READ; - state = data; - return mem[state++]; - } - } - return 'e'; -} + /* parse the given SPI device */ + dev = atoi(argv[1]); + if (dev < 0 || dev >= SPI_NUMOF) { + puts("error: invalid SPI device specified"); + return 1; + } + spiconf.dev = SPI_DEV(dev); -int cmd_init_master(int argc, char **argv) -{ - int res; - spi_master = -1; - if (parse_spi_dev(argc, argv) < 0) { + /* parse the SPI mode */ + mode = atoi(argv[2]); + switch (mode) { + case 0: spiconf.mode = SPI_MODE_0; break; + case 1: spiconf.mode = SPI_MODE_1; break; + case 2: spiconf.mode = SPI_MODE_2; break; + case 3: spiconf.mode = SPI_MODE_3; break; + default: + puts("error: invalid SPI mode specified"); + return 1; + } + + /* parse the targeted clock speed */ + clk = atoi(argv[3]); + switch (clk) { + case 0: spiconf.clk = SPI_CLK_100KHZ; break; + case 1: spiconf.clk = SPI_CLK_400KHZ; break; + case 2: spiconf.clk = SPI_CLK_1MHZ; break; + case 3: spiconf.clk = SPI_CLK_5MHZ; break; + case 4: spiconf.clk = SPI_CLK_10MHZ; break; + default: + puts("error: invalid bus speed specified"); + return 1; + } + + /* parse chip select port and pin */ + port = atoi(argv[4]); + pin = atoi(argv[5]); + if (pin < 0 || port < -1) { + puts("error: invalid CS port/pin combination specified"); + } + if (port == -1) { /* hardware chip select line */ + spiconf.cs = SPI_HWCS(pin); + } + else { + spiconf.cs = (spi_cs_t)GPIO_PIN(port, pin); + } + + /* test setup */ + tmp = spi_init_cs(spiconf.dev, spiconf.cs); + if (tmp != SPI_OK) { + puts("error: unable to initialize the given chip select line"); + return 1; + } + tmp = spi_acquire(spiconf.dev, spiconf.cs, spiconf.mode, spiconf.clk); + if (tmp == SPI_NOMODE) { + puts("error: given SPI mode is not supported"); return 1; } - spi_acquire(spi_dev); - res = spi_init_master(spi_dev, spi_mode, spi_speed); - spi_release(spi_dev); - if (res < 0) { - printf("spi_init_master: error initializing SPI_%i device (code %i)\n", - spi_dev, res); + else if (tmp == SPI_NOCLK) { + puts("error: targeted clock speed is not supported"); return 1; } - res = gpio_init(spi_cs, GPIO_OUT); - if (res < 0){ - printf("gpio_init: error initializing GPIO_PIN(%i, %i) as CS line (code %i)\n", - port, pin, res); + else if (tmp != SPI_OK) { + puts("error: unable to acquire bus with given parameters"); return 1; } - gpio_set(spi_cs); - spi_master = 1; - printf("SPI_%i successfully initialized as master, cs: GPIO_PIN(%i, %i), mode: %i, speed: %i\n", - spi_dev, port, pin, spi_mode_int, spi_speed_int); + spi_release(spiconf.dev); + + printf("SPI_DEV(%i) initialized: mode: %i, clk: %i, cs_port: %i, cs_pin: %i\n", + dev, mode, clk, port, pin); + return 0; } -int cmd_init_slave(int argc, char **argv) +int cmd_transfer(int argc, char **argv) { - int res; - spi_master = -1; - if (parse_spi_dev(argc, argv) < 0) { + size_t len; + + if (argc < 2) { + printf("usage: %s \n", argv[0]); return 1; } - spi_acquire(spi_dev); - res = spi_init_slave(spi_dev, spi_mode, slave_on_data); - spi_release(spi_dev); - if (res < 0) { - printf("spi_init_slave: error initializing SPI_%i device (code: %i)\n", - spi_dev, res); + + if (spiconf.dev == SPI_UNDEF) { + puts("error: SPI is not initialized, please initialize bus first"); return 1; } - res = gpio_init_int(spi_cs, GPIO_IN, GPIO_FALLING, slave_on_cs, 0); - if (res < 0){ - printf("gpio_init_int: error initializing GPIO_PIN(%i, %i) as CS line (code %i)\n", - port, pin, res); + + /* get bus access */ + if (spi_acquire(spiconf.dev, spiconf.cs, + spiconf.mode, spiconf.clk) != SPI_OK) { + puts("error: unable to acquire the SPI bus"); return 1; } - spi_master = 0; - printf("SPI_%i successfully initialized as slave, cs: GPIO_PIN(%i, %i), mode: %i\n", - spi_dev, port, pin, spi_mode_int); + + /* transfer data */ + len = strlen(argv[1]); + memset(buf, 0, sizeof(buf)); + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, argv[1], buf, len); + + /* release the bus */ + spi_release(spiconf.dev); + + /* print results */ + print_bytes("Sent bytes", (uint8_t *)argv[1], len); + print_bytes("Received bytes", buf, len); + return 0; } -int cmd_transfer(int argc, char **argv) +int cmd_bench(int argc, char **argv) { - int res; - char *hello = "Hello"; + uint32_t start, stop; + uint32_t sum = 0; + uint8_t in; + uint8_t out = (uint8_t)BENCH_PAYLOAD; - if (spi_master != 1) { - puts("error: node is not initialized as master, please do so first"); + if (spiconf.dev == SPI_UNDEF) { + puts("error: SPI is not initialized, please initialize bus first"); return 1; } - if (argc < 2) { - puts("No data to transfer given, will transfer 'Hello' to device"); + /* prepare buffer */ + memset(bench_wbuf, BENCH_PAYLOAD, BENCH_LARGE); + + /* get access to the bus */ + if (spi_acquire(spiconf.dev, spiconf.cs, + spiconf.mode, spiconf.clk) != SPI_OK) { + puts("error: unable to acquire the SPI bus"); + return 1; } - else { - hello = argv[1]; + + puts("### Running some benchmarks, all values in [us] ###\n"); + + /* 1 - write 1000 times 1 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + in = spi_transfer_byte(spiconf.dev, spiconf.cs, false, out); + (void)in; } + stop = xtimer_now_usec(); + printf(" 1 - write %i times %i byte:", BENCH_REDOS, 1); + printf("\t\t\t%i\n", (int)(stop - start)); + sum += (stop - start); - /* do the actual data transfer */ - spi_acquire(spi_dev); - gpio_clear(spi_cs); - res = spi_transfer_bytes(spi_dev, hello, buffer, strlen(hello)); - gpio_set(spi_cs); - spi_release(spi_dev); + /* 2 - write 1000 times 2 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, + bench_wbuf, NULL, BENCH_SMALL); + } + stop = xtimer_now_usec(); + printf(" 2 - write %i times %i byte:", BENCH_REDOS, BENCH_SMALL); + printf("\t\t\t%i\n", (int)(stop - start)); + sum += (stop - start); - /* look at the results */ - if (res < 0) { - printf("error: unable to transfer data to slave (code: %i)\n", res); - return 1; + /* 3 - write 1000 times 100 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, + bench_wbuf, NULL, BENCH_LARGE); } - else { - printf("Transfered %i bytes:\n", res); - print_bytes("MOSI", hello, res); - print_bytes("MISO", buffer, res); - return 0; + stop = xtimer_now_usec(); + printf(" 3 - write %i times %i byte:", BENCH_REDOS, BENCH_LARGE); + printf("\t\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 4 - write 1000 times 1 byte to register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + in = spi_transfer_reg(spiconf.dev, spiconf.cs, BENCH_REGADDR, out); + (void)in; } -} + stop = xtimer_now_usec(); + printf(" 4 - write %i times %i byte to register:", BENCH_REDOS, 1); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); -int cmd_print(int argc, char **argv) -{ - if (spi_master != 0) { - puts("error: node is not initialized as slave"); - return 1; + /* 5 - write 1000 times 2 byte to register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR, + bench_wbuf, NULL, BENCH_SMALL); } - else { - printf("Received %i bytes:\n", rx_counter); - print_bytes("MOSI", rx_buffer, rx_counter); + stop = xtimer_now_usec(); + printf(" 5 - write %i times %i byte to register:", BENCH_REDOS, BENCH_SMALL); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 6 - write 1000 times 100 byte to register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR, + bench_wbuf, NULL, BENCH_LARGE); } - rx_counter = 0; - memset(&rx_buffer, 0, 256); + stop = xtimer_now_usec(); + printf(" 6 - write %i times %i byte to register:", BENCH_REDOS, BENCH_LARGE); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 7 - read 1000 times 2 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, + NULL, bench_rbuf, BENCH_SMALL); + } + stop = xtimer_now_usec(); + printf(" 7 - read %i times %i byte:", BENCH_REDOS, BENCH_SMALL); + printf("\t\t\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 8 - read 1000 times 100 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, + NULL, bench_rbuf, BENCH_LARGE); + } + stop = xtimer_now_usec(); + printf(" 8 - read %i times %i byte:", BENCH_REDOS, BENCH_LARGE); + printf("\t\t\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 9 - read 1000 times 2 byte from register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR, + NULL, bench_rbuf, BENCH_SMALL); + } + stop = xtimer_now_usec(); + printf(" 9 - read %i times %i byte from register:", BENCH_REDOS, BENCH_SMALL); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 10 - read 1000 times 100 byte from register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR, + NULL, bench_rbuf, BENCH_LARGE); + } + stop = xtimer_now_usec(); + printf("10 - read %i times %i byte from register:", BENCH_REDOS, BENCH_LARGE); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 11 - transfer 1000 times 2 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, + bench_wbuf, bench_rbuf, BENCH_SMALL); + } + stop = xtimer_now_usec(); + printf("11 - transfer %i times %i byte:", BENCH_REDOS, BENCH_SMALL); + printf("\t\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 12 - transfer 1000 times 100 byte */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_bytes(spiconf.dev, spiconf.cs, false, + bench_wbuf, bench_rbuf, BENCH_LARGE); + } + stop = xtimer_now_usec(); + printf("12 - transfer %i times %i byte:", BENCH_REDOS, BENCH_LARGE); + printf("\t\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 13 - transfer 1000 times 2 byte from/to register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR, + bench_wbuf, bench_rbuf, BENCH_SMALL); + } + stop = xtimer_now_usec(); + printf("13 - transfer %i times %i byte to register:", BENCH_REDOS, BENCH_SMALL); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); + + /* 14 - transfer 1000 times 100 byte from/to register */ + start = xtimer_now_usec(); + for (int i = 0; i < BENCH_REDOS; i++) { + spi_transfer_regs(spiconf.dev, spiconf.cs, BENCH_REGADDR, + bench_wbuf, bench_rbuf, BENCH_LARGE); + } + stop = xtimer_now_usec(); + printf("14 - transfer %i times %i byte to register:", BENCH_REDOS, BENCH_LARGE); + printf("\t%i\n", (int)(stop - start)); + sum += (stop - start); + + printf("-- - SUM:\t\t\t\t\t%i\n", (int)sum); + + spi_release(spiconf.dev); + puts("\n### All runs complete ###"); + return 0; } static const shell_command_t shell_commands[] = { - { "init_master", "Initialize node as SPI master", cmd_init_master }, - { "init_slave", "Initialize node as SPI slave", cmd_init_slave }, - { "send", "Transfer string to slave (only in master mode)", cmd_transfer }, - { "print_rx", "Print the received string (only in slave mode)", cmd_print }, + { "init", "Setup a particular SPI configuration", cmd_init }, + { "send", "Transfer string to slave", cmd_transfer }, + { "bench", "Runs some benchmarks", cmd_bench }, { NULL, NULL, NULL } }; int main(void) { - puts("\nRIOT low-level SPI driver test"); - puts("This application enables you to test a platforms SPI driver implementation."); - puts("Enter 'help' to get started\n"); + puts("Manual SPI peripheral driver test"); + puts("Refer to the README.md file for more information.\n"); + + printf("There are %i SPI devices configured for your platform.\n", + (int)SPI_NUMOF); + + /* reset local SPI configuration */ + spiconf.dev = SPI_UNDEF; /* run the shell */ char line_buf[SHELL_DEFAULT_BUFSIZE]; diff --git a/tests/warn_conflict/Makefile b/tests/warn_conflict/Makefile index e3c6cd2750c2..b83cc4411cfd 100644 --- a/tests/warn_conflict/Makefile +++ b/tests/warn_conflict/Makefile @@ -5,8 +5,9 @@ include ../Makefile.tests_common # so using this compile test on other boards will not provide the expected warning. BOARD_WHITELIST := stm32f4discovery -# These features have a chance to use/access the shared `SPI_0` on stm32f4discovery, -# which would probably produce an unexpected behaviour in the user application. +# These features have a chance to use/access the shared `SPI_DEV(0)` on +# stm32f4discovery, which would probably produce an unexpected behavior in the +# user application. FEATURES_REQUIRED = periph_dac periph_spi include $(RIOTBASE)/Makefile.include diff --git a/tests/warn_conflict/README.md b/tests/warn_conflict/README.md index 0169964a8422..b274230efd33 100644 --- a/tests/warn_conflict/README.md +++ b/tests/warn_conflict/README.md @@ -9,7 +9,7 @@ It is expected to be presented with a warning on the conflicts with a short desc ``` $ make BOARD=stm32f4discovery The following features may conflict: periph_dac periph_spi -Rationale: On stm32f4discovery boards there are the same pins for the DAC and/or SPI_0. +Rationale: On stm32f4discovery boards there are the same pins for the DAC and/or SPI_DEV(0). EXPECT undesired behaviour! ``` @@ -23,7 +23,7 @@ Whenever an application, such as this test, requires board features that match a * Conflicting features are described in groups separated by a `:` (doublecolon) for each feature, e.g.: `FEATURES_CONFLICT = periph_spi:periph_dac`, which states that `periph_spi` conflicts with `periph_dac`. -As seen above, this is the conflict of `SPI_0` pinout is shared with `DAC` on the [stm32f4discovery](https://github.com/RIOT-OS/RIOT/wiki/Board%3A-STM32F4discovery) board. +As seen above, this is the conflict of `SPI_DEV(0)` pinout is shared with `DAC` on the [stm32f4discovery](https://github.com/RIOT-OS/RIOT/wiki/Board%3A-STM32F4discovery) board. * Distinct groups of conflicts are whitespace separated, e.g.: `featureA:featureB featureC:featureD`, which states that `featureA` conflicts with `featureB`, and `featureC` conflicts with `featureD`. diff --git a/tests/warn_conflict/test.py b/tests/warn_conflict/test.py index 65a2b2568d6e..1f3bfb2d1288 100755 --- a/tests/warn_conflict/test.py +++ b/tests/warn_conflict/test.py @@ -9,7 +9,7 @@ output = subprocess.Popen(["make", "BOARD=stm32f4discovery"], stderr=subprocess.PIPE, stdout=subprocess.PIPE ) out,err = output.communicate() - compare = b'\x1b[1;33mThe following features may conflict:\x1b[0m \x1b[1;32mperiph_dac periph_spi\x1b[0m\n\x1b[1;33mRationale: \x1b[0mOn stm32f4discovery boards there are the same pins for the DAC and/or SPI_0.\n\n\x1b[1;33mEXPECT undesired behaviour!\x1b[0m\n' + compare = b'\x1b[1;33mThe following features may conflict:\x1b[0m \x1b[1;32mperiph_dac periph_spi\x1b[0m\n\x1b[1;33mRationale: \x1b[0mOn stm32f4discovery boards there are the same pins for the DAC and/or SPI_DEV(0).\n\n\x1b[1;33mEXPECT undesired behaviour!\x1b[0m\n' if err == compare: print("Test SUCCEEDED! Compile time output is as expected!\n") else: