[PATCH 3/4] move spidev into the startup code
Yaroslav leshcinsky
midniwalker at gmail.com
Sun Mar 31 09:34:34 UTC 2019
From: Yaraslau Liashchynski <YLiashchynski at luxoft.com>
---
bsps/arm/stm32l4/dma/stm32l4_dma.c | 183 +++++++++
bsps/arm/stm32l4/gpio/stm32l4_gpio.c | 145 +++++++
bsps/arm/stm32l4/include/bsp/stm32l4_dma.h | 105 ++++++
bsps/arm/stm32l4/include/bsp/stm32l4_gpio.h | 129 +++++++
bsps/arm/stm32l4/include/bsp/stm32l4_spi.h | 24 ++
bsps/arm/stm32l4/spi/stm32l4_spi.c | 564 ++++++++++++++++++++++++++++
c/src/lib/libbsp/arm/stm32l4/Makefile.am | 5 +
7 files changed, 1155 insertions(+)
create mode 100644 bsps/arm/stm32l4/dma/stm32l4_dma.c
create mode 100644 bsps/arm/stm32l4/gpio/stm32l4_gpio.c
create mode 100644 bsps/arm/stm32l4/include/bsp/stm32l4_dma.h
create mode 100644 bsps/arm/stm32l4/include/bsp/stm32l4_gpio.h
create mode 100644 bsps/arm/stm32l4/include/bsp/stm32l4_spi.h
create mode 100644 bsps/arm/stm32l4/spi/stm32l4_spi.c
diff --git a/bsps/arm/stm32l4/dma/stm32l4_dma.c b/bsps/arm/stm32l4/dma/stm32l4_dma.c
new file mode 100644
index 0000000..d715e50
--- /dev/null
+++ b/bsps/arm/stm32l4/dma/stm32l4_dma.c
@@ -0,0 +1,183 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+
+#include <bsp/stm32l4xx.h>
+#include <bsp/stm32l4_dma.h>
+
+#define CELL_LEN 4
+#define REG_SZ 32
+
+static struct dma_cb dma1_channel_cb_func[CHANNEL_MAX];
+static struct dma_cb dma2_channel_cb_func[CHANNEL_MAX];
+
+static uint32_t get_cell_mask(uint32_t pos)
+{
+ for(uint8_t i = 0; i < REG_SZ; i += CELL_LEN)
+ {
+ uint8_t bit_pos = REG_SZ - __builtin_clz(pos) - 1;
+
+ if((bit_pos < i + CELL_LEN) && (bit_pos >= i))
+ {
+ uint32_t val = 0;
+ for(uint8_t j = 0; j < CELL_LEN; j++)
+ {
+ val |= 1 << j;
+ }
+
+ return val << i;
+ }
+ }
+
+ return 0;
+}
+
+static void dma_channel_config(struct dma_driver *dma)
+{
+ struct dma_ch *channel = dma->channel_cfg;
+ struct dma_cb *cb_func = &channel->cb_func;
+ struct dma_cb *cb_ptr = (dma->dmax == DMA1)? dma1_channel_cb_func :
+ dma2_channel_cb_func;
+ const size_t num = channel->ch_num;
+
+ cb_ptr[num].half_transfer = cb_func->half_transfer;
+ cb_ptr[num].transfer_error = cb_func->transfer_error;
+ cb_ptr[num].transfer_complete = cb_func->transfer_complete;
+
+ DMA_Channel_TypeDef *ch = channel->ch;
+
+ ch->CCR = channel->config;
+ ch->CPAR = channel->periph_addr;
+
+ uint32_t mask = get_cell_mask(channel->ch_select);
+
+ if(dma->dmax == DMA1)
+ {
+ DMA1_CSELR->CSELR &= ~mask;
+ DMA1_CSELR->CSELR |= channel->ch_select;
+ } else
+ {
+ DMA2_CSELR->CSELR &= ~mask;
+ DMA2_CSELR->CSELR |= channel->ch_select;
+ }
+}
+
+static void dma_init(struct dma_driver *dma_driver)
+{
+ dma_channel_config(dma_driver);
+
+ dma_driver->dmax->IFCR = 0;
+}
+
+static inline void dma_rcc_enable(DMA_TypeDef *dmax)
+{
+ RCC->AHB1ENR |= (dmax == DMA1)? RCC_AHB1ENR_DMA1EN : RCC_AHB1ENR_DMA2EN;
+}
+
+void dma_driver_config(void *dma_driver, ...)
+{
+ va_list list_ptr;
+ va_start(list_ptr, dma_driver);
+ struct dma_driver *driver = (struct dma_driver *)dma_driver;
+
+ while(true)
+ {
+ if(driver == NULL)
+ {
+ break;
+ }
+
+ dma_rcc_enable(driver->dmax);
+ dma_init(driver);
+
+ driver = va_arg(list_ptr, struct dma_driver *);
+ }
+
+ va_end(list_ptr);
+}
+
+void DMA1_Channel5_IRQHandler(void)
+{
+ if((DMA1->ISR & DMA_ISR_TCIF5) && (DMA1_Channel5->CCR & DMA_CCR_TCIE)) {
+ if(dma1_channel_cb_func[CH5].transfer_complete == NULL) return;
+
+ dma1_channel_cb_func[CH5].transfer_complete();
+ }
+
+ if((DMA1->ISR & DMA_ISR_HTIF5) && (DMA1_Channel5->CCR & DMA_CCR_HTIE)) {
+ if(dma1_channel_cb_func[CH5].half_transfer == NULL) return;
+
+ dma1_channel_cb_func[CH5].half_transfer();
+ }
+
+ if((DMA1->ISR & DMA_ISR_TEIF5) && (DMA1_Channel5->CCR & DMA_CCR_TEIE)) {
+ if(dma1_channel_cb_func[CH5].transfer_error == NULL) return;
+
+ dma1_channel_cb_func[CH5].transfer_error();
+ }
+}
+
+void DMA1_Channel4_IRQHandler(void)
+{
+ if((DMA1->ISR & DMA_ISR_TCIF4) && (DMA1_Channel4->CCR & DMA_CCR_TCIE)) {
+ if(dma1_channel_cb_func[CH4].transfer_complete == NULL) return;
+
+ dma1_channel_cb_func[CH4].transfer_complete();
+ }
+
+ if((DMA1->ISR & DMA_ISR_HTIF4) && (DMA1_Channel4->CCR & DMA_CCR_HTIE)) {
+ if(dma1_channel_cb_func[CH4].half_transfer == NULL) return;
+
+ dma1_channel_cb_func[CH4].half_transfer();
+ }
+
+ if((DMA1->ISR & DMA_ISR_TEIF4) && (DMA1_Channel4->CCR & DMA_CCR_TEIE)) {
+ if(dma1_channel_cb_func[CH4].transfer_error == NULL) return;
+
+ dma1_channel_cb_func[CH4].transfer_error();
+ }
+}
+
+void DMA1_Channel3_IRQHandler(void)
+{
+ if((DMA1->ISR & DMA_ISR_TCIF3) && (DMA1_Channel3->CCR & DMA_CCR_TCIE)) {
+ if(dma1_channel_cb_func[CH3].transfer_complete == NULL) return;
+
+ dma1_channel_cb_func[CH3].transfer_complete();
+ }
+
+ if((DMA1->ISR & DMA_ISR_HTIF3) && (DMA1_Channel3->CCR & DMA_CCR_HTIE)) {
+ if(dma1_channel_cb_func[CH3].half_transfer == NULL) return;
+
+ dma1_channel_cb_func[CH3].half_transfer();
+ }
+
+ if((DMA1->ISR & DMA_ISR_TEIF3) && (DMA1_Channel3->CCR & DMA_CCR_TEIE)) {
+ if(dma1_channel_cb_func[CH3].transfer_error == NULL) return;
+
+ dma1_channel_cb_func[CH3].transfer_error();
+ }
+}
+
+void DMA1_Channel2_IRQHandler(void)
+{
+ if((DMA1->ISR & DMA_ISR_TCIF2) && (DMA1_Channel2->CCR & DMA_CCR_TCIE)) {
+ if(dma1_channel_cb_func[CH2].transfer_complete == NULL) return;
+
+ dma1_channel_cb_func[CH2].transfer_complete();
+ }
+
+ if((DMA1->ISR & DMA_ISR_HTIF2) && (DMA1_Channel2->CCR & DMA_CCR_HTIE)) {
+ if(dma1_channel_cb_func[CH2].half_transfer == NULL) return;
+
+ dma1_channel_cb_func[CH2].half_transfer();
+ }
+
+ if((DMA1->ISR & DMA_ISR_TEIF2) && (DMA1_Channel2->CCR & DMA_CCR_TEIE)) {
+ if(dma1_channel_cb_func[CH2].transfer_error == NULL) return;
+
+ dma1_channel_cb_func[CH2].transfer_error();
+ }
+}
diff --git a/bsps/arm/stm32l4/gpio/stm32l4_gpio.c b/bsps/arm/stm32l4/gpio/stm32l4_gpio.c
new file mode 100644
index 0000000..223d010
--- /dev/null
+++ b/bsps/arm/stm32l4/gpio/stm32l4_gpio.c
@@ -0,0 +1,145 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <bsp/stm32l4xx.h>
+#include <bsp/stm32l4_gpio.h>
+
+static uint8_t gpio_get_pin_number(int pin)
+{
+ return ((PA0 <= pin) && (pin <= PA15))? pin - PA0 :
+ ((PB0 <= pin) && (pin <= PB15))? pin - PB0 :
+ ((PC0 <= pin) && (pin <= PC15))? pin - PC0 :
+ ((PD0 <= pin) && (pin <= PD15))? pin - PD0 :
+ ((PE0 <= pin) && (pin <= PE15))? pin - PE0 :
+ ((PF0 <= pin) && (pin <= PF15))? pin - PF0 :
+ ((PG0 <= pin) && (pin <= PG15))? pin - PG0 :
+ ((PH0 <= pin) && (pin <= PH15))? pin - PH0 : 0;
+}
+
+static void gpio_set_mode(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+ enum gpio_mode mode = gpio_driver->mode;
+
+ gpiox->MODER &= ~(3 << (pin * 2));
+ gpiox->MODER |= mode << (pin * 2);
+}
+
+static void gpio_set_alter_func(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+ enum gpio_alter_func func = gpio_driver->func;
+
+ const size_t afr = pin > 7? (pin -= 8), 1 : 0;
+
+ gpiox->AFR[afr] &= ~(0x0F << (pin * 4));
+ gpiox->AFR[afr] |= func << (pin * 4);
+}
+
+static void gpio_set_output_type(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+ enum gpio_type otype = gpio_driver->otype;
+
+ gpiox->OTYPER |= otype << pin;
+}
+
+static void gpio_set_pull_mode(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+ enum gpio_pull pull = gpio_driver->pull;
+
+ gpiox->PUPDR &= ~(3 << (pin * 2));
+ gpiox->PUPDR |= pull << (pin * 2);
+}
+
+static void gpio_set_speed(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+ enum gpio_speed speed = gpio_driver->speed;
+
+ gpiox->OSPEEDR &= ~(3 << (pin * 2));
+ gpiox->OSPEEDR |= speed << (pin * 2);
+}
+
+static void gpio_set_output_low(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+
+ gpiox->BRR |= 1 << pin;
+ gpio_driver->state = GPIO_LOW;
+}
+
+static enum gpio_level gpio_get_input_level(
+ struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+
+ return (gpiox->IDR & (1 << pin));
+}
+
+static void gpio_set_output_high(struct gpio_driver *gpio_driver)
+{
+ GPIO_TypeDef *gpiox = gpio_driver->gpiox;
+ uint8_t pin = gpio_get_pin_number(gpio_driver->pin);
+
+ gpiox->BSRR |= 1 << pin;
+ gpio_driver->state = GPIO_HIGH;
+}
+
+static void gpio_rcc_enable(GPIO_TypeDef *gpio)
+{
+ uint32_t mask =
+ (gpio == GPIOA)? RCC_AHB2ENR_GPIOAEN :
+ (gpio == GPIOB)? RCC_AHB2ENR_GPIOBEN :
+ (gpio == GPIOC)? RCC_AHB2ENR_GPIOCEN :
+ (gpio == GPIOD)? RCC_AHB2ENR_GPIODEN :
+ (gpio == GPIOE)? RCC_AHB2ENR_GPIOEEN :
+ (gpio == GPIOF)? RCC_AHB2ENR_GPIOFEN :
+ (gpio == GPIOG)? RCC_AHB2ENR_GPIOGEN :
+ (gpio == GPIOH)? RCC_AHB2ENR_GPIOHEN : 0;
+
+ assert(mask != 0);
+
+ RCC->AHB2ENR |= mask;
+}
+
+static void gpio_driver_init(struct gpio_driver *driver)
+{
+ gpio_set_mode(driver);
+ gpio_set_speed(driver);
+ gpio_set_pull_mode(driver);
+ gpio_set_alter_func(driver);
+ gpio_set_output_type(driver);
+}
+
+void gpio_driver_config(void *gpio_driver, ...)
+{
+ va_list list_ptr;
+ va_start(list_ptr, gpio_driver);
+ struct gpio_driver *driver = (struct gpio_driver *)gpio_driver;
+
+ while(true) {
+ if(driver == NULL) break;
+
+ gpio_rcc_enable(driver->gpiox);
+ driver->set_output_low = gpio_set_output_low;
+ driver->set_output_high = gpio_set_output_high;
+ driver->gpio_get_input_level = gpio_get_input_level;
+ gpio_driver_init(driver);
+ driver = va_arg(list_ptr, struct gpio_driver *);
+ }
+
+ va_end(list_ptr);
+}
+
diff --git a/bsps/arm/stm32l4/include/bsp/stm32l4_dma.h b/bsps/arm/stm32l4/include/bsp/stm32l4_dma.h
new file mode 100644
index 0000000..34330c0
--- /dev/null
+++ b/bsps/arm/stm32l4/include/bsp/stm32l4_dma.h
@@ -0,0 +1,105 @@
+/**
+ * stm32l4_dma.h
+ *
+ * Created on: Jan 25, 2016
+ * Author: leschinskii
+ */
+
+#ifndef SRC_DRIVERS_INCLUDE_STM32L4_DMA_H_
+#define SRC_DRIVERS_INCLUDE_STM32L4_DMA_H_
+
+
+enum channel_numb {
+ CH1 = 0,
+ CH2,
+ CH3,
+ CH4,
+ CH5,
+ CH6,
+ CH7,
+ CHANNEL_MAX
+};
+
+struct dma_cb {
+ void(*transfer_complete)(void);
+ void(*half_transfer)(void);
+ void(*transfer_error)(void);
+};
+
+struct dma_ch {
+ enum channel_numb ch_num;
+ DMA_Channel_TypeDef *ch;
+ const char name[16];
+
+ struct dma_cb cb_func;
+ uint8_t irq_channel;
+ uint32_t ch_select;
+ uint32_t mem_addr;
+ uint32_t periph_addr;
+ uint32_t config;
+ uint32_t transf_sz;
+};
+
+struct dma_driver {
+ DMA_TypeDef *dmax;
+ struct dma_ch *channel_cfg;
+};
+
+void dma_driver_config(void *dma_driver, ...);
+
+void DMA1_Channel5_IRQHandler(void);
+void DMA1_Channel4_IRQHandler(void);
+void DMA1_Channel3_IRQHandler(void);
+void DMA1_Channel2_IRQHandler(void);
+
+#define DMA1_CH1_ADC1 ((uint32_t)0x00)
+#define DMA1_CH1_TIM2_CH3 ((uint32_t)0x04)
+#define DMA1_CH1_TIM17_CH1_UP ((uint32_t)0x05)
+#define DMA1_CH1_TIM4_CH1 ((uint32_t)0x06)
+#define DMA1_CH2_ADC2 ((uint32_t)0x00)
+#define DMA1_CH2_SPI1_RX ((uint32_t)0x10)
+#define DMA1_CH2_USART3_TX ((uint32_t)0x20)
+#define DMA1_CH2_I2C3_TX ((uint32_t)0x30)
+#define DMA1_CH2_TIM2_UP ((uint32_t)0x40)
+#define DMA1_CH2_TIM3_CH3 ((uint32_t)0x50)
+#define DMA1_CH2_TIM1_CH1 ((uint32_t)0x70)
+#define DMA1_CH3_ADC3 ((uint32_t)0x000)
+#define DMA1_CH3_SPI1_TX ((uint32_t)0x100)
+#define DMA1_CH3_USART3_RX ((uint32_t)0x200)
+#define DMA1_CH3_I2C3_RX ((uint32_t)0x300)
+#define DMA1_CH3_TIM16_CH1_UP ((uint32_t)0x400)
+#define DMA1_CH3_TIM3_CH4_UP ((uint32_t)0x500)
+#define DMA1_CH3_TIM6_UP_DAC1 ((uint32_t)0x600)
+#define DMA1_CH3_TIM1_CH2 ((uint32_t)0x700)
+#define DMA1_CH4_DFSDM0 ((uint32_t)0x0000)
+#define DMA1_CH4_SPI2_RX ((uint32_t)0x1000)
+#define DMA1_CH4_USART1_TX ((uint32_t)0x2000)
+#define DMA1_CH4_I2C2_TX ((uint32_t)0x3000)
+#define DMA1_CH4_TIM7_UP_DAC2 ((uint32_t)0x5000)
+#define DMA1_CH4_TIM4_CH2 ((uint32_t)0x6000)
+#define DMA1_CH4_TIM1_CH4_TRIG_COM ((uint32_t)0x7000)
+#define DMA1_CH5_DFSDM1 ((uint32_t)0x00000)
+#define DMA1_CH5_SPI2_TX ((uint32_t)0x10000)
+#define DMA1_CH5_USART1_RX ((uint32_t)0x20000)
+#define DMA1_CH5_I2C2_RX ((uint32_t)0x30000)
+#define DMA1_CH5_TIM2_CH1 ((uint32_t)0x40000)
+#define DMA1_CH5_QUADSPI ((uint32_t)0x50000)
+#define DMA1_CH5_TIM4_CH3 ((uint32_t)0x60000)
+#define DMA1_CH5_TIM15_CH1_UP_TRIG_COM ((uint32_t)0x70000)
+#define DMA1_CH6_DFSDM2 ((uint32_t)0x000000)
+#define DMA1_CH6_SAI2_A ((uint32_t)0x100000)
+#define DMA1_CH6_USART2_RX ((uint32_t)0x200000)
+#define DMA1_CH6_I2C1_TX ((uint32_t)0x300000)
+#define DMA1_CH6_TIM16_CH1_UP ((uint32_t)0x400000)
+#define DMA1_CH6_TIM3_CH1_TRIG ((uint32_t)0x500000)
+#define DMA1_CH6_TIM1_UP ((uint32_t)0x700000)
+#define DMA1_CH7_DFSDM3 ((uint32_t)0x0000000)
+#define DMA1_CH7_SAI2_B ((uint32_t)0x1000000)
+#define DMA1_CH7_USART2_TX ((uint32_t)0x2000000)
+#define DMA1_CH7_I2C1_RX ((uint32_t)0x3000000)
+#define DMA1_CH7_TIM2_CH2_CH4 ((uint32_t)0x4000000)
+#define DMA1_CH7_TIM17_CH1_UP ((uint32_t)0x5000000)
+#define DMA1_CH7_TIM4_UP ((uint32_t)0x6000000)
+#define DMA1_CH7_TIM1_CH3 ((uint32_t)0x7000000)
+
+#endif /* SRC_DRIVERS_INCLUDE_STM32L4_DMA_H_ */
diff --git a/bsps/arm/stm32l4/include/bsp/stm32l4_gpio.h b/bsps/arm/stm32l4/include/bsp/stm32l4_gpio.h
new file mode 100644
index 0000000..ee5e2ae
--- /dev/null
+++ b/bsps/arm/stm32l4/include/bsp/stm32l4_gpio.h
@@ -0,0 +1,129 @@
+/**
+ * stm32l4_gpio.h
+ *
+ * Created on: Jan 15, 2016
+ * Author: leschinskii
+ */
+
+#ifndef SRC_DRIVERS_INCLUDE_STM32L4_GPIO_H_
+#define SRC_DRIVERS_INCLUDE_STM32L4_GPIO_H_
+
+#include <bsp/stm32l4xx.h>
+
+enum gpio_level {
+ GPIO_LOW = 0,
+ GPIO_HIGH
+};
+
+enum gpio_mode {
+ GPIO_MODE_INPUT = 0,
+ GPIO_MODE_OUTPUT,
+ GPIO_MODE_ALTER,
+ GPIO_MODE_ANALOG
+};
+
+enum gpio_type {
+ GPIO_TYPE_PUSH_PULL = 0,
+ GPIO_TYPE_OPENDRAIN
+};
+
+enum gpio_speed {
+ GPIO_SPEED_2MHZ = 0,
+ GPIO_SPEED_25MHZ,
+ GPIO_SPEED_50MHZ,
+ GPIO_SPEED_100MHZ
+};
+
+enum gpio_pull {
+ GPIO_PULLUP_NO = 0,
+ GPIO_PULLUP,
+ GPIO_PULLDN
+};
+enum gpio_alter_func {
+ GPIO_AF_SYS = 0,
+ GPIO_AF_TIM1 = 1,
+ GPIO_AF_TIM2 = 1,
+ GPIO_AF_TIM3 = 2,
+ GPIO_AF_TIM4 = 2,
+ GPIO_AF_TIM5 = 2,
+ GPIO_AF_TIM8 = 3,
+ GPIO_AF_TIM9 = 3,
+ GPIO_AF_TIM10 = 3,
+ GPIO_AF_TIM11 = 3,
+ GPIO_AF_I2C1 = 4,
+ GPIO_AF_I2C2 = 4,
+ GPIO_AF_I2C3 = 4,
+ GPIO_AF_SPI1 = 5,
+ GPIO_AF_SPI2 = 5,
+ GPIO_AF_I2S1 = 5,
+ GPIO_AF_I2S2ext = 5,
+ GPIO_AF_SPI3 = 6,
+ GPIO_AF_I2Sext = 6,
+ GPIO_AF_I2S3 = 6,
+ GPIO_AF_USART1 = 7,
+ GPIO_AF_USART2 = 7,
+ GPIO_AF_USART3 = 7,
+ GPIO_AF_I2S3ext = 7,
+ GPIO_AF_UART4 = 8,
+ GPIO_AF_UART5 = 8,
+ GPIO_AF_USART6 = 8,
+ GPIO_AF_CAN1 = 9,
+ GPIO_AF_CAN2 = 9,
+ GPIO_AF_TIM12 = 9,
+ GPIO_AF_TIM13 = 9,
+ GPIO_AF_TIM14 = 9,
+ GPIO_AF_OTG = 10,
+ GPIO_AF_ETH = 11,
+ GPIO_AF_FSMC = 12,
+ GPIO_AF_SDIO = 12,
+ GPIO_AF_OTG_FS = 12,
+ GPIO_AF_DCMI = 13,
+ GPIO_AF_14 = 14,
+ GPIO_AF_15 = 15,
+};
+
+enum gpio_pins {
+ PA0 = 0, PA1, PA2, PA3, PA4, PA5, PA6, PA7,
+ PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,
+
+ PB0 = 0x10, PB1, PB2, PB3, PB4, PB5, PB6, PB7,
+ PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15,
+
+ PC0 = 0x20, PC1, PC2, PC3, PC4, PC5, PC6, PC7,
+ PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15,
+
+ PD0 = 0x30, PD1, PD2, PD3, PD4, PD5, PD6, PD7,
+ PD8, PD9, PD10, PD11, PD12, PD13, PD14, PD15,
+
+ PE0 = 0x40, PE1, PE2, PE3, PE4, PE5, PE6, PE7,
+ PE8, PE9, PE10, PE11, PE12, PE13, PE14, PE15,
+
+ PF0 = 0x50, PF1, PF2, PF3, PF4, PF5, PF6, PF7,
+ PF8, PF9, PF10, PF11, PF12, PF13, PF14, PF15,
+
+ PG0 = 0x60, PG1, PG2, PG3, PG4, PG5, PG6, PG7,
+ PG8, PG9, PG10, PG11, PG12, PG13, PG14, PG15,
+
+ PH0 = 0x70, PH1, PH2, PH3, PH4, PH5, PH6, PH7,
+ PH8, PH9, PH10, PH11, PH12, PH13, PH14, PH15
+};
+
+struct gpio_driver {
+ GPIO_TypeDef *gpiox;
+
+ enum gpio_pins pin;
+ enum gpio_mode mode;
+ enum gpio_pull pull;
+ enum gpio_type otype;
+ enum gpio_speed speed;
+ enum gpio_alter_func func;
+ enum gpio_level state;
+
+ void (*set_output_low)(struct gpio_driver *gpio_driver);
+ void (*set_output_high)(struct gpio_driver *gpio_driver);
+ enum gpio_level (*gpio_get_input_level)(struct gpio_driver *gpio_driver);
+};
+
+void gpio_driver_config(void *gpio_driver, ...);
+
+#endif /* SRC_DRIVERS_INCLUDE_STM32L4_GPIO_H_ */
diff --git a/bsps/arm/stm32l4/include/bsp/stm32l4_spi.h b/bsps/arm/stm32l4/include/bsp/stm32l4_spi.h
new file mode 100644
index 0000000..771b1cf
--- /dev/null
+++ b/bsps/arm/stm32l4/include/bsp/stm32l4_spi.h
@@ -0,0 +1,24 @@
+#ifndef SRC_DRIVERS_INCLUDE_STM32L4_SPI_H_
+#define SRC_DRIVERS_INCLUDE_STM32L4_SPI_H_
+
+#define MAX_SPI_FREQUENCY 500000
+
+struct spi_driver
+{
+ void *spix;
+
+ struct gpio_driver *mosi;
+ struct gpio_driver *miso;
+ struct gpio_driver *sck;
+ struct gpio_driver *css;
+
+ uint8_t irq_n;
+ const char name[16];
+
+ struct dma_driver *dma_tx;
+ struct dma_driver *dma_rx;
+};
+
+int stm32l4_register_spi_1(void);
+
+#endif /* SRC_DRIVERS_INCLUDE_STM32L4_SPI_H_ */
diff --git a/bsps/arm/stm32l4/spi/stm32l4_spi.c b/bsps/arm/stm32l4/spi/stm32l4_spi.c
new file mode 100644
index 0000000..8bad729
--- /dev/null
+++ b/bsps/arm/stm32l4/spi/stm32l4_spi.c
@@ -0,0 +1,564 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "bsp/stm32l4xx.h"
+
+#include <rtems/bspIo.h>
+
+#include <rtems/irq-extension.h>
+#include <dev/spi/spi.h>
+
+#include <bsp/stm32l4_spi.h>
+#include <bsp/stm32l4_gpio.h>
+#include <bsp/stm32l4_dma.h>
+
+#define EIGHT_BIT_DATA_MASK (SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2)
+
+#define SIXTEEN_BIT_DATA_MASK (SPI_CR2_DS_0 | SPI_CR2_DS_1 | \
+ SPI_CR2_DS_2 | SPI_CR2_DS_3)
+
+#define MAX_SPI_TXRX_BUFFER_LEN 32
+#define STM32L4_SPI_1_BUS_PATH "/dev/spi-1"
+#define STM32L4_SPI_2_BUS_PATH "/dev/spi-2"
+
+static struct dma_driver spi1_dma_tx = {
+ .dmax = DMA1,
+ .channel_cfg = &(struct dma_ch)
+ {
+ .ch_num = CH3,
+ .irq_channel = DMA1_Channel3_IRQn,
+ .ch_select = DMA1_CH3_SPI1_TX,
+ .ch = DMA1_Channel3,
+ .periph_addr = (uint32_t)&SPI1->DR,
+ .config = DMA_CCR_TCIE | DMA_CCR_DIR | DMA_CCR_MSIZE_0 |
+ DMA_CCR_MINC | DMA_CCR_PSIZE_0
+ }
+};
+
+static struct dma_driver spi1_dma_rx = {
+ .dmax = DMA1,
+ .channel_cfg = &(struct dma_ch)
+ {
+ .ch_num = CH2,
+ .irq_channel = DMA1_Channel2_IRQn,
+ .ch_select = DMA1_CH2_SPI1_RX,
+ .ch = DMA1_Channel2,
+ .periph_addr = (uint32_t)&SPI1->DR,
+ .config = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_PSIZE_0 | DMA_CCR_MSIZE_0
+ }
+};
+
+static struct gpio_driver spi1_css =
+{
+ .gpiox = GPIOE,
+ .pin = PE12,
+ .mode = GPIO_MODE_ALTER,
+ .func = GPIO_AF_SPI1,
+ .pull = GPIO_PULLUP_NO,
+ .otype = GPIO_TYPE_PUSH_PULL,
+ .speed = GPIO_SPEED_50MHZ,
+};
+
+static struct gpio_driver spi1_sck =
+{
+ .gpiox = GPIOE,
+ .pin = PE13,
+ .mode = GPIO_MODE_ALTER,
+ .pull = GPIO_PULLUP_NO,
+ .otype = GPIO_TYPE_PUSH_PULL,
+ .speed = GPIO_SPEED_50MHZ,
+ .func = GPIO_AF_SPI1
+};
+
+static struct gpio_driver spi1_miso =
+{
+ .gpiox = GPIOE,
+ .pin = PE14,
+ .mode = GPIO_MODE_ALTER,
+ .pull = GPIO_PULLUP_NO,
+ .otype = GPIO_TYPE_PUSH_PULL,
+ .speed = GPIO_SPEED_50MHZ,
+ .func = GPIO_AF_SPI1
+};
+
+static struct gpio_driver spi1_mosi =
+{
+ .gpiox = GPIOE,
+ .pin = PE15,
+ .mode = GPIO_MODE_ALTER,
+ .pull = GPIO_PULLUP_NO,
+ .otype = GPIO_TYPE_PUSH_PULL,
+ .speed = GPIO_SPEED_50MHZ,
+ .func = GPIO_AF_SPI1
+};
+
+static struct spi_driver spi1 =
+{
+ .spix = SPI1,
+ .mosi = &spi1_mosi,
+ .miso = &spi1_miso,
+ .sck = &spi1_sck,
+ .css = &spi1_css,
+
+ .irq_n = SPI1_IRQn,
+ .name = "STM32L4_SPI1",
+
+ .dma_tx = &spi1_dma_tx,
+ .dma_rx = &spi1_dma_rx
+};
+
+enum spi_major_num
+{
+ SPI_NUM_INVALID = -1,
+ SPI1_NUM = 0,
+ SPI2_NUM,
+ SPI_NUM_TOTAL
+};
+
+struct stm32l4_spi_bus
+{
+ struct spi_bus base;
+ struct spi_driver driver;
+
+ rtems_binary_semaphore sem;
+
+ const struct spi_ioc_transfer *msg;
+ size_t messages_left;
+ size_t msg_count;
+};
+
+static struct stm32l4_spi_bus* spi_bus_table[SPI_NUM_TOTAL];
+static const uint8_t spi_dummy_buffer[MAX_SPI_TXRX_BUFFER_LEN];
+
+static void spi1_irq_handler(void);
+static void spi2_irq_handler(void);
+static void spi1_dma_rx_complete_handler(void);
+static void spi1_dma_tx_complete_handler(void);
+static void spi2_dma_rx_complete_handler(void);
+static void spi2_dma_tx_complete_handler(void);
+
+static inline enum spi_major_num get_spi_major_number(const SPI_TypeDef *spix)
+{
+ return (spix == SPI1)? SPI1_NUM :
+ (spix == SPI2)? SPI2_NUM : SPI_NUM_INVALID;
+}
+
+static int spi_install_corresponding_irq_handlers(
+ const struct stm32l4_spi_bus *bus)
+{
+ enum spi_major_num num = get_spi_major_number(bus->driver.spix);
+
+ if(num == SPI_NUM_INVALID)
+ {
+ return -1;
+ }
+
+ rtems_interrupt_handler_install(
+ (rtems_vector_number) bus->driver.irq_n,
+ bus->driver.name,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler) ((num == SPI1_NUM)? spi1_irq_handler :
+ spi2_irq_handler),
+ NULL);
+
+ rtems_interrupt_handler_install(
+ (rtems_vector_number) bus->driver.dma_tx->channel_cfg->irq_channel,
+ bus->driver.dma_tx->channel_cfg->name,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler) ((num == SPI1_NUM)? DMA1_Channel3_IRQHandler :
+ DMA1_Channel5_IRQHandler),
+ NULL);
+
+ rtems_interrupt_handler_install(
+ (rtems_vector_number) bus->driver.dma_rx->channel_cfg->irq_channel,
+ bus->driver.dma_rx->channel_cfg->name,
+ RTEMS_INTERRUPT_UNIQUE,
+ (rtems_interrupt_handler) ((num == SPI1_NUM)? DMA1_Channel2_IRQHandler :
+ DMA1_Channel4_IRQHandler),
+ NULL);
+
+ return 0;
+}
+
+static int spi_rcc_enable(const struct spi_driver *dev)
+{
+ enum spi_major_num num = get_spi_major_number(dev->spix);
+
+ if(num == SPI_NUM_INVALID)
+ {
+ return -1;
+ }
+
+ if(num == SPI1_NUM)
+ {
+ RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
+
+ return 1;
+ }
+
+ RCC->APB1ENR1 |= RCC_APB1ENR1_SPI2EN;
+
+ return 1;
+}
+
+static void spi_configure(struct stm32l4_spi_bus *bus)
+{
+ struct spi_driver *spi_driver = &bus->driver;
+
+ gpio_driver_config(
+ spi_driver->sck,
+ spi_driver->mosi,
+ spi_driver->miso,
+ spi_driver->css,
+ NULL);
+
+ spi_rcc_enable(spi_driver);
+
+
+ dma_driver_config(spi_driver->dma_tx, spi_driver->dma_rx, NULL);
+
+ SPI_TypeDef *spix = (SPI_TypeDef *)bus->driver.spix;
+
+ uint32_t bits_per_word = (bus->base.bits_per_word == 16)?
+ SIXTEEN_BIT_DATA_MASK : EIGHT_BIT_DATA_MASK;
+
+ spix->CR2 = bits_per_word | SPI_CR2_NSSP;
+
+ spix->CR1 = SPI_CR1_BR_0 | SPI_CR1_BR_2 |
+ SPI_CR1_MSTR | SPI_CR1_SPE;
+}
+
+static void spi_disable(struct spi_driver *spi_driver)
+{
+ SPI_TypeDef *spix = (SPI_TypeDef *)spi_driver->spix;
+
+ spix->CR1 &= ~SPI_CR1_SPE;
+}
+
+static void spi_css_deselect(struct spi_driver *spi_driver)
+{
+ struct gpio_driver *css = spi_driver->css;
+
+ css->set_output_high(css);
+}
+
+static void spi_css_select(struct spi_driver *spi_driver)
+{
+ struct gpio_driver *css = spi_driver->css;
+
+ css->set_output_low(css);
+}
+
+static void spi_destroy(spi_bus *base)
+{
+ struct stm32l4_spi_bus *bus = (struct stm32l4_spi_bus *)base;
+
+ spi_disable(&bus->driver);
+
+ spi_bus_destroy_and_free(&bus->base);
+ rtems_recursive_mutex_destroy(&bus->base.mutex);
+}
+
+static int spi_check_configuration(
+ struct stm32l4_spi_bus *bus,
+ const spi_ioc_transfer *msg)
+{
+ bool config_is_invalid =
+ msg->speed_hz > bus->base.max_speed_hz ||
+ msg->bits_per_word < 8 ||
+ msg->bits_per_word > 16 ||
+ msg->mode > SPI_MODE_3;
+
+ if(config_is_invalid == true)
+ {
+ return -EINVAL;
+ }
+
+ bool config_is_unset =
+ msg->bits_per_word != bus->base.bits_per_word ||
+ msg->delay_usecs != bus->base.delay_usecs ||
+ msg->speed_hz != bus->base.speed_hz ||
+ msg->mode != bus->base.mode ||
+ msg->cs != bus->base.cs;
+
+ if(config_is_unset == true)
+ {
+ bus->base.mode = msg->mode;
+ bus->base.speed_hz = msg->speed_hz;
+ bus->base.bits_per_word = msg->bits_per_word;
+ bus->base.cs = msg->cs;
+ bus->base.delay_usecs = msg->delay_usecs;
+ spi_configure(bus);
+ }
+
+ return 0;
+}
+
+static int spi_do_transfer(
+ struct stm32l4_spi_bus *bus,
+ const spi_ioc_transfer *msgs,
+ const size_t idx)
+{
+ bool data_is_invalid =
+ ((msgs[idx].tx_buf == NULL) &&
+ (msgs[idx].rx_buf == NULL)) ||
+ (msgs[idx].len > MAX_SPI_TXRX_BUFFER_LEN);
+
+ int ret = 0;
+
+ if(data_is_invalid == true)
+ {
+ return -EINVAL;
+ }
+
+ ret = spi_check_configuration(bus, &msgs[idx]);
+ if(ret != 0)
+ {
+ return -EINVAL;
+ }
+
+ spi_css_select(&bus->driver);
+
+ SPI_TypeDef *spix = bus->driver.spix;
+
+ struct dma_ch *rx_ch = bus->driver.dma_rx->channel_cfg;
+ struct dma_ch *tx_ch = bus->driver.dma_tx->channel_cfg;
+
+ tx_ch->ch->CMAR = (uint32_t)((msgs[idx].tx_buf == NULL)?
+ spi_dummy_buffer : msgs[idx].tx_buf);
+ tx_ch->ch->CNDTR = msgs[idx].len;
+
+ rx_ch->ch->CMAR = (uint32_t)((msgs[idx].rx_buf == NULL)?
+ spi_dummy_buffer : msgs[idx].rx_buf);
+ rx_ch->ch->CNDTR = msgs[idx].len;
+
+ spix->CR2 |= SPI_CR2_TXEIE;
+
+ return ret;
+}
+
+static int spi_setup_trasfer(
+ struct stm32l4_spi_bus *bus,
+ const spi_ioc_transfer *msgs,
+ const uint32_t msg_count)
+{
+ bool bus_is_broken = (bus == NULL) ||
+ (msg_count < bus->messages_left) ||
+ (msg_count == 0);
+ int ret = 0;
+
+ if(bus_is_broken == true)
+ {
+ return -EINVAL;
+ }
+
+ if(msgs->cs_change == true)
+ {
+ spi_css_deselect(&bus->driver);
+ }
+
+ if(bus->messages_left > 0)
+ {
+ const size_t msg_idx = msg_count - bus->messages_left;
+
+ ret = spi_do_transfer(bus, msgs, msg_idx);
+
+ if(ret != 0)
+ {
+ rtems_binary_semaphore_post(&bus->sem);
+ return ret;
+ }
+
+ bus->messages_left--;
+ }
+ else
+ {
+ rtems_binary_semaphore_post(&bus->sem);
+ }
+
+ return ret;
+}
+
+static int spi_transfer(
+ spi_bus *base,
+ const spi_ioc_transfer *msgs,
+ uint32_t msg_count)
+{
+ struct stm32l4_spi_bus *bus = (struct stm32l4_spi_bus *)base;
+
+ SPI_TypeDef *spix = (SPI_TypeDef *)bus->driver.spix;
+ enum spi_major_num num = get_spi_major_number(spix);
+
+ bus->msg = &msgs[0];
+ spi_bus_table[num] = bus;
+ spi_bus_table[num]->msg_count = msg_count;
+ spi_bus_table[num]->messages_left = msg_count;
+
+ int msg_error = spi_setup_trasfer(
+ spi_bus_table[num],
+ spi_bus_table[num]->msg,
+ spi_bus_table[num]->messages_left);
+
+ rtems_binary_semaphore_wait(&bus->sem);
+
+ return (msg_error == 0)? 0 : -EINVAL;
+}
+
+static int spi_setup(spi_bus *base)
+{
+ struct stm32l4_spi_bus *bus = (struct stm32l4_spi_bus *)base;
+
+ bool config_is_unset =
+ bus->base.speed_hz > MAX_SPI_FREQUENCY ||
+ bus->base.bits_per_word < 8 ||
+ bus->base.bits_per_word > 16;
+
+ if(config_is_unset == true)
+ {
+ return -EINVAL;
+ }
+
+ spi_configure(bus);
+
+ return 0;
+}
+
+static void spi1_dma_tx_complete_handler(void)
+{
+ DMA1->IFCR |= DMA_IFCR_CTCIF3;
+ DMA1_Channel3->CCR &= ~DMA_CCR_EN;
+
+ SPI1->CR2 &= ~SPI_CR2_TXEIE;
+ SPI1->CR2 &= ~SPI_CR2_TXDMAEN;
+ SPI1->CR2 |= SPI_CR2_RXNEIE;
+}
+
+static void spi1_dma_rx_complete_handler(void)
+{
+ DMA1->IFCR |= DMA_IFCR_CTCIF2;
+ DMA1_Channel2->CCR &= ~DMA_CCR_EN;
+
+ SPI1->CR2 &= ~SPI_CR2_RXDMAEN;
+ SPI1->CR2 &= ~SPI_CR2_RXNEIE;
+
+ spi_setup_trasfer(
+ spi_bus_table[SPI1_NUM],
+ spi_bus_table[SPI1_NUM]->msg,
+ spi_bus_table[SPI1_NUM]->msg_count);
+}
+
+static void spi1_irq_handler(void)
+{
+ uint32_t sr = SPI1->SR;
+ uint32_t cr = SPI1->CR2;
+
+ if((sr & SPI_SR_TXE) && (cr & SPI_CR2_TXEIE))
+ {
+ SPI1->CR2 |= SPI_CR2_TXDMAEN;
+ DMA1_Channel3->CCR |= DMA_CCR_EN;
+ }
+
+ if((sr & SPI_SR_RXNE) && (cr & SPI_CR2_RXNEIE))
+ {
+ SPI1->CR2 |= SPI_CR2_RXDMAEN;
+ DMA1_Channel2->CCR |= DMA_CCR_EN;
+ }
+
+}
+
+static void spi2_dma_tx_complete_handler(void)
+{
+ DMA1->IFCR |= DMA_IFCR_CTCIF5;
+ DMA1_Channel5->CCR &= ~DMA_CCR_EN;
+
+ SPI2->CR2 &= ~SPI_CR2_TXEIE;
+ SPI2->CR2 &= ~SPI_CR2_TXDMAEN;
+ SPI2->CR2 |= SPI_CR2_RXNEIE;
+}
+
+static void spi2_dma_rx_complete_handler(void)
+{
+ DMA1->IFCR |= DMA_IFCR_CTCIF4;
+ DMA1_Channel4->CCR &= ~DMA_CCR_EN;
+
+ SPI2->CR2 &= ~SPI_CR2_RXDMAEN;
+ SPI2->CR2 &= ~SPI_CR2_RXNEIE;
+
+ spi_setup_trasfer(
+ spi_bus_table[SPI2_NUM],
+ spi_bus_table[SPI2_NUM]->msg,
+ spi_bus_table[SPI2_NUM]->msg_count);
+}
+
+static void spi2_irq_handler(void)
+{
+ uint32_t sr = SPI2->SR;
+ uint32_t cr = SPI2->CR2;
+
+ if((sr & SPI_SR_TXE) && (cr & SPI_CR2_TXEIE))
+ {
+ SPI2->CR2 |= SPI_CR2_TXDMAEN;
+ DMA1_Channel5->CCR |= DMA_CCR_EN;
+ }
+
+ if((sr & SPI_SR_RXNE) && (cr & SPI_CR2_RXNEIE))
+ {
+ SPI2->CR2 |= SPI_CR2_RXDMAEN;
+ DMA1_Channel4->CCR |= DMA_CCR_EN;
+ }
+}
+
+static int stm32l4_spi_bus_register(
+ const char *spi_bus_path,
+ const struct spi_driver *spi_driver)
+{
+ struct stm32l4_spi_bus *bus;
+
+ bus = (struct stm32l4_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
+ if(bus == NULL)
+ {
+ printk("[%s]:%d\n", __FUNCTION__, __LINE__);
+ return -1;
+ }
+
+ bus->base.transfer = spi_transfer;
+ bus->base.destroy = spi_destroy;
+ bus->base.setup = spi_setup;
+ bus->base.max_speed_hz = 500000;
+ bus->base.bits_per_word = 8;
+ bus->base.speed_hz = bus->base.max_speed_hz;
+ bus->base.delay_usecs = 1;
+ bus->base.cs = 1;
+
+ memcpy(&bus->driver, spi_driver, sizeof(bus->driver));
+
+ enum spi_major_num num = get_spi_major_number(bus->driver.spix);
+
+ if(num == SPI_NUM_INVALID)
+ {
+ return -1;
+ }
+
+ bus->driver.dma_tx->channel_cfg->cb_func.transfer_complete =
+ (num == SPI1_NUM)? spi1_dma_tx_complete_handler :
+ spi2_dma_tx_complete_handler;
+
+ bus->driver.dma_rx->channel_cfg->cb_func.transfer_complete =
+ (num == SPI1_NUM)? spi1_dma_rx_complete_handler :
+ spi2_dma_rx_complete_handler;
+
+ spi_install_corresponding_irq_handlers(bus);
+
+ rtems_binary_semaphore_init(&bus->sem, "STM32L4 SPI");
+ spi_configure(bus);
+
+ return spi_bus_register(&bus->base, spi_bus_path);
+}
+
+int stm32l4_register_spi_1(void)
+{
+ int ret = stm32l4_spi_bus_register(STM32L4_SPI_1_BUS_PATH , &spi1);
+
+ return ret;
+}
diff --git a/c/src/lib/libbsp/arm/stm32l4/Makefile.am b/c/src/lib/libbsp/arm/stm32l4/Makefile.am
index 4c8b78c..a9e43ff 100644
--- a/c/src/lib/libbsp/arm/stm32l4/Makefile.am
+++ b/c/src/lib/libbsp/arm/stm32l4/Makefile.am
@@ -53,6 +53,11 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/irq/irq-dispatch-armv
# Console
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/stm32l4/console/usart.c
+# BSP
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/stm32l4/spi/stm32l4_spi.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/stm32l4/gpio/stm32l4_gpio.c
+librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/stm32l4/dma/stm32l4_dma.c
+
# Clock
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-armv7m.c
--
2.7.4
More information about the devel
mailing list