mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/stm32*+boards: adapted to new SPI API
- adapted the SPI driver - adapted all boards using the CPU
This commit is contained in:
parent
849ce20f5c
commit
0edef2a0e1
@ -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), \
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 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]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -31,18 +31,19 @@ extern "C" {
|
||||
* @brief SPI configuration
|
||||
* @{
|
||||
*/
|
||||
#define SPI_NUMOF (1U)
|
||||
#define SPI_0_EN 1
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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)
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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)}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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)
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
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_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 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]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
* @{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
* @{
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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)
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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
|
||||
* @{
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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))
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 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
|
||||
|
@ -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
|
||||
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 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
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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
|
||||
}
|
||||
};
|
||||
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 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]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
/** @} */
|
||||
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 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
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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
|
||||
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 */
|
||||
}
|
||||
};
|
||||
|
||||
/* 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 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
|
||||
}
|
||||
};
|
||||
|
||||
/* 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))
|
||||
#define SPI_NUMOF (sizeof(spi_config) / sizeof(spi_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*
|
||||
|
211
cpu/stm32_common/periph/spi.c
Normal file
211
cpu/stm32_common/periph/spi.c
Normal file
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Vincent Dupont <vincent@otakeys.com>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
165
cpu/stm32f0/periph/spi.cold
Normal file
165
cpu/stm32f0/periph/spi.cold
Normal file
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
@ -31,11 +31,14 @@ extern "C" {
|
||||
#define ADC_DEVS (2U)
|
||||
|
||||
/**
|
||||
* @brief declare needed generic SPI functions
|
||||
* @{
|
||||
* @brief All timers for the STM32F1 have 4 CC channels
|
||||
*/
|
||||
#undef PERIPH_SPI_NEEDS_TRANSFER_BYTES
|
||||
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE
|
||||
#define TIMER_CHANNELS (4U)
|
||||
|
||||
/**
|
||||
* @brief All timers have a width of 16-bit
|
||||
*/
|
||||
#define TIMER_MAXVAL (0xffff)
|
||||
|
||||
/**
|
||||
* @brief Generate GPIO mode bitfields
|
||||
|
@ -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 <thomas.eichinger@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
138
cpu/stm32f1/periph/spi.cold
Normal file
138
cpu/stm32f1/periph/spi.cold
Normal file
@ -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 <thomas.eichinger@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
@ -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
|
||||
*
|
||||
|
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
174
cpu/stm32f2/periph/spi.cold
Normal file
174
cpu/stm32f2/periph/spi.cold
Normal file
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Vincent Dupont <vincent@otakeys.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
@ -1,420 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Hamburg University of Applied Sciences
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* 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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
165
cpu/stm32f3/periph/spi.cold
Normal file
165
cpu/stm32f3/periph/spi.cold
Normal file
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
@ -4,4 +4,5 @@ export CPU_FAM = stm32f4
|
||||
USEMODULE += pm_layered
|
||||
|
||||
include $(RIOTCPU)/stm32_common/Makefile.include
|
||||
|
||||
include $(RIOTCPU)/Makefile.include.cortexm_common
|
||||
|
@ -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
|
||||
|
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#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 */
|
@ -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
|
||||
|
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
166
cpu/stm32l1/periph/spi.cold
Normal file
166
cpu/stm32l1/periph/spi.cold
Normal file
@ -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 <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Fabian Nack <nack@inf.fu-berlin.de>
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#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 */
|
Loading…
Reference in New Issue
Block a user