aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/STM32
diff options
context:
space:
mode:
authorbarthess <barthess@35acf78f-673a-0410-8e92-d51de3d6d3f4>2014-08-05 08:00:56 +0000
committerbarthess <barthess@35acf78f-673a-0410-8e92-d51de3d6d3f4>2014-08-05 08:00:56 +0000
commit88a09ec74105c34e3eb66eb5ba84f0e448ce7a2a (patch)
treefe8ade2bad038927e12d26ee9e39222dc974fa27 /os/hal/ports/STM32
parentadb00b4f8f7d34b0fa026bc8fc083e3464d6c32a (diff)
downloadChibiOS-88a09ec74105c34e3eb66eb5ba84f0e448ce7a2a.tar.gz
ChibiOS-88a09ec74105c34e3eb66eb5ba84f0e448ce7a2a.tar.bz2
ChibiOS-88a09ec74105c34e3eb66eb5ba84f0e448ce7a2a.zip
Added FSMC NAND driver
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7123 35acf78f-673a-0410-8e92-d51de3d6d3f4
Diffstat (limited to 'os/hal/ports/STM32')
-rw-r--r--os/hal/ports/STM32/LLD/emc_lld.c185
-rw-r--r--os/hal/ports/STM32/LLD/emc_lld.h247
-rw-r--r--os/hal/ports/STM32/LLD/emcnand_lld.c555
-rw-r--r--os/hal/ports/STM32/LLD/emcnand_lld.h361
-rw-r--r--os/hal/ports/STM32/STM32F4xx/platform.mk4
-rw-r--r--os/hal/ports/STM32/STM32F4xx/stm32_rcc.h29
-rw-r--r--os/hal/ports/STM32/STM32F4xx/stm32_registry.h12
7 files changed, 1392 insertions, 1 deletions
diff --git a/os/hal/ports/STM32/LLD/emc_lld.c b/os/hal/ports/STM32/LLD/emc_lld.c
new file mode 100644
index 000000000..3c6f16c5b
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/emc_lld.c
@@ -0,0 +1,185 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file emc_lld.c
+ * @brief EMC Driver subsystem low level driver source template.
+ *
+ * @addtogroup EMC
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_EMC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief EMC1 driver identifier.
+ */
+#if STM32_EMC_USE_FSMC1 || defined(__DOXYGEN__)
+EMCDriver EMCD1;
+#endif
+
+/*===========================================================================*/
+/* Driver local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level EMC driver initialization.
+ *
+ * @notapi
+ */
+void emc_lld_init(void) {
+
+#if STM32_EMC_USE_FSMC1
+ emcObjectInit(&EMCD1);
+
+#if STM32_EMCNAND_USE_EMCNAND1
+ EMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
+#endif
+
+#if STM32_EMCNAND_USE_EMCNAND2
+ EMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
+#endif
+
+#if STM32_USE_EMC_PCCARD
+ EMCD1.pccard = (FSMC_PCCARD_TypeDef *)FSMC_Bank4_R_BASE;
+#endif
+
+#endif /* STM32_EMC_USE_EMC1 */
+}
+
+/**
+ * @brief Configures and activates the EMC peripheral.
+ *
+ * @param[in] emcp pointer to the @p EMCDriver object
+ *
+ * @notapi
+ */
+void emc_lld_start(EMCDriver *emcp) {
+
+ if (emcp->state == EMC_STOP) {
+ /* Enables the peripheral.*/
+#if STM32_EMC_USE_FSMC1
+ if (&EMCD1 == emcp) {
+ rccResetFSMC();
+ rccEnableFSMC(FALSE);
+ #if STM32_EMC_USE_INT
+ nvicEnableVector(FSMC_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_EMC_FSMC1_IRQ_PRIORITY));
+ #endif /* STM32_EMC_USE_INT */
+ }
+#endif /* PLATFORM_STM32_USE_EMC1 */
+
+ emcp->state = EMC_READY;
+ }
+}
+
+/**
+ * @brief Deactivates the EMC peripheral.
+ *
+ * @param[in] emcp pointer to the @p EMCDriver object
+ *
+ * @notapi
+ */
+void emc_lld_stop(EMCDriver *emcp) {
+
+ if (emcp->state == EMC_READY) {
+ /* Resets the peripheral.*/
+ rccResetFSMC();
+
+ /* Disables the peripheral.*/
+#if STM32_EMC_USE_FSMC1
+ if (&EMCD1 == emcp) {
+ #if STM32_EMC_USE_INT
+ nvicDisableVector(FSMC_IRQn);
+ #endif
+ rccDisableFSMC(FALSE);
+ }
+#endif /* PLATFORM_STM32_USE_EMC1 */
+
+ emcp->state = EMC_STOP;
+ }
+}
+
+#if STM32_EMC_USE_INT
+/**
+ * @brief Serve common interrupt.
+ *
+ * @notapi
+ */
+void emc_lld_serve_interrupt(void) {
+#warning "This functionality untested"
+
+ chDbgPanic("Unrealized");
+}
+
+/**
+ * @brief FSMC shared interrupt handler.
+ *
+ * @notapi
+ */
+CH_IRQ_HANDLER(FSMC_IRQHandler) {
+#warning "This functionality untested"
+
+ CH_IRQ_PROLOGUE();
+
+ if (EMCD1.nand1->SR & FSMC_SR_ISR_MASK){
+ EMCNANDD1.isr_handler(&EMCNANDD1, EMCD1.nand1->SR);
+ }
+ if (EMCD1.nand2->SR & FSMC_SR_ISR_MASK){
+ EMCNANDD2.isr_handler(&EMCNANDD2, EMCD1.nand2->SR);
+ }
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_EMC_USE_INT */
+
+#endif /* HAL_USE_EMC */
+
+/** @} */
diff --git a/os/hal/ports/STM32/LLD/emc_lld.h b/os/hal/ports/STM32/LLD/emc_lld.h
new file mode 100644
index 000000000..6df1257ba
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/emc_lld.h
@@ -0,0 +1,247 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file emc_lld.h
+ * @brief EMC Driver subsystem low level driver header template.
+ *
+ * @addtogroup EMC
+ * @{
+ */
+
+
+#ifndef _EMC_LLD_H_
+#define _EMC_LLD_H_
+
+#if HAL_USE_EMC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*
+ * Base bank mappings
+ */
+#define FSMC_Bank1_MAP_BASE ((uint32_t) 0x60000000)
+#define FSMC_Bank2_MAP_BASE ((uint32_t) 0x70000000)
+#define FSMC_Bank3_MAP_BASE ((uint32_t) 0x80000000)
+#define FSMC_Bank4_MAP_BASE ((uint32_t) 0x90000000)
+
+/*
+ * Bank 2 (NAND)
+ */
+#define FSMC_Bank2_MAP_COMMON (FSMC_Bank2_MAP_BASE + 0)
+#define FSMC_Bank2_MAP_ATTR (FSMC_Bank2_MAP_BASE + 0x8000000)
+
+#define FSMC_Bank2_MAP_COMMON_DATA (FSMC_Bank2_MAP_COMMON + 0)
+#define FSMC_Bank2_MAP_COMMON_CMD (FSMC_Bank2_MAP_COMMON + 0x10000)
+#define FSMC_Bank2_MAP_COMMON_ADDR (FSMC_Bank2_MAP_COMMON + 0x20000)
+
+#define FSMC_Bank2_MAP_ATTR_DATA (FSMC_Bank2_MAP_ATTR + 0)
+#define FSMC_Bank2_MAP_ATTR_CMD (FSMC_Bank2_MAP_ATTR + 0x10000)
+#define FSMC_Bank2_MAP_ATTR_ADDR (FSMC_Bank2_MAP_ATTR + 0x20000)
+
+/*
+ * Bank 3 (NAND)
+ */
+#define FSMC_Bank3_MAP_COMMON (FSMC_Bank3_MAP_BASE + 0)
+#define FSMC_Bank3_MAP_ATTR (FSMC_Bank3_MAP_BASE + 0x8000000)
+
+#define FSMC_Bank3_MAP_COMMON_DATA (FSMC_Bank3_MAP_COMMON + 0)
+#define FSMC_Bank3_MAP_COMMON_CMD (FSMC_Bank3_MAP_COMMON + 0x10000)
+#define FSMC_Bank3_MAP_COMMON_ADDR (FSMC_Bank3_MAP_COMMON + 0x20000)
+
+#define FSMC_Bank3_MAP_ATTR_DATA (FSMC_Bank3_MAP_ATTR + 0)
+#define FSMC_Bank3_MAP_ATTR_CMD (FSMC_Bank3_MAP_ATTR + 0x10000)
+#define FSMC_Bank3_MAP_ATTR_ADDR (FSMC_Bank3_MAP_ATTR + 0x20000)
+
+/*
+ * Bank 4 (PC card)
+ */
+#define FSMC_Bank4_MAP_COMMON (FSMC_Bank4_MAP_BASE + 0)
+#define FSMC_Bank4_MAP_ATTR (FSMC_Bank4_MAP_BASE + 0x8000000)
+#define FSMC_Bank4_MAP_IO (FSMC_Bank4_MAP_BASE + 0xC000000)
+
+/*
+ * More convenient typedefs than CMSIS has
+ */
+typedef struct {
+ __IO uint32_t PCR; /**< NAND Flash control */
+ __IO uint32_t SR; /**< NAND Flash FIFO status and interrupt */
+ __IO uint32_t PMEM; /**< NAND Flash Common memory space timing */
+ __IO uint32_t PATT; /**< NAND Flash Attribute memory space timing */
+ uint32_t RESERVED0; /**< Reserved, 0x70 */
+ __IO uint32_t ECCR; /**< NAND Flash ECC result registers */
+} FSMC_NAND_TypeDef;
+
+typedef struct {
+ __IO uint32_t PCR; /**< PC Card control */
+ __IO uint32_t SR; /**< PC Card FIFO status and interrupt */
+ __IO uint32_t PMEM; /**< PC Card Common memory space timing */
+ __IO uint32_t PATT; /**< PC Card Attribute memory space timing */
+ __IO uint32_t PIO; /**< PC Card I/O space timing */
+} FSMC_PCCard_TypeDef;
+
+/**
+ * @brief PCR register
+ */
+#define FSMC_PCR_PWAITEN ((uint32_t)0x00000002)
+#define FSMC_PCR_PBKEN ((uint32_t)0x00000004)
+#define FSMC_PCR_PTYP ((uint32_t)0x00000008)
+#define FSMC_PCR_ECCEN ((uint32_t)0x00000040)
+#define FSMC_PCR_PTYP_PCCARD 0
+#define FSMC_PCR_PTYP_NAND FSMC_PCR_PTYP
+
+/**
+ * @brief SR register
+ */
+#define FSMC_SR_IRS ((uint8_t)0x01)
+#define FSMC_SR_ILS ((uint8_t)0x02)
+#define FSMC_SR_IFS ((uint8_t)0x04)
+#define FSMC_SR_IREN ((uint8_t)0x08)
+#define FSMC_SR_ILEN ((uint8_t)0x10)
+#define FSMC_SR_IFEN ((uint8_t)0x20)
+#define FSMC_SR_FEMPT ((uint8_t)0x40)
+#define FSMC_SR_ISR_MASK (FSMC_SR_IRS | FSMC_SR_ILS | FSMC_SR_IFS)
+
+/**
+ * @brief RCR register
+ */
+#define FSMC_BCR_MBKEN ((uint32_t)0x00000001)
+#define FSMC_BCR_MUXEN ((uint32_t)0x00000002)
+#define FSMC_BCR_FACCEN ((uint32_t)0x00000040)
+#define FSMC_BCR_BURSTEN ((uint32_t)0x00000100)
+#define FSMC_BCR_WAITPOL ((uint32_t)0x00000200)
+#define FSMC_BCR_WRAPMOD ((uint32_t)0x00000400)
+#define FSMC_BCR_WAITCFG ((uint32_t)0x00000800)
+#define FSMC_BCR_WREN ((uint32_t)0x00001000)
+#define FSMC_BCR_WAITEN ((uint32_t)0x00002000)
+#define FSMC_BCR_EXTMOD ((uint32_t)0x00004000)
+#define FSMC_BCR_ASYNCWAIT ((uint32_t)0x00008000)
+#define FSMC_BCR_CBURSTRW ((uint32_t)0x00080000)
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief EMC driver enable switch.
+ * @details If set to @p TRUE the support for EMC is included.
+ */
+#if !defined(STM32_EMC_USE_FSMC1) || defined(__DOXYGEN__)
+#define STM32_EMC_USE_FSMC1 FALSE
+#endif
+
+/**
+ * @brief Internal FSMC interrupt enable switch
+ * @details MCUs in 100-pin package has no dedicated interrupt pin for FSMC.
+ * You have to use EXTI module instead to workaround this issue.
+ */
+#if STM32_EMC_EMCNAND_USE_FSMC_INT
+#define STM32_EMC_USE_INT TRUE
+#else
+#define STM32_EMC_USE_INT FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+#if !STM32_EMC_USE_FSMC1
+#error "EMC driver activated but no EMC peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief Type of a structure representing an EMC driver.
+ */
+typedef struct EMCDriver EMCDriver;
+
+/**
+ * @brief Driver configuration structure.
+ * @note Empty on this architecture.
+ */
+typedef struct {
+
+} EMCConfig;
+
+/**
+ * @brief Structure representing an EMC driver.
+ */
+struct EMCDriver {
+ /**
+ * @brief Driver state.
+ */
+ emcstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const EMCConfig *config;
+ /* End of the mandatory fields.*/
+#if STM32_EMCNAND_USE_EMCNAND1
+ FSMC_NAND_TypeDef *nand1;
+#endif
+#if STM32_EMCNAND_USE_EMCNAND2
+ FSMC_NAND_TypeDef *nand2;
+#endif
+#if STM32_USE_EMC_PCCARD
+ FSMC_PCCard_TypeDef *pccard;
+#endif
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_EMC_USE_FSMC1 && !defined(__DOXYGEN__)
+extern EMCDriver EMCD1;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void emc_lld_init(void);
+ void emc_lld_start(EMCDriver *emcp);
+ void emc_lld_stop(EMCDriver *emcp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_EMC */
+
+#endif /* _EMC_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/ports/STM32/LLD/emcnand_lld.c b/os/hal/ports/STM32/LLD/emcnand_lld.c
new file mode 100644
index 000000000..242b47a14
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/emcnand_lld.c
@@ -0,0 +1,555 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file emcnand_lld.c
+ * @brief EMCNAND Driver subsystem low level driver source template.
+ *
+ * @addtogroup EMCNAND
+ * @{
+ */
+
+#include "hal.h"
+
+#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+#define EMCNAND_DMA_CHANNEL \
+ STM32_DMA_GETCHANNEL(STM32_EMCNAND_EMCNAND1_DMA_STREAM, \
+ STM32_EMC_DMA_CHN)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief EMCNAND1 driver identifier.
+ */
+#if STM32_EMCNAND_USE_EMCNAND1 || defined(__DOXYGEN__)
+EMCNANDDriver EMCNANDD1;
+#endif
+
+/**
+ * @brief EMCNAND2 driver identifier.
+ */
+#if STM32_EMCNAND_USE_EMCNAND2 || defined(__DOXYGEN__)
+EMCNANDDriver EMCNANDD2;
+#endif
+
+/*===========================================================================*/
+/* Driver local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+/**
+ * @brief Wakes up the waiting thread.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] msg wakeup message
+ *
+ * @notapi
+ */
+static void wakeup_isr(EMCNANDDriver *emcnandp, msg_t msg){
+
+ osalDbgCheck(emcnandp->thread != NULL);
+
+ if (emcnandp->thread) {
+ thread_t *tp = emcnandp->thread;
+ emcnandp->thread = NULL;
+ tp->p_u.rdymsg = msg;
+ chSchReadyI(tp);
+ }
+}
+
+/**
+ * @brief Put calling thread in suspend and switch driver state
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ */
+static void emcnand_lld_suspend_thread(EMCNANDDriver *emcnandp) {
+
+ emcnandp->thread = chThdGetSelfX();
+ chSchGoSleepS(CH_STATE_SUSPENDED);
+}
+
+/**
+ * @brief Caclulate ECCPS register value
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ */
+static uint32_t calc_eccps(EMCNANDDriver *emcnandp){
+
+ uint32_t i = 0;
+ uint32_t eccps = emcnandp->config->page_data_size;
+
+ eccps = eccps >> 9;
+ while (eccps > 0){
+ i++;
+ eccps >>= 1;
+ }
+
+ return i << 17;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_EMC_USE_INT
+/**
+ * @brief Enable interrupts from FSMC
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+static void emcnand_ready_isr_enable(EMCNANDDriver *emcnandp) {
+ emcnandp->nand->SR |= FSMC_SR_IREN;
+ chDbgPanic("Function untested");
+}
+
+/**
+ * @brief Disable interrupts from FSMC
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+static void emcnand_ready_isr_disable(EMCNANDDriver *emcnandp) {
+ emcnandp->nand->SR &= ~FSMC_SR_IREN;
+ chDbgPanic("Function untested");
+}
+
+/**
+ * @brief Ready interrupt handler
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] flags flags passed from FSMC intrrupt handler
+ *
+ * @notapi
+ */
+static void emcnand_isr_handler (EMCNANDDriver *emcnandp,
+ emcnandflags_t flags){
+ (void)emcnandp;
+ (void)flags;
+
+ chDbgPanic("Unrealized");
+}
+#else /* STM32_EMC_USE_INT */
+/**
+ * @brief Disable interrupts from EXTI
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+static void emcnand_ready_isr_enable(EMCNANDDriver *emcnandp) {
+ emcnandp->config->ext_isr_enable();
+}
+
+/**
+ * @brief Enable interrupts from EXTI
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+static void emcnand_ready_isr_disable(EMCNANDDriver *emcnandp) {
+ emcnandp->config->ext_isr_disable();
+}
+
+/**
+ * @brief Ready pin interrupt handler.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+static void emcnand_isr_handler(EMCNANDDriver *emcnandp){
+
+ osalSysLockFromISR();
+
+ switch (emcnandp->state){
+ case EMCNAND_READ:
+ emcnandp->state = EMCNAND_DMA_RX;
+ dmaStartMemCopy(emcnandp->dma, emcnandp->dmamode,
+ emcnandp->map_data, emcnandp->rxdata, emcnandp->datalen);
+ /* thread will be woked up from DMA ISR */
+ break;
+
+ case EMCNAND_ERASE:
+ /* NAND reports about erase finish */
+ emcnandp->state = EMCNAND_READY;
+ wakeup_isr(emcnandp, MSG_OK);
+ break;
+
+ case EMCNAND_PROGRAM:
+ /* NAND reports about page programming finish */
+ emcnandp->state = EMCNAND_READY;
+ wakeup_isr(emcnandp, MSG_OK);
+ break;
+
+ default:
+ osalSysHalt("Unhandled case");
+ break;
+ }
+
+ osalSysUnlockFromISR();
+}
+#endif /* STM32_EMC_USE_INT */
+
+/**
+ * @brief DMA RX end IRQ handler.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] flags pre-shifted content of the ISR register
+ *
+ * @notapi
+ */
+static void emcnand_lld_serve_transfer_end_irq(EMCNANDDriver *emcnandp,
+ uint32_t flags) {
+ /* DMA errors handling.*/
+#if defined(STM32_EMCNAND_DMA_ERROR_HOOK)
+ if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
+ STM32_EMCNAND_DMA_ERROR_HOOK(emcnandp);
+ }
+#else
+ (void)flags;
+#endif
+
+ osalSysLockFromISR();
+
+ dmaStreamDisable(emcnandp->dma);
+
+ switch (emcnandp->state){
+ case EMCNAND_DMA_TX:
+ emcnandp->state = EMCNAND_PROGRAM;
+ emcnandp->map_cmd[0] = NAND_CMD_PAGEPROG;
+ /* thread will be woken from ready_isr() */
+ break;
+
+ case EMCNAND_DMA_RX:
+ emcnandp->state = EMCNAND_READY;
+ emcnandp->rxdata = NULL;
+ emcnandp->datalen = 0;
+ wakeup_isr(emcnandp, MSG_OK);
+ break;
+
+ default:
+ osalSysHalt("Unhandled case");
+ break;
+ }
+
+ osalSysUnlockFromISR();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level EMCNAND driver initialization.
+ *
+ * @notapi
+ */
+void emcnand_lld_init(void) {
+
+#if STM32_EMCNAND_USE_EMCNAND1
+ /* Driver initialization.*/
+ emcnandObjectInit(&EMCNANDD1);
+ EMCNANDD1.rxdata = NULL;
+ EMCNANDD1.datalen = 0;
+ EMCNANDD1.thread = NULL;
+ EMCNANDD1.dma = STM32_DMA_STREAM(STM32_EMCNAND_EMCNAND1_DMA_STREAM);
+ EMCNANDD1.nand = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
+ EMCNANDD1.map_data = (uint8_t*)FSMC_Bank2_MAP_COMMON_DATA;
+ EMCNANDD1.map_cmd = (uint8_t*)FSMC_Bank2_MAP_COMMON_CMD;
+ EMCNANDD1.map_addr = (uint8_t*)FSMC_Bank2_MAP_COMMON_ADDR;
+#endif /* STM32_EMCNAND_USE_EMCNAND1 */
+
+#if STM32_EMCNAND_USE_EMCNAND2
+ /* Driver initialization.*/
+ #warning "Untested"
+ emcnandObjectInit(&EMCNANDD1);
+ EMCNANDD2.rxdata = NULL;
+ EMCNANDD2.datalen = 0;
+ EMCNANDD2.thread = NULL;
+ EMCNANDD2.dma = STM32_DMA_STREAM(STM32_EMCNAND_EMCNAND2_DMA_STREAM);
+ EMCNANDD2.nand = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
+ EMCNANDD2.map_data = (uint8_t*)FSMC_Bank3_MAP_COMMON_DATA;
+ EMCNANDD2.map_cmd = (uint8_t*)FSMC_Bank3_MAP_COMMON_CMD;
+ EMCNANDD2.map_addr = (uint8_t*)FSMC_Bank3_MAP_COMMON_ADDR;
+#endif /* STM32_EMCNAND_USE_EMCNAND2 */
+}
+
+/**
+ * @brief Configures and activates the EMCNAND peripheral.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+void emcnand_lld_start(EMCNANDDriver *emcnandp) {
+
+ bool_t b;
+
+ if (emcnandp->state == EMCNAND_STOP) {
+ b = dmaStreamAllocate(emcnandp->dma,
+ STM32_EMC_FSMC1_IRQ_PRIORITY,
+ (stm32_dmaisr_t)emcnand_lld_serve_transfer_end_irq,
+ (void *)emcnandp);
+ osalDbgAssert(!b, "stream already allocated");
+ emcnandp->dmamode = STM32_DMA_CR_CHSEL(EMCNAND_DMA_CHANNEL) |
+ STM32_DMA_CR_PL(STM32_EMCNAND_EMCNAND1_DMA_PRIORITY) |
+ STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
+ STM32_DMA_CR_DMEIE | STM32_DMA_CR_TEIE |
+ STM32_DMA_CR_TCIE;
+ /* dmaStreamSetFIFO(emcnandp->dma,
+ STM32_DMA_FCR_DMDIS | EMCNAND_STM32_DMA_FCR_FTH_LVL); */
+ emcnandp->nand->PCR = calc_eccps(emcnandp) | FSMC_PCR_PTYP | FSMC_PCR_PBKEN;
+ emcnandp->nand->PMEM = emcnandp->config->pmem;
+ emcnandp->nand->PATT = emcnandp->config->pmem;
+ emcnandp->isr_handler = emcnand_isr_handler;
+ emcnand_ready_isr_enable(emcnandp);
+ }
+}
+
+/**
+ * @brief Deactivates the EMCNAND peripheral.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @notapi
+ */
+void emcnand_lld_stop(EMCNANDDriver *emcnandp) {
+
+ if (emcnandp->state == EMCNAND_READY) {
+ dmaStreamRelease(emcnandp->dma);
+ emcnandp->nand->PCR &= ~FSMC_PCR_PBKEN;
+ emcnand_ready_isr_disable(emcnandp);
+ emcnandp->isr_handler = NULL;
+ }
+}
+
+/**
+ * @brief Read data from NAND.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[out] data pointer to data buffer
+ * @param[in] datalen size of data buffer
+ * @param[in] addr pointer to address buffer
+ * @param[in] addrlen length of address
+ * @param[out] ecc pointer to store computed ECC. Ignored when NULL.
+ *
+ * @notapi
+ */
+void emcnand_lld_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
+ size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc){
+
+ emcnandp->state = EMCNAND_READ;
+ emcnandp->rxdata = data;
+ emcnandp->datalen = datalen;
+
+ emcnand_lld_write_cmd (emcnandp, NAND_CMD_READ0);
+ emcnand_lld_write_addr(emcnandp, addr, addrlen);
+ osalSysLock();
+ emcnand_lld_write_cmd (emcnandp, NAND_CMD_READ0_CONFIRM);
+
+ /* Here NAND asserts busy signal and starts transferring from memory
+ array to page buffer. After the end of transmission ready_isr functions
+ starts DMA transfer from page buffer to MCU's RAM.*/
+ osalDbgAssert((emcnandp->nand->PCR & FSMC_PCR_ECCEN) == 0,
+ "State machine broken. ECCEN must be previously disabled.");
+
+ if (NULL != ecc){
+ emcnandp->nand->PCR |= FSMC_PCR_ECCEN;
+ }
+
+ emcnand_lld_suspend_thread(emcnandp);
+ osalSysUnlock();
+
+ /* thread was woken up from DMA ISR */
+ if (NULL != ecc){
+ while (! (emcnandp->nand->SR & FSMC_SR_FEMPT))
+ ;
+ *ecc = emcnandp->nand->ECCR;
+ emcnandp->nand->PCR &= ~FSMC_PCR_ECCEN;
+ }
+}
+
+/**
+ * @brief Write data to NAND.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] data buffer with data to be written
+ * @param[in] datalen size of data buffer
+ * @param[in] addr pointer to address buffer
+ * @param[in] addrlen length of address
+ * @param[out] ecc pointer to store computed ECC. Ignored when NULL.
+ *
+ * @return The operation status reported by NAND IC (0x70 command).
+ *
+ * @notapi
+ */
+uint8_t emcnand_lld_write_data(EMCNANDDriver *emcnandp, const uint8_t *data,
+ size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc){
+
+ emcnandp->state = EMCNAND_WRITE;
+
+ emcnand_lld_write_cmd (emcnandp, NAND_CMD_WRITE);
+ osalSysLock();
+ emcnand_lld_write_addr(emcnandp, addr, addrlen);
+
+ /* Now start DMA transfer to NAND buffer and put thread in sleep state.
+ Tread will we woken up from ready ISR. */
+ emcnandp->state = EMCNAND_DMA_TX;
+ osalDbgAssert((emcnandp->nand->PCR & FSMC_PCR_ECCEN) == 0,
+ "State machine broken. ECCEN must be previously disabled.");
+
+ if (NULL != ecc){
+ emcnandp->nand->PCR |= FSMC_PCR_ECCEN;
+ }
+
+ dmaStartMemCopy(emcnandp->dma, emcnandp->dmamode,
+ data, emcnandp->map_data, datalen);
+
+ emcnand_lld_suspend_thread(emcnandp);
+ osalSysUnlock();
+
+ if (NULL != ecc){
+ while (! (emcnandp->nand->SR & FSMC_SR_FEMPT))
+ ;
+ *ecc = emcnandp->nand->ECCR;
+ emcnandp->nand->PCR &= ~FSMC_PCR_ECCEN;
+ }
+
+ return emcnand_lld_read_status(emcnandp);
+}
+
+/**
+ * @brief Erase block.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] addr pointer to address buffer
+ * @param[in] addrlen length of address
+ *
+ * @return The operation status reported by NAND IC (0x70 command).
+ *
+ * @notapi
+ */
+uint8_t emcnand_lld_erase(EMCNANDDriver *emcnandp,
+ uint8_t *addr, size_t addrlen){
+
+ emcnandp->state = EMCNAND_ERASE;
+
+ emcnand_lld_write_cmd (emcnandp, NAND_CMD_ERASE);
+ emcnand_lld_write_addr(emcnandp, addr, addrlen);
+ osalSysLock();
+ emcnand_lld_write_cmd (emcnandp, NAND_CMD_ERASE_CONFIRM);
+ emcnand_lld_suspend_thread(emcnandp);
+ osalSysUnlock();
+
+ return emcnand_lld_read_status(emcnandp);
+}
+
+/**
+ * @brief Read data from NAND using polling approach.
+ *
+ * @detatils Use this function to read data when no waiting expected. For
+ * Example read status word after 0x70 command
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[out] data pointer to output buffer
+ * @param[in] len length of data to be read
+ *
+ * @notapi
+ */
+void emcnand_lld_polled_read_data(EMCNANDDriver *emcnandp,
+ uint8_t *data, size_t len){
+ size_t i = 0;
+
+ for (i=0; i<len; i++)
+ data[i] = emcnandp->map_data[i];
+}
+
+/**
+ * @brief Send addres to NAND.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] len length of address array
+ * @param[in] addr pointer to address array
+ *
+ * @notapi
+ */
+void emcnand_lld_write_addr(EMCNANDDriver *emcnandp,
+ const uint8_t *addr, size_t len){
+ size_t i = 0;
+
+ for (i=0; i<len; i++)
+ emcnandp->map_addr[i] = addr[i];
+}
+
+/**
+ * @brief Send command to NAND.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ * @param[in] cmd command value
+ *
+ * @notapi
+ */
+void emcnand_lld_write_cmd(EMCNANDDriver *emcnandp, uint8_t cmd){
+ emcnandp->map_cmd[0] = cmd;
+}
+
+/**
+ * @brief Read status byte from NAND.
+ *
+ * @param[in] emcnandp pointer to the @p EMCNANDDriver object
+ *
+ * @return Status byte.
+ *
+ * @notapi
+ */
+uint8_t emcnand_lld_read_status(EMCNANDDriver *emcnandp) {
+
+ uint8_t status[1] = {0x01}; /* presume worse */
+
+ emcnand_lld_write_cmd(emcnandp, NAND_CMD_STATUS);
+ emcnand_lld_polled_read_data(emcnandp, status, 1);
+
+ return status[0];
+}
+
+#endif /* HAL_USE_EMCNAND */
+
+/** @} */
+
diff --git a/os/hal/ports/STM32/LLD/emcnand_lld.h b/os/hal/ports/STM32/LLD/emcnand_lld.h
new file mode 100644
index 000000000..7f83a5723
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/emcnand_lld.h
@@ -0,0 +1,361 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011,2012,2013 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+ Concepts and parts of this file have been contributed by Uladzimir Pylinsky
+ aka barthess.
+ */
+
+/**
+ * @file emcnand_lld.h
+ * @brief EMCNAND Driver subsystem low level driver header template.
+ *
+ * @addtogroup EMCNAND
+ * @{
+ */
+
+#ifndef _EMCNAND_LLD_H_
+#define _EMCNAND_LLD_H_
+
+#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+#define EMCNAND_MIN_PAGE_SIZE 256
+#define EMCNAND_MAX_PAGE_SIZE 8192
+#define EMCNAND_BAD_MAP_END_MARK ((uint16_t)0xFFFF)
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @name Configuration options
+ * @{
+ */
+/**
+ * @brief EMD FSMC1 interrupt priority level setting.
+ */
+#if !defined(STM32_EMC_FSMC1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EMC_FSMC1_IRQ_PRIORITY 10
+#endif
+
+/**
+ * @brief EMCNAND driver enable switch.
+ * @details If set to @p TRUE the support for EMCNAND1 is included.
+ */
+#if !defined(STM32_EMCNAND_USE_EMCNAND1) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_USE_EMCNAND1 FALSE
+#endif
+
+/**
+ * @brief EMCNAND driver enable switch.
+ * @details If set to @p TRUE the support for EMCNAND2 is included.
+ */
+#if !defined(STM32_EMCNAND_USE_EMCNAND2) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_USE_EMCNAND2 FALSE
+#endif
+
+/**
+ * @brief EMCNAND DMA error hook.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
+ */
+#if !defined(STM32_EMCNAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_DMA_ERROR_HOOK(emcnandp) osalSysHalt("DMA failure")
+#endif
+
+/**
+ * @brief EMCNAND interrupt enable switch.
+ * @details If set to @p TRUE the support for internal FSMC interrupt included.
+ */
+#if !defined(STM32_EMCNAND_USE_INT) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_USE_INT FALSE
+#endif
+
+/**
+* @brief EMCNAND1 DMA priority (0..3|lowest..highest).
+*/
+#if !defined(STM32_EMCNAND_EMCNAND1_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_EMCNAND1_DMA_PRIORITY 0
+#endif
+
+/**
+* @brief EMCNAND2 DMA priority (0..3|lowest..highest).
+*/
+#if !defined(STM32_EMCNAND_EMCNAND2_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_EMCNAND2_DMA_PRIORITY 0
+#endif
+
+/**
+ * @brief DMA stream used for EMCNAND1 operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_EMCNAND_EMCNAND1_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_EMCNAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
+#endif
+
+/**
+ * @brief DMA stream used for EMCNAND2 operations.
+ * @note This option is only available on platforms with enhanced DMA.
+ */
+#if !defined(STM32_EMCNAND_EMCNAND2_DMA_STREAM) || defined(__DOXYGEN__)
+#define STM32_EMCNAND_EMCNAND2_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !STM32_EMCNAND_USE_EMCNAND1 && !STM32_EMCNAND_USE_EMCNAND2
+#error "EMCNAND driver activated but no EMCNAND peripheral assigned"
+#endif
+
+#if STM32_EMCNAND_USE_EMCNAND1 && !STM32_HAS_EMC
+#error "EMC not present in the selected device"
+#endif
+
+#if !STM32_EMCNAND_USE_INT && !HAL_USE_EXT
+#error "External interrupt controller must be enabled to use this feature"
+#endif
+
+#if STM32_EMCNAND_USE_EMCNAND1 && \
+ !STM32_DMA_IS_VALID_ID(STM32_EMCNAND_EMCNAND1_DMA_STREAM, \
+ STM32_EMC_DMA_MSK)
+#error "invalid DMA stream associated to EMCNAND"
+#endif
+
+#if STM32_EMCNAND_USE_EMCNAND2 && \
+ !STM32_DMA_IS_VALID_ID(STM32_EMCNAND_EMCNAND2_DMA_STREAM, \
+ STM32_EMC_DMA_MSK)
+#error "invalid DMA stream associated to EMCNAND"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief NAND driver condition flags type.
+ */
+typedef uint32_t emcnandflags_t;
+
+/**
+ * @brief Type of a structure representing an EMCNAND driver.
+ */
+typedef struct EMCNANDDriver EMCNANDDriver;
+
+#if STM32_EMC_USE_INT
+/**
+ * @brief Type of interrupt handler function
+ */
+typedef void (*emcnandisrhandler_t)
+ (EMCNANDDriver *emcnandp, emcnandflags_t flags);
+#else
+/**
+ * @brief Type of interrupt handler function
+ */
+typedef void (*emcnandisrhandler_t)(EMCNANDDriver *emcnandp);
+
+/**
+ * @brief Type of function switching external interrupts on and off.
+ */
+typedef void (*emcnandisrswitch_t)(void);
+#endif /* STM32_EMC_USE_INT */
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Pointer to lower level driver.
+ */
+ EMCDriver *emcp;
+ /**
+ * @brief Number of erase blocks in NAND device.
+ */
+ uint32_t blocks;
+ /**
+ * @brief Number of data bytes in page.
+ */
+ uint32_t page_data_size;
+ /**
+ * @brief Number of spare bytes in page.
+ */
+ uint32_t page_spare_size;
+ /**
+ * @brief Number of pages in block.
+ */
+ uint32_t pages_per_block;
+#if EMCNAND_USE_BAD_MAP
+ /**
+ * @brief Pointer to bad block map.
+ * @details One bit per block. Memory for map must be allocated by user.
+ */
+ uint32_t *bb_map;
+#endif /* EMCNAND_USE_BAD_MAP */
+ /**
+ * @brief Number of write cycles for row addressing.
+ */
+ uint8_t rowcycles;
+ /**
+ * @brief Number of write cycles for column addressing.
+ */
+ uint8_t colcycles;
+
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Number of wait cycles. This value will be used both for
+ * PMEM and PATTR registers
+ *
+ * @note For proper calculation procedure please look at AN2784 document
+ * from STMicroelectronics.
+ */
+ uint32_t pmem;
+#if !STM32_EMC_USE_INT
+ /**
+ * @brief Function enabling interrupts from EXTI
+ */
+ emcnandisrswitch_t ext_isr_enable;
+ /**
+ * @brief Function disabling interrupts from EXTI
+ */
+ emcnandisrswitch_t ext_isr_disable;
+#endif /* !STM32_EMC_USE_INT */
+} EMCNANDConfig;
+
+/**
+ * @brief Structure representing an EMCNAND driver.
+ */
+struct EMCNANDDriver {
+ /**
+ * @brief Driver state.
+ */
+ emcnandstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const EMCNANDConfig *config;
+ /**
+ * @brief Array to store bad block map.
+ */
+#if EMCNAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
+#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
+ /**
+ * @brief Mutex protecting the bus.
+ */
+ mutex_t mutex;
+#elif CH_CFG_USE_SEMAPHORES
+ semaphore_t semaphore;
+#endif
+#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Function enabling interrupts from FSMC
+ */
+ emcnandisrhandler_t isr_handler;
+ /**
+ * @brief Pointer to current transaction buffer
+ */
+ uint8_t *rxdata;
+ /**
+ * @brief Current transaction length
+ */
+ size_t datalen;
+ /**
+ * @brief DMA mode bit mask.
+ */
+ uint32_t dmamode;
+ /**
+ * @brief DMA channel.
+ */
+ const stm32_dma_stream_t *dma;
+ /**
+ * @brief Thread waiting for I/O completion.
+ */
+ thread_t *thread;
+ /**
+ * @brief Pointer to the FSMC NAND registers block.
+ */
+ FSMC_NAND_TypeDef *nand;
+ /**
+ * @brief Memory mapping for data.
+ */
+ uint8_t *map_data;
+ /**
+ * @brief Memory mapping for commands.
+ */
+ uint8_t *map_cmd;
+ /**
+ * @brief Memory mapping for addresses.
+ */
+ uint8_t *map_addr;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_EMCNAND_USE_EMCNAND1 && !defined(__DOXYGEN__)
+extern EMCNANDDriver EMCNANDD1;
+#endif
+
+#if STM32_EMCNAND_USE_EMCNAND2 && !defined(__DOXYGEN__)
+extern EMCNANDDriver EMCNANDD2;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void emcnand_lld_init(void);
+ void emcnand_lld_start(EMCNANDDriver *emcnandp);
+ void emcnand_lld_stop(EMCNANDDriver *emcnandp);
+ uint8_t emcnand_lld_write_data(EMCNANDDriver *emcnandp, const uint8_t *data,
+ size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
+ void emcnand_lld_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
+ size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
+ void emcnand_lld_polled_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
+ size_t len);
+ uint8_t emcnand_lld_erase(EMCNANDDriver *emcnandp, uint8_t *addr,
+ size_t addrlen);
+ void emcnand_lld_write_addr(EMCNANDDriver *emcnandp,
+ const uint8_t *addr, size_t len);
+ void emcnand_lld_write_cmd(EMCNANDDriver *emcnandp, uint8_t cmd);
+ uint8_t emcnand_lld_read_status(EMCNANDDriver *emcnandp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_EMCNAND */
+
+#endif /* _EMCNAND_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/ports/STM32/STM32F4xx/platform.mk b/os/hal/ports/STM32/STM32F4xx/platform.mk
index c9b74b45c..00dd5ccb4 100644
--- a/os/hal/ports/STM32/STM32F4xx/platform.mk
+++ b/os/hal/ports/STM32/STM32F4xx/platform.mk
@@ -20,7 +20,9 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/TIMv1/pwm_lld.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/TIMv1/st_lld.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/USARTv1/serial_lld.c \
- ${CHIBIOS}/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c
+ ${CHIBIOS}/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c \
+ ${CHIBIOS}/os/hal/ports/STM32/LLD/emc_lld.c \
+ ${CHIBIOS}/os/hal/ports/STM32/LLD/emcnand_lld.c
# Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \
diff --git a/os/hal/ports/STM32/STM32F4xx/stm32_rcc.h b/os/hal/ports/STM32/STM32F4xx/stm32_rcc.h
index 5d66fffa5..fa9fe14bd 100644
--- a/os/hal/ports/STM32/STM32F4xx/stm32_rcc.h
+++ b/os/hal/ports/STM32/STM32F4xx/stm32_rcc.h
@@ -1382,6 +1382,35 @@
* @api
*/
#define rccResetLTDC() rccResetAPB2(RCC_APB2RSTR_LTDCRST)
+
+/**
+ * @name FSMC peripherals specific RCC operations
+ * @{
+ */
+/**
+ * @brief Enables the FSMS peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccEnableFSMC(lp) rccEnableAHB3(RCC_AHB3ENR_FSMCEN, lp)
+
+/**
+ * @brief Disables the FSMC peripheral clock.
+ *
+ * @param[in] lp low power enable flag
+ *
+ * @api
+ */
+#define rccDisableFSMC(lp) rccDisableAHB3(RCC_AHB3ENR_FSMCEN, lp)
+
+/**
+ * @brief Resets the FSMC peripheral.
+ *
+ * @api
+ */
+#define rccResetFSMC() rccResetAHB3(RCC_AHB3RSTR_FSMCRST)
/** @} */
/*===========================================================================*/
diff --git a/os/hal/ports/STM32/STM32F4xx/stm32_registry.h b/os/hal/ports/STM32/STM32F4xx/stm32_registry.h
index 78a8d783a..816ae0353 100644
--- a/os/hal/ports/STM32/STM32F4xx/stm32_registry.h
+++ b/os/hal/ports/STM32/STM32F4xx/stm32_registry.h
@@ -325,6 +325,18 @@
#else /* defined(STM32F401xx) */
#define STM32_HAS_OTG2 FALSE
#endif /* defined(STM32F401xx) */
+
+/* EMC attributes.*/
+#define STM32_HAS_EMC TRUE
+#define STM32_EMC_DMA_MSK (STM32_DMA_STREAM_ID_MSK(2, 0) | \
+ STM32_DMA_STREAM_ID_MSK(2, 1) | \
+ STM32_DMA_STREAM_ID_MSK(2, 2) | \
+ STM32_DMA_STREAM_ID_MSK(2, 3) | \
+ STM32_DMA_STREAM_ID_MSK(2, 4) | \
+ STM32_DMA_STREAM_ID_MSK(2, 5) | \
+ STM32_DMA_STREAM_ID_MSK(2, 6) | \
+ STM32_DMA_STREAM_ID_MSK(2, 7))
+#define STM32_EMC_DMA_CHN 0x03010201
/** @} */
#endif /* _STM32_REGISTRY_H_ */