[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