From 48026bb824fd2d9cfb00ecd040db6ef3a416bae9 Mon Sep 17 00:00:00 2001
From: Clyne Sullivan <clyne@bitgloo.com>
Date: Fri, 22 Jan 2021 21:43:36 -0500
Subject: upload initial port

---
 .../boards/stm32f0xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32f0xx/templates/board.h.ftl         | 368 +++++++++++++++++
 .../boards/stm32f0xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32f3xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32f3xx/templates/board.h.ftl         | 368 +++++++++++++++++
 .../boards/stm32f3xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32f4xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32f4xx/templates/board.h.ftl         | 389 ++++++++++++++++++
 .../boards/stm32f4xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32f7xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32f7xx/templates/board.h.ftl         | 391 ++++++++++++++++++
 .../boards/stm32f7xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32g0xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32g0xx/templates/board.h.ftl         | 368 +++++++++++++++++
 .../boards/stm32g0xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32g4xx/templates/board.c.ftl         | 302 ++++++++++++++
 .../boards/stm32g4xx/templates/board.h.ftl         | 393 ++++++++++++++++++
 .../boards/stm32g4xx/templates/board.mk.ftl        |  39 ++
 .../boards/stm32h7xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32h7xx/templates/board.h.ftl         | 385 ++++++++++++++++++
 .../boards/stm32h7xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32l0xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32l0xx/templates/board.h.ftl         | 368 +++++++++++++++++
 .../boards/stm32l0xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32l1xx/templates/board.c.ftl         | 327 +++++++++++++++
 .../boards/stm32l1xx/templates/board.h.ftl         | 366 +++++++++++++++++
 .../boards/stm32l1xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32l4xx/templates/board.c.ftl         | 342 ++++++++++++++++
 .../boards/stm32l4xx/templates/board.h.ftl         | 449 +++++++++++++++++++++
 .../boards/stm32l4xx/templates/board.mk.ftl        |  43 ++
 .../boards/stm32l5xx/templates/board.c.ftl         | 299 ++++++++++++++
 .../boards/stm32l5xx/templates/board.h.ftl         | 420 +++++++++++++++++++
 .../boards/stm32l5xx/templates/board.mk.ftl        |  43 ++
 33 files changed, 8293 insertions(+)
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.mk.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.c.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.h.ftl
 create mode 100644 ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.mk.ftl

(limited to 'ChibiOS_20.3.2/tools/ftl/processors/boards')

diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.c.ftl
new file mode 100644
index 0000000..860fb8b
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB(STM32_GPIO_EN_MASK);
+  rccEnableAHB(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.h.ftl
new file mode 100644
index 0000000..fc8fee0
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.h.ftl
@@ -0,0 +1,368 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f0xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.c.ftl
new file mode 100644
index 0000000..860fb8b
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB(STM32_GPIO_EN_MASK);
+  rccEnableAHB(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.h.ftl
new file mode 100644
index 0000000..fc8fee0
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.h.ftl
@@ -0,0 +1,368 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f3xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.c.ftl
new file mode 100644
index 0000000..6a4b808
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB1(STM32_GPIO_EN_MASK);
+  rccEnableAHB1(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.h.ftl
new file mode 100644
index 0000000..845833a
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.h.ftl
@@ -0,0 +1,389 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+[#if doc1.board.ethernet_phy[0]??]
+
+/*
+ * Ethernet PHY type.
+ */
+#define BOARD_PHY_ID                ${doc1.board.ethernet_phy.identifier[0]}
+[#if doc1.board.ethernet_phy.bus_type[0]?string == "RMII"]
+#define BOARD_PHY_RMII
+[/#if]
+[/#if]
+[#if doc1.board.usb_phy[0]?? && doc1.board.usb_phy.bus_type[0]?string == "ULPI"]
+
+/*
+ * The board has an ULPI USB PHY.
+ */
+#define BOARD_OTG2_USES_ULPI
+[/#if]
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   ${doc1.board.clocks.@VDD[0]}U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f4xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.c.ftl
new file mode 100644
index 0000000..6a4b808
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB1(STM32_GPIO_EN_MASK);
+  rccEnableAHB1(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.h.ftl
new file mode 100644
index 0000000..42fef54
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.h.ftl
@@ -0,0 +1,391 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+[#if doc1.board.ethernet_phy[0]??]
+
+/*
+ * Ethernet PHY type.
+ */
+#define BOARD_PHY_ID                ${doc1.board.ethernet_phy.identifier[0]}
+[#if doc1.board.ethernet_phy.bus_type[0]?string == "RMII"]
+#define BOARD_PHY_RMII
+[/#if]
+[/#if]
+[#if doc1.board.usb_phy[0]?? && doc1.board.usb_phy.bus_type[0]?string == "ULPI"]
+
+/*
+ * The board has an ULPI USB PHY.
+ */
+#define BOARD_OTG2_USES_ULPI
+[/#if]
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   ${doc1.board.clocks.@VDD[0]}U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32f7xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.c.ftl
new file mode 100644
index 0000000..4d8c405
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetIOP(STM32_GPIO_EN_MASK);
+  rccEnableIOP(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    Add your board-specific code, if any.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.h.ftl
new file mode 100644
index 0000000..e023b4f
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.h.ftl
@@ -0,0 +1,368 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 11U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g0xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.c.ftl
new file mode 100644
index 0000000..6920194
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.c.ftl
@@ -0,0 +1,302 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+#include "stm32_gpio.h"
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB2(STM32_GPIO_EN_MASK);
+  rccEnableAHB2(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+ */
+void __early_init(void) {
+
+  stm32_gpio_init();
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.h.ftl
new file mode 100644
index 0000000..4499249
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.h.ftl
@@ -0,0 +1,393 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+[#if doc1.board.ethernet_phy[0]??]
+
+/*
+ * Ethernet PHY type.
+ */
+#define BOARD_PHY_ID                ${doc1.board.ethernet_phy.identifier[0]}
+[#if doc1.board.ethernet_phy.bus_type[0]?string == "RMII"]
+#define BOARD_PHY_RMII
+[/#if]
+[/#if]
+[#if doc1.board.usb_phy[0]?? && doc1.board.usb_phy.bus_type[0]?string == "ULPI"]
+
+/*
+ * The board has an ULPI USB PHY.
+ */
+#define BOARD_OTG2_USES_ULPI
+[/#if]
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   ${doc1.board.clocks.@VDD[0]}U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+#define PIN_LOCKR_DISABLED(n)       (0U << (n))
+#define PIN_LOCKR_ENABLED(n)        (1U << (n))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.mk.ftl
new file mode 100644
index 0000000..c9f14f5
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32g4xx/templates/board.mk.ftl
@@ -0,0 +1,39 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2019 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.c.ftl
new file mode 100644
index 0000000..821d732
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB4(STM32_GPIO_EN_MASK);
+  rccEnableAHB4(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.h.ftl
new file mode 100644
index 0000000..6dc453f
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.h.ftl
@@ -0,0 +1,385 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+[#if doc1.board.ethernet_phy[0]??]
+
+/*
+ * Ethernet PHY type.
+ */
+#define BOARD_PHY_ID                ${doc1.board.ethernet_phy.identifier[0]}
+[#if doc1.board.ethernet_phy.bus_type[0]?string == "RMII"]
+#define BOARD_PHY_RMII
+[/#if]
+[/#if]
+[#if doc1.board.usb_phy[0]?? && doc1.board.usb_phy.bus_type[0]?string == "ULPI"]
+
+/*
+ * The board has an ULPI USB PHY.
+ */
+#define BOARD_OTG2_USES_ULPI
+[/#if]
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32h7xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.c.ftl
new file mode 100644
index 0000000..0e896c9
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetIOP(STM32_GPIO_EN_MASK);
+  rccEnableIOP(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.h.ftl
new file mode 100644
index 0000000..b1cc1f7
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.h.ftl
@@ -0,0 +1,368 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 11U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l0xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.c.ftl
new file mode 100644
index 0000000..860fb8b
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.c.ftl
@@ -0,0 +1,327 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB(STM32_GPIO_EN_MASK);
+  rccEnableAHB(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.h.ftl
new file mode 100644
index 0000000..c68bad8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.h.ftl
@@ -0,0 +1,366 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l1xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.c.ftl
new file mode 100644
index 0000000..9ec1966
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.c.ftl
@@ -0,0 +1,342 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+  uint32_t              ascr;
+  uint32_t              lockr;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+#if STM32_HAS_GPIOI || defined(__DOXYGEN__)
+  gpio_setup_t          PIData;
+#endif
+#if STM32_HAS_GPIOJ || defined(__DOXYGEN__)
+  gpio_setup_t          PJData;
+#endif
+#if STM32_HAS_GPIOK || defined(__DOXYGEN__)
+  gpio_setup_t          PKData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH,    VAL_GPIOA_ASCR,
+   VAL_GPIOA_LOCKR},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH,    VAL_GPIOB_ASCR,
+   VAL_GPIOB_LOCKR},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH,    VAL_GPIOC_ASCR,
+   VAL_GPIOC_LOCKR},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH,    VAL_GPIOD_ASCR,
+   VAL_GPIOD_LOCKR},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH,    VAL_GPIOE_ASCR,
+   VAL_GPIOE_LOCKR},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH,    VAL_GPIOF_ASCR,
+   VAL_GPIOF_LOCKR},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH,    VAL_GPIOG_ASCR,
+   VAL_GPIOG_LOCKR},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH,    VAL_GPIOH_ASCR,
+   VAL_GPIOH_LOCKR},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH,    VAL_GPIOI_ASCR,
+   VAL_GPIOI_LOCKR},
+#endif
+#if STM32_HAS_GPIOJ
+  {VAL_GPIOJ_MODER, VAL_GPIOJ_OTYPER, VAL_GPIOJ_OSPEEDR, VAL_GPIOJ_PUPDR,
+   VAL_GPIOJ_ODR,   VAL_GPIOJ_AFRL,   VAL_GPIOJ_AFRH,    VAL_GPIOJ_ASCR,
+   VAL_GPIOJ_LOCKR},
+#endif
+#if STM32_HAS_GPIOK
+  {VAL_GPIOK_MODER, VAL_GPIOK_OTYPER, VAL_GPIOK_OSPEEDR, VAL_GPIOK_PUPDR,
+   VAL_GPIOK_ODR,   VAL_GPIOK_AFRL,   VAL_GPIOK_AFRH,    VAL_GPIOK_ASCR,
+   VAL_GPIOK_LOCKR}
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->ASCR    = config->ascr;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+  gpiop->LOCKR   = config->lockr;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB2(STM32_GPIO_EN_MASK);
+  rccEnableAHB2(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+#if STM32_HAS_GPIOI
+  gpio_init(GPIOI, &gpio_default_config.PIData);
+#endif
+#if STM32_HAS_GPIOJ
+  gpio_init(GPIOJ, &gpio_default_config.PJData);
+#endif
+#if STM32_HAS_GPIOK
+  gpio_init(GPIOK, &gpio_default_config.PKData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.h.ftl
new file mode 100644
index 0000000..b9018bb
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.h.ftl
@@ -0,0 +1,449 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+[#if doc1.board.ethernet_phy[0]??]
+
+/*
+ * Ethernet PHY type.
+ */
+#define BOARD_PHY_ID                ${doc1.board.ethernet_phy.identifier[0]}
+[#if doc1.board.ethernet_phy.bus_type[0]?string == "RMII"]
+#define BOARD_PHY_RMII
+[/#if]
+[/#if]
+[#if doc1.board.usb_phy[0]?? && doc1.board.usb_phy.bus_type[0]?string == "ULPI"]
+
+/*
+ * The board has an ULPI USB PHY.
+ */
+#define BOARD_OTG2_USES_ULPI
+[/#if]
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   ${doc1.board.clocks.@VDD[0]}U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+#define PIN_ASCR_DISABLED(n)        (0U << (n))
+#define PIN_ASCR_ENABLED(n)         (1U << (n))
+#define PIN_LOCKR_DISABLED(n)       (0U << (n))
+#define PIN_LOCKR_ENABLED(n)        (1U << (n))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ASCR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign switch = pin.@AnalogSwitch[0] /]
+    [#if switch == "Disabled"]
+      [#assign out = "PIN_ASCR_DISABLED(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ASCR_ENABLED(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ASCR              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating LOCKR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign lock = pin.@PinLock[0] /]
+    [#if lock == "Disabled"]
+      [#assign out = "PIN_LOCKR_DISABLED(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_LOCKR_ENABLED(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_LOCKR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l4xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.c.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.c.ftl
new file mode 100644
index 0000000..13f93d7
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.c.ftl
@@ -0,0 +1,299 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.c" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+[#list doc1.board.headers.header as header]
+#include "${header[0]?string?trim}"
+[/#list]
+#include "hal.h"
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+#include "stm32_gpio.h"
+[/#if]
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types.                                         */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   Type of STM32 GPIO port setup.
+ */
+typedef struct {
+  uint32_t              moder;
+  uint32_t              otyper;
+  uint32_t              ospeedr;
+  uint32_t              pupdr;
+  uint32_t              odr;
+  uint32_t              afrl;
+  uint32_t              afrh;
+  uint32_t              lockr;
+} gpio_setup_t;
+
+/**
+ * @brief   Type of STM32 GPIO initialization data.
+ */
+typedef struct {
+#if STM32_HAS_GPIOA || defined(__DOXYGEN__)
+  gpio_setup_t          PAData;
+#endif
+#if STM32_HAS_GPIOB || defined(__DOXYGEN__)
+  gpio_setup_t          PBData;
+#endif
+#if STM32_HAS_GPIOC || defined(__DOXYGEN__)
+  gpio_setup_t          PCData;
+#endif
+#if STM32_HAS_GPIOD || defined(__DOXYGEN__)
+  gpio_setup_t          PDData;
+#endif
+#if STM32_HAS_GPIOE || defined(__DOXYGEN__)
+  gpio_setup_t          PEData;
+#endif
+#if STM32_HAS_GPIOF || defined(__DOXYGEN__)
+  gpio_setup_t          PFData;
+#endif
+#if STM32_HAS_GPIOG || defined(__DOXYGEN__)
+  gpio_setup_t          PGData;
+#endif
+#if STM32_HAS_GPIOH || defined(__DOXYGEN__)
+  gpio_setup_t          PHData;
+#endif
+} gpio_config_t;
+
+[/#if]
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+/**
+ * @brief   STM32 GPIO static initialization data.
+ */
+static const gpio_config_t gpio_default_config = {
+[#else]
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+[/#if]
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH,    VAL_GPIOA_LOCKR},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH,    VAL_GPIOB_LOCKR},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH,    VAL_GPIOC_LOCKR},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH,    VAL_GPIOD_LOCKR},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH,    VAL_GPIOE_LOCKR},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH,    VAL_GPIOF_LOCKR},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH,    VAL_GPIOG_LOCKR},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH,    VAL_GPIOH_LOCKR},
+#endif
+};
+[#if doc1.board.configuration_settings.hal_version[0]?trim == "4.0.x"]
+#endif
+[/#if]
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+static void gpio_init(stm32_gpio_t *gpiop, const gpio_setup_t *config) {
+
+  gpiop->OTYPER  = config->otyper;
+  gpiop->OSPEEDR = config->ospeedr;
+  gpiop->PUPDR   = config->pupdr;
+  gpiop->ODR     = config->odr;
+  gpiop->AFRL    = config->afrl;
+  gpiop->AFRH    = config->afrh;
+  gpiop->MODER   = config->moder;
+  gpiop->LOCKR   = config->lockr;
+}
+
+static void stm32_gpio_init(void) {
+
+  /* Enabling GPIO-related clocks, the mask comes from the
+     registry header file.*/
+  rccResetAHB2(STM32_GPIO_EN_MASK);
+  rccEnableAHB2(STM32_GPIO_EN_MASK, true);
+
+  /* Initializing all the defined GPIO ports.*/
+#if STM32_HAS_GPIOA
+  gpio_init(GPIOA, &gpio_default_config.PAData);
+#endif
+#if STM32_HAS_GPIOB
+  gpio_init(GPIOB, &gpio_default_config.PBData);
+#endif
+#if STM32_HAS_GPIOC
+  gpio_init(GPIOC, &gpio_default_config.PCData);
+#endif
+#if STM32_HAS_GPIOD
+  gpio_init(GPIOD, &gpio_default_config.PDData);
+#endif
+#if STM32_HAS_GPIOE
+  gpio_init(GPIOE, &gpio_default_config.PEData);
+#endif
+#if STM32_HAS_GPIOF
+  gpio_init(GPIOF, &gpio_default_config.PFData);
+#endif
+#if STM32_HAS_GPIOG
+  gpio_init(GPIOG, &gpio_default_config.PGData);
+#endif
+#if STM32_HAS_GPIOH
+  gpio_init(GPIOH, &gpio_default_config.PHData);
+#endif
+}
+
+[/#if]
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Early initialization code.
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+ * @details GPIO ports and system clocks are initialized before everything
+ *          else.
+[#else]
+ * @details System clocks are initialized before everything else.
+[/#if]
+ */
+void __early_init(void) {
+
+[#if doc1.board.configuration_settings.hal_version[0]?trim != "4.0.x"]
+  stm32_gpio_init();
+[/#if]
+  stm32_clock_init();
+[#if doc1.board.board_functions.__early_init[0]??]
+  ${doc1.board.board_functions.__early_init[0]}
+[/#if]
+}
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+/**
+ * @brief   SDC card detection.
+ */
+bool sdc_lld_is_card_inserted(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.sdc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   SDC card write protection detection.
+ */
+bool sdc_lld_is_write_protected(SDCDriver *sdcp) {
+[#if doc1.board.board_functions.sdc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.sdc_lld_is_write_protected[0]}
+[#else]
+
+  (void)sdcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif /* HAL_USE_SDC */
+
+#if HAL_USE_MMC_SPI || defined(__DOXYGEN__)
+/**
+ * @brief   MMC_SPI card detection.
+ */
+bool mmc_lld_is_card_inserted(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_card_inserted[0]??]
+${doc1.board.board_functions.mmc_lld_is_card_inserted[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return true;
+[/#if]
+}
+
+/**
+ * @brief   MMC_SPI card write protection detection.
+ */
+bool mmc_lld_is_write_protected(MMCDriver *mmcp) {
+[#if doc1.board.board_functions.mmc_lld_is_write_protected[0]??]
+${doc1.board.board_functions.mmc_lld_is_write_protected[0]}
+[#else]
+
+  (void)mmcp;
+  /* CHTODO: Fill the implementation.*/
+  return false;
+[/#if]
+}
+#endif
+
+/**
+ * @brief   Board-specific initialization code.
+ * @note    You can add your board-specific code here.
+ */
+void boardInit(void) {
+
+[#if doc1.board.board_functions.boardInit[0]??]
+  ${doc1.board.board_functions.boardInit[0]}
+[/#if]
+}
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.h.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.h.ftl
new file mode 100644
index 0000000..80db153
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.h.ftl
@@ -0,0 +1,420 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[#import "/@lib/liblicense.ftl" as license /]
+[@pp.changeOutputFile name="board.h" /]
+/*
+[@license.EmitLicenseAsText /]
+*/
+
+/*
+ * This file has been automatically generated using ChibiStudio board
+ * generator plugin. Do not edit manually.
+ */
+
+#ifndef BOARD_H
+#define BOARD_H
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*
+ * Setup for ${doc1.board.board_name[0]} board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_${doc1.board.board_id[0]}
+#define BOARD_NAME                  "${doc1.board.board_name[0]}"
+[#if doc1.board.ethernet_phy[0]??]
+
+/*
+ * Ethernet PHY type.
+ */
+#define BOARD_PHY_ID                ${doc1.board.ethernet_phy.identifier[0]}
+[#if doc1.board.ethernet_phy.bus_type[0]?string == "RMII"]
+#define BOARD_PHY_RMII
+[/#if]
+[/#if]
+[#if doc1.board.usb_phy[0]?? && doc1.board.usb_phy.bus_type[0]?string == "ULPI"]
+
+/*
+ * The board has an ULPI USB PHY.
+ */
+#define BOARD_OTG2_USES_ULPI
+[/#if]
+
+/*
+ * Board oscillators-related settings.
+[#if doc1.board.clocks.@LSEFrequency[0]?number == 0]
+ * NOTE: LSE not fitted.
+[/#if]
+[#if doc1.board.clocks.@HSEFrequency[0]?number == 0]
+ * NOTE: HSE not fitted.
+[/#if]
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                ${doc1.board.clocks.@LSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@LSEBypass[0]?string == "true"]
+#define STM32_LSE_BYPASS
+
+[/#if]
+#define STM32_LSEDRV                (${doc1.board.clocks.@LSEDrive[0]?word_list[0]?number}U << 3U)
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                ${doc1.board.clocks.@HSEFrequency[0]}U
+#endif
+
+[#if doc1.board.clocks.@HSEBypass[0]?string == "true"]
+#define STM32_HSE_BYPASS
+
+[/#if]
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   ${doc1.board.clocks.@VDD[0]}U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define ${doc1.board.subtype[0]}
+
+/*
+ * IO pins assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign pin_name = pin?node_name?upper_case /]
+#define ${(port_name + "_" + pin_name)?right_pad(27, " ")} ${pin_index?string}U
+    [#else]
+      [#list names as name]
+#define ${(port_name + "_" + name)?right_pad(27, " ")} ${pin_index?string}U
+      [/#list]
+    [/#if]
+  [/#list]
+
+[/#list]
+/*
+ * IO lines assignments.
+ */
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size > 0]
+      [#list names as name]
+#define LINE_${name?right_pad(22, " ")} PAL_LINE(${port_name}, ${pin_index?string}U)
+      [/#list]
+    [/#if]
+  [/#list]
+[/#list]
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)           (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)          (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)       (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)          (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)       (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)      (1U << (n))
+#define PIN_OSPEED_VERYLOW(n)       (0U << ((n) * 2U))
+#define PIN_OSPEED_LOW(n)           (1U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)        (2U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)       (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)         (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)       (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)           ((v) << (((n) % 8U) * 4U))
+#define PIN_LOCKR_DISABLED(n)       (0U << (n))
+#define PIN_LOCKR_ENABLED(n)        (1U << (n))
+
+[#list doc1.board.ports.* as port]
+  [#assign port_name = port?node_name?upper_case /]
+/*
+ * ${port_name} setup:
+ *
+  [#-- Generating pin descriptions inside the comment.--]
+  [#list port.* as pin]
+    [#assign pin_name = pin?node_name?upper_case /]
+    [#assign name = pin.@ID[0]?string?trim /]
+    [#if name?length == 0]
+      [#assign name = pin_name /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#assign type = pin.@Type[0] /]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#assign speed = pin.@Speed[0] /]
+    [#assign alternate = pin.@Alternate[0] /]
+    [#if mode == "Input"]
+      [#assign desc = mode + " " + resistor /]
+    [#elseif mode == "Output"]
+      [#assign desc = mode + " " + type + " " + speed /]
+    [#elseif mode == "Alternate"]
+      [#assign desc = mode + " " + alternate /]
+    [#else]
+      [#assign desc = "Analog" /]
+    [/#if]
+ * P${(port?node_name[4..] + pin_index?string)?right_pad(3, " ")} - ${name?right_pad(26, " ")}(${desc?lower_case}).
+  [/#list]
+ */
+  [#--
+    -- Generating MODER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign mode = pin.@Mode[0] /]
+    [#if mode == "Input"]
+      [#assign out = "PIN_MODE_INPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Output"]
+      [#assign out = "PIN_MODE_OUTPUT(" + port_name + "_" + name + ")" /]
+    [#elseif mode == "Alternate"]
+      [#assign out = "PIN_MODE_ALTERNATE(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_MODE_ANALOG(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_MODER             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating OTYPER register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign type = pin.@Type[0] /]
+    [#if type == "PushPull"]
+      [#assign out = "PIN_OTYPE_PUSHPULL(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OTYPE_OPENDRAIN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OTYPER            (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating SPEEDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign speed = pin.@Speed[0] /]
+    [#if speed == "Minimum"]
+      [#assign out = "PIN_OSPEED_VERYLOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "Low"]
+      [#assign out = "PIN_OSPEED_LOW(" + port_name + "_" + name + ")" /]
+    [#elseif speed == "High"]
+      [#assign out = "PIN_OSPEED_MEDIUM(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_OSPEED_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_OSPEEDR           (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating PUPDR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign resistor = pin.@Resistor[0] /]
+    [#if resistor == "Floating"]
+      [#assign out = "PIN_PUPDR_FLOATING(" + port_name + "_" + name + ")" /]
+    [#elseif resistor == "PullUp"]
+      [#assign out = "PIN_PUPDR_PULLUP(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_PUPDR_PULLDOWN(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_PUPDR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating ODR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign level = pin.@Level[0] /]
+    [#if level == "Low"]
+      [#assign out = "PIN_ODR_LOW(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_ODR_HIGH(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_ODR               (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating AFRx registers values.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign alternate = pin.@Alternate[0]?trim /]
+    [#assign out = "PIN_AFIO_AF(" + port_name + "_" + name + ", " + alternate + "U)" /]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_AFRL              (" + out /]
+    [#elseif pin_index == 8]
+      [#assign line = "#define VAL_" + port_name + "_AFRH              (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if (pin_index == 7) || (pin_index == 15)]
+${line + ")"}
+    [#else]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [/#if]
+  [/#list]
+  [#--
+    -- Generating LOCKR register value.
+    --]
+  [#list port.* as pin]
+    [#assign names = pin.@ID[0]?string?word_list /]
+    [#if names?size == 0]
+      [#assign name = pin?node_name?upper_case /]
+    [#else]
+      [#assign name = names[0] /]
+    [/#if]
+    [#assign lock = pin.@PinLock[0] /]
+    [#if lock == "Disabled"]
+      [#assign out = "PIN_LOCKR_DISABLED(" + port_name + "_" + name + ")" /]
+    [#else]
+      [#assign out = "PIN_LOCKR_ENABLED(" + port_name + "_" + name + ")" /]
+    [/#if]
+    [#if pin_index == 0]
+      [#assign line = "#define VAL_" + port_name + "_LOCKR             (" + out /]
+    [#else]
+      [#assign line = "                                     " + out /]
+    [/#if]
+    [#if pin_index < 15]
+${(line + " |")?right_pad(76, " ") + "\\"}
+    [#else]
+${line + ")"}
+    [/#if]
+  [/#list]
+
+[/#list]
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* BOARD_H */
diff --git a/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.mk.ftl b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.mk.ftl
new file mode 100644
index 0000000..41edcf8
--- /dev/null
+++ b/ChibiOS_20.3.2/tools/ftl/processors/boards/stm32l5xx/templates/board.mk.ftl
@@ -0,0 +1,43 @@
+[#ftl]
+[#--
+    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
+
+    This file is part of ChibiOS.
+
+    ChibiOS is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    ChibiOS is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  --]
+[@pp.dropOutputFile /]
+[#import "/@lib/libutils.ftl" as utils /]
+[@pp.changeOutputFile name="board.mk" /]
+[#if doc1.board.configuration_settings.board_files_path[0]??]
+  [#assign path = doc1.board.configuration_settings.board_files_path[0]?string?trim /]
+  [#if !path?ends_with("/")]
+    [#assign path = path + "/"]
+  [/#if]
+[#else]
+  [#if doc1.board.configuration_settings.hal_version[0]?trim == "2.6.x"]
+    [#assign path = "$(CHIBIOS)/boards/" /]
+  [#else]
+    [#assign path = "$(CHIBIOS)/os/hal/boards/" /]
+  [/#if]
+[/#if]
+# List of all the board related files.
+BOARDSRC = ${path}${doc1.board.board_id[0]}/board.c
+
+# Required include directories
+BOARDINC = ${path}${doc1.board.board_id[0]}
+
+# Shared variables
+ALLCSRC += $(BOARDSRC)
+ALLINC  += $(BOARDINC)
-- 
cgit v1.2.3