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/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/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/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..9c0432165ed9 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, 5), + .miso_pin = GPIO_PIN(PORT_B, 4), + .sclk_pin = GPIO_PIN(PORT_B, 3), + .cs_pin = GPIO_PIN(PORT_B, 2), + .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 * @{ 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/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/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/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/include/periph_cpu.h b/cpu/stm32f1/include/periph_cpu.h index 035eec70f4a4..b9bbe757b9dc 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 + */ +#define TIMER_CHANNELS (4U) + +/** + * @brief All timers have a width of 16-bit */ -#undef PERIPH_SPI_NEEDS_TRANSFER_BYTES -#define PERIPH_SPI_NEEDS_TRANSFER_BYTE +#define TIMER_MAXVAL (0xffff) /** * @brief Generate GPIO mode bitfields 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/include/periph_cpu.h b/cpu/stm32f2/include/periph_cpu.h index d9197f38958e..82d740cbf8c1 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 * 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/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/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/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 */