[PATCH v5 4/4] bsps/stm32f4: Implementation for GPIO and ADC

Duc Doan dtbpkmte at gmail.com
Sun Jul 24 12:01:11 UTC 2022


---
 bsps/arm/stm32f4/adc/adc.c                    | 655 ++++++++++++++++++
 bsps/arm/stm32f4/gpio/gpio.c                  | 542 +++++++++++++++
 bsps/arm/stm32f4/include/bsp.h                |   4 -
 bsps/arm/stm32f4/include/bsp/stm32f4_adc.h    | 209 ++++++
 bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h   | 273 ++++++++
 bsps/arm/stm32f4/include/bsp/stm32f4_hal.h    |  17 +
 bsps/arm/stm32f4/include/bsp/stm32f4_periph.h |  50 ++
 bsps/arm/stm32f4/start/bspstart.c             |   7 +-
 bsps/arm/stm32f4/start/bspstarthook.c         |   8 +
 bsps/arm/stm32f4/start/periph.c               |  58 ++
 spec/build/bsps/arm/stm32f4/grp.yml           |   6 +-
 spec/build/bsps/arm/stm32f4/obj.yml           |   5 +
 spec/build/bsps/arm/stm32f4/optengpio.yml     |  16 +
 .../build/bsps/arm/stm32f4/optnumgpioctrl.yml |  16 +
 14 files changed, 1856 insertions(+), 10 deletions(-)
 create mode 100644 bsps/arm/stm32f4/adc/adc.c
 create mode 100644 bsps/arm/stm32f4/gpio/gpio.c
 create mode 100644 bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
 create mode 100644 bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h
 create mode 100644 bsps/arm/stm32f4/include/bsp/stm32f4_hal.h
 create mode 100644 bsps/arm/stm32f4/include/bsp/stm32f4_periph.h
 create mode 100644 bsps/arm/stm32f4/start/periph.c
 create mode 100644 spec/build/bsps/arm/stm32f4/optengpio.yml
 create mode 100644 spec/build/bsps/arm/stm32f4/optnumgpioctrl.yml

diff --git a/bsps/arm/stm32f4/adc/adc.c b/bsps/arm/stm32f4/adc/adc.c
new file mode 100644
index 0000000000..21baa9ee2c
--- /dev/null
+++ b/bsps/arm/stm32f4/adc/adc.c
@@ -0,0 +1,655 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bsp/stm32f4_adc.h>
+#include <bsp/stm32f4_gpio.h>
+#include <stdlib.h>
+
+#if defined(ADC3)
+#define NUM_ADC 3
+#elif defined(ADC2)
+#define NUM_ADC 2
+#else
+#define NUM_ADC 1
+#endif
+
+/************** Interrupt manager *****************/
+typedef struct {
+    void *arg;
+    stm32f4_gpio *gpio;
+} stm32f4_interrupt_arg;
+
+typedef struct {
+    stm32f4_interrupt_arg arg;
+    rtems_gpio_isr isr;
+} stm32f4_interrupt;
+
+void adc_irq_handler(void *arg);
+
+static stm32f4_interrupt isr_table[NUM_ADC];
+
+/**
+  * This tells if there is already an ISR registered at each
+  * table index (element set to true).
+  */
+static bool isr_registered[NUM_ADC] = {0};
+
+typedef struct {
+    uint32_t adc_value;
+    rtems_adc_status status;
+} stm32f4_adc_data;
+static stm32f4_adc_data adc_data[NUM_ADC] = {0};
+
+static rtems_status_code stm32f4_adc_select_channel(
+    rtems_gpio *base
+);
+
+/***************/
+#ifdef ADC1
+static ADC_TypeDef_Protected _ADC1_protected = { ADC1, false };
+ADC_TypeDef_Protected *const ADC1_protected = &_ADC1_protected;
+#endif
+#ifdef ADC2
+static ADC_TypeDef_Protected _ADC2_protected = { ADC2, false };
+ADC_TypeDef_Protected *const ADC2_protected = &_ADC2_protected;
+#endif
+#ifdef ADC3
+static ADC_TypeDef_Protected _ADC3_protected = { ADC3, false };
+ADC_TypeDef_Protected *const ADC3_protected = &_ADC3_protected;
+#endif
+
+/* Helpers */
+#define STM32F4_GET_ADC_NUMBER(ADCx) \
+    ( (uintptr_t) ( ADCx ) == (uintptr_t) ADC1 ? 1 : \
+      (uintptr_t) ( ADCx ) == (uintptr_t) ADC2 ? 2 : \
+      (uintptr_t) ( ADCx ) == (uintptr_t) ADC3 ? 3 : \
+                                                 0 )
+#define STM32F4_GET_ADCx_FROM_NUMBER(num)       (\
+    ( num ) == 1                 ? ADC1 :        \
+    ( num ) == 2 && NUM_ADC >= 2 ? ADC2 :        \
+    ( num ) == 3 && NUM_ADC == 3 ? ADC3 :        \
+                                   NULL)
+#define STM32F4_GET_ADCx_PROTECTED_FROM_NUMBER(num)     (\
+    ( num ) == 1                 ? ADC1_protected :      \
+    ( num ) == 2 && NUM_ADC >= 2 ? ADC2_protected :      \
+    ( num ) == 3 && NUM_ADC == 3 ? ADC3_protected :      \
+                                   NULL)
+
+// TODO: other variants
+ADC_TypeDef *stm32f4_get_ADCx(
+    GPIO_TypeDef *gpio
+)
+{
+    switch ((uintptr_t) gpio) {
+#if defined(STM32F405xx) || defined(STM32F407xx)
+        case (uintptr_t) GPIOA:
+        case (uintptr_t) GPIOB:
+        case (uintptr_t) GPIOC:
+            return ADC1;
+        case (uintptr_t) GPIOF:
+            return ADC3;
+#endif /* defined(STM32F405xx) || defined(STM32F407xx) */
+        default:
+            return NULL;
+    }
+}
+
+// TODO: other variants
+ADC_TypeDef_Protected *stm32f4_get_ADCx_protected(
+    GPIO_TypeDef *gpio
+)
+{
+    switch ((uintptr_t) gpio) {
+#if defined(STM32F405xx) || defined(STM32F407xx)
+        case (uintptr_t) GPIOA:
+        case (uintptr_t) GPIOB:
+        case (uintptr_t) GPIOC:
+            return ADC1_protected;
+        case (uintptr_t) GPIOF:
+            return ADC3_protected;
+#endif /* defined(STM32F405xx) || defined(STM32F407xx) */
+        default:
+            return NULL;
+    }
+}
+
+// TODO: other variants
+rtems_status_code stm32f4_get_LL_ADC_CHANNEL(
+    stm32f4_gpio *gpio,
+    uint32_t *channel
+)
+{
+    uintptr_t port = (uintptr_t) gpio->port;
+#if defined(STM32F405xx) || defined(STM32F407xx)
+    if (port == (uintptr_t) GPIOA) {
+        switch (gpio->pin) {
+            case 0:
+                *channel = LL_ADC_CHANNEL_0;
+                break;
+            case 1:
+                *channel = LL_ADC_CHANNEL_1;
+                break;
+            case 2:
+                *channel = LL_ADC_CHANNEL_2;
+                break;
+            case 3:
+                *channel = LL_ADC_CHANNEL_3;
+                break;
+            case 4:
+                *channel = LL_ADC_CHANNEL_4;
+                break;
+            case 5:
+                *channel = LL_ADC_CHANNEL_5;
+                break;
+            case 6:
+                *channel = LL_ADC_CHANNEL_6;
+                break;
+            case 7:
+                *channel = LL_ADC_CHANNEL_7;
+                break;
+            default:
+                return RTEMS_UNSATISFIED;
+        }
+    }
+    else if (port == (uintptr_t) GPIOB) {
+        switch (gpio->pin) {
+            case 0:
+                *channel = LL_ADC_CHANNEL_8;
+                break;
+            case 1:
+                *channel = LL_ADC_CHANNEL_9;
+                break;
+            default:
+                return RTEMS_UNSATISFIED;
+        }
+    }
+    else if (port == (uintptr_t) GPIOC) {
+        switch (gpio->pin) {
+            case 0:
+                *channel = LL_ADC_CHANNEL_10;
+                break;
+            case 1:
+                *channel = LL_ADC_CHANNEL_11;
+                break;
+            case 2:
+                *channel = LL_ADC_CHANNEL_12;
+                break;
+            case 3:
+                *channel = LL_ADC_CHANNEL_13;
+                break;
+            case 4:
+                *channel = LL_ADC_CHANNEL_14;
+                break;
+            case 5:
+                *channel = LL_ADC_CHANNEL_15;
+                break;
+            default:
+                return RTEMS_UNSATISFIED;
+        }
+    }
+    else if (port == (uintptr_t) GPIOF) {
+        switch (gpio->pin) {
+            case 3:
+                *channel = LL_ADC_CHANNEL_9;
+                break;
+            case 4:
+                *channel = LL_ADC_CHANNEL_14;
+                break;
+            case 5:
+                *channel = LL_ADC_CHANNEL_15;
+                break;
+            case 6:
+                *channel = LL_ADC_CHANNEL_4;
+                break;
+            case 7:
+                *channel = LL_ADC_CHANNEL_5;
+                break;
+            case 8:
+                *channel = LL_ADC_CHANNEL_6;
+                break;
+            case 9:
+                *channel = LL_ADC_CHANNEL_7;
+                break;
+            case 10:
+                *channel = LL_ADC_CHANNEL_8;
+                break;
+            default:
+                return RTEMS_UNSATISFIED;
+        }
+    }
+    else
+        return RTEMS_UNSATISFIED;
+#endif /* defined(STM32F405xx) || defined(STM32F407xx) */
+    return RTEMS_SUCCESSFUL;
+}
+
+bool stm32f4_is_adc_pin(
+    stm32f4_gpio *gpio
+)
+{
+    uint32_t tmp;
+    return stm32f4_get_LL_ADC_CHANNEL(gpio, &tmp) == RTEMS_SUCCESSFUL;
+}
+
+static const rtems_adc_api stm32f4_adc_base_api = 
+    RTEMS_ADC_BUILD_API(
+        stm32f4_adc_init,
+        stm32f4_adc_read_raw,
+        stm32f4_adc_start_read_raw_nb,
+        stm32f4_adc_read_raw_nb,
+        stm32f4_adc_set_resolution,
+        stm32f4_adc_set_alignment,
+        stm32f4_adc_configure_interrupt,
+        stm32f4_adc_remove_interrupt,
+        stm32f4_adc_enable_interrupt,
+        stm32f4_adc_disable_interrupt
+    );
+
+rtems_periph_api *stm32f4_adc_get(
+    rtems_gpio *pin
+)
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(pin);
+    uint32_t channel;
+    // if the pin does not have ADC functionality
+    if (stm32f4_get_LL_ADC_CHANNEL(gpio, &channel) != RTEMS_SUCCESSFUL) {
+        return NULL;
+    }
+
+    // First allocate space for stm32f4_adc object
+    stm32f4_adc *api = malloc(sizeof(stm32f4_adc));
+    if (api == NULL) {
+        return NULL;
+    }
+    api->base_api = stm32f4_adc_base_api;
+
+    // Then allocate space for stm32f4_adc_config object
+    api->adc_config = malloc(sizeof(stm32f4_adc_config));
+    if (api->adc_config == NULL) {
+        return NULL;
+    }
+    api->adc_config->ADCx = stm32f4_get_ADCx_protected(gpio->port);
+    api->adc_config->channel = channel;
+    api->adc_config->resolution = STM32F4_ADC_DEFAULT_RESOLUTION;
+    api->adc_config->alignment = STM32F4_ADC_DEFAULT_ALIGNMENT;
+    api->adc_config->locked = false;
+    return (rtems_periph_api *) api;
+}
+
+rtems_status_code stm32f4_adc_destroy(
+    rtems_gpio *pin
+)
+{
+    if (pin->api != NULL) {
+        free(((stm32f4_adc *) pin->api)->adc_config);
+        free(pin->api);
+        return RTEMS_SUCCESSFUL;
+    }
+    return RTEMS_UNSATISFIED;
+}
+
+static rtems_status_code stm32f4_adc_select_channel(
+    rtems_gpio *base
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    if (!STM32F4_IS_LOCKED(adc_config) &&
+            !STM32F4_IS_LOCKED(adc_config->ADCx)) {
+        STM32F4_LOCK(adc_config);
+        STM32F4_LOCK(adc_config->ADCx);
+
+        LL_ADC_Disable(adc_config->ADCx->ADCx);
+
+        LL_ADC_SetResolution(adc_config->ADCx->ADCx, adc_config->resolution);
+        LL_ADC_SetDataAlignment(adc_config->ADCx->ADCx, adc_config->alignment);
+        LL_ADC_REG_SetSequencerRanks(
+            adc_config->ADCx->ADCx, 
+            LL_ADC_REG_RANK_1, 
+            adc_config->channel
+        );
+        LL_ADC_SetChannelSamplingTime(
+            adc_config->ADCx->ADCx, 
+            adc_config->channel, 
+            STM32F4_ADC_DEFAULT_SAMPLINGTIME
+        );
+
+        LL_ADC_Enable(adc_config->ADCx->ADCx);
+        /* Delay for ADC stabilization time */
+        /* Compute number of CPU cycles to wait for */
+        volatile uint32_t counter = (ADC_STAB_DELAY_US * (SystemCoreClock / 1000000U));
+        while(counter != 0U)
+        {
+          counter--;
+        }
+
+        STM32F4_UNLOCK(adc_config);
+        STM32F4_UNLOCK(adc_config->ADCx);
+        return RTEMS_SUCCESSFUL;
+    }
+    return RTEMS_UNSATISFIED;
+}
+
+void stm32f4_adc_start(
+    void
+)
+{
+    // Install ISR for non-blocking read
+    rtems_status_code sc = rtems_interrupt_handler_install(
+            ADC_IRQn,
+            NULL,
+            RTEMS_INTERRUPT_SHARED,
+            adc_irq_handler,
+            NULL
+    );
+    while (sc != RTEMS_SUCCESSFUL);
+}
+RTEMS_SYSINIT_ITEM(
+    stm32f4_adc_start,
+    RTEMS_SYSINIT_DEVICE_DRIVERS,
+    RTEMS_SYSINIT_ORDER_LAST
+);
+
+void stm32f4_adc_init(
+    rtems_gpio *base
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    if (!LL_ADC_IsEnabled(adc_config->ADCx->ADCx)) {
+        // Enable clock
+        switch ((uintptr_t) adc_config->ADCx->ADCx) {
+#ifdef ADC1
+            case (uintptr_t) ADC1:
+                LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
+                break;
+#endif
+#ifdef ADC2
+            case (uintptr_t) ADC2:
+                LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC2);
+                break;
+#endif
+#ifdef ADC3
+            case (uintptr_t) ADC3:
+                LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC3);
+                break;
+#endif
+            default:
+                return;
+        }
+
+        // ADC common setup
+        LL_ADC_SetSequencersScanMode(adc_config->ADCx->ADCx, LL_ADC_SEQ_SCAN_DISABLE);
+        LL_ADC_REG_SetTriggerSource(adc_config->ADCx->ADCx, LL_ADC_REG_TRIG_SOFTWARE);
+        LL_ADC_REG_SetSequencerLength(adc_config->ADCx->ADCx, LL_ADC_REG_SEQ_SCAN_DISABLE);
+        LL_ADC_REG_SetSequencerDiscont(adc_config->ADCx->ADCx, LL_ADC_REG_SEQ_DISCONT_DISABLE);
+        LL_ADC_REG_SetContinuousMode(adc_config->ADCx->ADCx, LL_ADC_REG_CONV_SINGLE);
+        LL_ADC_REG_SetDMATransfer(adc_config->ADCx->ADCx, LL_ADC_REG_DMA_TRANSFER_NONE);
+
+        LL_ADC_REG_SetFlagEndOfConversion(adc_config->ADCx->ADCx, LL_ADC_REG_FLAG_EOC_UNITARY_CONV);
+
+        LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc_config->ADCx->ADCx), LL_ADC_CLOCK_SYNC_PCLK_DIV2);
+        LL_ADC_SetMultimode(__LL_ADC_COMMON_INSTANCE(adc_config->ADCx->ADCx), LL_ADC_MULTI_INDEPENDENT);
+
+        LL_ADC_Enable(adc_config->ADCx->ADCx);
+        /* Delay for ADC stabilization time */
+        /* Compute number of CPU cycles to wait for */
+        volatile uint32_t counter = (ADC_STAB_DELAY_US * (SystemCoreClock / 1000000U));
+        while(counter != 0U)
+        {
+            counter--;
+        }
+    }
+}
+
+rtems_status_code stm32f4_adc_read_raw(
+    rtems_gpio *base,
+    uint32_t *result,
+    uint32_t timeout
+)
+{
+    uint32_t tickstart = 0U;
+    rtems_status_code sc = stm32f4_adc_select_channel(base);
+    if (sc != RTEMS_SUCCESSFUL) {
+        return sc;
+    }
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    STM32F4_LOCK(adc_config->ADCx);
+    STM32F4_LOCK(adc_config);
+    LL_ADC_REG_StartConversionSWStart(adc_config->ADCx->ADCx);
+    while (!LL_ADC_IsActiveFlag_EOCS(adc_config->ADCx->ADCx)) {
+        if (timeout != RTEMS_ADC_NO_TIMEOUT) {
+            if (timeout == 0U || ((HAL_GetTick() - tickstart) > timeout)) {
+                if (!LL_ADC_IsActiveFlag_EOCS(adc_config->ADCx->ADCx)) {
+                    return RTEMS_TIMEOUT;
+                }
+            }
+        }
+    }
+    *result = LL_ADC_REG_ReadConversionData32(adc_config->ADCx->ADCx);
+    STM32F4_UNLOCK(adc_config->ADCx);
+    STM32F4_UNLOCK(adc_config);
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_adc_start_read_raw_nb(
+    rtems_gpio *base
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    unsigned int adc_idx = STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1;
+    if (adc_data[adc_idx].status == RTEMS_ADC_NOT_STARTED) {
+        // start conversion here
+        rtems_status_code sc = stm32f4_adc_select_channel(base);
+        if (sc != RTEMS_SUCCESSFUL) {
+            return sc;
+        }
+        STM32F4_LOCK(adc_config);
+        STM32F4_LOCK(adc_config->ADCx);
+        LL_ADC_EnableIT_EOCS(adc_config->ADCx->ADCx);
+        LL_ADC_REG_StartConversionSWStart(adc_config->ADCx->ADCx);
+        adc_data[adc_idx].status = RTEMS_ADC_NOT_READY;
+
+        return RTEMS_SUCCESSFUL;
+    }
+    return RTEMS_UNSATISFIED;
+}
+
+rtems_adc_status stm32f4_adc_read_raw_nb(
+    rtems_gpio *base,
+    uint32_t *result
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    unsigned int adc_idx = STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1;
+    rtems_adc_status ret = adc_data[adc_idx].status;
+    if (ret == RTEMS_ADC_READY) {
+        *result = adc_data[adc_idx].adc_value;
+        adc_data[adc_idx].status = RTEMS_ADC_NOT_STARTED;
+        
+        STM32F4_UNLOCK(adc_config->ADCx);
+        STM32F4_UNLOCK(adc_config);
+    }
+    return ret;
+}
+
+rtems_status_code stm32f4_adc_set_resolution(
+    rtems_gpio *base,
+    unsigned int bits
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    if (!STM32F4_IS_LOCKED(adc_config)) {
+        STM32F4_LOCK(adc_config);
+        switch (bits) {
+            case 12:
+                adc_config->resolution = LL_ADC_RESOLUTION_12B;
+                break;
+            case 10:
+                adc_config->resolution = LL_ADC_RESOLUTION_10B;
+                break;
+            case 8:
+                adc_config->resolution = LL_ADC_RESOLUTION_8B;
+                break;
+            case 6:
+                adc_config->resolution = LL_ADC_RESOLUTION_6B;
+                break;
+            default:
+                return RTEMS_UNSATISFIED;
+        }
+        STM32F4_UNLOCK(adc_config);
+        return RTEMS_SUCCESSFUL;
+    }
+    return RTEMS_RESOURCE_IN_USE;
+}
+
+rtems_status_code stm32f4_adc_set_alignment(
+    rtems_gpio *base,
+    rtems_adc_align align
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    if (!STM32F4_IS_LOCKED(adc_config)) {
+        STM32F4_LOCK(adc_config);
+        switch (align) {
+            case RTEMS_ADC_ALIGN_LEFT:
+                adc_config->alignment = LL_ADC_DATA_ALIGN_LEFT;
+                break;
+            case RTEMS_ADC_ALIGN_RIGHT:
+                adc_config->alignment = LL_ADC_DATA_ALIGN_RIGHT;
+                break;
+            default:
+                return RTEMS_UNSATISFIED;
+        }
+        STM32F4_UNLOCK(adc_config);
+        return RTEMS_SUCCESSFUL;
+    }
+    return RTEMS_RESOURCE_IN_USE;
+}
+
+rtems_status_code stm32f4_adc_configure_interrupt(
+    rtems_gpio *base,
+    rtems_adc_isr isr,
+    void *arg
+)
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    unsigned int adc_idx = STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1;
+    if (!isr_registered[adc_idx]) {
+        isr_table[adc_idx] = (stm32f4_interrupt){
+            .arg = {
+                .arg = arg,
+                .gpio = gpio
+            },
+            .isr = isr
+        };
+        isr_registered[adc_idx] = true;
+        return rtems_interrupt_handler_install(
+                ADC_IRQn,
+                NULL,
+                RTEMS_INTERRUPT_SHARED,
+                adc_irq_handler,
+                &isr_table[adc_idx].arg
+        );
+    }
+    return RTEMS_UNSATISFIED;
+}
+
+rtems_status_code stm32f4_adc_remove_interrupt(
+    rtems_gpio *base
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    unsigned int adc_idx = STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1;
+    rtems_status_code sc = rtems_interrupt_handler_remove(
+            ADC_IRQn,
+            adc_irq_handler,
+            &isr_table[adc_idx].arg
+    );
+    if (sc == RTEMS_SUCCESSFUL) {
+        isr_registered[adc_idx] = false;
+    }
+    return sc;
+}
+
+rtems_status_code stm32f4_adc_enable_interrupt(
+    rtems_gpio *base
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    if (!STM32F4_IS_LOCKED(adc_config->ADCx)) {
+        if (isr_registered[STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1]) {
+            LL_ADC_EnableIT_EOCS(adc_config->ADCx->ADCx);
+            return RTEMS_SUCCESSFUL;
+        }
+        return RTEMS_UNSATISFIED;
+    }
+    return RTEMS_RESOURCE_IN_USE;
+}
+
+rtems_status_code stm32f4_adc_disable_interrupt(
+    rtems_gpio *base
+)
+{
+    stm32f4_adc_config *adc_config = ((stm32f4_adc *) base->api)->adc_config;
+    if (!STM32F4_IS_LOCKED(adc_config->ADCx)) {
+        if (isr_registered[STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1]) {
+            LL_ADC_DisableIT_EOCS(adc_config->ADCx->ADCx);
+            return RTEMS_SUCCESSFUL;
+        }
+        return RTEMS_UNSATISFIED;
+    }
+    return RTEMS_RESOURCE_IN_USE;
+}
+
+void adc_irq_handler(void *arg) {
+    rtems_interrupt_level level;
+    rtems_interrupt_disable( level );
+    unsigned int i;
+    for (i = 0; i < NUM_ADC; ++i) {
+        ADC_TypeDef *adcx = STM32F4_GET_ADCx_FROM_NUMBER(i+1);
+        if (LL_ADC_IsActiveFlag_EOCS(adcx)) {
+            // if the current IRQ has no ISR registered,
+            // it means the IRQ happens from a non-blocking read
+            if (!isr_registered[i]) {
+                if (adc_data[i].status == RTEMS_ADC_NOT_READY) {
+                    LL_ADC_DisableIT_EOCS(adcx);
+                    adc_data[i].adc_value = LL_ADC_REG_ReadConversionData32(adcx);
+                    adc_data[i].status = RTEMS_ADC_READY;
+                }
+            } 
+            // if there is an ISR registered, call it
+            else {
+                LL_ADC_ClearFlag_EOCS(adcx);
+                stm32f4_interrupt_arg *stm32_arg = (stm32f4_interrupt_arg *) arg;
+                (*isr_table[i].isr)(stm32_arg->arg);
+            }
+            break;
+        }
+    }
+    rtems_interrupt_enable( level );
+}
+
diff --git a/bsps/arm/stm32f4/gpio/gpio.c b/bsps/arm/stm32f4/gpio/gpio.c
new file mode 100644
index 0000000000..0a54862ad2
--- /dev/null
+++ b/bsps/arm/stm32f4/gpio/gpio.c
@@ -0,0 +1,542 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bsp.h>
+#include <rtems.h>
+#include <stdlib.h>
+#include <bsp/stm32f4_gpio.h>
+#include <bsp/stm32f4_periph.h>
+
+/*********** GPIO API ***************/
+static rtems_status_code stm32f4_gpio_get(
+    uint32_t interm_pin,
+    rtems_gpio **out
+);
+
+static rtems_status_code stm32f4_gpio_destroy(
+    rtems_gpio *base
+);
+
+/*********************************************************/
+
+/**
+  * @brief STM32F4 GPIO handlers
+  */
+static const rtems_gpio_handlers stm32f4_gpio_handlers = {
+    .set_pin_mode = stm32f4_gpio_set_pin_mode,
+    .set_pull = stm32f4_gpio_set_pull,
+    .configure_interrupt = stm32f4_gpio_configure_interrupt,
+    .remove_interrupt = stm32f4_gpio_remove_interrupt,
+    .enable_interrupt = stm32f4_gpio_enable_interrupt,
+    .disable_interrupt = stm32f4_gpio_disable_interrupt,
+    .read = stm32f4_gpio_read,
+    .write = stm32f4_gpio_write,
+    .toggle = stm32f4_gpio_toggle
+};
+
+static GPIO_TypeDef * const GPIOx[] = {
+#ifdef GPIOA_BASE
+    GPIOA
+#endif /* GPIOA_BASE */
+#ifdef GPIOB_BASE
+    , GPIOB
+#endif /* GPIOB_BASE */
+#ifdef GPIOC_BASE
+    , GPIOC
+#endif /* GPIOC_BASE */
+#ifdef GPIOD_BASE
+    , GPIOD
+#endif /* GPIOD_BASE */
+#ifdef GPIOE_BASE
+    , GPIOE
+#endif /* GPIOE_BASE */
+#ifdef GPIOF_BASE
+    , GPIOF
+#endif /* GPIOF_BASE */
+#ifdef GPIOG_BASE
+    , GPIOG
+#endif /* GPIOG_BASE */
+#ifdef GPIOH_BASE
+    , GPIOH
+#endif /* GPIOH_BASE */
+#ifdef GPIOI_BASE
+    , GPIOI
+#endif /* GPIOI_BASE */
+#ifdef GPIOJ_BASE
+    , GPIOJ
+#endif /* GPIOJ_BASE */
+#ifdef GPIOK_BASE
+    , GPIOK
+#endif /* GPIOK_BASE */
+};
+
+static unsigned int const EXTIx_IRQn[] = {
+    EXTI0_IRQn,
+    EXTI1_IRQn,
+    EXTI2_IRQn,
+    EXTI3_IRQn,
+    EXTI4_IRQn,
+    EXTI9_5_IRQn,
+    EXTI9_5_IRQn,
+    EXTI9_5_IRQn,
+    EXTI9_5_IRQn,
+    EXTI9_5_IRQn,
+    EXTI15_10_IRQn,
+    EXTI15_10_IRQn,
+    EXTI15_10_IRQn,
+    EXTI15_10_IRQn,
+    EXTI15_10_IRQn,
+    EXTI15_10_IRQn
+};
+
+/**
+  * @brief Converts intermediate pin number to port pointer.
+  *
+  * Intermediate pin number is a way of numerically labeling
+  * pins. Pins are labeled incrementally across all ports.
+  * Pins 0-15 from port A are 0-15. Pins 0-15 from port B are
+  * 16-31. And so on.
+  *
+  * @param interm_pin is the intermediate pin number
+  */
+#define STM32F4_GET_PORT(interm_pin) (GPIOx[ ( interm_pin ) / 16 ])
+
+/**
+  * @brief Converts intermediate pin number to 0-15.
+  *
+  * Intermediate pin number is a way of numerically labeling
+  * pins. Pins are labeled incrementally across all ports.
+  * Pins 0-15 from port A are 0-15. Pins 0-15 from port B are
+  * 16-31. And so on.
+  *
+  * @param interm_pin is the intermediate pin number
+  */
+#define STM32F4_GET_PIN_0_15(interm_pin) (( interm_pin ) % 16) 
+
+/**
+  * @brief Converts pin number from 0-15 to HAL pin mask.
+  * @param pin is the pin number from 0-15
+  */
+#define STM32F4_GET_HAL_GPIO_PIN(pin) ((uint16_t) (1 << ( pin )))
+
+/**
+  * @brief Get EXTI Line from pin number 0-15
+  * @param pin is the pin number from 0-15
+  */
+#define STM32F4_GET_LL_EXTI_LINE(pin) (0x1UL << ( pin ))
+
+/**
+  * @brief Get EXTI IRQ number from pin 0-15
+  * @param pin is the pin number from 0-15
+  */
+#define STM32F4_GET_EXTI_IRQn(pin) (EXTIx_IRQn[( pin )])
+
+/************** Interrupt manager *****************/
+typedef struct {
+    void *arg;
+    stm32f4_gpio *gpio;
+} stm32f4_interrupt_arg;
+
+typedef struct {
+    stm32f4_interrupt_arg arg;
+    rtems_gpio_isr isr;
+} stm32f4_interrupt;
+
+static stm32f4_interrupt isr_table[16]; 
+static bool isr_registered[16] = {0};
+
+void exti_handler(void *arg);
+
+
+/********** STM32F4 GPIO API functions ************/
+
+rtems_status_code bsp_gpio_register_controllers(
+    void
+)
+{
+    return rtems_gpio_register(
+            stm32f4_gpio_get,
+            stm32f4_gpio_destroy,
+            stm32f4_periph_get_api,
+            stm32f4_periph_remove_api,
+            sizeof(GPIOx)/sizeof(GPIOx[0])*16
+    );
+}
+
+rtems_status_code stm32f4_gpio_get(
+    uint32_t interm_pin,
+    rtems_gpio **out
+)
+{
+    stm32f4_gpio *tmp = malloc(sizeof(stm32f4_gpio));
+    if (tmp == NULL) {
+        return RTEMS_NO_MEMORY;
+    }
+    tmp->base = RTEMS_GPIO_BUILD_BASE(&stm32f4_gpio_handlers);
+    tmp->pin = STM32F4_GET_PIN_0_15(interm_pin);
+    tmp->port = STM32F4_GET_PORT(interm_pin);
+    
+    // initialize the pin
+    stm32f4_gpio_init((rtems_gpio *) tmp);
+
+    *out = (rtems_gpio *) tmp;
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_destroy(
+    rtems_gpio *base
+)
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    free(gpio);
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_set_pin_mode(
+    rtems_gpio *base, 
+    rtems_gpio_pin_mode mode
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    uint32_t pin_mask = STM32F4_GET_HAL_GPIO_PIN(gpio->pin);
+
+    uint32_t stm32f4_mode, stm32f4_output_type;
+    switch (mode) {
+    case RTEMS_GPIO_PINMODE_OUTPUT_PP:
+        stm32f4_mode = LL_GPIO_MODE_OUTPUT;
+        stm32f4_output_type = LL_GPIO_OUTPUT_PUSHPULL;
+        break;
+    case RTEMS_GPIO_PINMODE_OUTPUT_OD:
+        stm32f4_mode = LL_GPIO_MODE_OUTPUT;
+        stm32f4_output_type = LL_GPIO_OUTPUT_OPENDRAIN;
+        break;
+    case RTEMS_GPIO_PINMODE_INPUT:
+        stm32f4_mode = LL_GPIO_MODE_INPUT;
+        break;
+    case RTEMS_GPIO_PINMODE_ANALOG:
+        stm32f4_mode = LL_GPIO_MODE_ANALOG;
+        break;
+    case RTEMS_GPIO_PINMODE_BSP_SPECIFIC:
+        stm32f4_mode = LL_GPIO_MODE_ALTERNATE;
+        break;
+    default:
+        /* illegal argument */
+        return RTEMS_UNSATISFIED;
+    }
+    LL_GPIO_SetPinMode(gpio->port, pin_mask, stm32f4_mode);
+    if (stm32f4_mode == LL_GPIO_MODE_OUTPUT) {
+        LL_GPIO_SetPinOutputType(gpio->port, pin_mask, stm32f4_output_type);
+    }
+
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_set_pull(
+    rtems_gpio *base, 
+    rtems_gpio_pull pull
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    uint32_t pin_mask = STM32F4_GET_HAL_GPIO_PIN(gpio->pin);
+    uint32_t stm32f4_pull;
+
+    switch (pull) {
+    case RTEMS_GPIO_NOPULL:
+        stm32f4_pull = LL_GPIO_PULL_NO;
+        break;
+    case RTEMS_GPIO_PULLUP:
+        stm32f4_pull = LL_GPIO_PULL_UP;
+        break;
+    case RTEMS_GPIO_PULLDOWN:
+        stm32f4_pull = LL_GPIO_PULL_DOWN;
+        break;
+    default:
+        /* Illegal argument */
+        return RTEMS_UNSATISFIED;
+    }
+    LL_GPIO_SetPinPull(gpio->port, pin_mask, stm32f4_pull);
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_configure_interrupt(
+    rtems_gpio *base, 
+    rtems_gpio_isr isr,
+    void *arg,
+    rtems_gpio_interrupt_trig trig,
+    rtems_gpio_pull pull
+) 
+{
+    // configure pin
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    uint32_t pin_mask = STM32F4_GET_HAL_GPIO_PIN(gpio->pin);
+    GPIO_InitTypeDef hal_conf;
+
+    switch (trig) {
+    case RTEMS_GPIO_INT_TRIG_NONE:
+        return RTEMS_SUCCESSFUL;
+    case RTEMS_GPIO_INT_TRIG_FALLING:
+        hal_conf.Mode = GPIO_MODE_IT_FALLING;
+        break;
+    case RTEMS_GPIO_INT_TRIG_RISING:
+        hal_conf.Mode = GPIO_MODE_IT_RISING;
+        break;
+    case RTEMS_GPIO_INT_TRIG_BOTH_EDGES:
+        hal_conf.Mode = GPIO_MODE_IT_RISING_FALLING;
+        break;
+    default:
+        /* Invalid argument */
+        return RTEMS_UNSATISFIED;
+    }
+    switch (pull) {
+    case RTEMS_GPIO_NOPULL:
+        hal_conf.Pull = GPIO_NOPULL;
+        break;
+    case RTEMS_GPIO_PULLUP:
+        hal_conf.Pull = GPIO_PULLUP;
+        break;
+    case RTEMS_GPIO_PULLDOWN:
+        hal_conf.Pull = GPIO_PULLDOWN;
+        break;
+    default:
+        /* Illegal argument */
+        return RTEMS_UNSATISFIED;
+    }
+    hal_conf.Pin = pin_mask;
+    HAL_GPIO_Init(gpio->port, &hal_conf);
+
+    // RTEMS interrupt config
+    if (isr_registered[gpio->pin]) {
+        return RTEMS_UNSATISFIED;
+    }
+    isr_table[gpio->pin] = (stm32f4_interrupt){
+        .arg = {
+            .arg = arg,
+            .gpio = gpio
+        },
+        .isr = isr
+    };
+    isr_registered[gpio->pin] = true;
+    rtems_option opt = gpio->pin < 5 ? 
+                        RTEMS_INTERRUPT_UNIQUE : 
+                        RTEMS_INTERRUPT_SHARED;
+    rtems_status_code sc = rtems_interrupt_handler_install(
+            STM32F4_GET_EXTI_IRQn(gpio->pin), 
+            NULL, 
+            opt, 
+            exti_handler, 
+            &isr_table[gpio->pin].arg
+    );
+
+    return sc;
+}
+
+rtems_status_code stm32f4_gpio_remove_interrupt(
+    rtems_gpio *base
+)
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    if (isr_registered[gpio->pin]) {
+        rtems_status_code sc = rtems_interrupt_handler_remove(
+                STM32F4_GET_EXTI_IRQn(gpio->pin), 
+                exti_handler, 
+                &isr_table[gpio->pin].arg
+        );
+        if (sc == RTEMS_SUCCESSFUL) {
+            isr_registered[gpio->pin] = false;
+        }
+        return sc;
+    }
+    return RTEMS_UNSATISFIED;
+}
+
+rtems_status_code stm32f4_gpio_enable_interrupt(
+    rtems_gpio *base
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    LL_EXTI_EnableIT_0_31(STM32F4_GET_LL_EXTI_LINE(gpio->pin));
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_disable_interrupt(
+    rtems_gpio *base
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    LL_EXTI_DisableIT_0_31(STM32F4_GET_LL_EXTI_LINE(gpio->pin));
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_write(
+    rtems_gpio *base, 
+    rtems_gpio_pin_state value
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+
+    if (value)
+        LL_GPIO_SetOutputPin(gpio->port, STM32F4_GET_HAL_GPIO_PIN(gpio->pin));
+    else
+        LL_GPIO_ResetOutputPin(gpio->port, STM32F4_GET_HAL_GPIO_PIN(gpio->pin));
+
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_read(
+    rtems_gpio *base, 
+    rtems_gpio_pin_state *value
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+
+    *value = LL_GPIO_IsInputPinSet(
+            gpio->port, 
+            STM32F4_GET_HAL_GPIO_PIN(gpio->pin)
+    );
+    return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_gpio_toggle(
+    rtems_gpio *base
+) 
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+
+    LL_GPIO_TogglePin(
+            gpio->port, 
+            STM32F4_GET_HAL_GPIO_PIN(gpio->pin)
+    );
+    return RTEMS_SUCCESSFUL;
+}
+
+void exti_handler(void *arg) {
+    stm32f4_interrupt_arg *stm32_arg = (stm32f4_interrupt_arg *) arg;
+    uint32_t pin_mask = STM32F4_GET_HAL_GPIO_PIN(stm32_arg->gpio->pin);
+    if(__HAL_GPIO_EXTI_GET_IT(pin_mask) != RESET)
+    {
+        __HAL_GPIO_EXTI_CLEAR_IT(pin_mask);
+        (*isr_table[stm32_arg->gpio->pin].isr)(stm32_arg->arg);
+    }
+}
+
+/************ STM32F4 Other specific GPIO functions ************/
+rtems_status_code stm32f4_gpio_init(rtems_gpio *base) {
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    
+    switch ((uintptr_t) gpio->port) {
+#ifdef GPIOA_BASE
+        case (uintptr_t) GPIOA:
+            __HAL_RCC_GPIOA_CLK_ENABLE();
+            break;
+#endif /* GPIOA_BASE */
+#ifdef GPIOB_BASE
+        case (uintptr_t) GPIOB:
+            __HAL_RCC_GPIOB_CLK_ENABLE();
+            break;
+#endif /* GPIOB_BASE */
+#ifdef GPIOC_BASE
+        case (uintptr_t) GPIOC:
+            __HAL_RCC_GPIOC_CLK_ENABLE();
+            break;
+#endif /* GPIOC_BASE */
+#ifdef GPIOD_BASE
+        case (uintptr_t) GPIOD:
+            __HAL_RCC_GPIOD_CLK_ENABLE();
+            break;
+#endif /* GPIOD_BASE */
+#ifdef GPIOE_BASE
+        case (uintptr_t) GPIOE:
+            __HAL_RCC_GPIOE_CLK_ENABLE();
+            break;
+#endif /* GPIOE_BASE */
+#ifdef GPIOF_BASE
+        case (uintptr_t) GPIOF:
+            __HAL_RCC_GPIOF_CLK_ENABLE();
+            break;
+#endif /* GPIOF_BASE */
+#ifdef GPIOG_BASE
+        case (uintptr_t) GPIOG:
+            __HAL_RCC_GPIOG_CLK_ENABLE();
+            break;
+#endif /* GPIOG_BASE */
+#ifdef GPIOH_BASE
+        case (uintptr_t) GPIOH:
+            __HAL_RCC_GPIOH_CLK_ENABLE();
+            break;
+#endif /* GPIOH_BASE */
+#ifdef GPIOI_BASE
+        case (uintptr_t) GPIOI:
+            __HAL_RCC_GPIOI_CLK_ENABLE();
+            break;
+#endif /* GPIOI_BASE */
+#ifdef GPIOJ_BASE
+        case (uintptr_t) GPIOJ:
+            __HAL_RCC_GPIOJ_CLK_ENABLE();
+            break;
+#endif /* GPIOJ_BASE */
+#ifdef GPIOK_BASE
+        case (uintptr_t) GPIOK:
+            __HAL_RCC_GPIOK_CLK_ENABLE();
+            break;
+#endif /* GPIOK_BASE */
+        default:
+            return RTEMS_UNSATISFIED;
+    }
+    return RTEMS_SUCCESSFUL;
+}
+
+void stm32f4_gpio_lock_pin(
+    rtems_gpio *base
+)
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    LL_GPIO_LockPin(
+            gpio->port,
+            STM32F4_GET_HAL_GPIO_PIN(gpio->pin)
+    );
+}
+
+void stm32f4_gpio_set_af(
+    rtems_gpio *base,
+    uint32_t alternate
+)
+{
+    stm32f4_gpio *gpio = stm32f4_get_gpio_from_base(base);
+    if (gpio->pin < 8)
+        LL_GPIO_SetAFPin_0_7(
+                gpio->port,
+                STM32F4_GET_HAL_GPIO_PIN(gpio->pin),
+                alternate
+        );
+    else
+        LL_GPIO_SetAFPin_8_15(
+                gpio->port,
+                STM32F4_GET_HAL_GPIO_PIN(gpio->pin),
+                alternate
+        );
+}
+
diff --git a/bsps/arm/stm32f4/include/bsp.h b/bsps/arm/stm32f4/include/bsp.h
index 42a74e109d..968545cd5a 100644
--- a/bsps/arm/stm32f4/include/bsp.h
+++ b/bsps/arm/stm32f4/include/bsp.h
@@ -42,10 +42,6 @@ extern "C" {
 
 #define BSP_ARMV7M_SYSTICK_FREQUENCY STM32F4_HCLK
 
-#ifdef __rtems__
-void Error_Handler(void);
-#endif /* __rtems__ */
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/bsps/arm/stm32f4/include/bsp/stm32f4_adc.h b/bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
new file mode 100644
index 0000000000..973fadf828
--- /dev/null
+++ b/bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_ARM_STM32F4_BSP_ADC
+#define LIBBSP_ARM_STM32F4_BSP_ADC
+
+#include <rtems/sysinit.h>
+#include <bsp/adc.h>
+#include <stm32f4xx_ll_bus.h>
+#include <stm32f4xx_ll_adc.h>
+#include <bsp/stm32f4_gpio.h>
+
+#define STM32F4_ADC_DEFAULT_RESOLUTION          LL_ADC_RESOLUTION_10B
+#define STM32F4_ADC_DEFAULT_ALIGNMENT           LL_ADC_DATA_ALIGN_RIGHT
+#define STM32F4_ADC_DEFAULT_SAMPLINGTIME        LL_ADC_SAMPLINGTIME_3CYCLES
+
+/**
+  * Macros for simple locking of shared objects.
+  * Structs must have a bool member named "locked"
+  */
+#define STM32F4_LOCK(obj)               \
+    do {                                \
+        ( obj )->locked = true;         \
+    } while (0)
+
+#define STM32F4_UNLOCK(obj)             \
+    do {                                \
+        ( obj )->locked = false;        \
+    } while (0)
+
+#define STM32F4_IS_LOCKED(obj)          \
+    (( obj )->locked)
+
+/**
+  * @brief Wrapper of ADC_TypeDef with a simple lock.
+  */
+typedef struct {
+    ADC_TypeDef *ADCx;
+    bool locked;
+} ADC_TypeDef_Protected;
+
+/**
+  * @brief Structure containing ADC configuration for an
+  *        ADC pin.
+  */
+typedef struct {
+    /**
+      * @brief Locks ADC configuration change on this pin
+      *        if set to true.
+      */
+    bool locked;
+    /**
+      * @brief STM32F4-defined ADCx.
+      */
+    ADC_TypeDef_Protected *ADCx;
+    /**
+      * @brief ADC channel of the pin.
+      * This can be LL_ADC_CHANNEL_n defined by STM32F4 LL
+      * driver, where 0 <= n <= 18. 
+      */
+    uint32_t channel;
+    /**
+      * @brief Resolution of the ADC pin.
+      * This can be one of the following values:
+      *     @ref LL_ADC_RESOLUTION_12B
+      *     @ref LL_ADC_RESOLUTION_10B
+      *     @ref LL_ADC_RESOLUTION_8B
+      *     @ref LL_ADC_RESOLUTION_6B
+      */
+    uint32_t resolution;
+    /**
+      * @brief Data alignment of the ADC pin.
+      * This can be one of the following values:
+      *     @ref LL_ADC_DATA_ALIGN_RIGHT
+      *     @ref LL_ADC_DATA_ALIGN_LEFT
+      */
+    uint32_t alignment;
+} stm32f4_adc_config;
+
+/**
+  * @brief STM32F4 wrapper of peripherals API.
+  */
+typedef struct {
+    rtems_adc_api base_api;
+    stm32f4_adc_config *adc_config;
+} stm32f4_adc;
+
+const rtems_adc_handlers *stm32f4_get_adc_handlers(
+    void
+);
+
+/**
+  * @brief Get the HAL-defined ADCx pointer.
+  * @note This function should not be called. Use 
+  *       @see stm32f4_get_ADCx_protected() instead.
+  */
+ADC_TypeDef *stm32f4_get_ADCx(
+    GPIO_TypeDef *gpiox
+);
+
+ADC_TypeDef_Protected *stm32f4_get_ADCx_protected(
+    GPIO_TypeDef *gpiox
+);
+
+rtems_status_code stm32f4_get_LL_ADC_CHANNEL(
+    stm32f4_gpio *gpio,
+    uint32_t *channel
+);
+
+bool stm32f4_is_adc_pin(
+    stm32f4_gpio *gpio
+);
+
+rtems_periph_api *stm32f4_adc_get(
+    rtems_gpio *gpio
+);
+
+rtems_status_code stm32f4_adc_destroy(
+    rtems_gpio *gpio
+);
+
+/***/
+/**
+  * @brief Perform initialization for STM32F4 ADC manager
+  *
+  * This function should be called in bspstarthook under
+  * if ADC is enabled.
+  */
+extern void stm32f4_adc_start(
+    void
+);
+
+/**
+  * @brief Performs initialization for an ADC pin
+  * @note This function needs to be registered with the
+  *       peripherals API.
+  */
+void stm32f4_adc_init(
+    rtems_gpio *base
+);
+
+rtems_status_code stm32f4_adc_read_raw(
+    rtems_gpio *base,
+    uint32_t *result,
+    uint32_t timeout
+);
+
+rtems_status_code stm32f4_adc_start_read_raw_nb(
+    rtems_gpio *base
+);
+
+rtems_adc_status stm32f4_adc_read_raw_nb(
+    rtems_gpio *base,
+    uint32_t *result
+);
+
+rtems_status_code stm32f4_adc_set_resolution(
+    rtems_gpio *base,
+    unsigned int bits
+);
+
+rtems_status_code stm32f4_adc_set_alignment(
+    rtems_gpio *base,
+    rtems_adc_align align
+);
+
+rtems_status_code stm32f4_adc_configure_interrupt(
+    rtems_gpio *base,
+    rtems_adc_isr isr,
+    void *arg
+);
+
+rtems_status_code stm32f4_adc_remove_interrupt(
+    rtems_gpio *base
+);
+
+rtems_status_code stm32f4_adc_enable_interrupt(
+    rtems_gpio *base
+);
+
+rtems_status_code stm32f4_adc_disable_interrupt(
+    rtems_gpio *base
+);
+
+#endif /* LIBBSP_ARM_STM32F4_BSP_ADC */
diff --git a/bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h b/bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h
new file mode 100644
index 0000000000..6bd6baea86
--- /dev/null
+++ b/bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h
@@ -0,0 +1,273 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+ 
+#ifndef LIBBSP_ARM_STM32F4_BSP_GPIO
+#define LIBBSP_ARM_STM32F4_BSP_GPIO
+
+#include <stdbool.h>
+#include <stm32f4xx.h>
+#include <stm32f4xx_ll_gpio.h>
+#include <stm32f4xx_ll_exti.h>
+#include <bsp/gpio2.h>
+
+/*********** Helpers *****************/
+/**
+  * @brief Macro to get stm32f4_gpio object from a base rtems_gpio
+  *        object.
+  * 
+  * This is a wrapper of RTEMS_CONTAINER_OF macro
+  *
+  * @param base The pointer to a rtems_gpio object
+  * @retval The pointer to the stm32f4_gpio object owning
+  *         the specified rtems_gpio object
+  */
+#define stm32f4_get_gpio_from_base(_base) \
+    RTEMS_CONTAINER_OF(_base, stm32f4_gpio, base)
+
+/**
+  * @brief STM32F4 BSP GPIO structure
+  *
+  */
+typedef struct {
+    /**
+      * @brief This member is a rtems_gpio object.
+      */
+    rtems_gpio base;
+    /**
+      *@brief This member is the pin number from 0 to 15.
+      */
+    uint32_t pin;
+    /**
+      * @brief This member is HAL GPIOx pointer.
+      */
+    GPIO_TypeDef *port;
+} stm32f4_gpio;
+
+/**
+  * @name STM32F4 GPIO functions
+  *
+  * @{
+  */
+
+/**
+  * @name GPIO API implementation of STM32F4 BSP
+  *
+  * @{
+  */
+
+
+/**
+  * @brief Sets the pin mode.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  * @param mode is a value of @see rtems_gpio_pin_mode
+  *
+  * @retval RTEMS_SUCCESSFUL if the pin mode is valid.
+  * @retval RTEMS_UNSATISFIED if the pin mode is 
+  *         invalid.
+  */
+extern rtems_status_code stm32f4_gpio_set_pin_mode(
+    rtems_gpio *base,
+    rtems_gpio_pin_mode mode
+);
+
+/**
+  * @brief Sets pull resistor mode.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  * @param pull is a value of @see rtems_gpio_pull
+  *
+  * @retval RTEMS_SUCCESSFUL if the pull resistor 
+  *         mode is valid.
+  * @retval RTEMS_UNSATISFIED if the pull resistor
+  *         mode is invalid.
+  */
+extern rtems_status_code stm32f4_gpio_set_pull(
+    rtems_gpio *base,
+    rtems_gpio_pull pull
+);
+
+/**
+  * @brief Configures user-defined ISR for an EXTI.
+  *
+  * This function is used to register a custom ISR
+  * with a GPIO pin. This API supports up to 1 ISR
+  * for each EXTI line (total 16 ISRs) at a time.
+  * 
+  * @note If there is already an ISR registered with 
+  *       a line, it needs to be removed to be able
+  *       to register a new one.
+  * @note This function does not enable interrupt.
+  *       use @see rtems_gpio_enable_interrupt().
+  *
+  * @param[in] base The pointer to the GPIO object.
+  *
+  * @retval RTEMS_SUCCESSFUL if interrupt 
+  *         configuration is successful.
+  * @retval RTEMS_UNSATISFIED if trigger mode/pull
+  *         resistor mode is invalid or an ISR
+  *         has already been registered for this 
+  *         EXTI line.
+  * @retval @see rtems_interrupt_handler_install()
+  */
+extern rtems_status_code stm32f4_gpio_configure_interrupt(
+    rtems_gpio *base, 
+    rtems_gpio_isr isr,
+    void *arg,
+    rtems_gpio_interrupt_trig trig,
+    rtems_gpio_pull pull
+);
+
+/**
+  * @brief Removes the registered ISR.
+  *
+  * @note This function does not disable interrupt.
+  * @ref rtems_gpio_disable_interrupt()
+  *
+  * @param[in] base The pointer to the GPIO object.
+  *
+  * @retval RTEMS_SUCCESSFUL if ISR removed successfully.
+  * @retval RTEMS_UNSATISFIED if no ISR registered for 
+  *         selected line.
+  * @retval @see rtems_interrupt_handler_remove()
+  */
+extern rtems_status_code stm32f4_gpio_remove_interrupt(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Enables EXTI for the line connected to this
+  *        pin.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  *
+  * @retval RTEMS_SUCCESSFUL
+  */
+extern rtems_status_code stm32f4_gpio_enable_interrupt(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Disables EXTI for the line connected to 
+  *        this pin.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  *
+  * @retval RTEMS_SUCCESSFUL
+  */
+extern rtems_status_code stm32f4_gpio_disable_interrupt(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Reads digital value into a variable.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  * @param[out] value The pointer to the output
+  *             variable.
+  *
+  * @retval RTEMS_SUCCESSFUL
+  */
+extern rtems_status_code stm32f4_gpio_read(
+    rtems_gpio *base,
+    rtems_gpio_pin_state *value
+);
+
+/**
+  * @brief Writes digital value to a pin.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  * @param value The output digital value.
+  *
+  * @retval RTEMS_SUCCESSFUL
+  */
+extern rtems_status_code stm32f4_gpio_write(
+    rtems_gpio *base,
+    rtems_gpio_pin_state value
+);
+
+/**
+  * @brief Toggles the state of a pin.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  *
+  * @retval RTEMS_SUCCESSFUL
+  */
+extern rtems_status_code stm32f4_gpio_toggle(
+    rtems_gpio *base
+);
+
+/** @} */
+
+/**
+  * @name Extra functionality of STM32F4 GPIO
+  *
+  * @{
+  */
+
+/**
+  * @brief Initializes clock for the GPIO port
+  *        owning this pin.
+  *
+  * @note This function is called in stm32f4_gpio_get().
+  *
+  * @param[in] base The pointer to the GPIO object.
+  *
+  * @retval RTEMS_SUCCESSFUL if the port argument is
+  *         valid
+  * @retval RTEMS_UNSATISFIED if the port argument is
+  *         invalid
+  */
+extern rtems_status_code stm32f4_gpio_init(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Lock configuration of a pin.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  */
+extern void stm32f4_gpio_lock_pin(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Sets the alternate function for a pin.
+  *
+  * @param[in] base The pointer to the GPIO object.
+  * @param alternate Alternate function, from 0-15.
+  */
+extern void stm32f4_gpio_set_af(
+    rtems_gpio *base,
+    uint32_t alternate
+);
+
+/** @} */
+
+/** @} */
+
+#endif /* LIBBSP_ARM_STM32F4_BSP_GPIO */
diff --git a/bsps/arm/stm32f4/include/bsp/stm32f4_hal.h b/bsps/arm/stm32f4/include/bsp/stm32f4_hal.h
new file mode 100644
index 0000000000..9e88b39067
--- /dev/null
+++ b/bsps/arm/stm32f4/include/bsp/stm32f4_hal.h
@@ -0,0 +1,17 @@
+#ifndef LIBBSP_ARM_STM32F4_BSP_STM32F4HAL_H
+#define LIBBSP_ARM_STM32F4_BSP_STM32F4HAL_H
+
+#include <stm32f4xx_hal.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void stm32f4_clk_enable();
+void stm32f4_clk_disable();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsps/arm/stm32f4/include/bsp/stm32f4_periph.h b/bsps/arm/stm32f4/include/bsp/stm32f4_periph.h
new file mode 100644
index 0000000000..f8b9ad2540
--- /dev/null
+++ b/bsps/arm/stm32f4/include/bsp/stm32f4_periph.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_BSP_ARM_STM32F4_PERIPH_H
+#define LIBBSP_BSP_ARM_STM32F4_PERIPH_H
+
+#include <bsp/periph_api.h>
+
+/**
+  * @brief STM32F4 BSP's function to get a
+  *        peripheral API.
+  */
+rtems_periph_api *stm32f4_periph_get_api(
+    rtems_gpio *pin,
+    rtems_periph_api_type type
+);
+
+/**
+  * @brief STM32F4 BSP's function to remove a
+  *        peripheral API assigned to a pin.
+  */
+rtems_status_code stm32f4_periph_remove_api(
+    rtems_gpio *pin
+);
+
+#endif /* LIBBSP_BSP_ARM_STM32F4_PERIPH_H */
diff --git a/bsps/arm/stm32f4/start/bspstart.c b/bsps/arm/stm32f4/start/bspstart.c
index 8589c6486c..2297430844 100644
--- a/bsps/arm/stm32f4/start/bspstart.c
+++ b/bsps/arm/stm32f4/start/bspstart.c
@@ -19,6 +19,7 @@
 #endif /* __rtems__ */
 #ifdef __rtems__
 #include <stm32f4xx.h>
+#include <bsp/gpio2.h>
 #endif /* __rtems__ */
 
 #ifdef STM32F4_FAMILY_F4XXXX
@@ -46,7 +47,7 @@ uint32_t HAL_GetTick(void)
   * @brief  This function is executed in case of error occurrence.
   * @retval None
   */
-void Error_Handler(void)
+static void Error_Handler(void)
 {
   /* USER CODE BEGIN Error_Handler_Debug */
   /* User can add his own implementation to report the HAL error return state */
@@ -166,7 +167,6 @@ static rtems_status_code SystemClock_Config(void)
     HAL_StatusTypeDef status = HAL_RCC_OscConfig(&RCC_OscInitStruct);
     if (status != HAL_OK)
     {
-//            Error_Handler();
         return RTEMS_UNSATISFIED;
     }
 
@@ -181,7 +181,6 @@ static rtems_status_code SystemClock_Config(void)
 
     if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, flash_latency) != HAL_OK)
     {
-//        Error_Handler();
         return RTEMS_UNSATISFIED;
     }
 
@@ -465,9 +464,7 @@ void bsp_start( void )
 {
     init_main_osc();
 
-#ifdef __rtems__
     stm32f4_gpio_set_config_array( &stm32f4_start_config_gpio[ 0 ] );
-#endif /* __rtems__ */
 
     bsp_interrupt_initialize();
 }
diff --git a/bsps/arm/stm32f4/start/bspstarthook.c b/bsps/arm/stm32f4/start/bspstarthook.c
index bbfaed615e..0aeba0ac13 100644
--- a/bsps/arm/stm32f4/start/bspstarthook.c
+++ b/bsps/arm/stm32f4/start/bspstarthook.c
@@ -20,4 +20,12 @@ void BSP_START_TEXT_SECTION bsp_start_hook_1(void)
   bsp_start_clear_bss();
 
   /* At this point we can use objects outside the .start section */
+  
+#ifndef __rtems__
+
+#if STM32F4_ENABLE_GENERIC_GPIO == 1
+  bsp_gpio_register_controllers();
+#endif /* STM32F4_ENABLE_GENERIC_GPIO */
+
+#endif /* __rtems__ */
 }
diff --git a/bsps/arm/stm32f4/start/periph.c b/bsps/arm/stm32f4/start/periph.c
new file mode 100644
index 0000000000..7b1b0f1bb5
--- /dev/null
+++ b/bsps/arm/stm32f4/start/periph.c
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bsp/stm32f4_gpio.h>
+#include <bsp/stm32f4_adc.h>
+#include <bsp/stm32f4_periph.h>
+
+rtems_periph_api *stm32f4_periph_get_api(
+    rtems_gpio *pin,
+    rtems_periph_api_type type
+)
+{
+    switch (type) {
+        case RTEMS_PERIPH_API_TYPE_ADC:
+            return stm32f4_adc_get(pin);
+        default:
+            return NULL;
+    }
+}
+
+rtems_status_code stm32f4_periph_remove_api(
+    rtems_gpio *pin
+)
+{
+    if (pin->api == NULL)
+        return RTEMS_UNSATISFIED;
+
+    switch (*(rtems_periph_api_type *) pin->api) {
+        case RTEMS_PERIPH_API_TYPE_ADC:
+            return stm32f4_adc_destroy(pin);
+        default:
+            return RTEMS_UNSATISFIED;
+    }
+}
diff --git a/spec/build/bsps/arm/stm32f4/grp.yml b/spec/build/bsps/arm/stm32f4/grp.yml
index 99a78e1890..99b3a10527 100644
--- a/spec/build/bsps/arm/stm32f4/grp.yml
+++ b/spec/build/bsps/arm/stm32f4/grp.yml
@@ -17,9 +17,11 @@ links:
 - role: build-dependency
   uid: abi
 - role: build-dependency
-  uid: obj
+  uid: optnumgpioctrl
 - role: build-dependency
   uid: optenhal
+- role: build-dependency
+  uid: optengpio
 - role: build-dependency
   uid: optvariant
 - role: build-dependency
@@ -66,6 +68,8 @@ links:
   uid: ../../objirq
 - role: build-dependency
   uid: ../../objmem
+- role: build-dependency
+  uid: obj
 - role: build-dependency
   uid: ../../bspopts
 type: build
diff --git a/spec/build/bsps/arm/stm32f4/obj.yml b/spec/build/bsps/arm/stm32f4/obj.yml
index 7afe000024..6d08c618c6 100644
--- a/spec/build/bsps/arm/stm32f4/obj.yml
+++ b/spec/build/bsps/arm/stm32f4/obj.yml
@@ -153,6 +153,8 @@ install:
   - bsps/arm/stm32f4/include/bsp/stm32f10xxx_rcc.h
   - bsps/arm/stm32f4/include/bsp/stm32f4.h
   - bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h
+  - bsps/arm/stm32f4/include/bsp/stm32f4_periph.h
+  - bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
   - bsps/arm/stm32f4/include/bsp/stm32f4xxxx_adc.h
   - bsps/arm/stm32f4/include/bsp/stm32f4xxxx_exti.h
   - bsps/arm/stm32f4/include/bsp/stm32f4xxxx_flash.h
@@ -261,6 +263,9 @@ source:
 - bsps/arm/stm32f4/hal/stm32f4xx_ll_usb.c
 - bsps/arm/stm32f4/hal/stm32f4xx_ll_utils.c
 - bsps/arm/stm32f4/hal/system_stm32f4xx.c
+- bsps/arm/stm32f4/gpio/gpio.c
+- bsps/arm/stm32f4/start/periph.c
+- bsps/arm/stm32f4/adc/adc.c
 - bsps/arm/shared/irq/irq-armv7m.c
 - bsps/arm/shared/irq/irq-dispatch-armv7m.c
 - bsps/arm/shared/start/bsp-start-memcpy.S
diff --git a/spec/build/bsps/arm/stm32f4/optengpio.yml b/spec/build/bsps/arm/stm32f4/optengpio.yml
new file mode 100644
index 0000000000..8b15bce9a9
--- /dev/null
+++ b/spec/build/bsps/arm/stm32f4/optengpio.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-boolean: null
+- define-condition: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+default: true
+default-by-variant: []
+description: |
+  This option enables the BSP to use RTEMS GPIO API.
+enabled-by: true
+format: '{}'
+links: []
+name: STM32F4_ENABLE_GENERIC_GPIO
+type: build
diff --git a/spec/build/bsps/arm/stm32f4/optnumgpioctrl.yml b/spec/build/bsps/arm/stm32f4/optnumgpioctrl.yml
new file mode 100644
index 0000000000..da21d9c62c
--- /dev/null
+++ b/spec/build/bsps/arm/stm32f4/optnumgpioctrl.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-integer: null
+- define: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+default: 1
+default-by-variant: []
+description: |
+  Number of GPIO controllers of this BSP.
+enabled-by: true
+format: '{}'
+links: []
+name: BSP_GPIO_NUM_CONTROLLERS
+type: build
-- 
2.36.1



More information about the devel mailing list