aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/SPC5/LLD
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/ports/SPC5/LLD')
-rw-r--r--os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.c.ftl119
-rw-r--r--os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.h.ftl87
-rw-r--r--os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.c1870
-rw-r--r--os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.h848
-rw-r--r--os/hal/ports/SPC5/LLD/DSPI_v1/spc5_dspi.h460
-rw-r--r--os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.c1397
-rw-r--r--os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.h1005
-rw-r--r--os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.c343
-rw-r--r--os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.h195
-rw-r--r--os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.c1171
-rw-r--r--os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.h574
-rw-r--r--os/hal/ports/SPC5/LLD/LINFlex_v1/spc5_linflex.h637
-rw-r--r--os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.c177
-rw-r--r--os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.h471
-rw-r--r--os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.c144
-rw-r--r--os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.h448
-rw-r--r--os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.c94
-rw-r--r--os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.h200
18 files changed, 10240 insertions, 0 deletions
diff --git a/os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.c.ftl b/os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.c.ftl
new file mode 100644
index 000000000..eaa8e0960
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.c.ftl
@@ -0,0 +1,119 @@
+[#ftl]
+[@pp.dropOutputFile /]
+[@pp.changeOutputFile name="hal_spi_lld_cfg.c" /]
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_spi_lld_cfg.c
+ * @brief SPI Driver configuration code.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+#include "hal_spi_lld_cfg.h"
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+[#list conf.instance.dspi_settings.spi_configurations.configs.spi_configuration_settings as settings]
+ [#assign name = settings.symbolic_name.value[0]?trim /]
+ [#-- Transfer group.--]
+ [#assign cpol = settings.transfer.clock_polarity[0].@index[0]?trim?number /]
+ [#assign cpha = settings.transfer.clock_phase[0].@index[0]?trim?number /]
+ [#assign frame_size = settings.transfer.frame_size[0].@index[0]?trim?number + 4 /]
+ [#assign frame_ordering = settings.transfer.frame_ordering[0].@index[0]?trim?number /]
+ [#-- Timings group.--]
+ [#assign brp = settings.timings.baud_rate_prescaler.value[0]?trim /]
+ [#assign brd = settings.timings.baud_rate_divider.value[0]?trim /]
+ [#assign dbr = (settings.timings.double_baud_rate.value[0]?trim?lower_case == "true") /]
+ [#assign cssckp = settings.timings.cssck_prescaler.value[0]?trim /]
+ [#assign cssckd = settings.timings.cssck_divider.value[0]?trim /]
+ [#assign ascp = settings.timings.asc_prescaler.value[0]?trim /]
+ [#assign ascd = settings.timings.asc_divider.value[0]?trim /]
+ [#assign dtp = settings.timings.dt_prescaler.value[0]?trim /]
+ [#assign dtd = settings.timings.dt_divider.value[0]?trim /]
+ [#-- Chip Select group.--]
+ [#assign mode = settings.chip_select.mode[0].@index[0]?trim?number /]
+ [#assign gpio_port = settings.chip_select.gpio_port.value[0]?trim /]
+ [#assign gpio_bit = settings.chip_select.gpio_bit.value[0]?trim?number /]
+ [#assign pcs_line = settings.chip_select.pcs_line[0].@index[0]?trim?number /]
+ [#-- Notifications group.--]
+ [#assign cb = settings.notifications.transfer_complete_callback.value[0]?string?trim /]
+ [#if cb == ""]
+ [#assign cb = "NULL" /]
+ [/#if]
+/**
+ * @brief Structure defining the SPI configuration "${name}".
+ */
+const SPIConfig spi_config_${name} = {
+ ${cb},
+ ${gpio_port},
+ ${gpio_bit},
+ 0 | SPC5_CTAR_FMSZ(${frame_size})[#rt]
+ [#if dbr]
+ | SPC5_CTAR_DBR[#rt]
+ [/#if]
+ [#if cpol != 0]
+ | SPC5_CTAR_CPOL[#rt]
+ [/#if]
+ [#if cpha != 0]
+ | SPC5_CTAR_CPHA[#rt]
+ [/#if]
+ [#if frame_ordering != 0]
+ | SPC5_CTAR_LSBFE[#rt]
+ [/#if]
+ |
+ SPC5_CTAR_PCSSCK_${cssckp} | SPC5_CTAR_PASC_${ascp} |
+ SPC5_CTAR_PDT_${dtp} | SPC5_CTAR_PBR_${brp} |
+ SPC5_CTAR_CSSCK_${cssckd} | SPC5_CTAR_ASC_${ascd} |
+ SPC5_CTAR_DT_${dtd} | SPC5_CTAR_BR_${brd},
+ 0[#rt]
+ [#if mode != 1]
+ | SPC5_PUSHR_CONT[#rt]
+ [/#if]
+ | SPC5_PUSHR_CTAS(0) | SPC5_PUSHR_PCS(${pcs_line})
+};
+
+[/#list]
+ /*===========================================================================*/
+/* Driver local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+ /*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+#endif /* HAL_USE_SPI */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.h.ftl b/os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.h.ftl
new file mode 100644
index 000000000..995fd8ae6
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/DSPI_v1/cfg/hal_spi_lld_cfg.h.ftl
@@ -0,0 +1,87 @@
+[#ftl]
+[@pp.dropOutputFile /]
+[@pp.changeOutputFile name="hal_spi_lld_cfg.h" /]
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file hal_spi_lld_cfg.h
+ * @brief SPI Driver configuration macros and structures.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef _SPI_LLD_CFG_H_
+#define _SPI_LLD_CFG_H_
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+/* List of the SPIConfig structures defined in spi_lld_cfg.c.*/
+[#list conf.instance.dspi_settings.spi_configurations.configs.spi_configuration_settings as settings]
+extern const SPIConfig spi_config_${settings.symbolic_name.value[0]?trim};
+[/#list]
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* List of the callback functions referenced from the SPIConfig
+ structures in spi_lld_cfg.c.*/
+[#assign transfer_complete_callbacks = []]
+[#list conf.instance.dspi_settings.spi_configurations.configs.spi_configuration_settings as settings]
+ [#assign callback = settings.notifications.transfer_complete_callback.value[0]?string?trim /]
+ [#if callback != ""]
+ [#if !transfer_complete_callbacks?seq_contains(callback)]
+ [#assign transfer_complete_callbacks = transfer_complete_callbacks + [callback]]
+ [/#if]
+ [/#if]
+[/#list]
+[#list transfer_complete_callbacks?sort as cb]
+ void ${cb}(SPIDriver *spip);
+[/#list]
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SPI */
+
+#endif /* _SPI_LLD_CFG_H_ */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.c b/os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.c
new file mode 100644
index 000000000..bc4fd57b2
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.c
@@ -0,0 +1,1870 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/DSPI_v1/hal_spi_lld.c
+ * @brief SPC5xx SPI subsystem low level driver source.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/* Some forward declarations.*/
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE
+static void spi_serve_rx_dma_irq(edma_channel_t channel, void *p);
+#endif
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+static void spi_serve_tx_dma_irq(edma_channel_t channel, void *p);
+#endif
+
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE
+static void spi_serve_dma_error_irq(edma_channel_t channel,
+ void *p,
+ uint32_t esr);
+#endif
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/* Excluded PUSHR bits.*/
+#define DSPI_PUSHR_EXCLUDED_BITS (SPC5_PUSHR_CTAS_MASK | \
+ SPC5_PUSHR_EOQ | \
+ SPC5_PUSHR_TXDATA_MASK)
+
+#define DSPI_POPR8_ADDRESS(spip) (((uint32_t)&(spip)->dspi->POPR.R) + 3)
+#define DSPI_POPR16_ADDRESS(spip) (((uint32_t)&(spip)->dspi->POPR.R) + 2)
+
+/* Set of macros dealing with the variable number of DMAs depending on
+ the chosen mode.*/
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+#define spi_lld_setdma(spip, tx1_cfg, tx2_cfg, rx_cfg) { \
+ (spip)->tx1_channel = edmaChannelAllocate(&(tx1_cfg)); \
+ (spip)->tx2_channel = edmaChannelAllocate(&(tx2_cfg)); \
+ (spip)->rx_channel = edmaChannelAllocate(&(rx_cfg)); \
+}
+#endif
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_ONLY
+#define spi_lld_setdma(spip, tx1_cfg, tx2_cfg, rx_cfg) { \
+ (spip)->rx_channel = edmaChannelAllocate(&(rx_cfg)); \
+}
+#endif
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+#define spi_lld_setdma(spip, tx1_cfg, tx2_cfg, rx_cfg) { \
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief SPID1 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI0 || defined(__DOXYGEN__)
+SPIDriver SPID1;
+#endif
+
+/**
+ * @brief SPID2 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI1 || defined(__DOXYGEN__)
+SPIDriver SPID2;
+#endif
+
+/**
+ * @brief SPID3 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI2 || defined(__DOXYGEN__)
+SPIDriver SPID3;
+#endif
+
+/**
+ * @brief SPID4 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI3 || defined(__DOXYGEN__)
+SPIDriver SPID4;
+#endif
+
+/**
+ * @brief SPID5 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__)
+SPIDriver SPID5;
+#endif
+
+/**
+ * @brief SPID6 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI5 || defined(__DOXYGEN__)
+SPIDriver SPID6;
+#endif
+
+/**
+ * @brief SPID7 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI6 || defined(__DOXYGEN__)
+SPIDriver SPID7;
+#endif
+
+/**
+ * @brief SPID8 driver identifier.
+ */
+#if SPC5_SPI_USE_DSPI7 || defined(__DOXYGEN__)
+SPIDriver SPID8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+#if SPC5_SPI_USE_DSPI0 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI0 TX1.
+ */
+static const edma_channel_config_t spi_dspi0_tx1_dma_config = {
+ SPC5_SPI_DSPI0_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI0_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI0_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID1
+};
+
+/**
+ * @brief DMA configuration for DSPI0 TX2.
+ */
+static const edma_channel_config_t spi_dspi0_tx2_dma_config = {
+ SPC5_SPI_DSPI0_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI0_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID1
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI0 RX.
+ */
+static const edma_channel_config_t spi_dspi0_rx_dma_config = {
+ SPC5_SPI_DSPI0_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI0_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI0_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID1
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI0 */
+
+#if SPC5_SPI_USE_DSPI1 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI1 TX1.
+ */
+static const edma_channel_config_t spi_dspi1_tx1_dma_config = {
+ SPC5_SPI_DSPI1_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI1_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI1_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID2
+};
+
+/**
+ * @brief DMA configuration for DSPI1 TX2.
+ */
+static const edma_channel_config_t spi_dspi1_tx2_dma_config = {
+ SPC5_SPI_DSPI1_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI1_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID2
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI1 RX.
+ */
+static const edma_channel_config_t spi_dspi1_rx_dma_config = {
+ SPC5_SPI_DSPI1_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI1_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI1_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID2
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI1 */
+
+#if SPC5_SPI_USE_DSPI2 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI2 TX1.
+ */
+static const edma_channel_config_t spi_dspi2_tx1_dma_config = {
+ SPC5_SPI_DSPI2_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI2_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI2_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID3
+};
+
+/**
+ * @brief DMA configuration for DSPI2 TX2.
+ */
+static const edma_channel_config_t spi_dspi2_tx2_dma_config = {
+ SPC5_SPI_DSPI2_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI2_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID3
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI2 RX.
+ */
+static const edma_channel_config_t spi_dspi2_rx_dma_config = {
+ SPC5_SPI_DSPI2_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI2_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI2_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID3
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI2 */
+
+#if SPC5_SPI_USE_DSPI3 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI3 TX1.
+ */
+static const edma_channel_config_t spi_dspi3_tx1_dma_config = {
+ SPC5_SPI_DSPI3_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI3_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI3_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID4
+};
+
+/**
+ * @brief DMA configuration for DSPI3 TX2.
+ */
+static const edma_channel_config_t spi_dspi3_tx2_dma_config = {
+ SPC5_SPI_DSPI3_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI3_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID4
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI3 RX.
+ */
+static const edma_channel_config_t spi_dspi3_rx_dma_config = {
+ SPC5_SPI_DSPI3_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI3_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI3_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID4
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI3 */
+
+#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI4 TX1.
+ */
+static const edma_channel_config_t spi_dspi4_tx1_dma_config = {
+ SPC5_SPI_DSPI4_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI4_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI4_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID5
+};
+
+/**
+ * @brief DMA configuration for DSPI4 TX2.
+ */
+static const edma_channel_config_t spi_dspi4_tx2_dma_config = {
+ SPC5_SPI_DSPI4_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI4_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID5
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI4 RX.
+ */
+static const edma_channel_config_t spi_dspi4_rx_dma_config = {
+ SPC5_SPI_DSPI4_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI4_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI4_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID5
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI4 */
+
+#if SPC5_SPI_USE_DSPI5 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI5 TX1.
+ */
+static const edma_channel_config_t spi_dspi5_tx1_dma_config = {
+ SPC5_SPI_DSPI5_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI5_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI5_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID6
+};
+
+/**
+ * @brief DMA configuration for DSPI5 TX2.
+ */
+static const edma_channel_config_t spi_dspi5_tx2_dma_config = {
+ SPC5_SPI_DSPI5_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI5_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID6
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI5 RX.
+ */
+static const edma_channel_config_t spi_dspi5_rx_dma_config = {
+ SPC5_SPI_DSPI5_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI5_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI5_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID6
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI5 */
+
+#if SPC5_SPI_USE_DSPI6 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI6 TX1.
+ */
+static const edma_channel_config_t spi_dspi6_tx1_dma_config = {
+ SPC5_SPI_DSPI6_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI6_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI6_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID7
+};
+
+/**
+ * @brief DMA configuration for DSPI6 TX2.
+ */
+static const edma_channel_config_t spi_dspi6_tx2_dma_config = {
+ SPC5_SPI_DSPI6_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI6_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID7
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI6 RX.
+ */
+static const edma_channel_config_t spi_dspi6_rx_dma_config = {
+ SPC5_SPI_DSPI6_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI6_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI6_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID7
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI6 */
+
+#if SPC5_SPI_USE_DSPI7 || defined(__DOXYGEN__)
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI7 TX1.
+ */
+static const edma_channel_config_t spi_dspi7_tx1_dma_config = {
+ SPC5_SPI_DSPI7_TX1_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI7_TX1_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI7_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID8
+};
+
+/**
+ * @brief DMA configuration for DSPI7 TX2.
+ */
+static const edma_channel_config_t spi_dspi7_tx2_dma_config = {
+ SPC5_SPI_DSPI7_TX2_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ 0,
+#endif
+ SPC5_SPI_DSPI7_DMA_IRQ_PRIO,
+ spi_serve_tx_dma_irq, spi_serve_dma_error_irq, &SPID8
+};
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief DMA configuration for DSPI7 RX.
+ */
+static const edma_channel_config_t spi_dspi7_rx_dma_config = {
+ SPC5_SPI_DSPI7_RX_DMA_CH_ID,
+#if SPC5_EDMA_HAS_MUX
+ SPC5_DSPI7_RX_DMA_DEV_ID,
+#endif
+ SPC5_SPI_DSPI7_DMA_IRQ_PRIO,
+ spi_serve_rx_dma_irq, spi_serve_dma_error_irq, &SPID8
+};
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+#endif /* SPC5_SPI_USE_DSPI7 */
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Initializes the invariant part of the @p SPIDriver structure.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] dspi the physical DSPI unit to be associated to the object
+ *
+ * @notapi
+ */
+static void spi_lld_obj_init(SPIDriver *spip, struct spc5_dspi *dspi) {
+
+ spip->dspi = dspi;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+ spip->tx1_channel = EDMA_ERROR;
+ spip->tx2_channel = EDMA_ERROR;
+#endif
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE
+ spip->rx_channel = EDMA_ERROR;
+#endif
+}
+
+/**
+ * @brief DSPI unit setup for transfer.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+static void spi_dspi_start(SPIDriver *spip) {
+
+ spip->dspi->SR.R = spip->dspi->SR.R;
+ spip->dspi->MCR.B.HALT = 0;
+}
+
+/**
+ * @brief DSPI unit transfer stop.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+static void spi_dspi_stop(SPIDriver *spip) {
+
+ /* Stops the DSPI and clears the queues.*/
+ spip->dspi->MCR.R |= SPC5_MCR_HALT | SPC5_MCR_CLR_TXF | SPC5_MCR_CLR_RXF;
+}
+
+/**
+ * @brief Prefills the TX FIFO with idle frames.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in,out] np pointer to the number of frames to send, must be
+ * greater than zero, contains the number of remaining
+ * frames on return
+ *
+ * @notapi
+ */
+static void spi_dspi_prefill_txfifo_idle(SPIDriver *spip, size_t *np) {
+ uint32_t cmd = spip->config->pushr;
+
+ while (spip->dspi->SR.B.TXCTR < SPC5_DSPI_FIFO_DEPTH) {
+ if (--(*np) == 0) {
+ spip->dspi->PUSHR.R = (SPC5_PUSHR_EOQ | cmd | 0xFFFF) & ~SPC5_PUSHR_CONT;
+ break;
+ }
+ spip->dspi->PUSHR.R = cmd | 0x0000FFFF;
+ }
+}
+
+/**
+ * @brief Prefills the TX FIFO using 8 bits frames.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in,out] np pointer to the number of frames to send, must be
+ * greater than zero, contains the number of remaining
+ * frames on return
+ * @param[in,out] txpp pointer to the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+static void spi_dspi_prefill_txfifo8(SPIDriver *spip,
+ size_t *np,
+ const uint8_t **txpp) {
+ uint32_t cmd = spip->config->pushr;
+
+ while (spip->dspi->SR.B.TXCTR < SPC5_DSPI_FIFO_DEPTH) {
+ uint32_t frame = **txpp;
+ (*txpp)++;
+
+ if (--(*np) == 0) {
+ spip->dspi->PUSHR.R = (SPC5_PUSHR_EOQ | cmd | frame) & ~SPC5_PUSHR_CONT;
+ break;
+ }
+ spip->dspi->PUSHR.R = cmd | frame;
+ }
+}
+
+/**
+ * @brief Prefills the TX FIFO using 16 bits frames.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in,out] np pointer to the number of frames to send, must be
+ * greater than zero, contains the number of remaining
+ * frames on return
+ * @param[in,out] txpp pointer to the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+static void spi_dspi_prefill_txfifo16(SPIDriver *spip,
+ size_t *np,
+ const uint16_t **txpp) {
+ uint32_t cmd = spip->config->pushr;
+
+ while (spip->dspi->SR.B.TXCTR < SPC5_DSPI_FIFO_DEPTH) {
+ uint32_t frame = **txpp;
+ (*txpp)++;
+
+ if (--(*np) == 0) {
+ spip->dspi->PUSHR.R = (SPC5_PUSHR_EOQ | cmd | frame) & ~SPC5_PUSHR_CONT;
+ break;
+ }
+ spip->dspi->PUSHR.R = cmd | frame;
+ }
+}
+
+/**
+ * @brief Starts reception using DMA ignoring the received data.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ *
+ * @notapi
+ */
+static void spi_start_rx_ignore(SPIDriver *spip, size_t n) {
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ /* Setting up the fields required for operation continuation.*/
+ spip->rx_ptr = NULL;
+ spip->rx_cnt = n;
+
+#else /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+ static uint32_t datasink;
+
+ edmaChannelSetup(spip->rx_channel, /* channel. */
+ DSPI_POPR8_ADDRESS(spip), /* src. */
+ &datasink, /* dst. */
+ 0, /* soff, do not advance. */
+ 0, /* doff, do not advance. */
+ 0, /* ssize, 8 bits transfers. */
+ 0, /* dsize, 8 bits transfers. */
+ 1, /* nbytes, always one. */
+ n, /* iter. */
+ 0, /* slast. */
+ 0, /* dlast. */
+ EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode.*/
+
+ edmaChannelStart(spip->rx_channel);
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+}
+
+/**
+ * @brief Starts reception using DMA for frames up to 8 bits.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+static void spi_start_rx8(SPIDriver *spip, size_t n, uint8_t *rxbuf) {
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ /* Setting up the fields required for operation continuation.*/
+ spip->rx_ptr8 = rxbuf;
+ spip->rx_cnt = n;
+
+#else /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+ edmaChannelSetup(spip->rx_channel, /* channel. */
+ DSPI_POPR8_ADDRESS(spip), /* src. */
+ rxbuf, /* dst. */
+ 0, /* soff, do not advance. */
+ 1, /* doff, advance by one. */
+ 0, /* ssize, 8 bits transfers. */
+ 0, /* dsize, 8 bits transfers. */
+ 1, /* nbytes, always one. */
+ n, /* iter. */
+ 0, /* slast. */
+ 0, /* dlast. */
+ EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode.*/
+
+ edmaChannelStart(spip->rx_channel);
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+}
+
+/**
+ * @brief Starts reception using DMA for frames up to 16 bits.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+static void spi_start_rx16(SPIDriver *spip, size_t n, uint16_t *rxbuf) {
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ /* Setting up the fields required for operation continuation.*/
+ spip->rx_ptr16 = rxbuf;
+ spip->rx_cnt = n;
+
+#else /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+ edmaChannelSetup(spip->rx_channel, /* channel. */
+ DSPI_POPR16_ADDRESS(spip), /* src. */
+ rxbuf, /* dst. */
+ 0, /* soff, do not advance. */
+ 2, /* doff, advance by two. */
+ 1, /* ssize, 16 bits transfers.*/
+ 1, /* dsize, 16 bits transfers.*/
+ 2, /* nbytes, always two. */
+ n, /* iter. */
+ 0, /* slast, no source adjust. */
+ 0, /* dlast. */
+ EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode. */
+
+ edmaChannelStart(spip->rx_channel);
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+}
+
+/**
+ * @brief Starts transmission using DMA for frames up to 8 bits.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ *
+ * @notapi
+ */
+static void spi_start_tx_ignore(SPIDriver *spip, size_t n) {
+
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_RX_AND_TX
+ /* Preloading the TX FIFO with as much frames as possible.*/
+ spi_dspi_prefill_txfifo_idle(spip, &n);
+
+ /* This is the case where the whole operation can be satisfied using the
+ preloading alone.*/
+ if (n == 0)
+ return;
+
+ /* Setting up the fields required for operation continuation.*/
+ spip->tx_ptr = NULL;
+ spip->tx_cnt = n;
+
+ /* Enabling the TFFF interrupt source for transfer continuation.*/
+ spip->dspi->RSER.B.TFFFRE = 1;
+
+#else /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+ /* Special case when the data to be transmitted can entirely fit into the
+ TX FIFO, in this case the TX DMAs are not activated.*/
+ if (n <= SPC5_DSPI_FIFO_DEPTH) {
+ spi_dspi_prefill_txfifo_idle(spip, &n);
+ return;
+ }
+
+ /* Preparing the TX intermediate buffer with the fixed part.*/
+ spip->tx_cmd = spip->config->pushr | (uint32_t)0xFFFF;
+
+ /* The first frame is pushed by the CPU, then the DMA is activated to
+ send the following frames. This should reduce latency on the operation
+ start.*/
+ spip->dspi->PUSHR.R = spip->tx_last = spip->tx_cmd;
+
+ /* Setting up TX1 DMA TCD parameters for 32 bits transfers.*/
+ edmaChannelSetup(spip->tx1_channel, /* channel. */
+ &spip->tx_cmd, /* src. */
+ &spip->dspi->PUSHR.R, /* dst. */
+ 0, /* soff, do not advance. */
+ 0, /* doff, do not advance. */
+ 2, /* ssize, 32 bits transfers.*/
+ 2, /* dsize, 32 bits transfers.*/
+ 4, /* nbytes, always four. */
+ n - 2, /* iter. */
+ 0, /* slast, no source adjust. */
+ 0, /* dlast, no dest.adjust. */
+ EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode. */
+
+ /* Starting TX1 DMA channel.*/
+ edmaChannelStart(spip->tx1_channel);
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+}
+
+/**
+ * @brief Starts transmission using DMA for frames up to 8 bits.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+static void spi_start_tx8(SPIDriver *spip, size_t n, const uint8_t *txbuf) {
+
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_RX_AND_TX
+ /* Preloading the TX FIFO with as much frames as possible.*/
+ spi_dspi_prefill_txfifo8(spip, &n, &txbuf);
+
+ /* This is the case where the whole operation can be satisfied using the
+ preloading alone.*/
+ if (n == 0)
+ return;
+
+ /* Setting up the fields required for operation continuation.*/
+ spip->tx_ptr8 = txbuf;
+ spip->tx_cnt = n;
+
+ /* Enabling the TFFF interrupt source for transfer continuation.*/
+ spip->dspi->RSER.B.TFFFRE = 1;
+
+#else /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+ /* Special case when the data to be transmitted can entirely fit into the
+ TX FIFO, in this case the TX DMAs are not activated.*/
+ if (n <= SPC5_DSPI_FIFO_DEPTH) {
+ spi_dspi_prefill_txfifo8(spip, &n, &txbuf);
+ return;
+ }
+
+ /* Preparing the TX intermediate buffer with the fixed part.*/
+ spip->tx_cmd = spip->config->pushr;
+
+ /* The first frame is pushed immediately, then the DMA is activated to
+ send the following frames. This should reduce latency on the operation
+ start.*/
+ spip->dspi->PUSHR.R = spip->config->pushr | (uint32_t)*txbuf;
+
+ /* The last frame is a special case, will be pushed by the TX FIFO drain
+ interrupt handler or the DMA final callback.*/
+ spip->tx_last = txbuf[n - 1];
+
+ /* At least two frames left, the DMA is enabled in order to handle the
+ long transfer, note that the final frame is not pushed by the DMA.*/
+ /* Setting up TX1 DMA TCD parameters for 8 bits transfers.*/
+ edmaChannelSetupLinked(
+ spip->tx1_channel, /* channel. */
+ spip->tx2_channel, /* linkch. */
+ txbuf + 1, /* src. */
+ ((const uint8_t *)&spip->tx_cmd) + 3, /* dst. */
+ 1, /* soff, advance by 1. */
+ 0, /* doff, do not advance. */
+ 0, /* ssize, 8 bits transfers. */
+ 0, /* dsize, 8 bits transfers. */
+ 1, /* nbytes, always one. */
+ n - 2, /* iter. */
+ 0, /* slast, no source adjust. */
+ 0, /* dlast, no dest.adjust. */
+ EDMA_TCD_MODE_DREQ); /* mode. */
+
+ /* Setting up TX2 DMA TCD parameters for 32 bits transfers.*/
+ edmaChannelSetup(spip->tx2_channel, /* channel. */
+ &spip->tx_cmd, /* src. */
+ &spip->dspi->PUSHR.R, /* dst. */
+ 0, /* soff, do not advance. */
+ 0, /* doff, do not advance. */
+ 2, /* ssize, 32 bits transfers.*/
+ 2, /* dsize, 32 bits transfers.*/
+ 4, /* nbytes, always four. */
+ n - 2, /* iter. */
+ 0, /* slast, no source adjust. */
+ 0, /* dlast, no dest.adjust. */
+ EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode. */
+
+ /* Starting TX DMA channels.*/
+ edmaChannelStart(spip->tx2_channel);
+ edmaChannelStart(spip->tx1_channel);
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+}
+
+/**
+ * @brief Starts transmission using DMA for frames up to 16 bits.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+static void spi_start_tx16(SPIDriver *spip, size_t n, const uint16_t *txbuf) {
+
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_RX_AND_TX
+ /* Preloading the TX FIFO with as much frames as possible.*/
+ spi_dspi_prefill_txfifo16(spip, &n, &txbuf);
+
+ /* This is the case where the whole operation can be satisfied using the
+ preloading alone.*/
+ if (n == 0)
+ return;
+
+ /* Setting up the fields required for operation continuation.*/
+ spip->tx_ptr16 = txbuf;
+ spip->tx_cnt = n;
+
+ /* Enabling the TFFF interrupt source for transfer continuation.*/
+ spip->dspi->RSER.B.TFFFRE = 1;
+
+#else /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+ /* Special case when the data to be transmitted can entirely fit into the
+ TX FIFO, in this case the TX DMAs are not activated.*/
+ if (n <= SPC5_DSPI_FIFO_DEPTH) {
+ spi_dspi_prefill_txfifo16(spip, &n, &txbuf);
+ return;
+ }
+
+ /* Preparing the TX intermediate buffer with the fixed part.*/
+ spip->tx_cmd = spip->config->pushr;
+
+ /* The first frame is pushed immediately, then the DMA is activated to
+ send the following frames. This should reduce latency on the operation
+ start.*/
+ spip->dspi->PUSHR.R = spip->config->pushr | (uint32_t)*txbuf;
+
+ /* The last frame is a special case, will be pushed by the TX FIFO drain
+ interrupt handler or the DMA final callback.*/
+ spip->tx_last = txbuf[n - 1];
+
+ /* At least two frames left, the DMA is enabled in order to handle the
+ long transfer, note that the final frame is not pushed by the DMA.*/
+ /* Setting up TX1 DMA TCD parameters for 16 bits transfers.*/
+ edmaChannelSetupLinked(
+ spip->tx1_channel, /* channel. */
+ spip->tx2_channel, /* linkch. */
+ txbuf + 1, /* src. */
+ ((const uint8_t *)&spip->tx_cmd) + 2, /* dst. */
+ 2, /* soff, advance by 2. */
+ 0, /* doff, do not advance. */
+ 1, /* ssize, 16 bits transfers.*/
+ 1, /* dsize, 16 bits transfers.*/
+ 2, /* nbytes, always two. */
+ n - 2, /* iter. */
+ 0, /* slast, no source adjust. */
+ 0, /* dlast, no dest.adjust. */
+ EDMA_TCD_MODE_DREQ); /* mode. */
+
+ /* Setting up TX2 DMA TCD parameters for 32 bits transfers.*/
+ edmaChannelSetup(spip->tx2_channel, /* channel. */
+ &spip->tx_cmd, /* src. */
+ &spip->dspi->PUSHR.R, /* dst. */
+ 0, /* soff, do not advance. */
+ 0, /* doff, do not advance. */
+ 2, /* ssize, 32 bits transfers.*/
+ 2, /* dsize, 32 bits transfers.*/
+ 4, /* nbytes, always four. */
+ n - 2, /* iter. */
+ 0, /* slast, no source adjust. */
+ 0, /* dlast, no dest.adjust. */
+ EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END); /* mode. */
+
+ /* Starting TX DMA channels.*/
+ edmaChannelStart(spip->tx2_channel);
+ edmaChannelStart(spip->tx1_channel);
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+}
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared RX DMA events service routine.
+ *
+ * @param[in] channel the channel number
+ * @param[in] p parameter for the registered function
+ *
+ * @notapi
+ */
+static void spi_serve_rx_dma_irq(edma_channel_t channel, void *p) {
+ SPIDriver *spip = (SPIDriver *)p;
+
+ /* Clearing RX channel state.*/
+ edmaChannelStop(channel);
+
+ /* Stops the transfer.*/
+ spi_dspi_stop(spip);
+
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+}
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+/**
+ * @brief Shared TX1/TX2 DMA events service routine.
+ *
+ * @param[in] channel the channel number
+ * @param[in] p parameter for the registered function
+ *
+ * @notapi
+ */
+static void spi_serve_tx_dma_irq(edma_channel_t channel, void *p) {
+ SPIDriver *spip = (SPIDriver *)p;
+
+ (void)channel;
+
+ /* Clearing TX channels state.*/
+ edmaChannelStop(spip->tx1_channel);
+ edmaChannelStop(spip->tx2_channel);
+
+ /* If the TX FIFO is full then the push of the last frame is delegated to
+ an interrupt handler else it is performed immediately. Both conditions
+ can be true depending on the SPI speed and ISR latency.*/
+ if (spip->dspi->SR.B.TFFF) {
+ spip->dspi->PUSHR.R = (spip->config->pushr | spip->tx_last | SPC5_PUSHR_EOQ) &
+ ~SPC5_PUSHR_CONT;
+ }
+ else {
+ spip->dspi->RSER.B.TFFFDIRS = 0;
+ }
+}
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared ISR for DMA error events.
+ *
+ * @param[in] channel the channel number
+ * @param[in] p parameter for the registered function
+ * @param[in] esr content of the ESR register
+ *
+ * @notapi
+ */
+static void spi_serve_dma_error_irq(edma_channel_t channel,
+ void *p,
+ uint32_t esr) {
+ SPIDriver *spip = (SPIDriver *)p;
+
+ (void)channel;
+ (void)esr;
+
+ /* Stops the transfer.*/
+ spi_dspi_stop(spip);
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+ edmaChannelStop(spip->tx1_channel);
+ edmaChannelStop(spip->tx2_channel);
+#endif
+ edmaChannelStop(spip->rx_channel);
+
+ SPC5_SPI_DMA_ERROR_HOOK(spip);
+}
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared ISR for RFDF DSPI events.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_serve_dspi_rfdf(SPIDriver *spip) {
+
+ osalSysLockFromISR();
+
+ /* Emptying the RX FIFO.*/
+ while ((spip->rx_cnt > 0) && (spip->dspi->SR.B.RXCTR > 0)) {
+ uint32_t frame = spip->dspi->POPR.R;
+ if (spip->rx_ptr != NULL) {
+ if (spip->dspi->CTAR[0].B.FMSZ < 8)
+ *spip->rx_ptr8++ = (uint8_t)frame;
+ else
+ *spip->rx_ptr16++ = (uint16_t)frame;
+ }
+ spip->rx_cnt--;
+ }
+
+ /* Interrupt served.*/
+ spip->dspi->SR.B.RFDF = 1;
+
+ if (spip->rx_cnt == 0) {
+ /* Stops the transfer.*/
+ spi_dspi_stop(spip);
+
+ /* Portable SPI ISR code defined in the high level driver, note, it is
+ a macro.*/
+ _spi_isr_code(spip);
+ }
+ else {
+ if (spip->tx_cnt > 0) {
+ /* Filling the TX FIFO.*/
+ if (spip->tx_ptr == NULL)
+ spi_dspi_prefill_txfifo_idle(spip, &spip->tx_cnt);
+ else {
+ if (spip->dspi->CTAR[0].B.FMSZ < 8)
+ spi_dspi_prefill_txfifo8(spip, &spip->tx_cnt, &spip->tx_ptr8);
+ else
+ spi_dspi_prefill_txfifo16(spip, &spip->tx_cnt, &spip->tx_ptr16);
+ }
+ }
+ }
+
+ osalSysUnlockFromISR();
+}
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+/**
+ * @brief Shared ISR for TFFF DSPI events.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_serve_dspi_tfff(SPIDriver *spip) {
+
+ osalSysLockFromISR();
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+ /* Interrupt served and back to DMA mode.*/
+ spip->dspi->RSER.B.TFFFDIRS = 1;
+ spip->dspi->SR.B.TFFF = 1;
+
+ /* Pushing last frame.*/
+ spip->dspi->PUSHR.R = (spip->config->pushr | spip->tx_last | SPC5_PUSHR_EOQ) &
+ ~SPC5_PUSHR_CONT;
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX */
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_ONLY
+ /* Pushing some more frames in the TX FIFO.*/
+ if (spip->tx_ptr == NULL)
+ spi_dspi_prefill_txfifo_idle(spip, &spip->tx_cnt);
+ else {
+ if (spip->dspi->CTAR[0].B.FMSZ < 8)
+ spi_dspi_prefill_txfifo8(spip, &spip->tx_cnt, &spip->tx_ptr8);
+ else
+ spi_dspi_prefill_txfifo16(spip, &spip->tx_cnt, &spip->tx_ptr16);
+ }
+
+ /* Interrupt served.*/
+ spip->dspi->SR.B.TFFF = 1;
+
+ /* If there are no more frames to be pushed then the TFFF interrupt source
+ is disabled.*/
+ if (spip->tx_cnt == 0)
+ spip->dspi->RSER.B.TFFFRE = 0;
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_ONLY */
+
+ osalSysUnlockFromISR();
+}
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+#if SPC5_SPI_USE_DSPI0 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI0_RFDF_HANDLER)
+#error "SPC5_DSPI0_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI0 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI0_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI0 */
+
+#if SPC5_SPI_USE_DSPI1 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI1_RFDF_HANDLER)
+#error "SPC5_DSPI1_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI1 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI1_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI1 */
+
+#if SPC5_SPI_USE_DSPI2 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI2_RFDF_HANDLER)
+#error "SPC5_DSPI2_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI2 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI2_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI2 */
+
+#if SPC5_SPI_USE_DSPI3 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI3_RFDF_HANDLER)
+#error "SPC5_DSPI3_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI3 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI3_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI3 */
+
+#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI4_RFDF_HANDLER)
+#error "SPC5_DSPI4_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI4 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI4_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI4 */
+
+#if SPC5_SPI_USE_DSPI5 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI5_RFDF_HANDLER)
+#error "SPC5_DSPI5_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI5 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI5_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI5 */
+
+#if SPC5_SPI_USE_DSPI6 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI6_RFDF_HANDLER)
+#error "SPC5_DSPI6_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI6 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI6_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI6 */
+
+#if SPC5_SPI_USE_DSPI7 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI7_RFDF_HANDLER)
+#error "SPC5_DSPI7_RFDF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI7 RFDF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI7_RFDF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_rfdf(&SPID8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI7 */
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE */
+
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+#if SPC5_SPI_USE_DSPI0 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI0_TFFF_HANDLER)
+#error "SPC5_DSPI0_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI0 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI0_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI0 */
+
+#if SPC5_SPI_USE_DSPI1 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI1_TFFF_HANDLER)
+#error "SPC5_DSPI1_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI1 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI1_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI1 */
+
+#if SPC5_SPI_USE_DSPI2 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI2_TFFF_HANDLER)
+#error "SPC5_DSPI2_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI2 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI2_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI2 */
+
+#if SPC5_SPI_USE_DSPI3 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI3_TFFF_HANDLER)
+#error "SPC5_DSPI3_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI3 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI3_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI3 */
+
+#if SPC5_SPI_USE_DSPI4 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI4_TFFF_HANDLER)
+#error "SPC5_DSPI4_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI4 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI4_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI4 */
+
+#if SPC5_SPI_USE_DSPI5 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI5_TFFF_HANDLER)
+#error "SPC5_DSPI5_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI5 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI5_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI5 */
+
+#if SPC5_SPI_USE_DSPI6 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI6_TFFF_HANDLER)
+#error "SPC5_DSPI6_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI6 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI6_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI6 */
+
+#if SPC5_SPI_USE_DSPI7 || defined(__DOXYGEN__)
+#if !defined(SPC5_DSPI7_TFFF_HANDLER)
+#error "SPC5_DSPI7_TFFF_HANDLER not defined"
+#endif
+/**
+ * @brief DSPI7 TFFF interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_DSPI7_TFFF_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spi_serve_dspi_tfff(&SPID8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_SPI_USE_DSPI7 */
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SPI driver initialization.
+ *
+ * @notapi
+ */
+void spi_lld_init(void) {
+
+#if SPC5_SPI_USE_DSPI0
+ /* Driver initialization.*/
+ SPC5_DSPI0_ENABLE_CLOCK();
+ spiObjectInit(&SPID1);
+ spi_lld_obj_init(&SPID1, &SPC5_DSPI0);
+ SPC5_DSPI0.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI0_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI0_RFDF_NUMBER].R = SPC5_SPI_DSPI0_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI0_TFFF_NUMBER].R = SPC5_SPI_DSPI0_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI0 */
+
+#if SPC5_SPI_USE_DSPI1
+ /* Driver initialization.*/
+ SPC5_DSPI1_ENABLE_CLOCK();
+ spiObjectInit(&SPID2);
+ spi_lld_obj_init(&SPID2, &SPC5_DSPI1);
+ SPC5_DSPI1.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI1_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI1_RFDF_NUMBER].R = SPC5_SPI_DSPI1_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI1_TFFF_NUMBER].R = SPC5_SPI_DSPI1_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI1 */
+
+#if SPC5_SPI_USE_DSPI2
+ /* Driver initialization.*/
+ SPC5_DSPI2_ENABLE_CLOCK();
+ spiObjectInit(&SPID3);
+ spi_lld_obj_init(&SPID3, &SPC5_DSPI2);
+ SPC5_DSPI2.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI2_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI2_RFDF_NUMBER].R = SPC5_SPI_DSPI2_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI2_TFFF_NUMBER].R = SPC5_SPI_DSPI2_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI2 */
+
+#if SPC5_SPI_USE_DSPI3
+ /* Driver initialization.*/
+ SPC5_DSPI3_ENABLE_CLOCK();
+ spiObjectInit(&SPID4);
+ spi_lld_obj_init(&SPID4, &SPC5_DSPI3);
+ SPC5_DSPI3.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI3_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI3_RFDF_NUMBER].R = SPC5_SPI_DSPI3_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI3_TFFF_NUMBER].R = SPC5_SPI_DSPI3_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI3 */
+
+#if SPC5_SPI_USE_DSPI4
+ /* Driver initialization.*/
+ SPC5_DSPI4_ENABLE_CLOCK();
+ spiObjectInit(&SPID5);
+ spi_lld_obj_init(&SPID5, &SPC5_DSPI4);
+ SPC5_DSPI4.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI4_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI4_RFDF_NUMBER].R = SPC5_SPI_DSPI4_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI4_TFFF_NUMBER].R = SPC5_SPI_DSPI4_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI4 */
+
+#if SPC5_SPI_USE_DSPI5
+ /* Driver initialization.*/
+ SPC5_DSPI5_ENABLE_CLOCK();
+ spiObjectInit(&SPID6);
+ spi_lld_obj_init(&SPID6, &SPC5_DSPI5);
+ SPC5_DSPI5.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI5_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI5_RFDF_NUMBER].R = SPC5_SPI_DSPI5_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI5_TFFF_NUMBER].R = SPC5_SPI_DSPI5_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI5 */
+
+#if SPC5_SPI_USE_DSPI6
+ /* Driver initialization.*/
+ SPC5_DSPI6_ENABLE_CLOCK();
+ spiObjectInit(&SPID7);
+ spi_lld_obj_init(&SPID7, &SPC5_DSPI6);
+ SPC5_DSPI6.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI6_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI6_RFDF_NUMBER].R = SPC5_SPI_DSPI6_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI6_TFFF_NUMBER].R = SPC5_SPI_DSPI6_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI6 */
+
+#if SPC5_SPI_USE_DSPI7
+ /* Driver initialization.*/
+ SPC5_DSPI7_ENABLE_CLOCK();
+ spiObjectInit(&SPID8);
+ spi_lld_obj_init(&SPID8, &SPC5_DSPI7);
+ SPC5_DSPI7.MCR.R = SPC5_MCR_MSTR | SPC5_MCR_HALT | SPC5_MCR_MDIS |
+ SPC5_SPI_DSPI7_MCR;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ INTC.PSR[SPC5_DSPI7_RFDF_NUMBER].R = SPC5_SPI_DSPI7_IRQ_PRIO;
+#else
+ INTC.PSR[SPC5_DSPI7_TFFF_NUMBER].R = SPC5_SPI_DSPI7_IRQ_PRIO;
+#endif
+#endif /* SPC5_SPI_USE_DSPI7 */
+}
+
+/**
+ * @brief Configures and activates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_start(SPIDriver *spip) {
+
+ osalDbgAssert((spip->config->pushr & DSPI_PUSHR_EXCLUDED_BITS) == 0,
+ "invalid PUSHR bits specified");
+
+ if (spip->state == SPI_STOP) {
+ /* Enables the peripheral.*/
+
+#if SPC5_SPI_USE_DSPI0
+ if (&SPID1 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi0_tx1_dma_config,
+ spi_dspi0_tx2_dma_config,
+ spi_dspi0_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI0 */
+
+#if SPC5_SPI_USE_DSPI1
+ if (&SPID2 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi1_tx1_dma_config,
+ spi_dspi1_tx2_dma_config,
+ spi_dspi1_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI1 */
+
+#if SPC5_SPI_USE_DSPI2
+ if (&SPID3 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi2_tx1_dma_config,
+ spi_dspi2_tx2_dma_config,
+ spi_dspi2_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI2 */
+
+#if SPC5_SPI_USE_DSPI3
+ if (&SPID4 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi3_tx1_dma_config,
+ spi_dspi3_tx2_dma_config,
+ spi_dspi3_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI3 */
+
+#if SPC5_SPI_USE_DSPI4
+ if (&SPID5 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi4_tx1_dma_config,
+ spi_dspi4_tx2_dma_config,
+ spi_dspi4_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI4 */
+
+#if SPC5_SPI_USE_DSPI5
+ if (&SPID6 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi5_tx1_dma_config,
+ spi_dspi5_tx2_dma_config,
+ spi_dspi5_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI5 */
+
+#if SPC5_SPI_USE_DSPI6
+ if (&SPID7 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi6_tx1_dma_config,
+ spi_dspi6_tx2_dma_config,
+ spi_dspi6_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI6 */
+
+#if SPC5_SPI_USE_DSPI7
+ if (&SPID8 == spip) {
+ spi_lld_setdma(spip,
+ spi_dspi7_tx1_dma_config,
+ spi_dspi7_tx2_dma_config,
+ spi_dspi7_rx_dma_config)
+ }
+#endif /* SPC5_SPI_USE_DSPI7 */
+
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+ osalDbgAssert((spip->tx1_channel != EDMA_ERROR) &&
+ (spip->tx2_channel != EDMA_ERROR),
+ "TX DMA channels cannot be allocated");
+#endif
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE
+ osalDbgAssert(spip->rx_channel != EDMA_ERROR,
+ "RX DMA channels cannot be allocated");
+#endif
+ }
+
+ /* Configures the peripheral, the RSER register setting depend on the
+ chosen DMA use mode.*/
+ spip->dspi->MCR.B.MDIS = 0;
+ spip->dspi->CTAR[0].R = spip->config->ctar0;
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE
+ spip->dspi->RSER.R = SPC5_RSER_RFDF_RE;
+#endif
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_ONLY
+ spip->dspi->RSER.R = SPC5_RSER_RFDF_RE | SPC5_RSER_RFDF_DIRS;
+#endif
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+ spip->dspi->RSER.R = SPC5_RSER_TFFF_RE | SPC5_RSER_TFFF_DIRS |
+ SPC5_RSER_RFDF_RE | SPC5_RSER_RFDF_DIRS;
+#endif
+ spip->dspi->SR.R = spip->dspi->SR.R;
+}
+
+/**
+ * @brief Deactivates the SPI peripheral.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_stop(SPIDriver *spip) {
+
+ if (spip->state == SPI_READY) {
+ /* Releases the allocated EDMA channels.*/
+#if SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX
+ edmaChannelRelease(spip->tx1_channel);
+ edmaChannelRelease(spip->tx2_channel);
+#endif
+#if SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE
+ edmaChannelRelease(spip->rx_channel);
+#endif
+
+ /* Resets the peripheral.*/
+ spip->dspi->CTAR[0].R = 0;
+ spip->dspi->RSER.R = 0;
+ spip->dspi->SR.R = spip->dspi->SR.R;
+ spip->dspi->MCR.R |= SPC5_MCR_HALT |
+ SPC5_MCR_CLR_TXF | SPC5_MCR_CLR_RXF;
+ spip->dspi->MCR.B.MDIS = 1;
+ }
+}
+
+/**
+ * @brief Asserts the slave select signal and prepares for transfers.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_select(SPIDriver *spip) {
+
+ palClearPad(spip->config->ssport, spip->config->sspad);
+}
+
+/**
+ * @brief Deasserts the slave select signal.
+ * @details The previously selected peripheral is unselected.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ *
+ * @notapi
+ */
+void spi_lld_unselect(SPIDriver *spip) {
+
+ palSetPad(spip->config->ssport, spip->config->sspad);
+}
+
+/**
+ * @brief Ignores data on the SPI bus.
+ * @details This asynchronous function starts the transmission of a series of
+ * idle words on the SPI bus and ignores the received data.
+ * @post At the end of the operation the configured callback is invoked.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be ignored
+ *
+ * @notapi
+ */
+void spi_lld_ignore(SPIDriver *spip, size_t n) {
+
+ /* Starting transfer.*/
+ spi_dspi_start(spip);
+
+ /* Setting up the DMA channels.*/
+ spi_start_rx_ignore(spip, n);
+ spi_start_tx_ignore(spip, n);
+}
+
+/**
+ * @brief Exchanges data on the SPI bus.
+ * @details This asynchronous function starts a simultaneous transmit/receive
+ * operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to be exchanged
+ * @param[in] txbuf the pointer to the transmit buffer
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf) {
+
+ /* Starting transfer.*/
+ spi_dspi_start(spip);
+
+ /* DMAs require a different setup depending on the frame size.*/
+ if (spip->dspi->CTAR[0].B.FMSZ < 8) {
+ spi_start_rx8(spip, n, rxbuf);
+ spi_start_tx8(spip, n, txbuf);
+ }
+ else {
+ spi_start_rx16(spip, n, rxbuf);
+ spi_start_tx16(spip, n, txbuf);
+ }
+}
+
+/**
+ * @brief Sends data over the SPI bus.
+ * @details This asynchronous function starts a transmit operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to send
+ * @param[in] txbuf the pointer to the transmit buffer
+ *
+ * @notapi
+ */
+void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
+
+ /* Starting transfer.*/
+ spi_dspi_start(spip);
+
+ /* Setting up the RX DMA channel.*/
+ spi_start_rx_ignore(spip, n);
+
+ /* DMAs require a different setup depending on the frame size.*/
+ if (spip->dspi->CTAR[0].B.FMSZ < 8)
+ spi_start_tx8(spip, n, txbuf);
+ else
+ spi_start_tx16(spip, n, txbuf);
+}
+
+/**
+ * @brief Receives data from the SPI bus.
+ * @details This asynchronous function starts a receive operation.
+ * @post At the end of the operation the configured callback is invoked.
+ * @note The buffers are organized as uint8_t arrays for data sizes below or
+ * equal to 8 bits else it is organized as uint16_t arrays.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] n number of words to receive
+ * @param[out] rxbuf the pointer to the receive buffer
+ *
+ * @notapi
+ */
+void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
+
+ /* Starting transfer.*/
+ spi_dspi_start(spip);
+
+ /* DMAs require a different setup depending on the frame size.*/
+ if (spip->dspi->CTAR[0].B.FMSZ < 8)
+ spi_start_rx8(spip, n, rxbuf);
+ else
+ spi_start_rx16(spip, n, rxbuf);
+
+ spi_start_tx_ignore(spip, n);
+}
+
+/**
+ * @brief Exchanges one frame using a polled wait.
+ * @details This synchronous function exchanges one frame using a polled
+ * synchronization method. This function is useful when exchanging
+ * small amount of data on high speed channels, usually in this
+ * situation is much more efficient just wait for completion using
+ * polling than suspending the thread waiting for an interrupt.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] frame the data frame to send over the SPI bus
+ * @return The received data frame from the SPI bus.
+ */
+uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
+ uint32_t popr;
+
+ /* Starting transfer.*/
+ spi_dspi_start(spip);
+
+ /* Data exchange.*/
+ spip->dspi->PUSHR.R = (SPC5_PUSHR_EOQ | spip->config->pushr |
+ (uint32_t)frame) & ~SPC5_PUSHR_CONT;
+ while (!spip->dspi->SR.B.RFDF)
+ ;
+ popr = spip->dspi->POPR.R;
+
+ /* Stopping transfer.*/
+ spi_dspi_stop(spip);
+
+ return (uint16_t)popr;
+}
+
+#endif /* HAL_USE_SPI */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.h b/os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.h
new file mode 100644
index 000000000..397f96efe
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/DSPI_v1/hal_spi_lld.h
@@ -0,0 +1,848 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/DSPI_v1/hal_spi_lld.h
+ * @brief SPC5xx SPI subsystem low level driver header.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef HAL_SPI_LLD_H
+#define HAL_SPI_LLD_H
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+#include "spc5_dspi.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name SPI DMA modes
+ * @{
+ */
+#define SPC5_SPI_DMA_NONE 0
+#define SPC5_SPI_DMA_RX_ONLY 1
+#define SPC5_SPI_DMA_RX_AND_TX 2
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief SPID1 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI0 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI0) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI0 FALSE
+#endif
+
+/**
+ * @brief SPID2 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI1 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI1) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI1 FALSE
+#endif
+
+/**
+ * @brief SPID3 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI2 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI2) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI2 FALSE
+#endif
+
+/**
+ * @brief SPID4 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI3 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI3) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI3 FALSE
+#endif
+
+/**
+ * @brief SPID5 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI4 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI4) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI4 FALSE
+#endif
+
+/**
+ * @brief SPID6 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI5 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI5) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI5 FALSE
+#endif
+
+/**
+ * @brief SPID7 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI6 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI6) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI6 FALSE
+#endif
+
+/**
+ * @brief SPID8 driver enable switch.
+ * @details If set to @p TRUE the support for DSPI7 is included.
+ */
+#if !defined(SPC5_SPI_USE_DSPI7) || defined(__DOXYGEN__)
+#define SPC5_SPI_USE_DSPI7 FALSE
+#endif
+
+/**
+ * @brief Selects the DMA mode for the SPI driver.
+ * @details The driver is able to work using three distinct DMA modes:
+ * - SPC5_SPI_DMA_RX_AND_TX, 3 DMA channels are used for both RX
+ * and TX. Note, the transmission size is limited to 512 frames
+ * in this mode because EDMA limitations.
+ * - SPC5_SPI_DMA_RX_ONLY, 1 DMA channels is used for RX only. TX
+ * is handled using interrupts.
+ * - SPC5_SPI_DMA_NONE, the DMA is not used at all, the drivers
+ * works in a fully interrupt-driven way.
+ * .
+ * @note DMA modes are only possible on those platforms where a DMA
+ * controllers is present.
+ */
+#if !defined(SPC5_SPI_DMA_MODE) || defined(__DOXYGEN__)
+#define SPC5_SPI_DMA_MODE SPC5_SPI_DMA_NONE
+#endif
+
+/**
+ * @brief DSPI0 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI0_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI0_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI1 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI1_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI1_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSP2 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI2_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI2_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI3 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI3_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI3_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI4 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI4_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI4_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI5 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI5_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI5_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI6 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI6_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI6_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI7 MCR PCS defaults.
+ */
+#if !defined(SPC5_SPI_DSPI7_MCR) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI7_MCR (SPC5_MCR_PCSIS0 | \
+ SPC5_MCR_PCSIS1 | \
+ SPC5_MCR_PCSIS2 | \
+ SPC5_MCR_PCSIS3 | \
+ SPC5_MCR_PCSIS4 | \
+ SPC5_MCR_PCSIS5 | \
+ SPC5_MCR_PCSIS6 | \
+ SPC5_MCR_PCSIS7)
+#endif
+
+/**
+ * @brief DSPI0 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI0_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI0_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI1 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI1_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI1_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI2 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI2_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI2_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI3 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI3_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI3_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI4 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI4_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI4_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI5 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI5_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI5_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI6 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI6_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI6_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI7 DMA IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI7_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI7_DMA_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief SPI DMA error hook.
+ */
+#if !defined(SPC5_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define SPC5_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DSPI DMA failure")
+#endif
+
+/**
+ * @brief DSPI0 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI0_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI0_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI1 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI1_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI1_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI2 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI2_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI2_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI3 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI3_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI3_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI4 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI4_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI4_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI5 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI5_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI5_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI6 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI6_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI6_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI7 IRQ priority.
+ */
+#if !defined(SPC5_SPI_DSPI7_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI7_IRQ_PRIO 10
+#endif
+
+/**
+ * @brief DSPI0 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI0_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI0_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI0 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI0_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI0_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI1 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI1_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI1_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI1 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI1_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI1_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI2 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI2_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI2_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI2 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI2_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI2_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI3 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI3_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI3_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI3 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI3_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI3_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI4 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI4_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI4_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI4 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI4_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI4_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI5 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI5_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI5_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI5 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI5_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI5_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI6 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI6_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI6_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI6 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI6_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI6_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief DSPI7 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI7_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI7_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief DSPI7 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SPI_DSPI7_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SPI_DSPI7_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !(SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE) && \
+ !(SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_ONLY) && \
+ !(SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX)
+#error "invalid SPC5_SPI_DMA_MODE selected"
+#endif
+
+#if !SPC5_HAS_EDMA && (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE)
+#error "SPI with DMA modes are not supported on this device, no DMA found"
+#endif
+
+#if SPC5_SPI_USE_DSPI0 && !SPC5_HAS_DSPI0
+#error "DSPI0 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI1 && !SPC5_HAS_DSPI1
+#error "DSPI1 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI2 && !SPC5_HAS_DSPI2
+#error "DSPI2 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI3 && !SPC5_HAS_DSPI3
+#error "DSPI3 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI4 && !SPC5_HAS_DSPI4
+#error "DSPI4 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI5 && !SPC5_HAS_DSPI5
+#error "DSPI5 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI6 && !SPC5_HAS_DSPI6
+#error "DSPI6 not present in the selected device"
+#endif
+
+#if SPC5_SPI_USE_DSPI7 && !SPC5_HAS_DSPI7
+#error "DSPI7 not present in the selected device"
+#endif
+
+#if !SPC5_SPI_USE_DSPI0 && !SPC5_SPI_USE_DSPI1 && \
+ !SPC5_SPI_USE_DSPI2 && !SPC5_SPI_USE_DSPI3 && \
+ !SPC5_SPI_USE_DSPI4 && !SPC5_SPI_USE_DSPI5 && \
+ !SPC5_SPI_USE_DSPI6 && !SPC5_SPI_USE_DSPI7
+#error "SPI driver activated but no DSPI peripheral assigned"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI0 && \
+ (!defined(SPC5_SPI_DSPI0_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI0_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI0_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI0, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI1 && \
+ (!defined(SPC5_SPI_DSPI1_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI1_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI1_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI1, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI2 && \
+ (!defined(SPC5_SPI_DSPI2_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI2_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI2_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI2, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI3 && \
+ (!defined(SPC5_SPI_DSPI3_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI3_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI3_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI3, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI4 && \
+ (!defined(SPC5_SPI_DSPI4_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI4_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI4_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI4, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI5 && \
+ (!defined(SPC5_SPI_DSPI5_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI5_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI5_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI5, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI6 && \
+ (!defined(SPC5_SPI_DSPI6_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI6_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI6_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI6, check mcuconf.h"
+#endif
+
+#if SPC5_HAS_EDMA && SPC5_SPI_USE_DSPI7 && \
+ (!defined(SPC5_SPI_DSPI7_TX1_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI7_TX2_DMA_CH_ID) || \
+ !defined(SPC5_SPI_DSPI7_RX_DMA_CH_ID))
+#error "DMA channels not defined for DSPI7, check mcuconf.h"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an SPI driver.
+ */
+typedef struct SPIDriver SPIDriver;
+
+/**
+ * @brief SPI notification callback type.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object triggering the
+ * callback
+ */
+typedef void (*spicallback_t)(SPIDriver *spip);
+
+/**
+ * @brief Driver configuration structure.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+typedef struct {
+ /**
+ * @brief Operation complete callback.
+ */
+ spicallback_t end_cb;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief The chip select line port.
+ */
+ ioportid_t ssport;
+ /**
+ * @brief The chip select line pad number.
+ */
+ uint16_t sspad;
+ /**
+ * @brief DSPI CTAR0 value for this session.
+ */
+ uint32_t ctar0;
+ /**
+ * @brief DSPI PUSHR command for this session.
+ * @note Only CTAR0 can be referenced, the other CTARs are not
+ * initialized. The data part must be left to zero.
+ */
+ uint32_t pushr;
+} SPIConfig;
+
+/**
+ * @brief Structure representing an SPI driver.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+struct SPIDriver {
+ /**
+ * @brief Driver state.
+ */
+ volatile spistate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const SPIConfig *config;
+#if SPI_USE_WAIT || defined(__DOXYGEN__)
+ /**
+ * @brief Waiting thread.
+ */
+ thread_reference_t thread;
+#endif /* SPI_USE_WAIT */
+#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the peripheral.
+ */
+ mutex_t mutex;
+#endif /* SPI_USE_MUTUAL_EXCLUSION */
+#if defined(SPI_DRIVER_EXT_FIELDS)
+ SPI_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the DSPI registers block.
+ */
+ struct spc5_dspi *dspi;
+#if (SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_NONE) || defined(__DOXYGEN__)
+ /**
+ * @brief EDMA channel used for receive.
+ */
+ edma_channel_t rx_channel;
+#else /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE */
+ /**
+ * @brief Memory pointer for RX operations.
+ */
+ union {
+ void *rx_ptr;
+ uint8_t *rx_ptr8;
+ uint16_t *rx_ptr16;
+ };
+ /**
+ * @brief Remaining frames to be received.
+ */
+ size_t rx_cnt;
+#endif /* SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_NONE */
+#if (SPC5_SPI_DMA_MODE == SPC5_SPI_DMA_RX_AND_TX) || defined(__DOXYGEN__)
+ /**
+ * @brief EDMA channel used for data memory to memory copy.
+ */
+ edma_channel_t tx1_channel;
+ /**
+ * @brief EDMA channel used for transmit.
+ */
+ edma_channel_t tx2_channel;
+ /**
+ * @brief Command for the ongoing TX operation.
+ */
+ uint32_t tx_cmd;
+ /**
+ * @brief Last frame of a transmission sequence.
+ */
+ uint32_t tx_last;
+#else /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_RX_AND_TX */
+ /**
+ * @brief Memory pointer for TX operations.
+ */
+ union {
+ const void *tx_ptr;
+ const uint8_t *tx_ptr8;
+ const uint16_t *tx_ptr16;
+ };
+ /**
+ * @brief Remaining frames to be transmitted.
+ */
+ size_t tx_cnt;
+#endif /* SPC5_SPI_DMA_MODE != SPC5_SPI_DMA_RX_AND_TX */
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if SPC5_SPI_USE_DSPI0 && !defined(__DOXYGEN__)
+extern SPIDriver SPID1;
+#endif
+
+#if SPC5_SPI_USE_DSPI1 && !defined(__DOXYGEN__)
+extern SPIDriver SPID2;
+#endif
+
+#if SPC5_SPI_USE_DSPI2 && !defined(__DOXYGEN__)
+extern SPIDriver SPID3;
+#endif
+
+#if SPC5_SPI_USE_DSPI3 && !defined(__DOXYGEN__)
+extern SPIDriver SPID4;
+#endif
+
+#if SPC5_SPI_USE_DSPI4 && !defined(__DOXYGEN__)
+extern SPIDriver SPID5;
+#endif
+
+#if SPC5_SPI_USE_DSPI5 && !defined(__DOXYGEN__)
+extern SPIDriver SPID6;
+#endif
+
+#if SPC5_SPI_USE_DSPI6 && !defined(__DOXYGEN__)
+extern SPIDriver SPID7;
+#endif
+
+#if SPC5_SPI_USE_DSPI7 && !defined(__DOXYGEN__)
+extern SPIDriver SPID8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void spi_lld_init(void);
+ void spi_lld_start(SPIDriver *spip);
+ void spi_lld_stop(SPIDriver *spip);
+ void spi_lld_select(SPIDriver *spip);
+ void spi_lld_unselect(SPIDriver *spip);
+ void spi_lld_ignore(SPIDriver *spip, size_t n);
+ void spi_lld_exchange(SPIDriver *spip, size_t n,
+ const void *txbuf, void *rxbuf);
+ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
+ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SPI */
+
+#endif /* HAL_SPI_LLD_H */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/DSPI_v1/spc5_dspi.h b/os/hal/ports/SPC5/LLD/DSPI_v1/spc5_dspi.h
new file mode 100644
index 000000000..6f88f5edd
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/DSPI_v1/spc5_dspi.h
@@ -0,0 +1,460 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file DSPI_v1/spc5_dspi.h
+ * @brief SPC5xx DSPI header file.
+ *
+ * @addtogroup SPI
+ * @{
+ */
+
+#ifndef _SPC5_DSPI_H_
+#define _SPC5_DSPI_H_
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name MCR register definitions
+ * @{
+ */
+#define SPC5_MCR_MSTR (1U << 31)
+#define SPC5_MCR_CONT_SCKE (1U << 30)
+#define SPC5_MCR_DCONF_MASK (3U << 28)
+#define SPC5_MCR_FRZ (1U << 27)
+#define SPC5_MCR_MTFE (1U << 26)
+#define SPC5_MCR_PCSSE (1U << 25)
+#define SPC5_MCR_ROOE (1U << 24)
+#define SPC5_MCR_PCSIS7 (1U << 23)
+#define SPC5_MCR_PCSIS6 (1U << 22)
+#define SPC5_MCR_PCSIS5 (1U << 21)
+#define SPC5_MCR_PCSIS4 (1U << 20)
+#define SPC5_MCR_PCSIS3 (1U << 19)
+#define SPC5_MCR_PCSIS2 (1U << 18)
+#define SPC5_MCR_PCSIS1 (1U << 17)
+#define SPC5_MCR_PCSIS0 (1U << 16)
+#define SPC5_MCR_DOZE (1U << 15)
+#define SPC5_MCR_MDIS (1U << 14)
+#define SPC5_MCR_DIS_TXF (1U << 13)
+#define SPC5_MCR_DIS_RXF (1U << 12)
+#define SPC5_MCR_CLR_TXF (1U << 11)
+#define SPC5_MCR_CLR_RXF (1U << 10)
+#define SPC5_MCR_SMPL_PT_MASK (3U << 8)
+#define SPC5_MCR_SMPL_PT(n) ((n) << 8)
+#define SPC5_MCR_FCPCS (1U << 2)
+#define SPC5_MCR_PES (1U << 1)
+#define SPC5_MCR_HALT (1U << 0)
+/** @} */
+
+/**
+ * @name RSER register definitions
+ * @{
+ */
+#define SPC5_RSER_TCF_RE (1U << 31)
+#define SPC5_RSER_DSITCF_RE (1U << 29)
+#define SPC5_RSER_EOQF_RE (1U << 28)
+#define SPC5_RSER_TFUF_RE (1U << 27)
+#define SPC5_RSER_SPITCF_RE (1U << 26)
+#define SPC5_RSER_TFFF_RE (1U << 25)
+#define SPC5_RSER_TFFF_DIRS (1U << 24)
+#define SPC5_RSER_DPEF_RE (1U << 22)
+#define SPC5_RSER_SPEF_RE (1U << 21)
+#define SPC5_RSER_DDIF_RE (1U << 20)
+#define SPC5_RSER_RFOF_RE (1U << 19)
+#define SPC5_RSER_RFDF_RE (1U << 17)
+#define SPC5_RSER_RFDF_DIRS (1U << 16)
+/** @} */
+
+/**
+ * @name CTAR registers definitions
+ * @{
+ */
+#define SPC5_CTAR_DBR (1U << 31)
+#define SPC5_CTAR_FMSZ_MASK (15U << 27)
+#define SPC5_CTAR_FMSZ(n) (((n) - 1) << 27)
+#define SPC5_CTAR_CPOL (1U << 26)
+#define SPC5_CTAR_CPHA (1U << 25)
+#define SPC5_CTAR_LSBFE (1U << 24)
+#define SPC5_CTAR_PCSSCK_MASK (3U << 22)
+#define SPC5_CTAR_PCSSCK_PRE1 (0U << 22)
+#define SPC5_CTAR_PCSSCK_PRE3 (1U << 22)
+#define SPC5_CTAR_PCSSCK_PRE5 (2U << 22)
+#define SPC5_CTAR_PCSSCK_PRE7 (3U << 22)
+#define SPC5_CTAR_PASC_MASK (3U << 20)
+#define SPC5_CTAR_PASC_PRE1 (0U << 20)
+#define SPC5_CTAR_PASC_PRE3 (1U << 20)
+#define SPC5_CTAR_PASC_PRE5 (2U << 20)
+#define SPC5_CTAR_PASC_PRE7 (3U << 20)
+#define SPC5_CTAR_PDT_MASK (3U << 18)
+#define SPC5_CTAR_PDT_PRE1 (0U << 18)
+#define SPC5_CTAR_PDT_PRE3 (1U << 18)
+#define SPC5_CTAR_PDT_PRE5 (2U << 18)
+#define SPC5_CTAR_PDT_PRE7 (3U << 18)
+#define SPC5_CTAR_PBR_MASK (3U << 16)
+#define SPC5_CTAR_PBR_PRE2 (0U << 16)
+#define SPC5_CTAR_PBR_PRE3 (1U << 16)
+#define SPC5_CTAR_PBR_PRE5 (2U << 16)
+#define SPC5_CTAR_PBR_PRE7 (3U << 16)
+#define SPC5_CTAR_CSSCK_MASK (15U << 12)
+#define SPC5_CTAR_CSSCK_DIV2 (0U << 12)
+#define SPC5_CTAR_CSSCK_DIV4 (1U << 12)
+#define SPC5_CTAR_CSSCK_DIV8 (2U << 12)
+#define SPC5_CTAR_CSSCK_DIV16 (3U << 12)
+#define SPC5_CTAR_CSSCK_DIV32 (4U << 12)
+#define SPC5_CTAR_CSSCK_DIV64 (5U << 12)
+#define SPC5_CTAR_CSSCK_DIV128 (6U << 12)
+#define SPC5_CTAR_CSSCK_DIV256 (7U << 12)
+#define SPC5_CTAR_CSSCK_DIV512 (8U << 12)
+#define SPC5_CTAR_CSSCK_DIV1024 (9U << 12)
+#define SPC5_CTAR_CSSCK_DIV2048 (10U << 12)
+#define SPC5_CTAR_CSSCK_DIV4096 (11U << 12)
+#define SPC5_CTAR_CSSCK_DIV8192 (12U << 12)
+#define SPC5_CTAR_CSSCK_DIV16384 (13U << 12)
+#define SPC5_CTAR_CSSCK_DIV32768 (14U << 12)
+#define SPC5_CTAR_CSSCK_DIV65536 (15U << 12)
+#define SPC5_CTAR_ASC_MASK (15U << 8)
+#define SPC5_CTAR_ASC_DIV2 (0U << 8)
+#define SPC5_CTAR_ASC_DIV4 (1U << 8)
+#define SPC5_CTAR_ASC_DIV8 (2U << 8)
+#define SPC5_CTAR_ASC_DIV16 (3U << 8)
+#define SPC5_CTAR_ASC_DIV32 (4U << 8)
+#define SPC5_CTAR_ASC_DIV64 (5U << 8)
+#define SPC5_CTAR_ASC_DIV128 (6U << 8)
+#define SPC5_CTAR_ASC_DIV256 (7U << 8)
+#define SPC5_CTAR_ASC_DIV512 (8U << 8)
+#define SPC5_CTAR_ASC_DIV1024 (9U << 8)
+#define SPC5_CTAR_ASC_DIV2048 (10U << 8)
+#define SPC5_CTAR_ASC_DIV4096 (11U << 8)
+#define SPC5_CTAR_ASC_DIV8192 (12U << 8)
+#define SPC5_CTAR_ASC_DIV16384 (13U << 8)
+#define SPC5_CTAR_ASC_DIV32768 (14U << 8)
+#define SPC5_CTAR_ASC_DIV65536 (15U << 8)
+#define SPC5_CTAR_DT_MASK (15U << 4)
+#define SPC5_CTAR_DT_DIV2 (0U << 4)
+#define SPC5_CTAR_DT_DIV4 (1U << 4)
+#define SPC5_CTAR_DT_DIV8 (2U << 4)
+#define SPC5_CTAR_DT_DIV16 (3U << 4)
+#define SPC5_CTAR_DT_DIV32 (4U << 4)
+#define SPC5_CTAR_DT_DIV64 (5U << 4)
+#define SPC5_CTAR_DT_DIV128 (6U << 4)
+#define SPC5_CTAR_DT_DIV256 (7U << 4)
+#define SPC5_CTAR_DT_DIV512 (8U << 4)
+#define SPC5_CTAR_DT_DIV1024 (9U << 4)
+#define SPC5_CTAR_DT_DIV2048 (10U << 4)
+#define SPC5_CTAR_DT_DIV4096 (11U << 4)
+#define SPC5_CTAR_DT_DIV8192 (12U << 4)
+#define SPC5_CTAR_DT_DIV16384 (13U << 4)
+#define SPC5_CTAR_DT_DIV32768 (14U << 4)
+#define SPC5_CTAR_DT_DIV65536 (15U << 4)
+#define SPC5_CTAR_BR_MASK (15U << 0)
+#define SPC5_CTAR_BR_DIV2 (0U << 0)
+#define SPC5_CTAR_BR_DIV4 (1U << 0)
+#define SPC5_CTAR_BR_DIV6 (2U << 0)
+#define SPC5_CTAR_BR_DIV8 (3U << 0)
+#define SPC5_CTAR_BR_DIV16 (4U << 0)
+#define SPC5_CTAR_BR_DIV32 (5U << 0)
+#define SPC5_CTAR_BR_DIV64 (6U << 0)
+#define SPC5_CTAR_BR_DIV128 (7U << 0)
+#define SPC5_CTAR_BR_DIV256 (8U << 0)
+#define SPC5_CTAR_BR_DIV512 (9U << 0)
+#define SPC5_CTAR_BR_DIV1024 (10U << 0)
+#define SPC5_CTAR_BR_DIV2048 (11U << 0)
+#define SPC5_CTAR_BR_DIV4096 (12U << 0)
+#define SPC5_CTAR_BR_DIV8192 (13U << 0)
+#define SPC5_CTAR_BR_DIV16384 (14U << 0)
+#define SPC5_CTAR_BR_DIV32768 (15U << 0)
+/** @} */
+
+/**
+ * @name PUSHR register definitions
+ * @{
+ */
+#define SPC5_PUSHR_CONT (1U << 31)
+#define SPC5_PUSHR_CTAS_MASK (3U << 28)
+#define SPC5_PUSHR_CTAS(n) ((n) << 29)
+#define SPC5_PUSHR_EOQ (1U << 27)
+#define SPC5_PUSHR_CTCNT (1U << 26)
+#define SPC5_PUSHR_MASC (1U << 25)
+#define SPC5_PUSHR_MCSC (1U << 24)
+#define SPC5_PUSHR_PCS_MASK (255U << 16)
+#define SPC5_PUSHR_PCS(n) ((1U << (n)) << 16)
+#define SPC5_PUSHR_TXDATA_MASK (0xFFFFU << 0)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+struct spc5_dspi {
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t MSTR :1;
+ vuint32_t CONT_SCKE :1;
+ vuint32_t DCONF :2;
+ vuint32_t FRZ :1;
+ vuint32_t MTFE :1;
+ vuint32_t PCSSE :1;
+ vuint32_t ROOE :1;
+ vuint32_t PCSIS7 :1;
+ vuint32_t PCSIS6 :1;
+ vuint32_t PCSIS5 :1;
+ vuint32_t PCSIS4 :1;
+ vuint32_t PCSIS3 :1;
+ vuint32_t PCSIS2 :1;
+ vuint32_t PCSIS1 :1;
+ vuint32_t PCSIS0 :1;
+ vuint32_t :1;
+ vuint32_t MDIS :1;
+ vuint32_t DIS_TXF :1;
+ vuint32_t DIS_RXF :1;
+ vuint32_t CLR_TXF :1;
+ vuint32_t CLR_RXF :1;
+ vuint32_t SMPL_PT :2;
+ vuint32_t :7;
+ vuint32_t HALT :1;
+ } B;
+ } MCR; /* Module Configuration Register */
+
+ uint32_t dspi_reserved1;
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t TCNT :16;
+ vuint32_t :16;
+ } B;
+ } TCR;
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t DBR :1;
+ vuint32_t FMSZ :4;
+ vuint32_t CPOL :1;
+ vuint32_t CPHA :1;
+ vuint32_t LSBFE :1;
+ vuint32_t PCSSCK :2;
+ vuint32_t PASC :2;
+ vuint32_t PDT :2;
+ vuint32_t PBR :2;
+ vuint32_t CSSCK :4;
+ vuint32_t ASC :4;
+ vuint32_t DT :4;
+ vuint32_t BR :4;
+ } B;
+ } CTAR[8]; /* Clock and Transfer Attributes Registers */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t TCF :1;
+ vuint32_t TXRXS :1;
+ vuint32_t :1;
+ vuint32_t EOQF :1;
+ vuint32_t TFUF :1;
+ vuint32_t :1;
+ vuint32_t TFFF :1;
+ vuint32_t :5;
+ vuint32_t RFOF :1;
+ vuint32_t :1;
+ vuint32_t RFDF :1;
+ vuint32_t :1;
+ vuint32_t TXCTR :4;
+ vuint32_t TXNXTPTR :4;
+ vuint32_t RXCTR :4;
+ vuint32_t POPNXTPTR :4;
+ } B;
+ } SR; /* Status Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t TCFRE :1;
+ vuint32_t :2;
+ vuint32_t EOQFRE :1;
+ vuint32_t TFUFRE :1;
+ vuint32_t :1;
+ vuint32_t TFFFRE :1;
+ vuint32_t TFFFDIRS :1;
+ vuint32_t :4;
+ vuint32_t RFOFRE :1;
+ vuint32_t :1;
+ vuint32_t RFDFRE :1;
+ vuint32_t RFDFDIRS :1;
+ vuint32_t :16;
+ } B;
+ } RSER; /* DMA/Interrupt Request Select and Enable Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t CONT :1;
+ vuint32_t CTAS :3;
+ vuint32_t EOQ :1;
+ vuint32_t CTCNT :1;
+ vuint32_t :2;
+ vuint32_t PCS7 :1;
+ vuint32_t PCS6 :1;
+ vuint32_t PCS5 :1;
+ vuint32_t PCS4 :1;
+ vuint32_t PCS3 :1;
+ vuint32_t PCS2 :1;
+ vuint32_t PCS1 :1;
+ vuint32_t PCS0 :1;
+ vuint32_t TXDATA :16;
+ } B;
+ } PUSHR; /* PUSH TX FIFO Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :16;
+ vuint32_t RXDATA :16;
+ } B;
+ } POPR; /* POP RX FIFO Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t TXCMD :16;
+ vuint32_t TXDATA :16;
+ } B;
+ } TXFR[5]; /* Transmit FIFO Registers */
+
+ vuint32_t DSPI_reserved_txf[11];
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :16;
+ vuint32_t RXDATA :16;
+ } B;
+ } RXFR[5]; /* Receive FIFO Registers */
+
+ vuint32_t DSPI_reserved_rxf[12];
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t MTOE :1;
+ vuint32_t :1;
+ vuint32_t MTOCNT :6;
+ vuint32_t :4;
+ vuint32_t TXSS :1;
+ vuint32_t TPOL :1;
+ vuint32_t TRRE :1;
+ vuint32_t CID :1;
+ vuint32_t DCONT :1;
+ vuint32_t DSICTAS :3;
+ vuint32_t :6;
+ vuint32_t DPCS5 :1;
+ vuint32_t DPCS4 :1;
+ vuint32_t DPCS3 :1;
+ vuint32_t DPCS2 :1;
+ vuint32_t DPCS1 :1;
+ vuint32_t DPCS0 :1;
+ } B;
+ } DSICR; /* DSI Configuration Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :16;
+ vuint32_t SER_DATA :16;
+ } B;
+ } SDR; /* DSI Serialization Data Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :16;
+ vuint32_t ASER_DATA :16;
+ } B;
+ } ASDR; /* DSI Alternate Serialization Data Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :16;
+ vuint32_t COMP_DATA :16;
+ } B;
+ } COMPR; /* DSI Transmit Comparison Register */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :16;
+ vuint32_t DESER_DATA :16;
+ } B;
+ } DDR; /* DSI deserialization Data Register */
+
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name DSPI units references
+ * @{
+ */
+#if SPC5_HAS_DSPI0 || defined(__DOXYGEN__)
+#define SPC5_DSPI0 (*(struct spc5_dspi *)0xFFF90000U)
+#endif
+
+#if SPC5_HAS_DSPI1 || defined(__DOXYGEN__)
+#define SPC5_DSPI1 (*(struct spc5_dspi *)0xFFF94000U)
+#endif
+
+#if SPC5_HAS_DSPI2 || defined(__DOXYGEN__)
+#define SPC5_DSPI2 (*(struct spc5_dspi *)0xFFF98000U)
+#endif
+
+#if SPC5_HAS_DSPI3 || defined(__DOXYGEN__)
+#define SPC5_DSPI3 (*(struct spc5_dspi *)0xFFF9C000U)
+#endif
+
+#if SPC5_HAS_DSPI4 || defined(__DOXYGEN__)
+#define SPC5_DSPI4 (*(struct spc5_dspi *)0xFFFA0000U)
+#endif
+
+#if SPC5_HAS_DSPI5 || defined(__DOXYGEN__)
+#define SPC5_DSPI5 (*(struct spc5_dspi *)0xFFFA4000U)
+#endif
+
+#if SPC5_HAS_DSPI6 || defined(__DOXYGEN__)
+#define SPC5_DSPI6 (*(struct spc5_dspi *)0xFFFA8000U)
+#endif
+
+#if SPC5_HAS_DSPI7 || defined(__DOXYGEN__)
+#define SPC5_DSPI7 (*(struct spc5_dspi *)0xFFFAC000U)
+#endif
+/** @} */
+
+#endif /* _SPC5_DSPI_H_ */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.c b/os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.c
new file mode 100644
index 000000000..6a50b1d26
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.c
@@ -0,0 +1,1397 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/spc5_edma.c
+ * @brief EDMA helper driver code.
+ *
+ * @addtogroup SPC5xx_EDMA
+ * @{
+ */
+
+#include "hal.h"
+
+#if SPC5_HAS_EDMA || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+static const uint8_t g0[16] = {SPC5_EDMA_GROUP0_PRIORITIES};
+#if (SPC5_EDMA_NCHANNELS > 16) || defined(__DOXYGEN__)
+static const uint8_t g1[16] = {SPC5_EDMA_GROUP1_PRIORITIES};
+#endif
+#if (SPC5_EDMA_NCHANNELS > 32) || defined(__DOXYGEN__)
+static const uint8_t g2[16] = {SPC5_EDMA_GROUP2_PRIORITIES};
+static const uint8_t g3[16] = {SPC5_EDMA_GROUP3_PRIORITIES};
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Configurations for the various EDMA channels.
+ */
+static const edma_channel_config_t *channels[SPC5_EDMA_NCHANNELS];
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief EDMA (channels 0..31) error interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector10) {
+ edma_channel_t channel;
+ uint32_t erl, esr = SPC5_EDMA.ESR.R;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Scanning for errors.*/
+ channel = 0;
+ while (((erl = SPC5_EDMA.ERL.R) != 0) &&
+ (channel < (SPC5_EDMA_NCHANNELS > 32 ? 32 : SPC5_EDMA_NCHANNELS))) {
+ if ((erl & (1U << channel)) != 0) {
+ /* Error flag cleared.*/
+ SPC5_EDMA.CER.R = channel;
+
+ /* If the channel is not associated then the error is simply discarded
+ else the error callback is invoked.*/
+ if ((channels[channel] != NULL) &&
+ (channels[channel]->dma_error_func != NULL))
+ channels[channel]->dma_error_func(channel,
+ channels[channel]->dma_param,
+ esr);
+ }
+ channel++;
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 0 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector11) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[0] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 0;
+ channels[0]->dma_func(0, channels[0]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 1 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector12) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[1] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 1;
+ channels[1]->dma_func(1, channels[1]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 2 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector13) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[2] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 2;
+ channels[2]->dma_func(2, channels[2]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 3 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector14) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[3] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 3;
+ channels[3]->dma_func(3, channels[3]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 4 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector15) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[4] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 4;
+ channels[4]->dma_func(4, channels[4]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 5 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector16) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[5] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 5;
+ channels[5]->dma_func(5, channels[5]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 6 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector17) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[6] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 6;
+ channels[6]->dma_func(6, channels[6]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 7 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector18) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[7] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 7;
+ channels[7]->dma_func(7, channels[7]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 8 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector19) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[8] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 8;
+ channels[8]->dma_func(8, channels[8]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 9 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector20) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[9] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 9;
+ channels[9]->dma_func(9, channels[9]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 10 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector21) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[10] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 10;
+ channels[10]->dma_func(10, channels[10]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 11 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector22) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[11] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 11;
+ channels[11]->dma_func(11, channels[11]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 12 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector23) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[12] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 12;
+ channels[12]->dma_func(12, channels[12]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 13 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector24) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[13] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 13;
+ channels[13]->dma_func(13, channels[13]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 14 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector25) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[14] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 14;
+ channels[14]->dma_func(14, channels[14]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 15 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector26) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[15] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 15;
+ channels[15]->dma_func(15, channels[15]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if (SPC5_EDMA_NCHANNELS > 16) || defined(__DOXYGEN__)
+/**
+ * @brief EDMA channel 16 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector27) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[16] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 16;
+ channels[16]->dma_func(16, channels[16]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 17 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector28) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[17] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 17;
+ channels[17]->dma_func(17, channels[17]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 18 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector29) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[18] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 18;
+ channels[18]->dma_func(18, channels[18]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 19 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector30) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[19] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 19;
+ channels[19]->dma_func(19, channels[19]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 20 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector31) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[20] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 20;
+ channels[20]->dma_func(20, channels[20]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 21 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector32) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[21] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 21;
+ channels[21]->dma_func(21, channels[21]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 22 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector33) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[22] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 22;
+ channels[22]->dma_func(22, channels[22]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 23 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector34) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[23] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 23;
+ channels[23]->dma_func(23, channels[23]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 24 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector35) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[24] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 24;
+ channels[24]->dma_func(24, channels[24]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 25 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector36) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[25] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 25;
+ channels[25]->dma_func(25, channels[25]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 26 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector37) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[26] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 26;
+ channels[26]->dma_func(26, channels[26]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 27 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector38) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[27] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 27;
+ channels[27]->dma_func(27, channels[27]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 28 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector39) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[28] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 28;
+ channels[28]->dma_func(28, channels[28]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 29 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector40) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[29] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 29;
+ channels[29]->dma_func(29, channels[29]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 30 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector41) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[30] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 30;
+ channels[30]->dma_func(30, channels[30]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 31 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector42) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[31] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 31;
+ channels[31]->dma_func(31, channels[31]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#if (SPC5_EDMA_NCHANNELS > 32) || defined(__DOXYGEN__)
+/**
+ * @brief EDMA (channels 32..64) error interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector210) {
+ edma_channel_t channel;
+ uint32_t erh, esr = SPC5_EDMA.ESR.R;
+
+ OSAL_IRQ_PROLOGUE();
+
+ /* Scanning for errors.*/
+ channel = 32;
+ while (((erh = SPC5_EDMA.ERH.R) != 0) && (channel < SPC5_EDMA_NCHANNELS)) {
+
+ if ((erh & (1U << (channel - 32))) != 0) {
+ /* Error flag cleared.*/
+ SPC5_EDMA.CER.R = channel;
+
+ /* If the channel is not associated then the error is simply discarded
+ else the error callback is invoked.*/
+ if ((channels[channel] != NULL) &&
+ (channels[channel]->dma_error_func != NULL))
+ channels[channel]->dma_error_func(channel,
+ channels[channel]->dma_param,
+ esr);
+ channel++;
+ }
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 32 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector211) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[32] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 32;
+ channels[32]->dma_func(32, channels[32]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 33 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector212) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[33] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 33;
+ channels[33]->dma_func(33, channels[33]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 34 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector213) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[34] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 34;
+ channels[34]->dma_func(34, channels[34]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 35 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector214) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[35] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 35;
+ channels[35]->dma_func(35, channels[35]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 36 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector215) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[36] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 36;
+ channels[36]->dma_func(36, channels[36]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 37 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector216) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[37] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 37;
+ channels[37]->dma_func(37, channels[37]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 38 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector217) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[38] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 38;
+ channels[38]->dma_func(38, channels[38]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 39 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector218) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[39] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 39;
+ channels[39]->dma_func(39, channels[39]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 40 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector219) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[40] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 40;
+ channels[40]->dma_func(40, channels[40]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 41 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector220) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[41] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 41;
+ channels[41]->dma_func(41, channels[41]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 42 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector221) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[42] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 42;
+ channels[42]->dma_func(42, channels[42]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 43 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector222) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[43] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 43;
+ channels[43]->dma_func(43, channels[43]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 44 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector223) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[44] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 44;
+ channels[44]->dma_func(44, channels[44]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 45 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector224) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[45] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 45;
+ channels[45]->dma_func(45, channels[45]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 46 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector225) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[46] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 46;
+ channels[46]->dma_func(46, channels[46]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 47 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector226) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[47] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 47;
+ channels[47]->dma_func(47, channels[47]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 48 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector227) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[48] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 48;
+ channels[48]->dma_func(48, channels[48]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 49 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector228) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[49] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 49;
+ channels[49]->dma_func(49, channels[49]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 50 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector229) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[50] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 50;
+ channels[50]->dma_func(50, channels[50]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 51 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector230) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[51] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 51;
+ channels[51]->dma_func(51, channels[51]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 52 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector231) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[52] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 52;
+ channels[52]->dma_func(52, channels[52]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 53 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector232) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[53] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 53;
+ channels[53]->dma_func(53, channels[53]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 54 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector233) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[54] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 54;
+ channels[54]->dma_func(54, channels[54]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 55 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector234) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[55] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 55;
+ channels[55]->dma_func(55, channels[55]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 56 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector235) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[56] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 56;
+ channels[56]->dma_func(56, channels[56]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 57 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector236) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[57] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 57;
+ channels[57]->dma_func(57, channels[57]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 58 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector237) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[58] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 58;
+ channels[58]->dma_func(58, channels[58]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 59 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector238) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[59] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 59;
+ channels[59]->dma_func(59, channels[59]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 60 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector239) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[60] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 60;
+ channels[60]->dma_func(60, channels[60]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 61 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector240) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[61] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 61;
+ channels[61]->dma_func(61, channels[61]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 62 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector241) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[62] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 62;
+ channels[62]->dma_func(62, channels[62]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief EDMA channel 63 interrupt.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(vector242) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (channels[63] == NULL) {
+ SPC5_EDMA_ERROR_HANDLER();
+ }
+ SPC5_EDMA.CIRQR.R = 63;
+ channels[63]->dma_func(63, channels[63]->dma_param);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif /* SPC5_EDMA_NCHANNELS > 32 */
+#endif /* SPC5_EDMA_NCHANNELS > 16 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief EDMA driver initialization.
+ *
+ * @special
+ */
+void edmaInit(void) {
+ unsigned i;
+
+ SPC5_EDMA.CR.R = SPC5_EDMA_CR_SETTING;
+ SPC5_EDMA.ERQRL.R = 0x00000000;
+ SPC5_EDMA.EEIRL.R = 0x00000000;
+ SPC5_EDMA.IRQRL.R = 0xFFFFFFFF;
+ SPC5_EDMA.ERL.R = 0xFFFFFFFF;
+#if SPC5_EDMA_NCHANNELS > 32
+ SPC5_EDMA.ERQRH.R = 0x00000000;
+ SPC5_EDMA.EEIRH.R = 0x00000000;
+ SPC5_EDMA.IRQRH.R = 0xFFFFFFFF;
+ SPC5_EDMA.ERH.R = 0xFFFFFFFF;
+#endif
+ /* Initializing all the channels with a different priority withing the
+ channels group.*/
+ for (i = 0; i < 16; i++) {
+ SPC5_EDMA.CPR[i].R = g0[i];
+#if SPC5_EDMA_NCHANNELS > 16
+ SPC5_EDMA.CPR[i + 16].R = g1[i];
+#endif
+#if SPC5_EDMA_NCHANNELS > 32
+ SPC5_EDMA.CPR[i + 32].R = g2[i];
+ SPC5_EDMA.CPR[i + 48].R = g3[i];
+#endif
+ }
+
+ /* Error interrupt source.*/
+ INTC.PSR[10].R = SPC5_EDMA_ERROR_IRQ_PRIO;
+
+#if defined(SPC5_EDMA_MUX_PCTL)
+ /* DMA MUX PCTL setup, only if required.*/
+ halSPCSetPeripheralClockMode(SPC5_EDMA_MUX_PCTL, SPC5_EDMA_MUX_START_PCTL);
+#endif
+}
+
+/**
+ * @brief EDMA channel allocation.
+ *
+ * @param[in] ccfg channel configuration
+ * @return The channel number.
+ * @retval EDMA_ERROR if the channel cannot be allocated.
+ *
+ * @special
+ */
+edma_channel_t edmaChannelAllocate(const edma_channel_config_t *ccfg) {
+
+ osalDbgCheck((ccfg != NULL) && (ccfg->dma_irq_prio < 16));
+
+ /* If the channel is already taken then an error is returned.*/
+ if (channels[ccfg->dma_channel] != NULL)
+ return EDMA_ERROR; /* Already taken. */
+
+#if SPC5_EDMA_HAS_MUX
+ /* Programming the MUX.*/
+ SPC5_DMAMUX.CHCONFIG[ccfg->dma_channel].R = (uint8_t)(0x80 |
+ ccfg->dma_periph);
+#endif /* !SPC5_EDMA_HAS_MUX */
+
+ /* Associating the configuration to the channel.*/
+ channels[ccfg->dma_channel] = ccfg;
+
+ /* If an error callback is defined then the error interrupt source is
+ enabled for the channel.*/
+ if (ccfg->dma_error_func != NULL)
+ SPC5_EDMA.SEEIR.R = (uint32_t)ccfg->dma_channel;
+
+ /* Setting up IRQ priority for the selected channel.*/
+ INTC.PSR[11 + ccfg->dma_channel].R = ccfg->dma_irq_prio;
+
+ return ccfg->dma_channel;
+}
+
+/**
+ * @brief EDMA channel release.
+ *
+ * @param[in] channel the channel number
+ *
+ * @special
+ */
+void edmaChannelRelease(edma_channel_t channel) {
+
+ osalDbgCheck((channel >= 0) && (channel < SPC5_EDMA_NCHANNELS));
+ osalDbgAssert(channels[channel] != NULL, "not allocated");
+
+ /* Enforcing a stop.*/
+ edmaChannelStop(channel);
+
+#if SPC5_EDMA_HAS_MUX
+ /* Disabling the MUX slot.*/
+ SPC5_DMAMUX.CHCONFIG[channel].R = 0;
+#endif
+
+ /* Clearing ISR sources for the channel.*/
+ SPC5_EDMA.CIRQR.R = channel;
+ SPC5_EDMA.CEEIR.R = channel;
+ SPC5_EDMA.CER.R = channel;
+
+ /* The channels is flagged as available.*/
+ channels[channel] = NULL;
+}
+
+#endif /* SPC5_HAS_EDMA */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.h b/os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.h
new file mode 100644
index 000000000..c621baea3
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/EDMA_v1/spc5_edma.h
@@ -0,0 +1,1005 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/spc5_edma.h
+ * @brief EDMA helper driver header.
+ *
+ * @addtogroup SPC5xx_EDMA
+ * @{
+ */
+
+#ifndef _SPC5_EDMA_H_
+#define _SPC5_EDMA_H_
+
+#if SPC5_HAS_EDMA || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @brief EDMA channel allocation error.
+ */
+#define EDMA_ERROR -1
+
+/**
+ * @name EDMA CR register definitions
+ * @{
+ */
+#define EDMA_CR_CX (1U << 17)
+#define EDMA_CR_ECX (1U << 16)
+#define EDMA_CR_GRP3PRI_MASK (3U << 14)
+#define EDMA_CR_GRP3PRI(n) ((n) << 14)
+#define EDMA_CR_GRP2PRI_MASK (3U << 12)
+#define EDMA_CR_GRP2PRI(n) ((n) << 12)
+#define EDMA_CR_GRP1PRI_MASK (3U << 10)
+#define EDMA_CR_GRP1PRI(n) ((n) << 10)
+#define EDMA_CR_GRP0PRI_MASK (3U << 8)
+#define EDMA_CR_GRP0PRI(n) ((n) << 8)
+#define EDMA_CR_EMLM (1U << 7)
+#define EDMA_CR_CLM (1U << 6)
+#define EDMA_CR_HALT (1U << 5)
+#define EDMA_CR_HOE (1U << 4)
+#define EDMA_CR_ERGA (1U << 3)
+#define EDMA_CR_ERCA (1U << 2)
+#define EDMA_CR_EDBG (1U << 1)
+#define EDMA_CR_EBW (1U << 0)
+/** @} */
+
+/**
+ * @name EDMA mode constants
+ * @{
+ */
+#define EDMA_TCD_MODE_START (1U << 0)
+#define EDMA_TCD_MODE_INT_END (1U << 1)
+#define EDMA_TCD_MODE_INT_HALF (1U << 2)
+#define EDMA_TCD_MODE_DREQ (1U << 3)
+#define EDMA_TCD_MODE_SG (1U << 4)
+#define EDMA_TCD_MODE_MELINK (1U << 5)
+#define EDMA_TCD_MODE_ACTIVE (1U << 6)
+#define EDMA_TCD_MODE_DONE (1U << 7)
+#define EDMA_TCD_MODE_MLINKCH_MASK (63U << 8)
+#define EDMA_TCD_MODE_MLINKCH(n) ((uint32_t)(n) << 8)
+#define EDMA_TCD_MODE_BWC_MASK (3U << 14)
+#define EDMA_TCD_MODE_BWC(n) ((uint32_t)(n) << 14)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief Default EDMA CR register initialization.
+ */
+#if !defined(SPC5_EDMA_CR_SETTING) || defined(__DOXYGEN__)
+#define SPC5_EDMA_CR_SETTING (EDMA_CR_GRP3PRI(3) | \
+ EDMA_CR_GRP2PRI(2) | \
+ EDMA_CR_GRP1PRI(1) | \
+ EDMA_CR_GRP0PRI(0) | \
+ EDMA_CR_EMLM | \
+ EDMA_CR_ERGA)
+#endif
+
+/**
+ * @brief Static priorities for channels group 0.
+ */
+#if !defined(SPC5_EDMA_GROUP0_PRIORITIES) || defined(__DOXYGEN__)
+#define SPC5_EDMA_GROUP0_PRIORITIES \
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+#endif
+
+/**
+ * @brief Static priorities for channels group 1.
+ */
+#if !defined(SPC5_EDMA_GROUP1_PRIORITIES) || defined(__DOXYGEN__)
+#define SPC5_EDMA_GROUP1_PRIORITIES \
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+#endif
+
+/**
+ * @brief Static priorities for channels group 2.
+ */
+#if !defined(SPC5_EDMA_GROUP2_PRIORITIES) || defined(__DOXYGEN__)
+#define SPC5_EDMA_GROUP2_PRIORITIES \
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+#endif
+
+/**
+ * @brief Static priorities for channels group 3.
+ */
+#if !defined(SPC5_EDMA_GROUP3_PRIORITIES) || defined(__DOXYGEN__)
+#define SPC5_EDMA_GROUP3_PRIORITIES \
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+#endif
+
+/**
+ * @brief EDMA error handler IRQ priority.
+ */
+#if !defined(SPC5_EDMA_ERROR_IRQ_PRIO) || defined(__DOXYGEN__)
+#define SPC5_EDMA_ERROR_IRQ_PRIO 12
+#endif
+
+/**
+ * @brief EDMA peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_EDMA_MUX_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_EDMA_MUX_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief EDMA critical error handler, must not return.
+ */
+#if !defined(SPC5_EDMA_ERROR_HANDLER) || defined(__DOXYGEN__)
+#define SPC5_EDMA_ERROR_HANDLER() osalSysHalt("EDMA failure")
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of and eDMA channel number.
+ */
+typedef int32_t edma_channel_t;
+
+/**
+ * @brief Type of an eDMA TCD.
+ */
+typedef struct {
+ union {
+ uint32_t word[8];
+ };
+} edma_tcd_t;
+
+/**
+ * @brief Type of an eDMA peripheral.
+ */
+typedef struct {
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t :14;
+ vuint32_t CX :1;
+ vuint32_t ECX :1;
+ vuint32_t GRP3PRI :2;
+ vuint32_t GRP2PRI :2;
+ vuint32_t GRP1PRI :2;
+ vuint32_t GRP0PRI :2;
+ vuint32_t EMLM :1;
+ vuint32_t CLM :1;
+ vuint32_t HALT :1;
+ vuint32_t HOE :1;
+ vuint32_t ERGA :1;
+ vuint32_t ERCA :1;
+ vuint32_t EDBG :1;
+ vuint32_t :1;
+ } B;
+ } CR; /* DMA Control Register @baseaddress + 0x0 */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t VLD :1;
+ vuint32_t :14;
+ vuint32_t ECX :1;
+ vuint32_t GPE :1;
+ vuint32_t CPE :1;
+ vuint32_t ERRCHN :6;
+ vuint32_t SAE :1;
+ vuint32_t SOE :1;
+ vuint32_t DAE :1;
+ vuint32_t DOE :1;
+ vuint32_t NCE :1;
+ vuint32_t SGE :1;
+ vuint32_t SBE :1;
+ vuint32_t DBE :1;
+ } B;
+ } ESR; /* Error Status Register @baseaddress + 0x4 */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t ERQ63 :1;
+ vuint32_t ERQ62 :1;
+ vuint32_t ERQ61 :1;
+ vuint32_t ERQ60 :1;
+ vuint32_t ERQ59 :1;
+ vuint32_t ERQ58 :1;
+ vuint32_t ERQ57 :1;
+ vuint32_t ERQ56 :1;
+ vuint32_t ERQ55 :1;
+ vuint32_t ERQ54 :1;
+ vuint32_t ERQ53 :1;
+ vuint32_t ERQ52 :1;
+ vuint32_t ERQ51 :1;
+ vuint32_t ERQ50 :1;
+ vuint32_t ERQ49 :1;
+ vuint32_t ERQ48 :1;
+ vuint32_t ERQ47 :1;
+ vuint32_t ERQ46 :1;
+ vuint32_t ERQ45 :1;
+ vuint32_t ERQ44 :1;
+ vuint32_t ERQ43 :1;
+ vuint32_t ERQ42 :1;
+ vuint32_t ERQ41 :1;
+ vuint32_t ERQ40 :1;
+ vuint32_t ERQ39 :1;
+ vuint32_t ERQ38 :1;
+ vuint32_t ERQ37 :1;
+ vuint32_t ERQ36 :1;
+ vuint32_t ERQ35 :1;
+ vuint32_t ERQ34 :1;
+ vuint32_t ERQ33 :1;
+ vuint32_t ERQ32 :1;
+ } B;
+ } ERQRH; /* DMA Enable Request Register High @baseaddress + 0x8*/
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t ERQ31 :1;
+ vuint32_t ERQ30 :1;
+ vuint32_t ERQ29 :1;
+ vuint32_t ERQ28 :1;
+ vuint32_t ERQ27 :1;
+ vuint32_t ERQ26 :1;
+ vuint32_t ERQ25 :1;
+ vuint32_t ERQ24 :1;
+ vuint32_t ERQ23 :1;
+ vuint32_t ERQ22 :1;
+ vuint32_t ERQ21 :1;
+ vuint32_t ERQ20 :1;
+ vuint32_t ERQ19 :1;
+ vuint32_t ERQ18 :1;
+ vuint32_t ERQ17 :1;
+ vuint32_t ERQ16 :1;
+ vuint32_t ERQ15 :1;
+ vuint32_t ERQ14 :1;
+ vuint32_t ERQ13 :1;
+ vuint32_t ERQ12 :1;
+ vuint32_t ERQ11 :1;
+ vuint32_t ERQ10 :1;
+ vuint32_t ERQ09 :1;
+ vuint32_t ERQ08 :1;
+ vuint32_t ERQ07 :1;
+ vuint32_t ERQ06 :1;
+ vuint32_t ERQ05 :1;
+ vuint32_t ERQ04 :1;
+ vuint32_t ERQ03 :1;
+ vuint32_t ERQ02 :1;
+ vuint32_t ERQ01 :1;
+ vuint32_t ERQ00 :1;
+ } B;
+ } ERQRL; /* DMA Enable Request Register Low @baseaddress + 0xC*/
+
+ union {
+ vuint32_t R;
+ struct {
+
+ vuint32_t EEI63 :1;
+ vuint32_t EEI62 :1;
+ vuint32_t EEI61 :1;
+ vuint32_t EEI60 :1;
+ vuint32_t EEI59 :1;
+ vuint32_t EEI58 :1;
+ vuint32_t EEI57 :1;
+ vuint32_t EEI56 :1;
+ vuint32_t EEI55 :1;
+ vuint32_t EEI54 :1;
+ vuint32_t EEI53 :1;
+ vuint32_t EEI52 :1;
+ vuint32_t EEI51 :1;
+ vuint32_t EEI50 :1;
+ vuint32_t EEI49 :1;
+ vuint32_t EEI48 :1;
+ vuint32_t EEI47 :1;
+ vuint32_t EEI46 :1;
+ vuint32_t EEI45 :1;
+ vuint32_t EEI44 :1;
+ vuint32_t EEI43 :1;
+ vuint32_t EEI42 :1;
+ vuint32_t EEI41 :1;
+ vuint32_t EEI40 :1;
+ vuint32_t EEI39 :1;
+ vuint32_t EEI38 :1;
+ vuint32_t EEI37 :1;
+ vuint32_t EEI36 :1;
+ vuint32_t EEI35 :1;
+ vuint32_t EEI34 :1;
+ vuint32_t EEI33 :1;
+ vuint32_t EEI32 :1;
+ } B;
+ } EEIRH; /* DMA Enable Error Interrupt Register High @baseaddress + 0x10*/
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t EEI31 :1;
+ vuint32_t EEI30 :1;
+ vuint32_t EEI29 :1;
+ vuint32_t EEI28 :1;
+ vuint32_t EEI27 :1;
+ vuint32_t EEI26 :1;
+ vuint32_t EEI25 :1;
+ vuint32_t EEI24 :1;
+ vuint32_t EEI23 :1;
+ vuint32_t EEI22 :1;
+ vuint32_t EEI21 :1;
+ vuint32_t EEI20 :1;
+ vuint32_t EEI19 :1;
+ vuint32_t EEI18 :1;
+ vuint32_t EEI17 :1;
+ vuint32_t EEI16 :1;
+ vuint32_t EEI15 :1;
+ vuint32_t EEI14 :1;
+ vuint32_t EEI13 :1;
+ vuint32_t EEI12 :1;
+ vuint32_t EEI11 :1;
+ vuint32_t EEI10 :1;
+ vuint32_t EEI09 :1;
+ vuint32_t EEI08 :1;
+ vuint32_t EEI07 :1;
+ vuint32_t EEI06 :1;
+ vuint32_t EEI05 :1;
+ vuint32_t EEI04 :1;
+ vuint32_t EEI03 :1;
+ vuint32_t EEI02 :1;
+ vuint32_t EEI01 :1;
+ vuint32_t EEI00 :1;
+ } B;
+ } EEIRL; /* DMA Enable Error Interrupt Register Low @baseaddress + 0x14*/
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t SERQ :7;
+ } B;
+ } SERQR; /* DMA Set Enable Request Register @baseaddress + 0x18*/
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t CERQ :7;
+ } B;
+ } CERQR; /* DMA Clear Enable Request Register @baseaddress + 0x19*/
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t SEEI :7;
+ } B;
+ } SEEIR; /* DMA Set Enable Error Interrupt Register @baseaddress + 0x1A*/
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t CEEI :7;
+ } B;
+ } CEEIR; /* DMA Clear Enable Error Interrupt Register @baseaddress + 0x1B*/
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t CINT :7;
+ } B;
+ } CIRQR; /* DMA Clear Interrupt Request Register @baseaddress + 0x1C */
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t CERR :7;
+ } B;
+ } CER; /* DMA Clear error Register @baseaddress + 0x1D */
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t SSB :7;
+ } B;
+ } SSBR; /* Set Start Bit Register @baseaddress + 0x1E */
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t NOP :1;
+ vuint8_t CDSB :7;
+ } B;
+ } CDSBR; /* Clear Done Status Bit Register @baseaddress + 0x1F */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t INT63 :1;
+ vuint32_t INT62 :1;
+ vuint32_t INT61 :1;
+ vuint32_t INT60 :1;
+ vuint32_t INT59 :1;
+ vuint32_t INT58 :1;
+ vuint32_t INT57 :1;
+ vuint32_t INT56 :1;
+ vuint32_t INT55 :1;
+ vuint32_t INT54 :1;
+ vuint32_t INT53 :1;
+ vuint32_t INT52 :1;
+ vuint32_t INT51 :1;
+ vuint32_t INT50 :1;
+ vuint32_t INT49 :1;
+ vuint32_t INT48 :1;
+ vuint32_t INT47 :1;
+ vuint32_t INT46 :1;
+ vuint32_t INT45 :1;
+ vuint32_t INT44 :1;
+ vuint32_t INT43 :1;
+ vuint32_t INT42 :1;
+ vuint32_t INT41 :1;
+ vuint32_t INT40 :1;
+ vuint32_t INT39 :1;
+ vuint32_t INT38 :1;
+ vuint32_t INT37 :1;
+ vuint32_t INT36 :1;
+ vuint32_t INT35 :1;
+ vuint32_t INT34 :1;
+ vuint32_t INT33 :1;
+ vuint32_t INT32 :1;
+ } B;
+ } IRQRH; /* DMA Interrupt Request High @baseaddress + 0x20 */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t INT31 :1;
+ vuint32_t INT30 :1;
+ vuint32_t INT29 :1;
+ vuint32_t INT28 :1;
+ vuint32_t INT27 :1;
+ vuint32_t INT26 :1;
+ vuint32_t INT25 :1;
+ vuint32_t INT24 :1;
+ vuint32_t INT23 :1;
+ vuint32_t INT22 :1;
+ vuint32_t INT21 :1;
+ vuint32_t INT20 :1;
+ vuint32_t INT19 :1;
+ vuint32_t INT18 :1;
+ vuint32_t INT17 :1;
+ vuint32_t INT16 :1;
+ vuint32_t INT15 :1;
+ vuint32_t INT14 :1;
+ vuint32_t INT13 :1;
+ vuint32_t INT12 :1;
+ vuint32_t INT11 :1;
+ vuint32_t INT10 :1;
+ vuint32_t INT09 :1;
+ vuint32_t INT08 :1;
+ vuint32_t INT07 :1;
+ vuint32_t INT06 :1;
+ vuint32_t INT05 :1;
+ vuint32_t INT04 :1;
+ vuint32_t INT03 :1;
+ vuint32_t INT02 :1;
+ vuint32_t INT01 :1;
+ vuint32_t INT00 :1;
+ } B;
+ } IRQRL; /* DMA Interrupt Request Low @baseaddress + 0x24 */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t ERR63 :1;
+ vuint32_t ERR62 :1;
+ vuint32_t ERR61 :1;
+ vuint32_t ERR60 :1;
+ vuint32_t ERR59 :1;
+ vuint32_t ERR58 :1;
+ vuint32_t ERR57 :1;
+ vuint32_t ERR56 :1;
+ vuint32_t ERR55 :1;
+ vuint32_t ERR54 :1;
+ vuint32_t ERR53 :1;
+ vuint32_t ERR52 :1;
+ vuint32_t ERR51 :1;
+ vuint32_t ERR50 :1;
+ vuint32_t ERR49 :1;
+ vuint32_t ERR48 :1;
+ vuint32_t ERR47 :1;
+ vuint32_t ERR46 :1;
+ vuint32_t ERR45 :1;
+ vuint32_t ERR44 :1;
+ vuint32_t ERR43 :1;
+ vuint32_t ERR42 :1;
+ vuint32_t ERR41 :1;
+ vuint32_t ERR40 :1;
+ vuint32_t ERR39 :1;
+ vuint32_t ERR38 :1;
+ vuint32_t ERR37 :1;
+ vuint32_t ERR36 :1;
+ vuint32_t ERR35 :1;
+ vuint32_t ERR34 :1;
+ vuint32_t ERR33 :1;
+ vuint32_t ERR32 :1;
+ } B;
+ } ERH; /* DMA Error High @baseaddress + 0x28 */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t ERR31 :1;
+ vuint32_t ERR30 :1;
+ vuint32_t ERR29 :1;
+ vuint32_t ERR28 :1;
+ vuint32_t ERR27 :1;
+ vuint32_t ERR26 :1;
+ vuint32_t ERR25 :1;
+ vuint32_t ERR24 :1;
+ vuint32_t ERR23 :1;
+ vuint32_t ERR22 :1;
+ vuint32_t ERR21 :1;
+ vuint32_t ERR20 :1;
+ vuint32_t ERR19 :1;
+ vuint32_t ERR18 :1;
+ vuint32_t ERR17 :1;
+ vuint32_t ERR16 :1;
+ vuint32_t ERR15 :1;
+ vuint32_t ERR14 :1;
+ vuint32_t ERR13 :1;
+ vuint32_t ERR12 :1;
+ vuint32_t ERR11 :1;
+ vuint32_t ERR10 :1;
+ vuint32_t ERR09 :1;
+ vuint32_t ERR08 :1;
+ vuint32_t ERR07 :1;
+ vuint32_t ERR06 :1;
+ vuint32_t ERR05 :1;
+ vuint32_t ERR04 :1;
+ vuint32_t ERR03 :1;
+ vuint32_t ERR02 :1;
+ vuint32_t ERR01 :1;
+ vuint32_t ERR00 :1;
+ } B;
+ } ERL; /* DMA Error Low @baseaddress + 0x2C */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t HRS63 :1;
+ vuint32_t HRS62 :1;
+ vuint32_t HRS61 :1;
+ vuint32_t HRS60 :1;
+ vuint32_t HRS59 :1;
+ vuint32_t HRS58 :1;
+ vuint32_t HRS57 :1;
+ vuint32_t HRS56 :1;
+ vuint32_t HRS55 :1;
+ vuint32_t HRS54 :1;
+ vuint32_t HRS53 :1;
+ vuint32_t HRS52 :1;
+ vuint32_t HRS51 :1;
+ vuint32_t HRS50 :1;
+ vuint32_t HRS49 :1;
+ vuint32_t HRS48 :1;
+ vuint32_t HRS47 :1;
+ vuint32_t HRS46 :1;
+ vuint32_t HRS45 :1;
+ vuint32_t HRS44 :1;
+ vuint32_t HRS43 :1;
+ vuint32_t HRS42 :1;
+ vuint32_t HRS41 :1;
+ vuint32_t HRS40 :1;
+ vuint32_t HRS39 :1;
+ vuint32_t HRS38 :1;
+ vuint32_t HRS37 :1;
+ vuint32_t HRS36 :1;
+ vuint32_t HRS35 :1;
+ vuint32_t HRS34 :1;
+ vuint32_t HRS33 :1;
+ vuint32_t HRS32 :1;
+ } B;
+ } HRSH; /* hardware request status high @baseaddress + 0x30 */
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t HRS31 :1;
+ vuint32_t HRS30 :1;
+ vuint32_t HRS29 :1;
+ vuint32_t HRS28 :1;
+ vuint32_t HRS27 :1;
+ vuint32_t HRS26 :1;
+ vuint32_t HRS25 :1;
+ vuint32_t HRS24 :1;
+ vuint32_t HRS23 :1;
+ vuint32_t HRS22 :1;
+ vuint32_t HRS21 :1;
+ vuint32_t HRS20 :1;
+ vuint32_t HRS19 :1;
+ vuint32_t HRS18 :1;
+ vuint32_t HRS17 :1;
+ vuint32_t HRS16 :1;
+ vuint32_t HRS15 :1;
+ vuint32_t HRS14 :1;
+ vuint32_t HRS13 :1;
+ vuint32_t HRS12 :1;
+ vuint32_t HRS11 :1;
+ vuint32_t HRS10 :1;
+ vuint32_t HRS09 :1;
+ vuint32_t HRS08 :1;
+ vuint32_t HRS07 :1;
+ vuint32_t HRS06 :1;
+ vuint32_t HRS05 :1;
+ vuint32_t HRS04 :1;
+ vuint32_t HRS03 :1;
+ vuint32_t HRS02 :1;
+ vuint32_t HRS01 :1;
+ vuint32_t HRS00 :1;
+ } B;
+ } HRSL; /* hardware request status low @baseaddress + 0x34 */
+
+ uint32_t eDMA_reserved0038[50]; /* 0x0038-0x00FF */
+
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t ECP :1;
+ vuint8_t DPA :1;
+ vuint8_t GRPPRI :2;
+ vuint8_t CHPRI :4;
+ } B;
+ } CPR[64]; /* Channel n Priority @baseaddress + 0x100 */
+
+ uint32_t eDMA_reserved0140[944]; /* 0x0140-0x0FFF */
+
+ edma_tcd_t TCD[64];
+} edma_t;
+
+#if SPC5_EDMA_HAS_MUX || defined(__DOXYGEN__)
+/**
+ * @brief Type of a DMA-MUX peripheral.
+ */
+typedef struct {
+ union {
+ vuint8_t R;
+ struct {
+ vuint8_t ENBL:1;
+ vuint8_t TRIG:1;
+ vuint8_t SOURCE:6;
+ } B;
+ } CHCONFIG[SPC5_EDMA_NCHANNELS];
+} dma_mux_t;
+#endif /* SPC5_EDMA_HAS_MUX */
+
+/**
+ * @brief DMA callback type.
+ *
+ * @param[in] channel the channel number
+ * @param[in] p parameter for the registered function
+ */
+typedef void (*edma_callback_t)(edma_channel_t channel, void *p);
+
+/**
+ * @brief DMA error callback type.
+ *
+ * @param[in] channel the channel number
+ * @param[in] p parameter for the registered function
+ * @param[in] esr content of the ESR register
+ */
+typedef void (*edma_error_callback_t)(edma_channel_t channel,
+ void *p,
+ uint32_t esr);
+
+/**
+ * @brief Type of an EDMA channel configuration structure.
+ */
+typedef struct {
+ edma_channel_t dma_channel; /**< @brief Channel to be allocated.*/
+#if SPC5_EDMA_HAS_MUX || defined(__DOXYGEN__)
+ uint8_t dma_periph; /**< @brief Peripheral to be
+ associated to the channel. */
+#endif
+ uint8_t dma_irq_prio; /**< @brief IRQ priority level for
+ this channel. */
+ edma_callback_t dma_func; /**< @brief Channel callback,
+ can be NULL if not required. */
+ edma_error_callback_t dma_error_func; /**< @brief Channel error callback,
+ can be NULL if not required. */
+ void *dma_param; /**< @brief Channel callback param. */
+} edma_channel_config_t;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @name Peripherals references
+ *
+ * @{
+ */
+#if SPC5_HAS_EDMA || defined(__DOXYGEN__)
+#define SPC5_EDMA (*(edma_t *)0xFFF44000U)
+#endif
+
+#if SPC5_EDMA_HAS_MUX || defined(__DOXYGEN__)
+#define SPC5_DMAMUX (*(dma_mux_t *)0xFFFDC000UL)
+#endif
+/** @} */
+
+/**
+ * @brief Returns the TCD address associated to a channel.
+ *
+ * @param[in] channel the channel number
+ * @return A pointer to an @p edma_tcd_t structure.
+ *
+ * @api
+ */
+#define edmaGetTCD(channel) ((edma_tcd_t *)&SPC5_EDMA.TCD[channel])
+
+/**
+ * @brief Sets the word 0 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] src the source address
+ *
+ * @api
+ */
+#define edmaTCDSetWord0(tcdp, src) \
+ ((tcdp)->word[0] = (uint32_t)(src))
+
+/**
+ * @brief Sets the word 1 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] ssize the source width
+ * @param[in] dst the destination width
+ * @param[in] soff the source increment value
+ *
+ * @api
+ */
+#define edmaTCDSetWord1(tcdp, ssize, dsize, soff) \
+ ((tcdp)->word[1] = (((uint32_t)(ssize) << 24) | \
+ ((uint32_t)(dsize) << 16) | \
+ ((uint32_t)(soff) << 0)))
+
+/**
+ * @brief Sets the word 2 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] nbytes the inner counter value
+ *
+ * @api
+ */
+#define edmaTCDSetWord2(tcdp, nbytes) \
+ ((tcdp)->word[2] = (uint32_t)(nbytes))
+
+/**
+ * @brief Sets the word 3 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] slast the adjustment value
+ *
+ * @api
+ */
+#define edmaTCDSetWord3(tcdp, slast) \
+ ((tcdp)->word[3] = (uint32_t)(slast))
+
+/**
+ * @brief Sets the word 4 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] dst the destination address
+ *
+ * @api
+ */
+#define edmaTCDSetWord4(tcdp, dst) \
+ ((tcdp)->word[4] = (uint32_t)(dst))
+
+/**
+ * @brief Sets the word 5 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] citer the current outer counter value
+ * @param[in] doff the destination increment value
+ *
+ * @api
+ */
+#define edmaTCDSetWord5(tcdp, citer, doff) \
+ ((tcdp)->word[5] = (((uint32_t)(citer) << 16) | \
+ ((uint32_t)(doff) << 0)))
+
+/**
+ * @brief Sets the word 5 fields into a TCD.
+ * @note Transfers are limited to 512 operations using this modality
+ * (citer parameter).
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] linkch channel linked on minor loop counter
+ * @param[in] citer the current outer counter value
+ * @param[in] doff the destination increment value
+ *
+ * @api
+ */
+#define edmaTCDSetWord5Linked(tcdp, linkch, citer, doff) \
+ ((tcdp)->word[5] = (((uint32_t)0x80000000) | \
+ ((uint32_t)(linkch) << 25) | \
+ ((uint32_t)(citer) << 16) | \
+ ((uint32_t)(doff) << 0)))
+
+/**
+ * @brief Sets the word 6 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] dlast the adjustment value
+ *
+ * @api
+ */
+#define edmaTCDSetWord6(tcdp, dlast) \
+ ((tcdp)->word[6] = (uint32_t)(dlast))
+
+/**
+ * @brief Sets the word 7 fields into a TCD.
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] biter the base outer counter value
+ * @param[in] mode the mode value
+ *
+ * @api
+ */
+#define edmaTCDSetWord7(tcdp, biter, mode) \
+ ((tcdp)->word[7] = (((uint32_t)(biter) << 16) | \
+ ((uint32_t)(mode) << 0)))
+
+/**
+ * @brief Sets the word 7 fields into a TCD.
+ * @note Transfers are limited to 512 operations using this modality
+ * (biter parameter).
+ *
+ * @param[in] tcdp pointer to an @p edma_tcd_t structure
+ * @param[in] linkch channel linked on minor loop counter
+ * @param[in] biter the base outer counter value
+ * @param[in] mode the mode value
+ *
+ * @api
+ */
+#define edmaTCDSetWord7Linked(tcdp, linkch, biter, mode) \
+ ((tcdp)->word[7] = (((uint32_t)0x80000000) | \
+ ((uint32_t)(linkch) << 25) | \
+ ((uint32_t)(biter) << 16) | \
+ ((uint32_t)(mode) << 0)))
+
+/**
+ * @brief Starts or restarts an EDMA channel.
+ *
+ * @param[in] channel the channel number
+ *
+ * @api
+ */
+#define edmaChannelStart(channel) (SPC5_EDMA.SERQR.R = (channel))
+
+/**
+ * @brief Stops an EDMA channel.
+ *
+ * @param[in] channel the channel number
+ *
+ * @api
+ */
+#define edmaChannelStop(channel) { \
+ SPC5_EDMA.CERQR.R = (channel); \
+ SPC5_EDMA.CDSBR.R = (channel); \
+}
+
+/**
+ * @brief EDMA channel setup.
+ *
+ * @param[in] channel eDMA channel number
+ * @param[in] src source address
+ * @param[in] dst destination address
+ * @param[in] soff source address offset
+ * @param[in] doff destination address offset
+ * @param[in] ssize source transfer size
+ * @param[in] dsize destination transfer size
+ * @param[in] nbytes minor loop count
+ * @param[in] iter major loop count
+ * @param[in] dlast last destination address adjustment
+ * @param[in] slast last source address adjustment
+ * @param[in] mode LSW of TCD register 7
+ *
+ * @api
+ */
+#define edmaChannelSetup(channel, src, dst, soff, doff, ssize, dsize, \
+ nbytes, iter, slast, dlast, mode) { \
+ edma_tcd_t *tcdp = edmaGetTCD(channel); \
+ edmaTCDSetWord0(tcdp, src); \
+ edmaTCDSetWord1(tcdp, ssize, dsize, soff); \
+ edmaTCDSetWord2(tcdp, nbytes); \
+ edmaTCDSetWord3(tcdp, slast); \
+ edmaTCDSetWord4(tcdp, dst); \
+ edmaTCDSetWord5(tcdp, iter, doff); \
+ edmaTCDSetWord6(tcdp, dlast); \
+ edmaTCDSetWord7(tcdp, iter, mode); \
+}
+
+/**
+ * @brief EDMA channel setup with linked channel on both minor and major
+ * loop counters.
+ * @note Transfers are limited to 512 operations using this modality
+ * (iter parameter).
+ *
+ * @param[in] channel eDMA channel number
+ * @param[in] linkch channel linked on minor loop counter
+ * @param[in] src source address
+ * @param[in] dst destination address
+ * @param[in] soff source address offset
+ * @param[in] doff destination address offset
+ * @param[in] ssize source transfer size
+ * @param[in] dsize destination transfer size
+ * @param[in] nbytes minor loop count
+ * @param[in] iter major loop count
+ * @param[in] dlast last destination address adjustment
+ * @param[in] slast last source address adjustment
+ * @param[in] mode LSW of TCD register 7
+ *
+ * @api
+ */
+#define edmaChannelSetupLinked(channel, linkch, src, dst, soff, \
+ doff, ssize, dsize, nbytes, iter, \
+ slast, dlast, mode) { \
+ edma_tcd_t *tcdp = edmaGetTCD(channel); \
+ edmaTCDSetWord0(tcdp, src); \
+ edmaTCDSetWord1(tcdp, ssize, dsize, soff); \
+ edmaTCDSetWord2(tcdp, nbytes); \
+ edmaTCDSetWord3(tcdp, slast); \
+ edmaTCDSetWord4(tcdp, dst); \
+ edmaTCDSetWord5Linked(tcdp, linkch, iter, doff); \
+ edmaTCDSetWord6(tcdp, dlast); \
+ edmaTCDSetWord7Linked(tcdp, linkch, iter, (mode) | \
+ EDMA_TCD_MODE_MELINK | \
+ EDMA_TCD_MODE_MLINKCH(linkch)); \
+}
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void edmaInit(void);
+ edma_channel_t edmaChannelAllocate(const edma_channel_config_t *ccfg);
+ void edmaChannelRelease(edma_channel_t channel);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SPC5_HAS_EDMA */
+
+#endif /* _SPC5_EDMA_H_ */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.c b/os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.c
new file mode 100644
index 000000000..8f16d5a23
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.c
@@ -0,0 +1,343 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/ESCI_v1/hal_serial_lld.c
+ * @brief SPC5xx low level serial driver code.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief eSCI-A serial driver identifier.
+ */
+#if SPC5_USE_ESCIA || defined(__DOXYGEN__)
+SerialDriver SD1;
+#endif
+
+/**
+ * @brief eSCI-B serial driver identifier.
+ */
+#if SPC5_USE_ESCIB || defined(__DOXYGEN__)
+SerialDriver SD2;
+#endif
+
+/**
+ * @brief eSCI-C serial driver identifier.
+ */
+#if SPC5_USE_ESCIC || defined(__DOXYGEN__)
+SerialDriver SD3;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Driver default configuration.
+ */
+static const SerialConfig default_config = {
+ SERIAL_DEFAULT_BITRATE,
+ SD_MODE_NORMAL | SD_MODE_PARITY_NONE
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief eSCI initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration
+ */
+static void esci_init(SerialDriver *sdp, const SerialConfig *config) {
+ volatile struct ESCI_tag *escip = sdp->escip;
+ uint8_t mode = config->sc_mode;
+
+ escip->CR2.R = 0; /* MDIS off. */
+ escip->CR1.R = 0;
+ escip->LCR.R = 0;
+ escip->CR1.B.SBR = SPC5_SYSCLK / (16 * config->sc_speed);
+ if (mode & SD_MODE_LOOPBACK)
+ escip->CR1.B.LOOPS = 1;
+ switch (mode & SD_MODE_PARITY_MASK) {
+ case SD_MODE_PARITY_ODD:
+ escip->CR1.B.PT = 1;
+ case SD_MODE_PARITY_EVEN:
+ escip->CR1.B.PE = 1;
+ escip->CR1.B.M = 1; /* Makes it 8 bits data + 1 bit parity. */
+ default:
+ ;
+ }
+ escip->LPR.R = 0;
+ escip->CR1.R |= 0x0000002C; /* RIE, TE, RE to 1. */
+ escip->CR2.R = 0x000F; /* ORIE, NFIE, FEIE, PFIE to 1. */
+}
+
+/**
+ * @brief eSCI de-initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] escip pointer to an eSCI I/O block
+ */
+static void esci_deinit(volatile struct ESCI_tag *escip) {
+
+ escip->LPR.R = 0;
+ escip->SR.R = 0xFFFFFFFF;
+ escip->CR1.R = 0;
+ escip->CR2.R = 0x8000; /* MDIS on. */
+}
+
+/**
+ * @brief Error handling routine.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] sr eSCI SR register value
+ */
+static void set_error(SerialDriver *sdp, uint32_t sr) {
+ eventflags_t sts = 0;
+
+ if (sr & 0x08000000)
+ sts |= SD_OVERRUN_ERROR;
+ if (sr & 0x04000000)
+ sts |= SD_NOISE_ERROR;
+ if (sr & 0x02000000)
+ sts |= SD_FRAMING_ERROR;
+ if (sr & 0x01000000)
+ sts |= SD_PARITY_ERROR;
+/* if (sr & 0x00000000)
+ sts |= SD_BREAK_DETECTED;*/
+ osalSysLockFromISR();
+ chnAddFlagsI(sdp, sts);
+ osalSysUnlockFromISR();
+}
+
+/**
+ * @brief Common IRQ handler.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ */
+static void serve_interrupt(SerialDriver *sdp) {
+ volatile struct ESCI_tag *escip = sdp->escip;
+
+ uint32_t sr = escip->SR.R;
+ escip->SR.R = 0x3FFFFFFF; /* Does not clear TDRE | TC.*/
+ if (sr & 0x0F000000) /* OR | NF | FE | PF. */
+ set_error(sdp, sr);
+ if (sr & 0x20000000) { /* RDRF. */
+ osalSysLockFromISR();
+ sdIncomingDataI(sdp, escip->DR.B.D);
+ osalSysUnlockFromISR();
+ }
+ if (escip->CR1.B.TIE && (sr & 0x80000000)) { /* TDRE. */
+ msg_t b;
+ osalSysLockFromISR();
+ b = oqGetI(&sdp->oqueue);
+ if (b < Q_OK) {
+ chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
+ escip->CR1.B.TIE = 0;
+ }
+ else {
+ escip->SR.B.TDRE = 1;
+ escip->DR.R = (uint16_t)b;
+ }
+ osalSysUnlockFromISR();
+ }
+}
+
+#if SPC5_USE_ESCIA || defined(__DOXYGEN__)
+static void notify1(io_queue_t *qp) {
+
+ (void)qp;
+ if (ESCI_A.SR.B.TDRE) {
+ msg_t b = sdRequestDataI(&SD1);
+ if (b != Q_EMPTY) {
+ ESCI_A.SR.B.TDRE = 1;
+ ESCI_A.CR1.B.TIE = 1;
+ ESCI_A.DR.R = (uint16_t)b;
+ }
+ }
+}
+#endif
+
+#if SPC5_USE_ESCIB || defined(__DOXYGEN__)
+static void notify2(io_queue_t *qp) {
+
+ (void)qp;
+ if (ESCI_B.SR.B.TDRE) {
+ msg_t b = sdRequestDataI(&SD2);
+ if (b != Q_EMPTY) {
+ ESCI_B.SR.B.TDRE = 1;
+ ESCI_B.CR1.B.TIE = 1;
+ ESCI_B.DR.R = (uint16_t)b;
+ }
+ }
+}
+#endif
+
+#if SPC5_USE_ESCIC || defined(__DOXYGEN__)
+static void notify3(io_queue_t *qp) {
+
+ (void)qp;
+ if (ESCI_C.SR.B.TDRE) {
+ msg_t b = sdRequestDataI(&SD3);
+ if (b != Q_EMPTY) {
+ ESCI_C.SR.B.TDRE = 1;
+ ESCI_C.CR1.B.TIE = 1;
+ ESCI_C.DR.R = (uint16_t)b;
+ }
+ }
+}
+#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if SPC5_USE_ESCIA || defined(__DOXYGEN__)
+#if !defined(SPC5_ESCIA_HANDLER)
+#error "SPC5_ESCIA_HANDLER not defined"
+#endif
+/**
+ * @brief eSCI-A interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_ESCIA_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_USE_ESCIB || defined(__DOXYGEN__)
+#if !defined(SPC5_ESCIB_HANDLER)
+#error "SPC5_ESCIB_HANDLER not defined"
+#endif
+/**
+ * @brief eSCI-B interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_ESCIB_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_USE_ESCIC || defined(__DOXYGEN__)
+#if !defined(SPC5_ESCIC_HANDLER)
+#error "SPC5_ESCIC_HANDLER not defined"
+#endif
+/**
+ * @brief eSCI-C interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_ESCIC_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ serve_interrupt(&SD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level serial driver initialization.
+ *
+ * @notapi
+ */
+void sd_lld_init(void) {
+
+#if SPC5_USE_ESCIA
+ sdObjectInit(&SD1, NULL, notify1);
+ SD1.escip = &ESCI_A;
+ ESCI_A.CR2.R = 0x8000; /* MDIS ON. */
+ INTC.PSR[SPC5_ESCIA_NUMBER].R = SPC5_ESCIA_PRIORITY;
+#endif
+
+#if SPC5_USE_ESCIB
+ sdObjectInit(&SD2, NULL, notify2);
+ SD2.escip = &ESCI_B;
+ ESCI_B.CR2.R = 0x8000; /* MDIS ON. */
+ INTC.PSR[SPC5_ESCIB_NUMBER].R = SPC5_ESCIB_PRIORITY;
+#endif
+
+#if SPC5_USE_ESCIC
+ sdObjectInit(&SD3, NULL, notify3);
+ SD3.escip = &ESCI_C;
+ ESCI_C.CR2.R = 0x8000; /* MDIS ON. */
+ INTC.PSR[SPC5_ESCIC_NUMBER].R = SPC5_ESCIC_PRIORITY;
+#endif
+}
+
+/**
+ * @brief Low level serial driver configuration and (re)start.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration.
+ * If this parameter is set to @p NULL then a default
+ * configuration is used.
+ *
+ * @notapi
+ */
+void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
+
+ if (config == NULL)
+ config = &default_config;
+ esci_init(sdp, config);
+}
+
+/**
+ * @brief Low level serial driver stop.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ *
+ * @notapi
+ */
+void sd_lld_stop(SerialDriver *sdp) {
+
+ if (sdp->state == SD_READY)
+ esci_deinit(sdp->escip);
+}
+
+#endif /* HAL_USE_SERIAL */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.h b/os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.h
new file mode 100644
index 000000000..041edf4cb
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/ESCI_v1/hal_serial_lld.h
@@ -0,0 +1,195 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/ESCI_v1/hal_serial_lld.c
+ * @brief SPC5xx low level serial driver header.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#ifndef HAL_SERIAL_LLD_H
+#define HAL_SERIAL_LLD_H
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Serial port modes
+ * @{
+ */
+#define SD_MODE_PARITY_MASK 0x03 /**< @brief Parity field mask. */
+#define SD_MODE_PARITY_NONE 0x00 /**< @brief No parity. */
+#define SD_MODE_PARITY_EVEN 0x01 /**< @brief Even parity. */
+#define SD_MODE_PARITY_ODD 0x02 /**< @brief Odd parity. */
+
+#define SD_MODE_NORMAL 0x00 /**< @brief Normal operations. */
+#define SD_MODE_LOOPBACK 0x80 /**< @brief Internal loopback. */
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief eSCI-A driver enable switch.
+ * @details If set to @p TRUE the support for eSCI-A is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(SPC5_USE_ESCIA) || defined(__DOXYGEN__)
+#define SPC5_USE_ESCIA FALSE
+#endif
+
+/**
+ * @brief eSCI-B driver enable switch.
+ * @details If set to @p TRUE the support for eSCI-B is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(SPC5_USE_ESCIB) || defined(__DOXYGEN__)
+#define SPC5_USE_ESCIB FALSE
+#endif
+
+/**
+ * @brief eSCI-C driver enable switch.
+ * @details If set to @p TRUE the support for eSCI-C is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(SPC5_USE_ESCIC) || defined(__DOXYGEN__)
+#define SPC5_USE_ESCIC FALSE
+#endif
+
+/**
+ * @brief eSCI-A interrupt priority level setting.
+ */
+#if !defined(SPC5_ESCIA_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_ESCIA_PRIORITY 8
+#endif
+
+/**
+ * @brief eSCI-B interrupt priority level setting.
+ */
+#if !defined(SPC5_ESCIB_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_ESCIB_PRIORITY 8
+#endif
+
+/**
+ * @brief eSCI-C interrupt priority level setting.
+ */
+#if !defined(SPC5_ESCIC_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_ESCIC_PRIORITY 8
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if SPC5_USE_ESCIA && !SPC5_HAS_ESCIA
+#error "eSCI-A not present in the selected device"
+#endif
+
+#if SPC5_USE_ESCIB && !SPC5_HAS_ESCIB
+#error "eSCI-B not present in the selected device"
+#endif
+
+#if SPC5_USE_ESCIC && !SPC5_HAS_ESCIC
+#error "eSCI-C not present in the selected device"
+#endif
+
+#if !SPC5_USE_ESCIA && !SPC5_USE_ESCIB && !SPC5_USE_ESCIC
+#error "SERIAL driver activated but no eSCI peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Generic Serial Driver configuration structure.
+ * @details An instance of this structure must be passed to @p sdStart()
+ * in order to configure and start a serial driver operations.
+ * @note This structure content is architecture dependent, each driver
+ * implementation defines its own version and the custom static
+ * initializers.
+ */
+typedef struct {
+ /**
+ * @brief Bit rate.
+ */
+ uint32_t sc_speed;
+ /**
+ * @brief Mode flags.
+ */
+ uint8_t sc_mode;
+} SerialConfig;
+
+/**
+ * @brief @p SerialDriver specific data.
+ */
+#define _serial_driver_data \
+ _base_asynchronous_channel_data \
+ /* Driver state.*/ \
+ volatile sdstate_t state; \
+ /* Input queue.*/ \
+ input_queue_t iqueue; \
+ /* Output queue.*/ \
+ output_queue_t oqueue; \
+ /* Input circular buffer.*/ \
+ uint8_t ib[SERIAL_BUFFERS_SIZE]; \
+ /* Output circular buffer.*/ \
+ uint8_t ob[SERIAL_BUFFERS_SIZE]; \
+ /* End of the mandatory fields.*/ \
+ /* Pointer to the volatile eSCI registers block.*/ \
+ volatile struct ESCI_tag *escip;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if SPC5_USE_ESCIA && !defined(__DOXYGEN__)
+extern SerialDriver SD1;
+#endif
+
+#if SPC5_USE_ESCIB && !defined(__DOXYGEN__)
+extern SerialDriver SD2;
+#endif
+
+#if SPC5_USE_ESCIC && !defined(__DOXYGEN__)
+extern SerialDriver SD3;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sd_lld_init(void);
+ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
+ void sd_lld_stop(SerialDriver *sdp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SERIAL */
+
+#endif /* HAL_SERIAL_LLD_H */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.c b/os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.c
new file mode 100644
index 000000000..0f5faae5a
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.c
@@ -0,0 +1,1171 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/LINFlex_v1/hal_serial_lld.c
+ * @brief SPC5xx low level serial driver code.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief LIINFlex-0 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX0 || defined(__DOXYGEN__)
+SerialDriver SD1;
+#endif
+
+/**
+ * @brief LIINFlex-1 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX1 || defined(__DOXYGEN__)
+SerialDriver SD2;
+#endif
+
+/**
+ * @brief LIINFlex-2 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX2 || defined(__DOXYGEN__)
+SerialDriver SD3;
+#endif
+
+/**
+ * @brief LIINFlex-3 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX3 || defined(__DOXYGEN__)
+SerialDriver SD4;
+#endif
+
+/**
+ * @brief LIINFlex-4 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX4 || defined(__DOXYGEN__)
+SerialDriver SD5;
+#endif
+
+/**
+ * @brief LIINFlex-5 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX5 || defined(__DOXYGEN__)
+SerialDriver SD6;
+#endif
+
+/**
+ * @brief LIINFlex-6 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX6 || defined(__DOXYGEN__)
+SerialDriver SD7;
+#endif
+
+/**
+ * @brief LIINFlex-7 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX7 || defined(__DOXYGEN__)
+SerialDriver SD8;
+#endif
+
+/**
+ * @brief LIINFlex-8 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX8 || defined(__DOXYGEN__)
+SerialDriver SD9;
+#endif
+
+/**
+ * @brief LIINFlex-9 serial driver identifier.
+ */
+#if SPC5_SERIAL_USE_LINFLEX9 || defined(__DOXYGEN__)
+SerialDriver SD10;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Driver default configuration.
+ */
+static const SerialConfig default_config = {
+ SERIAL_DEFAULT_BITRATE,
+ SD_MODE_8BITS_PARITY_NONE
+};
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief LINFlex initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration
+ */
+static void spc5_linflex_init(SerialDriver *sdp, const SerialConfig *config) {
+ uint32_t div;
+ volatile struct spc5_linflex *linflexp = sdp->linflexp;
+
+ /* Enters the configuration mode.*/
+ linflexp->LINCR1.R = 1; /* INIT bit. */
+
+ /* Configures the LINFlex in UART mode with all the required
+ parameters.*/
+ linflexp->UARTCR.R = SPC5_UARTCR_UART; /* UART mode FIRST. */
+ linflexp->UARTCR.R = SPC5_UARTCR_UART | SPC5_UARTCR_RXEN | config->mode;
+ div = SPC5_LINFLEX0_CLK / config->speed;
+ linflexp->LINFBRR.R = (uint16_t)(div & 15); /* Fractional divider. */
+ linflexp->LINIBRR.R = (uint16_t)(div >> 4); /* Integer divider. */
+ linflexp->UARTSR.R = 0xFFFF; /* Clearing UARTSR register.*/
+ linflexp->LINIER.R = SPC5_LINIER_DTIE | SPC5_LINIER_DRIE |
+ SPC5_LINIER_BOIE | SPC5_LINIER_FEIE |
+ SPC5_LINIER_SZIE; /* Interrupts enabled. */
+
+ /* Leaves the configuration mode.*/
+ linflexp->LINCR1.R = 0;
+}
+
+/**
+ * @brief LINFlex de-initialization.
+ * @details This function must be invoked with interrupts disabled.
+ *
+ * @param[in] linflexp pointer to a LINFlex I/O block
+ */
+static void spc5_linflex_deinit(volatile struct spc5_linflex *linflexp) {
+
+ /* Enters the configuration mode.*/
+ linflexp->LINCR1.R = 1; /* INIT bit. */
+
+ /* Resets the LINFlex registers.*/
+ linflexp->LINFBRR.R = 0; /* Fractional divider. */
+ linflexp->LINIBRR.R = 0; /* Integer divider. */
+ linflexp->UARTSR.R = 0xFFFF; /* Clearing UARTSR register.*/
+ linflexp->UARTCR.R = SPC5_UARTCR_UART;
+ linflexp->LINIER.R = 0; /* Interrupts disabled. */
+
+ /* Leaves the configuration mode.*/
+ linflexp->LINCR1.R = 0;
+}
+
+/**
+ * @brief Common RXI IRQ handler.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ */
+static void spc5xx_serve_rxi_interrupt(SerialDriver *sdp) {
+ eventflags_t sts = 0;
+ uint16_t sr = sdp->linflexp->UARTSR.R;
+
+ sdp->linflexp->UARTSR.R = SPC5_UARTSR_NF | SPC5_UARTSR_DRF |
+ SPC5_UARTSR_PE0;
+ if (sr & SPC5_UARTSR_NF)
+ sts |= SD_NOISE_ERROR;
+ if (sr & SPC5_UARTSR_PE0)
+ sts |= SD_PARITY_ERROR;
+ osalSysLockFromISR();
+ if (sts)
+ chnAddFlagsI(sdp, sts);
+ if (sr & SPC5_UARTSR_DRF) {
+ sdIncomingDataI(sdp, sdp->linflexp->BDRM.B.DATA4);
+ sdp->linflexp->UARTSR.R = SPC5_UARTSR_RMB;
+ }
+ osalSysUnlockFromISR();
+}
+
+/**
+ * @brief Common TXI IRQ handler.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ */
+static void spc5xx_serve_txi_interrupt(SerialDriver *sdp) {
+ msg_t b;
+
+ sdp->linflexp->UARTSR.R = SPC5_UARTSR_DTF;
+ osalSysLockFromISR();
+ b = oqGetI(&sdp->oqueue);
+ if (b < Q_OK) {
+ chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
+ sdp->linflexp->UARTCR.B.TXEN = 0;
+ }
+ else
+ sdp->linflexp->BDRL.B.DATA0 = b;
+ osalSysUnlockFromISR();
+}
+
+/**
+ * @brief Common ERR IRQ handler.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ */
+static void spc5xx_serve_err_interrupt(SerialDriver *sdp) {
+ eventflags_t sts = 0;
+ uint16_t sr = sdp->linflexp->UARTSR.R;
+
+ sdp->linflexp->UARTSR.R = SPC5_UARTSR_BOF | SPC5_UARTSR_FEF |
+ SPC5_UARTSR_SZF;
+ if (sr & SPC5_UARTSR_BOF)
+ sts |= SD_OVERRUN_ERROR;
+ if (sr & SPC5_UARTSR_FEF)
+ sts |= SD_FRAMING_ERROR;
+ if (sr & SPC5_UARTSR_SZF)
+ sts |= SD_BREAK_DETECTED;
+ osalSysLockFromISR();
+ chnAddFlagsI(sdp, sts);
+ osalSysUnlockFromISR();
+}
+
+#if SPC5_SERIAL_USE_LINFLEX0 || defined(__DOXYGEN__)
+static void notify1(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD1.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD1);
+ if (b != Q_EMPTY) {
+ SD1.linflexp->UARTCR.B.TXEN = 1;
+ SD1.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX1 || defined(__DOXYGEN__)
+static void notify2(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD2.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD2);
+ if (b != Q_EMPTY) {
+ SD2.linflexp->UARTCR.B.TXEN = 1;
+ SD2.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX2 || defined(__DOXYGEN__)
+static void notify3(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD3.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD3);
+ if (b != Q_EMPTY) {
+ SD3.linflexp->UARTCR.B.TXEN = 1;
+ SD3.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX3 || defined(__DOXYGEN__)
+static void notify4(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD4.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD4);
+ if (b != Q_EMPTY) {
+ SD4.linflexp->UARTCR.B.TXEN = 1;
+ SD4.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX4 || defined(__DOXYGEN__)
+static void notify5(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD5.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD5);
+ if (b != Q_EMPTY) {
+ SD5.linflexp->UARTCR.B.TXEN = 1;
+ SD5.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX5 || defined(__DOXYGEN__)
+static void notify6(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD6.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD6);
+ if (b != Q_EMPTY) {
+ SD6.linflexp->UARTCR.B.TXEN = 1;
+ SD6.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX6 || defined(__DOXYGEN__)
+static void notify7(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD7.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD7);
+ if (b != Q_EMPTY) {
+ SD7.linflexp->UARTCR.B.TXEN = 1;
+ SD7.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX7 || defined(__DOXYGEN__)
+static void notify8(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD8.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD8);
+ if (b != Q_EMPTY) {
+ SD8.linflexp->UARTCR.B.TXEN = 1;
+ SD8.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX8 || defined(__DOXYGEN__)
+static void notify9(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD9.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD9);
+ if (b != Q_EMPTY) {
+ SD9.linflexp->UARTCR.B.TXEN = 1;
+ SD9.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX9 || defined(__DOXYGEN__)
+static void notify10(io_queue_t *qp) {
+
+ (void)qp;
+ if (!SD10.linflexp->UARTCR.B.TXEN) {
+ msg_t b = sdRequestDataI(&SD10);
+ if (b != Q_EMPTY) {
+ SD10.linflexp->UARTCR.B.TXEN = 1;
+ SD10.linflexp->BDRL.B.DATA0 = b;
+ }
+ }
+}
+#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if SPC5_SERIAL_USE_LINFLEX0 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX0_RXI_HANDLER)
+#error "SPC5_LINFLEX0_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-0 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX0_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX0_TXI_HANDLER)
+#error "SPC5_LINFLEX0_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-0 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX0_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX0_ERR_HANDLER)
+#error "SPC5_LINFLEX0_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-0 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX0_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD1);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX1 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX1_RXI_HANDLER)
+#error "SPC5_LINFLEX1_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-1 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX1_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX1_TXI_HANDLER)
+#error "SPC5_LINFLEX1_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-1 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX1_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX1_ERR_HANDLER)
+#error "SPC5_LINFLEX1_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-1 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX1_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD2);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX2 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX2_RXI_HANDLER)
+#error "SPC5_LINFLEX2_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-2 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX2_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX2_TXI_HANDLER)
+#error "SPC5_LINFLEX2_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-2 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX2_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX2_ERR_HANDLER)
+#error "SPC5_LINFLEX2_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-2 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX2_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD3);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX3 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX3_RXI_HANDLER)
+#error "SPC5_LINFLEX3_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-3 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX3_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX3_TXI_HANDLER)
+#error "SPC5_LINFLEX3_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-3 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX3_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX3_ERR_HANDLER)
+#error "SPC5_LINFLEX3_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-3 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX3_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD4);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX4 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX4_RXI_HANDLER)
+#error "SPC5_LINFLEX4_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-4 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX4_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX4_TXI_HANDLER)
+#error "SPC5_LINFLEX4_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-4 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX4_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX4_ERR_HANDLER)
+#error "SPC5_LINFLEX4_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-4 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX4_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD5);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX5 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX5_RXI_HANDLER)
+#error "SPC5_LINFLEX5_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-5 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX5_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX5_TXI_HANDLER)
+#error "SPC5_LINFLEX5_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-5 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX5_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX5_ERR_HANDLER)
+#error "SPC5_LINFLEX5_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-5 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX5_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD6);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX6 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX6_RXI_HANDLER)
+#error "SPC5_LINFLEX6_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-6 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX6_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX6_TXI_HANDLER)
+#error "SPC5_LINFLEX6_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-6 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX6_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX6_ERR_HANDLER)
+#error "SPC5_LINFLEX6_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-6 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX6_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD7);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX7 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX7_RXI_HANDLER)
+#error "SPC5_LINFLEX7_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-7 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX7_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX7_TXI_HANDLER)
+#error "SPC5_LINFLEX7_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-7 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX7_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX7_ERR_HANDLER)
+#error "SPC5_LINFLEX7_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-7 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX7_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD8);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX8 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX8_RXI_HANDLER)
+#error "SPC5_LINFLEX8_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-8 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX8_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD9);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX8_TXI_HANDLER)
+#error "SPC5_LINFLEX8_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-8 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX8_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD9);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX8_ERR_HANDLER)
+#error "SPC5_LINFLEX8_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-8 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX8_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD9);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX9 || defined(__DOXYGEN__)
+#if !defined(SPC5_LINFLEX9_RXI_HANDLER)
+#error "SPC5_LINFLEX9_RXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-9 RXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX9_RXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_rxi_interrupt(&SD10);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX9_TXI_HANDLER)
+#error "SPC5_LINFLEX9_TXI_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-9 TXI interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX9_TXI_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_txi_interrupt(&SD10);
+
+ OSAL_IRQ_EPILOGUE();
+}
+
+#if !defined(SPC5_LINFLEX9_ERR_HANDLER)
+#error "SPC5_LINFLEX9_ERR_HANDLER not defined"
+#endif
+/**
+ * @brief LINFlex-9 ERR interrupt handler.
+ *
+ * @isr
+ */
+OSAL_IRQ_HANDLER(SPC5_LINFLEX9_ERR_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ spc5xx_serve_err_interrupt(&SD10);
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level serial driver initialization.
+ *
+ * @notapi
+ */
+void sd_lld_init(void) {
+
+#if SPC5_SERIAL_USE_LINFLEX0
+ sdObjectInit(&SD1, NULL, notify1);
+ SD1.linflexp = &SPC5_LINFLEX0;
+ INTC_PSR(SPC5_LINFLEX0_RXI_NUMBER) = SPC5_SERIAL_LINFLEX0_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX0_TXI_NUMBER) = SPC5_SERIAL_LINFLEX0_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX0_ERR_NUMBER) = SPC5_SERIAL_LINFLEX0_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX1
+ sdObjectInit(&SD2, NULL, notify2);
+ SD2.linflexp = &SPC5_LINFLEX1;
+ INTC_PSR(SPC5_LINFLEX1_RXI_NUMBER) = SPC5_SERIAL_LINFLEX1_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX1_TXI_NUMBER) = SPC5_SERIAL_LINFLEX1_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX1_ERR_NUMBER) = SPC5_SERIAL_LINFLEX1_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX2
+ sdObjectInit(&SD3, NULL, notify3);
+ SD3.linflexp = &SPC5_LINFLEX2;
+ INTC_PSR(SPC5_LINFLEX2_RXI_NUMBER) = SPC5_SERIAL_LINFLEX2_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX2_TXI_NUMBER) = SPC5_SERIAL_LINFLEX2_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX2_ERR_NUMBER) = SPC5_SERIAL_LINFLEX2_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX3
+ sdObjectInit(&SD4, NULL, notify4);
+ SD4.linflexp = &SPC5_LINFLEX3;
+ INTC_PSR(SPC5_LINFLEX3_RXI_NUMBER) = SPC5_SERIAL_LINFLEX3_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX3_TXI_NUMBER) = SPC5_SERIAL_LINFLEX3_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX3_ERR_NUMBER) = SPC5_SERIAL_LINFLEX3_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX4
+ sdObjectInit(&SD5, NULL, notify5);
+ SD5.linflexp = &SPC5_LINFLEX4;
+ INTC_PSR(SPC5_LINFLEX4_RXI_NUMBER) = SPC5_SERIAL_LINFLEX4_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX4_TXI_NUMBER) = SPC5_SERIAL_LINFLEX4_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX4_ERR_NUMBER) = SPC5_SERIAL_LINFLEX4_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX5
+ sdObjectInit(&SD6, NULL, notify6);
+ SD6.linflexp = &SPC5_LINFLEX5;
+ INTC_PSR(SPC5_LINFLEX5_RXI_NUMBER) = SPC5_SERIAL_LINFLEX5_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX5_TXI_NUMBER) = SPC5_SERIAL_LINFLEX5_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX5_ERR_NUMBER) = SPC5_SERIAL_LINFLEX5_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX6
+ sdObjectInit(&SD7, NULL, notify7);
+ SD7.linflexp = &SPC5_LINFLEX6;
+ INTC_PSR(SPC5_LINFLEX6_RXI_NUMBER) = SPC5_SERIAL_LINFLEX6_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX6_TXI_NUMBER) = SPC5_SERIAL_LINFLEX6_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX6_ERR_NUMBER) = SPC5_SERIAL_LINFLEX6_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX7
+ sdObjectInit(&SD8, NULL, notify8);
+ SD8.linflexp = &SPC5_LINFLEX7;
+ INTC_PSR(SPC5_LINFLEX7_RXI_NUMBER) = SPC5_SERIAL_LINFLEX7_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX7_TXI_NUMBER) = SPC5_SERIAL_LINFLEX7_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX7_ERR_NUMBER) = SPC5_SERIAL_LINFLEX7_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX8
+ sdObjectInit(&SD9, NULL, notify9);
+ SD9.linflexp = &SPC5_LINFLEX8;
+ INTC_PSR(SPC5_LINFLEX8_RXI_NUMBER) = SPC5_SERIAL_LINFLEX8_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX8_TXI_NUMBER) = SPC5_SERIAL_LINFLEX8_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX8_ERR_NUMBER) = SPC5_SERIAL_LINFLEX8_PRIORITY;
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX9
+ sdObjectInit(&SD10, NULL, notify10);
+ SD10.linflexp = &SPC5_LINFLEX9;
+ INTC_PSR(SPC5_LINFLEX9_RXI_NUMBER) = SPC5_SERIAL_LINFLEX9_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX9_TXI_NUMBER) = SPC5_SERIAL_LINFLEX9_PRIORITY;
+ INTC_PSR(SPC5_LINFLEX9_ERR_NUMBER) = SPC5_SERIAL_LINFLEX9_PRIORITY;
+#endif
+}
+
+/**
+ * @brief Low level serial driver configuration and (re)start.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ * @param[in] config the architecture-dependent serial driver configuration.
+ * If this parameter is set to @p NULL then a default
+ * configuration is used.
+ *
+ * @notapi
+ */
+void sd_lld_start(SerialDriver *sdp, const SerialConfig *config) {
+
+ if (config == NULL)
+ config = &default_config;
+
+ if (sdp->state == SD_STOP) {
+#if SPC5_SERIAL_USE_LINFLEX0
+ if (&SD1 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX0_PCTL,
+ SPC5_SERIAL_LINFLEX0_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX1
+ if (&SD2 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX1_PCTL,
+ SPC5_SERIAL_LINFLEX1_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX2
+ if (&SD3 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX2_PCTL,
+ SPC5_SERIAL_LINFLEX2_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX3
+ if (&SD4 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX3_PCTL,
+ SPC5_SERIAL_LINFLEX3_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX4
+ if (&SD5 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX4_PCTL,
+ SPC5_SERIAL_LINFLEX4_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX5
+ if (&SD6 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX5_PCTL,
+ SPC5_SERIAL_LINFLEX5_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX6
+ if (&SD7 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX6_PCTL,
+ SPC5_SERIAL_LINFLEX6_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX7
+ if (&SD8 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX7_PCTL,
+ SPC5_SERIAL_LINFLEX7_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX8
+ if (&SD9 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX8_PCTL,
+ SPC5_SERIAL_LINFLEX8_START_PCTL);
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX9
+ if (&SD10 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX9_PCTL,
+ SPC5_SERIAL_LINFLEX9_START_PCTL);
+ }
+#endif
+ }
+ spc5_linflex_init(sdp, config);
+}
+
+/**
+ * @brief Low level serial driver stop.
+ *
+ * @param[in] sdp pointer to a @p SerialDriver object
+ *
+ * @notapi
+ */
+void sd_lld_stop(SerialDriver *sdp) {
+
+ if (sdp->state == SD_READY) {
+ spc5_linflex_deinit(sdp->linflexp);
+
+#if SPC5_SERIAL_USE_LINFLEX0
+ if (&SD1 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX0_PCTL,
+ SPC5_SERIAL_LINFLEX0_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX1
+ if (&SD2 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX1_PCTL,
+ SPC5_SERIAL_LINFLEX1_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX2
+ if (&SD3 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX2_PCTL,
+ SPC5_SERIAL_LINFLEX2_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX3
+ if (&SD4 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX3_PCTL,
+ SPC5_SERIAL_LINFLEX3_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX4
+ if (&SD5 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX4_PCTL,
+ SPC5_SERIAL_LINFLEX4_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX5
+ if (&SD6 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX5_PCTL,
+ SPC5_SERIAL_LINFLEX5_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX6
+ if (&SD7 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX6_PCTL,
+ SPC5_SERIAL_LINFLEX6_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX7
+ if (&SD8 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX7_PCTL,
+ SPC5_SERIAL_LINFLEX7_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX8
+ if (&SD9 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX8_PCTL,
+ SPC5_SERIAL_LINFLEX8_STOP_PCTL);
+ return;
+ }
+#endif
+#if SPC5_SERIAL_USE_LINFLEX9
+ if (&SD10 == sdp) {
+ halSPCSetPeripheralClockMode(SPC5_LINFLEX9_PCTL,
+ SPC5_SERIAL_LINFLEX9_STOP_PCTL);
+ return;
+ }
+#endif
+ }
+}
+
+#endif /* HAL_USE_SERIAL */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.h b/os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.h
new file mode 100644
index 000000000..31eb3e002
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/LINFlex_v1/hal_serial_lld.h
@@ -0,0 +1,574 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/LINFlex_v1/hal_serial_lld.h
+ * @brief SPC5xx low level serial driver header.
+ *
+ * @addtogroup SERIAL
+ * @{
+ */
+
+#ifndef HAL_SERIAL_LLD_H
+#define HAL_SERIAL_LLD_H
+
+#if HAL_USE_SERIAL || defined(__DOXYGEN__)
+
+#include "spc5_linflex.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name Serial driver allowable modes
+ * @{
+ */
+#define SD_MODE_8BITS_PARITY_NONE (SPC5_UARTCR_WL)
+#define SD_MODE_8BITS_PARITY_EVEN (SPC5_UARTCR_WL | \
+ SPC5_UARTCR_PCE)
+#define SD_MODE_8BITS_PARITY_ODD (SPC5_UARTCR_WL | \
+ SPC5_UARTCR_PCE | \
+ SPC5_UARTCR_OP)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief LINFlex-0 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-0 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX0) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX0 FALSE
+#endif
+
+/**
+ * @brief LINFlex-1 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-1 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX1) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX1 FALSE
+#endif
+
+/**
+ * @brief LINFlex-2 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-2 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX2) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX2 FALSE
+#endif
+
+/**
+ * @brief LINFlex-3 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-3 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX3) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX3 FALSE
+#endif
+
+/**
+ * @brief LINFlex-4 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-4 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX4) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX4 FALSE
+#endif
+
+/**
+ * @brief LINFlex-5 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-5 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX5) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX5 FALSE
+#endif
+
+/**
+ * @brief LINFlex-6 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-6 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX6) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX6 FALSE
+#endif
+
+/**
+ * @brief LINFlex-7 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-7 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX7) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX7 FALSE
+#endif
+
+/**
+ * @brief LINFlex-8 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-8 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX8) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX8 FALSE
+#endif
+
+/**
+ * @brief LINFlex-9 driver enable switch.
+ * @details If set to @p TRUE the support for LINFlex-9 is included.
+ */
+#if !defined(SPC5_SERIAL_USE_LINFLEX9) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_USE_LINFLEX9 FALSE
+#endif
+
+/**
+ * @brief LINFlex-0 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX0_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX0_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-1 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX1_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX1_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-2 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX2_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX2_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-3 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX3_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX3_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-4 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX4_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX4_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-5 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX5_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX5_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-6 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX6_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX6_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-7 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX7_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX7_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-8 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX8_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX8_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-9 interrupt priority level setting.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX9_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX9_PRIORITY 8
+#endif
+
+/**
+ * @brief LINFlex-0 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX0_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX0_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-0 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX0_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX0_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-1 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX1_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX1_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-1 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX1_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX1_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-2 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX2_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX2_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-2 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX2_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX2_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-3 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX3_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX3_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-3 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX3_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX3_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-4 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX4_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX4_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-4 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX4_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX4_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-5 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX5_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX5_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-5 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX5_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX5_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-6 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX6_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX6_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-6 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX6_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX6_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-7 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX7_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX7_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-7 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX7_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX7_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-8 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX8_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX8_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-8 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX8_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX8_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+
+/**
+ * @brief LINFlex-9 peripheral configuration when started.
+ * @note The default configuration is 1 (always run) in run mode and
+ * 2 (only halt) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX9_START_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX9_START_PCTL (SPC5_ME_PCTL_RUN(1) | \
+ SPC5_ME_PCTL_LP(2))
+#endif
+
+/**
+ * @brief LINFlex-9 peripheral configuration when stopped.
+ * @note The default configuration is 0 (never run) in run mode and
+ * 0 (never run) in low power mode. The defaults of the run modes
+ * are defined in @p hal_lld.h.
+ */
+#if !defined(SPC5_SERIAL_LINFLEX9_STOP_PCTL) || defined(__DOXYGEN__)
+#define SPC5_SERIAL_LINFLEX9_STOP_PCTL (SPC5_ME_PCTL_RUN(0) | \
+ SPC5_ME_PCTL_LP(0))
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if SPC5_SERIAL_USE_LINFLEX0 && !SPC5_HAS_LINFLEX0
+#error "LINFlex-0 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX1 && !SPC5_HAS_LINFLEX1
+#error "LINFlex-1 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX2 && !SPC5_HAS_LINFLEX2
+#error "LINFlex-2 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX3 && !SPC5_HAS_LINFLEX3
+#error "LINFlex-3 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX4 && !SPC5_HAS_LINFLEX4
+#error "LINFlex-4 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX5 && !SPC5_HAS_LINFLEX5
+#error "LINFlex-5 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX6 && !SPC5_HAS_LINFLEX6
+#error "LINFlex-6 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX7 && !SPC5_HAS_LINFLEX7
+#error "LINFlex-7 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX8 && !SPC5_HAS_LINFLEX8
+#error "LINFlex-8 not present in the selected device"
+#endif
+
+#if SPC5_SERIAL_USE_LINFLEX9 && !SPC5_HAS_LINFLEX9
+#error "LINFlex-9 not present in the selected device"
+#endif
+
+#if !SPC5_SERIAL_USE_LINFLEX0 && !SPC5_SERIAL_USE_LINFLEX1 && \
+ !SPC5_SERIAL_USE_LINFLEX2 && !SPC5_SERIAL_USE_LINFLEX3 && \
+ !SPC5_SERIAL_USE_LINFLEX4 && !SPC5_SERIAL_USE_LINFLEX5 && \
+ !SPC5_SERIAL_USE_LINFLEX6 && !SPC5_SERIAL_USE_LINFLEX7 && \
+ !SPC5_SERIAL_USE_LINFLEX8 && !SPC5_SERIAL_USE_LINFLEX9
+#error "SERIAL driver activated but no LINFlex peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Generic Serial Driver configuration structure.
+ * @details An instance of this structure must be passed to @p sdStart()
+ * in order to configure and start a serial driver operations.
+ * @note This structure content is architecture dependent, each driver
+ * implementation defines its own version and the custom static
+ * initializers.
+ */
+typedef struct {
+ /**
+ * @brief Bit rate.
+ */
+ uint32_t speed;
+ /**
+ * @brief Mode flags.
+ */
+ uint8_t mode;
+} SerialConfig;
+
+/**
+ * @brief @p SerialDriver specific data.
+ */
+#define _serial_driver_data \
+ _base_asynchronous_channel_data \
+ /* Driver state.*/ \
+ volatile sdstate_t state; \
+ /* Input queue.*/ \
+ input_queue_t iqueue; \
+ /* Output queue.*/ \
+ output_queue_t oqueue; \
+ /* Input circular buffer.*/ \
+ uint8_t ib[SERIAL_BUFFERS_SIZE]; \
+ /* Output circular buffer.*/ \
+ uint8_t ob[SERIAL_BUFFERS_SIZE]; \
+ /* End of the mandatory fields.*/ \
+ /* Pointer to the volatile LINFlex registers block.*/ \
+ volatile struct spc5_linflex *linflexp;
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if SPC5_SERIAL_USE_LINFLEX0 && !defined(__DOXYGEN__)
+extern SerialDriver SD1;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX1 && !defined(__DOXYGEN__)
+extern SerialDriver SD2;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX2 && !defined(__DOXYGEN__)
+extern SerialDriver SD3;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX3 && !defined(__DOXYGEN__)
+extern SerialDriver SD4;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX4 && !defined(__DOXYGEN__)
+extern SerialDriver SD5;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX5 && !defined(__DOXYGEN__)
+extern SerialDriver SD6;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX6 && !defined(__DOXYGEN__)
+extern SerialDriver SD7;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX7 && !defined(__DOXYGEN__)
+extern SerialDriver SD8;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX8 && !defined(__DOXYGEN__)
+extern SerialDriver SD9;
+#endif
+#if SPC5_SERIAL_USE_LINFLEX9 && !defined(__DOXYGEN__)
+extern SerialDriver SD10;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void sd_lld_init(void);
+ void sd_lld_start(SerialDriver *sdp, const SerialConfig *config);
+ void sd_lld_stop(SerialDriver *sdp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_SERIAL */
+
+#endif /* HAL_SERIAL_LLD_H */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/LINFlex_v1/spc5_linflex.h b/os/hal/ports/SPC5/LLD/LINFlex_v1/spc5_linflex.h
new file mode 100644
index 000000000..7c668fba1
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/LINFlex_v1/spc5_linflex.h
@@ -0,0 +1,637 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/spc5_linflex.h
+ * @brief LINFlex helper driver header.
+ *
+ * @addtogroup SPC5xx_LINFLEX
+ * @{
+ */
+
+#ifndef _SPC5_LINFLEX_H_
+#define _SPC5_LINFLEX_H_
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name LINIER register bits definitions
+ * @{
+ */
+#define SPC5_LINIER_HRIE (1U << 0)
+#define SPC5_LINIER_DTIE (1U << 1)
+#define SPC5_LINIER_DRIE (1U << 2)
+#define SPC5_LINIER_DBEIE (1U << 3)
+#define SPC5_LINIER_DBFIE (1U << 4)
+#define SPC5_LINIER_WUIE (1U << 5)
+#define SPC5_LINIER_LSIE (1U << 6)
+#define SPC5_LINIER_BOIE (1U << 7)
+#define SPC5_LINIER_FEIE (1U << 8)
+#define SPC5_LINIER_HEIE (1U << 11)
+#define SPC5_LINIER_CEIE (1U << 12)
+#define SPC5_LINIER_BEIE (1U << 13)
+#define SPC5_LINIER_OCIE (1U << 14)
+#define SPC5_LINIER_SZIE (1U << 15)
+/** @} */
+
+/**
+ * @name UARTSR register bits definitions
+ * @{
+ */
+#define SPC5_UARTSR_NF (1U << 0)
+#define SPC5_UARTSR_DTF (1U << 1)
+#define SPC5_UARTSR_DRF (1U << 2)
+#define SPC5_UARTSR_WUF (1U << 5)
+#define SPC5_UARTSR_RPS (1U << 6)
+#define SPC5_UARTSR_BOF (1U << 7)
+#define SPC5_UARTSR_FEF (1U << 8)
+#define SPC5_UARTSR_RMB (1U << 9)
+#define SPC5_UARTSR_PE0 (1U << 10)
+#define SPC5_UARTSR_PE1 (1U << 11)
+#define SPC5_UARTSR_PE2 (1U << 12)
+#define SPC5_UARTSR_PE3 (1U << 13)
+#define SPC5_UARTSR_OCF (1U << 14)
+#define SPC5_UARTSR_SZF (1U << 15)
+/** @} */
+
+/**
+ * @name UARTCR register bits definitions
+ * @{
+ */
+#define SPC5_UARTCR_UART (1U << 0)
+#define SPC5_UARTCR_WL (1U << 1)
+#define SPC5_UARTCR_PCE (1U << 2)
+#define SPC5_UARTCR_OP (1U << 3)
+#define SPC5_UARTCR_TXEN (1U << 4)
+#define SPC5_UARTCR_RXEN (1U << 5)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+
+struct spc5_linflex {
+
+ int16_t LINFLEX_reserved1;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t CCD :1;
+ vuint16_t CFD :1;
+ vuint16_t LASE :1;
+ vuint16_t AWUM :1;
+ vuint16_t MBL :4;
+ vuint16_t BF :1;
+ vuint16_t SFTM :1;
+ vuint16_t LBKM :1;
+ vuint16_t MME :1;
+ vuint16_t SBDT :1;
+ vuint16_t RBLM :1;
+ vuint16_t SLEEP :1;
+ vuint16_t INIT :1;
+ } B;
+ } LINCR1;
+
+ int16_t LINFLEX_reserved2;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t SZIE :1;
+ vuint16_t OCIE :1;
+ vuint16_t BEIE :1;
+ vuint16_t CEIE :1;
+ vuint16_t HEIE :1;
+ vuint16_t :2;
+ vuint16_t FEIE :1;
+ vuint16_t BOIE :1;
+ vuint16_t LSIE :1;
+ vuint16_t WUIE :1;
+ vuint16_t DBFIE :1;
+ vuint16_t DBEIE :1;
+ vuint16_t DRIE :1;
+ vuint16_t DTIE :1;
+ vuint16_t HRIE :1;
+ } B;
+ } LINIER;
+
+ int16_t LINFLEX_reserved3;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t LINS :4;
+ vuint16_t :2;
+ vuint16_t RMB :1;
+ vuint16_t :1;
+ vuint16_t RBSY :1;
+ vuint16_t RPS :1;
+ vuint16_t WUF :1;
+ vuint16_t DBFF :1;
+ vuint16_t DBEF :1;
+ vuint16_t DRF :1;
+ vuint16_t DTF :1;
+ vuint16_t HRF :1;
+ } B;
+ } LINSR;
+
+ int16_t LINFLEX_reserved4;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t SZF :1;
+ vuint16_t OCF :1;
+ vuint16_t BEF :1;
+ vuint16_t CEF :1;
+ vuint16_t SFEF :1;
+ vuint16_t BDEF :1;
+ vuint16_t IDPEF :1;
+ vuint16_t FEF :1;
+ vuint16_t BOF :1;
+ vuint16_t :6;
+ vuint16_t NF :1;
+ } B;
+ } LINESR;
+
+ int16_t LINFLEX_reserved5;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :1;
+ vuint16_t TDFL :2;
+ vuint16_t :1;
+ vuint16_t RDFL :2;
+ vuint16_t :4;
+ vuint16_t RXEN :1;
+ vuint16_t TXEN :1;
+ vuint16_t OP :1;
+ vuint16_t PCE :1;
+ vuint16_t WL :1;
+ vuint16_t UART :1;
+ } B;
+ } UARTCR;
+
+ int16_t LINFLEX_reserved6;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t SZF :1;
+ vuint16_t OCF :1;
+ vuint16_t PE :4;
+ vuint16_t RMB :1;
+ vuint16_t FEF :1;
+ vuint16_t BOF :1;
+ vuint16_t RPS :1;
+ vuint16_t WUF :1;
+ vuint16_t :2;
+ vuint16_t DRF :1;
+ vuint16_t DTF :1;
+ vuint16_t NF :1;
+ } B;
+ } UARTSR;
+
+ int16_t LINFLEX_reserved7;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :5;
+ vuint16_t LTOM :1;
+ vuint16_t IOT :1;
+ vuint16_t TOCE :1;
+ vuint16_t CNT :8;
+ } B;
+ } LINTCSR;
+
+ int16_t LINFLEX_reserved8;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t OC2 :8;
+ vuint16_t OC1 :8;
+ } B;
+ } LINOCR;
+
+ int16_t LINFLEX_reserved9;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :4;
+ vuint16_t RTO :4;
+ vuint16_t :1;
+ vuint16_t HTO :7;
+ } B;
+ } LINTOCR;
+
+ int16_t LINFLEX_reserved10;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :12;
+ vuint16_t DIV_F :4;
+ } B;
+ } LINFBRR;
+
+ int16_t LINFLEX_reserved11;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DIV_M :13;
+ } B;
+ } LINIBRR;
+
+ int16_t LINFLEX_reserved12;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :8;
+ vuint16_t CF :8;
+ } B;
+ } LINCFR;
+
+ int16_t LINFLEX_reserved13;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :1;
+ vuint16_t IOBE :1;
+ vuint16_t IOPE :1;
+ vuint16_t WURQ :1;
+ vuint16_t DDRQ :1;
+ vuint16_t DTRQ :1;
+ vuint16_t ABRQ :1;
+ vuint16_t HTRQ :1;
+ vuint16_t :8;
+ } B;
+ } LINCR2;
+
+ int16_t LINFLEX_reserved14;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t DFL :6;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } BIDR;
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t DATA3 :8;
+ vuint32_t DATA2 :8;
+ vuint32_t DATA1 :8;
+ vuint32_t DATA0 :8;
+ } B;
+ } BDRL;
+
+ union {
+ vuint32_t R;
+ struct {
+ vuint32_t DATA7 :8;
+ vuint32_t DATA6 :8;
+ vuint32_t DATA5 :8;
+ vuint32_t DATA4 :8;
+ } B;
+ } BDRM;
+
+ int16_t LINFLEX_reserved15;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :8;
+ vuint16_t FACT :8;
+ } B;
+ } IFER;
+
+ int16_t LINFLEX_reserved16;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :12;
+ vuint16_t IFMI :4;
+ } B;
+ } IFMI;
+
+ int16_t LINFLEX_reserved17;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :12;
+ vuint16_t IFM :4;
+ } B;
+ } IFMR;
+
+ int16_t LINFLEX_reserved18;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR0;
+
+ int16_t LINFLEX_reserved19;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR1;
+
+ int16_t LINFLEX_reserved20;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR2;
+
+ int16_t LINFLEX_reserved21;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR3;
+
+ int16_t LINFLEX_reserved22;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR4;
+
+ int16_t LINFLEX_reserved23;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR5;
+
+ int16_t LINFLEX_reserved24;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR6;
+
+ int16_t LINFLEX_reserved25;
+
+ union {
+ vuint16_t R;
+ struct {
+ vuint16_t :3;
+ vuint16_t DFL :3;
+ vuint16_t DIR :1;
+ vuint16_t CCS :1;
+ vuint16_t :2;
+ vuint16_t ID :6;
+ } B;
+ } IFCR7;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+/**
+ * @name LINFlex units references
+ * @{
+ */
+#if defined(_SPC570Sxx_)
+/* Locations for SPC570Sxx devices.*/
+#if SPC5_HAS_LINFLEX0 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX0 (*(struct spc5_linflex *)0xFFE8C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX1 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX1 (*(struct spc5_linflex *)0xFBE8C000UL)
+#endif
+
+#elif defined(_SPC57EMxx_)
+/* Locations for SPC57EMxx devices.*/
+#if SPC5_HAS_LINFLEX0 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX0 (*(struct spc5_linflex *)0xFFE8C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX1 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX1 (*(struct spc5_linflex *)0xFFE90000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX2 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX2 (*(struct spc5_linflex *)0xFBE8C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX14 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX14 (*(struct spc5_linflex *)0xFFEA8000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX15 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX15 (*(struct spc5_linflex *)0xFBEA8000UL)
+#endif
+
+#elif defined(_SPC58NExx_) || defined(_SPC58ECxx_)
+/* Locations for _SPC58NExx_ and _SPC58ECxx_ devices.*/
+#if SPC5_HAS_LINFLEX0 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX0 (*(struct spc5_linflex *)0xF7E8C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX1 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX1 (*(struct spc5_linflex *)0xFBE8C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX2 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX2 (*(struct spc5_linflex *)0xF7E90000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX3 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX3 (*(struct spc5_linflex *)0xFBE90000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX4 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX4 (*(struct spc5_linflex *)0xF7E94000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX5 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX5 (*(struct spc5_linflex *)0xFBE94000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX6 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX6 (*(struct spc5_linflex *)0xF7E98000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX7 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX7 (*(struct spc5_linflex *)0xFBE98000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX8 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX8 (*(struct spc5_linflex *)0x0xF7E9C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX9 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX9 (*(struct spc5_linflex *)0xFBE9C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX10 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX10 (*(struct spc5_linflex *)xF7EA0000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX11 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX11 (*(struct spc5_linflex *)0xFBEA0000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX12 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX12 (*(struct spc5_linflex *)0xF7EA4000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX13 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX13 (*(struct spc5_linflex *)0xFBEA4000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX14 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX14 (*(struct spc5_linflex *)0xFFEA8000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX15 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX15 (*(struct spc5_linflex *)0xFBEA8000UL)
+#endif
+
+#else /* !defined(_SPC570Sxx_) && !defined(_SPC57EMxx_) */
+/* Default locations for SPC56x devices.*/
+#if SPC5_HAS_LINFLEX0 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX0 (*(struct spc5_linflex *)0xFFE40000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX1 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX1 (*(struct spc5_linflex *)0xFFE44000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX2 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX2 (*(struct spc5_linflex *)0xFFE48000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX3 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX3 (*(struct spc5_linflex *)0xFFE4C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX4 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX4 (*(struct spc5_linflex *)0xFFE50000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX5 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX5 (*(struct spc5_linflex *)0xFFE54000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX6 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX6 (*(struct spc5_linflex *)0xFFE58000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX7 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX7 (*(struct spc5_linflex *)0xFFE5C000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX8 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX8 (*(struct spc5_linflex *)0xFFFB0000UL)
+#endif
+
+#if SPC5_HAS_LINFLEX9 || defined(__DOXYGEN__)
+#define SPC5_LINFLEX9 (*(struct spc5_linflex *)0xFFFB4000UL)
+#endif
+
+#endif /* !defined(_SPC57EMxx_) */
+
+/** @} */
+
+#endif /* _SPC5_LINFLEX_H_ */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.c b/os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.c
new file mode 100644
index 000000000..07d14556f
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.c
@@ -0,0 +1,177 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/SIUL_v1/hal_pal_lld.c
+ * @brief SPC5xx SIUL low level driver code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief Event records (to be implemented).
+ */
+palevent_t _pal_events[1];
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+#if defined(SPC5_SIUL_SYSTEM_PINS)
+static const unsigned system_pins[] = {SPC5_SIUL_SYSTEM_PINS};
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief SPC5xx I/O ports configuration.
+ *
+ * @param[in] config the SPC5xx ports configuration
+ *
+ * @notapi
+ */
+void _pal_lld_init(const PALConfig *config) {
+ unsigned i;
+
+#if defined(SPC5_SIUL_PCTL)
+ /* SIUL clock gating if present.*/
+ halSPCSetPeripheralClockMode(SPC5_SIUL_PCTL,
+ SPC5_ME_PCTL_RUN(2) | SPC5_ME_PCTL_LP(2));
+#endif
+
+ /* Initialize PCR registers for undefined pads.*/
+ for (i = 0; i < SPC5_SIUL_NUM_PCRS; i++) {
+#if defined(SPC5_SIUL_SYSTEM_PINS)
+ /* Handling the case where some SIU pins are not meant to be reprogrammed,
+ for example JTAG pins.*/
+ unsigned j;
+ for (j = 0; j < sizeof system_pins; j++) {
+ if (i == system_pins[j])
+ goto skip;
+ }
+ SIU.PCR[i].R = config->default_mode;
+skip:
+ ;
+#else
+ SIU.PCR[i].R = config->default_mode;
+#endif
+ }
+
+ /* Initialize PADSEL registers.*/
+ for (i = 0; i < SPC5_SIUL_NUM_PADSELS; i++)
+ SIU.PSMI[i].R = config->padsels[i];
+
+ /* Initialize PCR registers for defined pads.*/
+ i = 0;
+ while (config->inits[i].pcr_index != -1) {
+ SIU.GPDO[config->inits[i].pcr_index].R = config->inits[i].gpdo_value;
+ SIU.PCR[config->inits[i].pcr_index].R = config->inits[i].pcr_value;
+ i++;
+ }
+}
+
+/**
+ * @brief Reads a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @return The group logical states.
+ *
+ * @notapi
+ */
+ioportmask_t _pal_lld_readgroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset) {
+
+ (void)port;
+ (void)mask;
+ (void)offset;
+ return 0;
+}
+
+/**
+ * @brief Writes a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group width
+ * are masked.
+ *
+ * @notapi
+ */
+void _pal_lld_writegroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset,
+ ioportmask_t bits) {
+
+ (void)port;
+ (void)mask;
+ (void)offset;
+ (void)bits;
+}
+
+/**
+ * @brief Pads mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ *
+ * @param[in] port the port identifier
+ * @param[in] mask the group mask
+ * @param[in] mode the mode
+ *
+ * @notapi
+ */
+void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode) {
+ unsigned pcr_index = (unsigned)(port * PAL_IOPORTS_WIDTH);
+ ioportmask_t m1 = 0x8000;
+ while (m1) {
+ if (mask & m1)
+ SIU.PCR[pcr_index].R = mode;
+ m1 >>= 1;
+ ++pcr_index;
+ }
+}
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.h b/os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.h
new file mode 100644
index 000000000..d7871701e
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/SIUL_v1/hal_pal_lld.h
@@ -0,0 +1,471 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/SIUL_v1/hal_pal_lld.h
+ * @brief SPC5xx SIUL low level driver header.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#ifndef HAL_PAL_LLD_H
+#define HAL_PAL_LLD_H
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Unsupported modes and specific modes */
+/*===========================================================================*/
+
+#undef PAL_MODE_RESET
+#undef PAL_MODE_UNCONNECTED
+#undef PAL_MODE_INPUT
+#undef PAL_MODE_INPUT_PULLUP
+#undef PAL_MODE_INPUT_PULLDOWN
+#undef PAL_MODE_INPUT_ANALOG
+#undef PAL_MODE_OUTPUT_PUSHPULL
+#undef PAL_MODE_OUTPUT_OPENDRAIN
+
+/**
+ * @name SIUL-specific PAL modes
+ * @{
+ */
+#define PAL_SPC5_SMC (1U << 14)
+#define PAL_SPC5_APC (1U << 13)
+#define PAL_SPC5_PA_MASK (7U << 10)
+#define PAL_SPC5_PA(n) ((n) << 10)
+#define PAL_SPC5_OBE (1U << 9)
+#define PAL_SPC5_IBE (1U << 8)
+#define PAL_SPC5_ODE (1U << 5)
+#define PAL_SPC5_SRC (1U << 2)
+#define PAL_SPC5_WPE (1U << 1)
+#define PAL_SPC5_WPS (1U << 0)
+/** @} */
+
+/**
+ * @name Pads mode constants
+ * @{
+ */
+/**
+ * @brief After reset state.
+ */
+#define PAL_MODE_RESET 0
+
+/**
+ * @brief Safe state for <b>unconnected</b> pads.
+ */
+#define PAL_MODE_UNCONNECTED (PAL_SPC5_WPE | PAL_SPC5_WPS)
+
+/**
+ * @brief Regular input high-Z pad.
+ */
+#define PAL_MODE_INPUT (PAL_SPC5_IBE)
+
+/**
+ * @brief Input pad with weak pull up resistor.
+ */
+#define PAL_MODE_INPUT_PULLUP (PAL_SPC5_IBE | PAL_SPC5_WPE | \
+ PAL_SPC5_WPS)
+
+/**
+ * @brief Input pad with weak pull down resistor.
+ */
+#define PAL_MODE_INPUT_PULLDOWN (PAL_SPC5_IBE | PAL_SPC5_WPE)
+
+/**
+ * @brief Analog input mode.
+ */
+#define PAL_MODE_INPUT_ANALOG PAL_SPC5_APC
+
+/**
+ * @brief Push-pull output pad.
+ */
+#define PAL_MODE_OUTPUT_PUSHPULL (PAL_SPC5_IBE | PAL_SPC5_OBE)
+
+/**
+ * @brief Open-drain output pad.
+ */
+#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_SPC5_IBE | PAL_SPC5_OBE | \
+ PAL_SPC5_ODE)
+
+/**
+ * @brief Alternate "n" output pad.
+ * @note Both the IBE and OBE bits are specified in this mask, the OBE
+ * bit is not required for some PCRs but in that case it is
+ * ignored.
+ */
+#define PAL_MODE_OUTPUT_ALTERNATE(n) (PAL_SPC5_IBE | PAL_SPC5_OBE | \
+ PAL_SPC5_PA(n))
+/** @} */
+
+/*===========================================================================*/
+/* I/O Ports Types and constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Width, in bits, of an I/O port.
+ */
+#define PAL_IOPORTS_WIDTH 16
+
+/**
+ * @brief Whole port mask.
+ * @brief This macro specifies all the valid bits into a port.
+ */
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
+
+/**
+ * @brief Digital I/O port sized unsigned type.
+ */
+typedef uint16_t ioportmask_t;
+
+/**
+ * @brief Digital I/O modes.
+ */
+typedef uint16_t iomode_t;
+
+/**
+ * @brief Type of an I/O line.
+ */
+typedef uint32_t ioline_t;
+
+/**
+ * @brief Port Identifier.
+ * @details This type can be a scalar or some kind of pointer, do not make
+ * any assumption about it, use the provided macros when populating
+ * variables of this type.
+ */
+typedef uint32_t ioportid_t;
+
+/**
+ * @brief Type of an pad identifier.
+ */
+typedef uint32_t iopadid_t;
+
+/**
+ * @brief SIUL register initializer type.
+ */
+typedef struct {
+ int32_t pcr_index;
+ uint8_t gpdo_value;
+ iomode_t pcr_value;
+} spc_siu_init_t;
+
+/**
+ * @brief Generic I/O ports static initializer.
+ * @details An instance of this structure must be passed to @p palInit() at
+ * system startup time in order to initialized the digital I/O
+ * subsystem. This represents only the initial setup, specific pads
+ * or whole ports can be reprogrammed at later time.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+typedef struct {
+ iomode_t default_mode;
+ const spc_siu_init_t *inits;
+ const uint8_t *padsels;
+} PALConfig;
+
+/*===========================================================================*/
+/* I/O Ports Identifiers. */
+/*===========================================================================*/
+
+/**
+ * @brief I/O port A identifier.
+ */
+#define PORT_A 0
+
+/**
+ * @brief I/O port B identifier.
+ */
+#define PORT_B 1
+
+/**
+ * @brief I/O port C identifier.
+ */
+#define PORT_C 2
+
+/**
+ * @brief I/O port D identifier.
+ */
+#define PORT_D 3
+
+/**
+ * @brief I/O port E identifier.
+ */
+#define PORT_E 4
+
+/**
+ * @brief I/O port F identifier.
+ */
+#define PORT_F 5
+
+/**
+ * @brief I/O port G identifier.
+ */
+#define PORT_G 6
+
+/**
+ * @brief I/O port H identifier.
+ */
+#define PORT_H 7
+
+/**
+ * @brief I/O port I identifier.
+ */
+#define PORT_I 8
+
+/**
+ * @brief I/O port J identifier.
+ */
+#define PORT_J 9
+
+/*===========================================================================*/
+/* Implementation, some of the following macros could be implemented as */
+/* functions, if so please put them in pal_lld.c. */
+/*===========================================================================*/
+
+/**
+ * @brief Port bit helper macro.
+ * @note Overrides the one in @p pal.h.
+ *
+ * @param[in] n bit position within the port
+ *
+ * @return The bit mask.
+ */
+#define PAL_PORT_BIT(n) ((ioportmask_t)(0x8000U >> (n)))
+
+/**
+ * @brief Low level PAL subsystem initialization.
+ *
+ * @param[in] config architecture-dependent ports configuration
+ *
+ * @notapi
+ */
+#define pal_lld_init(config) _pal_lld_init(config)
+
+/**
+ * @brief Reads the physical I/O port states.
+ *
+ * @param[in] port port identifier
+ * @return The port bits.
+ *
+ * @notapi
+ */
+#define pal_lld_readport(port) (((volatile uint16_t *)SIU.PGPDI)[port])
+
+/**
+ * @brief Reads the output latch.
+ * @details The purpose of this function is to read back the latched output
+ * value.
+ *
+ * @param[in] port port identifier
+ * @return The latched logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readlatch(port) (((volatile uint16_t *)SIU.PGPDO)[port])
+
+/**
+ * @brief Writes a bits mask on a I/O port.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be written on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_writeport(port, bits) \
+ (((volatile uint16_t *)SIU.PGPDO)[port] = (bits))
+
+/**
+ * @brief Reads a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @return The group logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readgroup(port, mask, offset) \
+ _pal_lld_readgroup(port, mask, offset)
+
+/**
+ * @brief Writes a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group width
+ * are masked.
+ *
+ * @notapi
+ */
+#define pal_lld_writegroup(port, mask, offset, bits) \
+ _pal_lld_writegroup(port, mask, offset, bits)
+
+/**
+ * @brief Pads group mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] mode group mode
+ *
+ * @notapi
+ */
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
+ _pal_lld_setgroupmode(port, mask << offset, mode)
+
+/**
+ * @brief Reads a logical state from an I/O pad.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return The logical state.
+ * @retval PAL_LOW low logical state.
+ * @retval PAL_HIGH high logical state.
+ *
+ * @notapi
+ */
+#define pal_lld_readpad(port, pad) \
+ (SIU.GPDI[((port) * 16) + (pad)].R)
+
+/**
+ * @brief Writes a logical state on an output pad.
+ * @note This function is not meant to be invoked directly by the
+ * application code.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] bit logical value, the value must be @p PAL_LOW or
+ * @p PAL_HIGH
+ *
+ * @notapi
+ */
+#define pal_lld_writepad(port, pad, bit) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = (bit))
+
+/**
+ * @brief Sets a pad logical state to @p PAL_HIGH.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_setpad(port, pad) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = 1)
+
+/**
+ * @brief Clears a pad logical state to @p PAL_LOW.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_clearpad(port, pad) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = 0)
+
+/**
+ * @brief Toggles a pad logical state.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_togglepad(port, pad) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = ~SIU.GPDO[((port) * 16) + (pad)].R)
+
+/**
+ * @brief Pad mode setup.
+ * @details This function programs a pad with the specified mode.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad mode
+ *
+ * @notapi
+ */
+#define pal_lld_setpadmode(port, pad, mode)
+
+/**
+ * @brief Returns a PAL event structure associated to a pad.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_get_pad_event(port, pad) \
+ &_pal_events[0]; (void)(port); (void)pad
+
+/**
+ * @brief Returns a PAL event structure associated to a line.
+ *
+ * @param[in] line line identifier
+ *
+ * @notapi
+ */
+#define pal_lld_get_line_event(line) \
+ &_pal_events[0]; (void)line
+
+#if !defined(__DOXYGEN__)
+extern const PALConfig pal_default_config;
+extern palevent_t _pal_events[1];
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _pal_lld_init(const PALConfig *config);
+ ioportmask_t _pal_lld_readgroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset);
+ void _pal_lld_writegroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset,
+ ioportmask_t bits);
+ void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PAL */
+
+#endif /* HAL_PAL_LLD_H */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.c b/os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.c
new file mode 100644
index 000000000..31412d473
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.c
@@ -0,0 +1,144 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/SIU_v1/hal_pal_lld.c
+ * @brief SPC5xx SIU low level driver code.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+#if defined(SPC5_SIU_SYSTEM_PINS)
+static const unsigned system_pins[] = {SPC5_SIU_SYSTEM_PINS};
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief SPC5xx I/O ports configuration.
+ *
+ * @param[in] config the SPC5xx ports configuration
+ *
+ * @notapi
+ */
+void _pal_lld_init(const PALConfig *config) {
+ unsigned i;
+
+ /* Initialize PCR registers for defined pads.*/
+ i = 0;
+ while (config->inits[i].pcr_index != -1) {
+ SIU.GPDO[config->inits[i].pcr_index].R = config->inits[i].gpdo_value;
+ SIU.PCR[config->inits[i].pcr_index].R = config->inits[i].pcr_value;
+ i++;
+ }
+}
+
+/**
+ * @brief Reads a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @return The group logical states.
+ *
+ * @notapi
+ */
+ioportmask_t _pal_lld_readgroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset) {
+
+ (void)port;
+ (void)mask;
+ (void)offset;
+ return 0;
+}
+
+/**
+ * @brief Writes a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group width
+ * are masked.
+ *
+ * @notapi
+ */
+void _pal_lld_writegroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset,
+ ioportmask_t bits) {
+
+ (void)port;
+ (void)mask;
+ (void)offset;
+ (void)bits;
+}
+
+/**
+ * @brief Pads mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ *
+ * @param[in] port the port identifier
+ * @param[in] mask the group mask
+ * @param[in] mode the mode
+ *
+ * @notapi
+ */
+void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode) {
+ unsigned pcr_index = (unsigned)(port * PAL_IOPORTS_WIDTH);
+ ioportmask_t m1 = 0x8000;
+ while (m1) {
+ if (mask & m1)
+ SIU.PCR[pcr_index].R = mode;
+ m1 >>= 1;
+ ++pcr_index;
+ }
+}
+
+#endif /* HAL_USE_PAL */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.h b/os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.h
new file mode 100644
index 000000000..5a256e88c
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/SIU_v1/hal_pal_lld.h
@@ -0,0 +1,448 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/SIU_v1/hal_pal_lld.h
+ * @brief SPC5xx SIU low level driver header.
+ *
+ * @addtogroup PAL
+ * @{
+ */
+
+#ifndef HAL_PAL_LLD_H
+#define HAL_PAL_LLD_H
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Unsupported modes and specific modes */
+/*===========================================================================*/
+
+#undef PAL_MODE_RESET
+#undef PAL_MODE_UNCONNECTED
+#undef PAL_MODE_INPUT
+#undef PAL_MODE_INPUT_PULLUP
+#undef PAL_MODE_INPUT_PULLDOWN
+#undef PAL_MODE_INPUT_ANALOG
+#undef PAL_MODE_OUTPUT_PUSHPULL
+#undef PAL_MODE_OUTPUT_OPENDRAIN
+
+/**
+ * @name SIU-specific PAL modes
+ * @{
+ */
+#define PAL_SPC5_PA_MASK (15U << 10)
+#define PAL_SPC5_PA_GPIO (0U << 10)
+#define PAL_SPC5_PA_PRIMARY PAL_SPC5_PA(0)
+#define PAL_SPC5_PA(n) ((1U << (n)) << 10)
+#define PAL_SPC5_OBE (1U << 9)
+#define PAL_SPC5_IBE (1U << 8)
+#define PAL_SPC5_DSC_MASK (3U << 6)
+#define PAL_SPC5_DSC_10PF (0U << 6)
+#define PAL_SPC5_DSC_20PF (1U << 6)
+#define PAL_SPC5_DSC_30PF (2U << 6)
+#define PAL_SPC5_DSC_50PF (3U << 6)
+#define PAL_SPC5_ODE (1U << 5)
+#define PAL_SPC5_HYS (1U << 4)
+#define PAL_SPC5_SRC_MASK (3U << 2)
+#define PAL_SPC5_SRC_MIN (0U << 2)
+#define PAL_SPC5_SRC_MID (1U << 2)
+#define PAL_SPC5_SRC_MAX (3U << 2)
+#define PAL_SPC5_WPE (1U << 1)
+#define PAL_SPC5_WPS (1U << 0)
+/** @} */
+
+/**
+ * @name Pads mode constants
+ * @{
+ */
+/**
+ * @brief After reset state.
+ */
+#define PAL_MODE_RESET 0
+
+/**
+ * @brief Safe state for <b>unconnected</b> pads.
+ */
+#define PAL_MODE_UNCONNECTED (PAL_SPC5_WPE | PAL_SPC5_WPS)
+
+/**
+ * @brief Regular input high-Z pad.
+ */
+#define PAL_MODE_INPUT (PAL_SPC5_IBE)
+
+/**
+ * @brief Input pad with weak pull up resistor.
+ */
+#define PAL_MODE_INPUT_PULLUP (PAL_SPC5_IBE | PAL_SPC5_WPE | \
+ PAL_SPC5_WPS)
+
+/**
+ * @brief Input pad with weak pull down resistor.
+ */
+#define PAL_MODE_INPUT_PULLDOWN (PAL_SPC5_IBE | PAL_SPC5_WPE)
+
+/**
+ * @brief Push-pull output pad.
+ */
+#define PAL_MODE_OUTPUT_PUSHPULL (PAL_SPC5_IBE | PAL_SPC5_OBE)
+
+/**
+ * @brief Open-drain output pad.
+ */
+#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_SPC5_IBE | PAL_SPC5_OBE | \
+ PAL_SPC5_ODE)
+
+/**
+ * @brief Primary function input pad.
+ * @note Both the IBE and OBE bits are specified in this mask.
+ */
+#define PAL_MODE_INPUT_ALTERNATE_PRIMARY \
+ PAL_MODE_INPUT_ALTERNATE(0)
+
+/**
+ * @brief Alternate function input pad.
+ * @note Both the IBE and OBE bits are specified in this mask.
+ */
+#define PAL_MODE_INPUT_ALTERNATE(n) (PAL_SPC5_IBE | PAL_SPC5_PA(n))
+
+/**
+ * @brief Primary function output pad.
+ * @note Both the IBE and OBE bits are specified in this mask.
+ */
+#define PAL_MODE_OUTPUT_ALTERNATE_PRIMARY \
+ PAL_MODE_OUTPUT_ALTERNATE(0)
+
+/**
+ * @brief Alternate function output pad.
+ * @note Both the IBE and OBE bits are specified in this mask.
+ */
+#define PAL_MODE_OUTPUT_ALTERNATE(n) (PAL_SPC5_IBE | PAL_SPC5_OBE | \
+ PAL_SPC5_PA(n))
+/** @} */
+
+/*===========================================================================*/
+/* I/O Ports Types and constants. */
+/*===========================================================================*/
+
+/**
+ * @brief Width, in bits, of an I/O port.
+ */
+#define PAL_IOPORTS_WIDTH 16
+
+/**
+ * @brief Whole port mask.
+ * @brief This macro specifies all the valid bits into a port.
+ */
+#define PAL_WHOLE_PORT ((ioportmask_t)0xFFFF)
+
+/**
+ * @brief Digital I/O port sized unsigned type.
+ */
+typedef uint16_t ioportmask_t;
+
+/**
+ * @brief Port Identifier.
+ * @details This type can be a scalar or some kind of pointer, do not make
+ * any assumption about it, use the provided macros when populating
+ * variables of this type.
+ */
+typedef uint32_t ioportid_t;
+
+/**
+ * @brief Digital I/O modes.
+ */
+typedef uint16_t iomode_t;
+
+/**
+ * @brief SIU/SIUL register initializer type.
+ */
+typedef struct {
+ int32_t pcr_index;
+ uint8_t gpdo_value;
+ iomode_t pcr_value;
+} spc_siu_init_t;
+
+/**
+ * @brief Generic I/O ports static initializer.
+ * @details An instance of this structure must be passed to @p palInit() at
+ * system startup time in order to initialized the digital I/O
+ * subsystem. This represents only the initial setup, specific pads
+ * or whole ports can be reprogrammed at later time.
+ * @note Implementations may extend this structure to contain more,
+ * architecture dependent, fields.
+ */
+typedef struct {
+ const spc_siu_init_t *inits;
+} PALConfig;
+
+/*===========================================================================*/
+/* I/O Ports Identifiers. */
+/*===========================================================================*/
+
+/**
+ * @name Port identifiers
+ * @{
+ */
+#define PORT0 0
+#define PORT1 1
+#define PORT2 2
+#define PORT3 3
+#define PORT4 4
+#define PORT5 5
+#define PORT6 6
+#define PORT7 7
+#define PORT8 8
+#define PORT9 9
+#define PORT10 10
+#define PORT11 11
+#define PORT12 12
+#define PORT13 13
+#define PORT14 14
+#define PORT15 15
+#define PORT16 16
+#define PORT17 17
+#define PORT18 18
+#define PORT19 19
+#define PORT20 20
+#define PORT21 21
+#define PORT22 22
+#define PORT23 23
+#define PORT24 24
+#define PORT25 25
+#define PORT26 26
+#define PORT27 27
+#define PORT28 28
+#define PORT29 29
+#define PORT30 30
+#define PORT31 31
+/** @} */
+
+/*===========================================================================*/
+/* Implementation, some of the following macros could be implemented as */
+/* functions, if so please put them in pal_lld.c. */
+/*===========================================================================*/
+
+/**
+ * @brief Port bit helper macro.
+ * @note Overrides the one in @p pal.h.
+ *
+ * @param[in] n bit position within the port
+ *
+ * @return The bit mask.
+ */
+#define PAL_PORT_BIT(n) ((ioportmask_t)(0x8000U >> (n)))
+
+/**
+ * @brief Low level PAL subsystem initialization.
+ *
+ * @param[in] config architecture-dependent ports configuration
+ *
+ * @notapi
+ */
+#define pal_lld_init(config) _pal_lld_init(config)
+
+#if SPC5_SIU_SUPPORTS_PORTS || defined(__DOXYGEN__)
+/**
+ * @brief Reads the physical I/O port states.
+ *
+ * @param[in] port port identifier
+ * @return The port bits.
+ *
+ * @notapi
+ */
+#define pal_lld_readport(port) (((volatile uint16_t *)SIU.PGPDI)[port])
+
+/**
+ * @brief Reads the output latch.
+ * @details The purpose of this function is to read back the latched output
+ * value.
+ *
+ * @param[in] port port identifier
+ * @return The latched logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readlatch(port) (((volatile uint16_t *)SIU.PGPDO)[port])
+
+/**
+ * @brief Writes a bits mask on a I/O port.
+ *
+ * @param[in] port port identifier
+ * @param[in] bits bits to be written on the specified port
+ *
+ * @notapi
+ */
+#define pal_lld_writeport(port, bits) \
+ (((volatile uint16_t *)SIU.PGPDO)[port] = (bits))
+
+/**
+ * @brief Reads a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @return The group logical states.
+ *
+ * @notapi
+ */
+#define pal_lld_readgroup(port, mask, offset) \
+ _pal_lld_readgroup(port, mask, offset)
+
+/**
+ * @brief Writes a group of bits.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] bits bits to be written. Values exceeding the group width
+ * are masked.
+ *
+ * @notapi
+ */
+#define pal_lld_writegroup(port, mask, offset, bits) \
+ _pal_lld_writegroup(port, mask, offset, bits)
+
+#endif /* SPC5_SIU_SUPPORTS_PORTS */
+
+/**
+ * @brief Pads group mode setup.
+ * @details This function programs a pads group belonging to the same port
+ * with the specified mode.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] mask group mask
+ * @param[in] offset group bit offset within the port
+ * @param[in] mode group mode
+ *
+ * @notapi
+ */
+#define pal_lld_setgroupmode(port, mask, offset, mode) \
+ _pal_lld_setgroupmode(port, mask << offset, mode)
+
+/**
+ * @brief Reads a logical state from an I/O pad.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @return The logical state.
+ * @retval PAL_LOW low logical state.
+ * @retval PAL_HIGH high logical state.
+ *
+ * @notapi
+ */
+#define pal_lld_readpad(port, pad) \
+ (SIU.GPDI[((port) * 16) + (pad)].R)
+
+/**
+ * @brief Writes a logical state on an output pad.
+ * @note This function is not meant to be invoked directly by the
+ * application code.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] bit logical value, the value must be @p PAL_LOW or
+ * @p PAL_HIGH
+ *
+ * @notapi
+ */
+#define pal_lld_writepad(port, pad, bit) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = (bit))
+
+/**
+ * @brief Sets a pad logical state to @p PAL_HIGH.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_setpad(port, pad) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = 1)
+
+/**
+ * @brief Clears a pad logical state to @p PAL_LOW.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_clearpad(port, pad) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = 0)
+
+/**
+ * @brief Toggles a pad logical state.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ *
+ * @notapi
+ */
+#define pal_lld_togglepad(port, pad) \
+ (SIU.GPDO[((port) * 16) + (pad)].R = ~SIU.GPDO[((port) * 16) + (pad)].R)
+
+/**
+ * @brief Pad mode setup.
+ * @details This function programs a pad with the specified mode.
+ * @note The @ref PAL provides a default software implementation of this
+ * functionality, implement this function if can optimize it by using
+ * special hardware functionalities or special coding.
+ * @note Programming an unknown or unsupported mode is silently ignored.
+ *
+ * @param[in] port port identifier
+ * @param[in] pad pad number within the port
+ * @param[in] mode pad mode
+ *
+ * @notapi
+ */
+#define pal_lld_setpadmode(port, pad, mode)
+
+extern const PALConfig pal_default_config;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void _pal_lld_init(const PALConfig *config);
+ ioportmask_t _pal_lld_readgroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset);
+ void _pal_lld_writegroup(ioportid_t port,
+ ioportmask_t mask,
+ uint_fast8_t offset,
+ ioportmask_t bits);
+ void _pal_lld_setgroupmode(ioportid_t port,
+ ioportmask_t mask,
+ iomode_t mode);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_PAL */
+
+#endif /* HAL_PAL_LLD_H */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.c b/os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.c
new file mode 100644
index 000000000..36ec49bfb
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.c
@@ -0,0 +1,94 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/hal_st_lld.c
+ * @brief ST Driver subsystem low level driver code.
+ *
+ * @addtogroup ST
+ * @{
+ */
+
+#include "hal.h"
+
+#if (OSAL_ST_MODE != OSAL_ST_MODE_NONE) || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if defined(SPC5_USE_STM) || defined(__DOXYGEN__)
+OSAL_IRQ_HANDLER(STM_HANDLER) {
+
+ OSAL_IRQ_PROLOGUE();
+
+ if (SPC5_STM_UNIT->CH[0].CIR.CIF != 0U) {
+ SPC5_STM_UNIT->CH[0].CIR.CIF = 1U;
+
+ osalSysLockFromISR();
+ osalOsTimerHandlerI();
+ osalSysUnlockFromISR();
+ }
+
+ OSAL_IRQ_EPILOGUE();
+}
+#endif
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ST driver initialization.
+ *
+ * @notapi
+ */
+void st_lld_init(void) {
+
+#if defined(SPC5_USE_STM)
+ SPC5_STM_UNIT->CNT = 0;
+ SPC5_STM_UNIT->CH[0].CCR = 0;
+ SPC5_STM_UNIT->CH[1].CCR = 0;
+ SPC5_STM_UNIT->CH[2].CCR = 0;
+ SPC5_STM_UNIT->CH[3].CCR = 0;
+ SPC5_STM_UNIT->CR.R = STM_CR_CNT(SPC5_STM_CPL_VALUE - 1) |
+ STM_CR_FRZ | STM_CR_TEN;
+#endif
+}
+
+#endif /* OSAL_ST_MODE != OSAL_ST_MODE_NONE */
+
+/** @} */
diff --git a/os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.h b/os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.h
new file mode 100644
index 000000000..53cd7cc8b
--- /dev/null
+++ b/os/hal/ports/SPC5/LLD/STM_v1/hal_st_lld.h
@@ -0,0 +1,200 @@
+/*
+ SPC5 HAL - Copyright (C) 2013 STMicroelectronics
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file SPC5xx/STMv1/hal_st_lld.h
+ * @brief ST Driver subsystem low level driver header.
+ * @details This header is designed to be include-able without having to
+ * include other files from the HAL.
+ *
+ * @addtogroup ST
+ * @{
+ */
+
+#ifndef HAL_ST_LLD_H
+#define HAL_ST_LLD_H
+
+#include "mcuconf.h"
+#include "spc5_registry.h"
+#include "registers.h"
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/**
+ * @name STM CR register definitions.
+ * @{
+ */
+#define STM_CR_CNT_MASK (255U << 8U)
+#define STM_CR_CNT(n) ((n) << 8U)
+#define STM_CR_FRZ (1U << 1U)
+#define STM_CR_TEN (1U << 0U)
+/** @} */
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief STM unit to be used by the ST driver.
+ */
+#if !defined(SPC5_STM_UNIT) || defined(__DOXYGEN__)
+#define SPC5_STM_UNIT STM_2
+#endif
+
+/**
+ * @brief SysTick timer IRQ priority.
+ */
+#if !defined(SPC5_STM_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define SPC5_STM_IRQ_PRIORITY 8
+#endif
+
+/**
+ * @brief Counter clock to be programmed in the STM unit.
+ */
+#if !defined(SPC5_STM_CNT_CLOCK) || defined(__DOXYGEN__)
+#define SPC5_STM_CNT_CLOCK 8000000U
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if 0
+#if !defined(STM_HANDLER)
+#error "STM_HANDLER not defined in registry"
+#endif
+
+#if !defined(SPC5_STM_CLK)
+#error "SPC5_STM_CLK not defined in registry"
+#endif
+
+/**
+ * @brief Prescaler value.
+ */
+#define SPC5_STM_CPL_VALUE (SPC5_STM_CLK / SPC5_STM_CNT_CLOCK)
+
+#if (SPC5_STM_CPL_VALUE * SPC5_STM_CNT_CLOCK) != SPC5_STM_CLK
+#error "SPC5_STM_CNT_CLOCK is invalid"
+#endif
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void st_lld_init(void);
+#ifdef __cplusplus
+}
+#endif
+
+/*===========================================================================*/
+/* Driver inline functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Returns the time counter value.
+ *
+ * @return The counter value.
+ *
+ * @notapi
+ */
+static inline systime_t st_lld_get_counter(void) {
+
+ return (systime_t)0;
+}
+
+/**
+ * @brief Starts the alarm.
+ * @note Makes sure that no spurious alarms are triggered after
+ * this call.
+ *
+ * @param[in] time the time to be set for the first alarm
+ *
+ * @notapi
+ */
+static inline void st_lld_start_alarm(systime_t time) {
+
+ (void)time;
+}
+
+/**
+ * @brief Stops the alarm interrupt.
+ *
+ * @notapi
+ */
+static inline void st_lld_stop_alarm(void) {
+
+}
+
+/**
+ * @brief Sets the alarm time.
+ *
+ * @param[in] time the time to be set for the next alarm
+ *
+ * @notapi
+ */
+static inline void st_lld_set_alarm(systime_t time) {
+
+ (void)time;
+}
+
+/**
+ * @brief Returns the current alarm time.
+ *
+ * @return The currently set alarm time.
+ *
+ * @notapi
+ */
+static inline systime_t st_lld_get_alarm(void) {
+
+ return (systime_t)0;
+}
+
+/**
+ * @brief Determines if the alarm is active.
+ *
+ * @return The alarm status.
+ * @retval false if the alarm is not active.
+ * @retval true is the alarm is active
+ *
+ * @notapi
+ */
+static inline bool st_lld_is_alarm_active(void) {
+
+ return false;
+}
+
+#endif /* HAL_ST_LLD_H */
+
+/** @} */