STM32 FSMC NAND. Change driver file layout and naming conventions.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@7145 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
2a6b156390
commit
156ff76940
|
@ -23,8 +23,7 @@ HALSRC = ${CHIBIOS}/os/hal/src/hal.c \
|
||||||
${CHIBIOS}/os/hal/src/st.c \
|
${CHIBIOS}/os/hal/src/st.c \
|
||||||
${CHIBIOS}/os/hal/src/uart.c \
|
${CHIBIOS}/os/hal/src/uart.c \
|
||||||
${CHIBIOS}/os/hal/src/usb.c \
|
${CHIBIOS}/os/hal/src/usb.c \
|
||||||
${CHIBIOS}/os/hal/src/emc.c \
|
${CHIBIOS}/os/hal/src/nand.c
|
||||||
${CHIBIOS}/os/hal/src/emcnand.c
|
|
||||||
|
|
||||||
# Required include directories
|
# Required include directories
|
||||||
HALINC = ${CHIBIOS}/os/hal/include
|
HALINC = ${CHIBIOS}/os/hal/include
|
||||||
|
|
|
@ -1,93 +0,0 @@
|
||||||
/*
|
|
||||||
ChibiOS/HAL - Copyright (C) 2006,2007,2008,2009,2010,
|
|
||||||
2011,2012,2013,2014 Giovanni Di Sirio.
|
|
||||||
|
|
||||||
This file is part of ChibiOS/HAL
|
|
||||||
|
|
||||||
ChibiOS/HAL 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.h
|
|
||||||
* @brief EMC Driver macros and structures.
|
|
||||||
*
|
|
||||||
* @addtogroup EMC
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _EMC_H_
|
|
||||||
#define _EMC_H_
|
|
||||||
|
|
||||||
#if HAL_USE_EMC || defined(__DOXYGEN__)
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver constants. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver pre-compile time settings. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Derived constants and error checks. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver data structures and types. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Driver state machine possible states.
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
EMC_UNINIT = 0, /**< Not initialized. */
|
|
||||||
EMC_STOP = 1, /**< Stopped. */
|
|
||||||
EMC_READY = 2, /**< Ready. */
|
|
||||||
} emcstate_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Type of a structure representing a EMC driver.
|
|
||||||
*/
|
|
||||||
typedef struct EMCDriver EMCDriver;
|
|
||||||
|
|
||||||
#include "emc_lld.h"
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver macros. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* External declarations. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
void emcInit(void);
|
|
||||||
void emcObjectInit(EMCDriver *emcp);
|
|
||||||
void emcStart(EMCDriver *emcp, const EMCConfig *config);
|
|
||||||
void emcStop(EMCDriver *emcp);
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* HAL_USE_EMC */
|
|
||||||
|
|
||||||
#endif /* _EMC_H_ */
|
|
||||||
|
|
||||||
/** @} */
|
|
|
@ -64,8 +64,7 @@
|
||||||
#include "st.h"
|
#include "st.h"
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "emc.h"
|
#include "nand.h"
|
||||||
#include "emcnand.h"
|
|
||||||
|
|
||||||
/* Complex drivers.*/
|
/* Complex drivers.*/
|
||||||
#include "mmc_spi.h"
|
#include "mmc_spi.h"
|
||||||
|
|
|
@ -23,17 +23,17 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file emcnand.h
|
* @file nand.h
|
||||||
* @brief EMCNAND Driver macros and structures.
|
* @brief NAND Driver macros and structures.
|
||||||
*
|
*
|
||||||
* @addtogroup EMCNAND
|
* @addtogroup NAND
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _EMCNAND_H_
|
#ifndef _NAND_H_
|
||||||
#define _EMCNAND_H_
|
#define _NAND_H_
|
||||||
|
|
||||||
#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
|
#if HAL_USE_NAND || defined(__DOXYGEN__)
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver constants. */
|
/* Driver constants. */
|
||||||
|
@ -62,19 +62,15 @@
|
||||||
/**
|
/**
|
||||||
* @brief Enables the mutual exclusion APIs on the NAND.
|
* @brief Enables the mutual exclusion APIs on the NAND.
|
||||||
*/
|
*/
|
||||||
#if !defined(EMCNAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
#if !defined(NAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||||
#define EMCNAND_USE_MUTUAL_EXCLUSION FALSE
|
#define NAND_USE_MUTUAL_EXCLUSION FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Derived constants and error checks. */
|
/* Derived constants and error checks. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
#if EMCNAND_USE_MUTUAL_EXCLUSION && !CH_CFG_USE_MUTEXES && !CH_CFG_USE_SEMAPHORES
|
#if NAND_USE_MUTUAL_EXCLUSION && !CH_CFG_USE_MUTEXES && !CH_CFG_USE_SEMAPHORES
|
||||||
#error "EMCNAND_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
|
#error "NAND_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !HAL_USE_EMC
|
|
||||||
#error "This driver requires EMC controller"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -85,23 +81,23 @@
|
||||||
* @brief Driver state machine possible states.
|
* @brief Driver state machine possible states.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EMCNAND_UNINIT = 0, /**< Not initialized. */
|
NAND_UNINIT = 0, /**< Not initialized. */
|
||||||
EMCNAND_STOP = 1, /**< Stopped. */
|
NAND_STOP = 1, /**< Stopped. */
|
||||||
EMCNAND_READY = 2, /**< Ready. */
|
NAND_READY = 2, /**< Ready. */
|
||||||
EMCNAND_PROGRAM = 3, /**< Programming in progress. */
|
NAND_PROGRAM = 3, /**< Programming in progress. */
|
||||||
EMCNAND_ERASE = 4, /**< Erasing in progress. */
|
NAND_ERASE = 4, /**< Erasing in progress. */
|
||||||
EMCNAND_WRITE = 5, /**< Writing to NAND buffer. */
|
NAND_WRITE = 5, /**< Writing to NAND buffer. */
|
||||||
EMCNAND_READ = 6, /**< Reading from NAND. */
|
NAND_READ = 6, /**< Reading from NAND. */
|
||||||
EMCNAND_DMA_TX = 7, /**< DMA transmitting. */
|
NAND_DMA_TX = 7, /**< DMA transmitting. */
|
||||||
EMCNAND_DMA_RX = 8, /**< DMA receiving. */
|
NAND_DMA_RX = 8, /**< DMA receiving. */
|
||||||
} emcnandstate_t;
|
} nandstate_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type of a structure representing a EMCNAND driver.
|
* @brief Type of a structure representing a NAND driver.
|
||||||
*/
|
*/
|
||||||
typedef struct EMCNANDDriver EMCNANDDriver;
|
typedef struct NANDDriver NANDDriver;
|
||||||
|
|
||||||
#include "emcnand_lld.h"
|
#include "nand_lld.h"
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver macros. */
|
/* Driver macros. */
|
||||||
|
@ -114,39 +110,39 @@ typedef struct EMCNANDDriver EMCNANDDriver;
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
void emcnandInit(void);
|
void nandInit(void);
|
||||||
void emcnandObjectInit(EMCNANDDriver *emcnandp);
|
void nandObjectInit(NANDDriver *nandp);
|
||||||
void emcnandStart(EMCNANDDriver *emcnandp, const EMCNANDConfig *config);
|
void nandStart(NANDDriver *nandp, const NANDConfig *config);
|
||||||
void emcnandStop(EMCNANDDriver *emcnandp);
|
void nandStop(NANDDriver *nandp);
|
||||||
void emcnandReadPageWhole(EMCNANDDriver *emcnandp, uint32_t block,
|
void nandReadPageWhole(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, uint8_t *data, size_t datalen);
|
uint32_t page, uint8_t *data, size_t datalen);
|
||||||
uint8_t emcnandWritePageWhole(EMCNANDDriver *emcnandp, uint32_t block,
|
uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, const uint8_t *data, size_t datalen);
|
uint32_t page, const uint8_t *data, size_t datalen);
|
||||||
void emcnandReadPageData(EMCNANDDriver *emcnandp, uint32_t block,
|
void nandReadPageData(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, uint8_t *data, size_t datalen, uint32_t *ecc);
|
uint32_t page, uint8_t *data, size_t datalen, uint32_t *ecc);
|
||||||
uint8_t emcnandWritePageData(EMCNANDDriver *emcnandp, uint32_t block,
|
uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, const uint8_t *data, size_t datalen, uint32_t *ecc);
|
uint32_t page, const uint8_t *data, size_t datalen, uint32_t *ecc);
|
||||||
void emcnandReadPageSpare(EMCNANDDriver *emcnandp, uint32_t block,
|
void nandReadPageSpare(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, uint8_t *spare, size_t sparelen);
|
uint32_t page, uint8_t *spare, size_t sparelen);
|
||||||
uint8_t emcnandWritePageSpare(EMCNANDDriver *emcnandp, uint32_t block,
|
uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, const uint8_t *spare, size_t sparelen);
|
uint32_t page, const uint8_t *spare, size_t sparelen);
|
||||||
void emcnandMarkBad(EMCNANDDriver *emcnandp, uint32_t block);
|
void nandMarkBad(NANDDriver *nandp, uint32_t block);
|
||||||
uint8_t emcnandReadBadMark(EMCNANDDriver *emcnandp,
|
uint8_t nandReadBadMark(NANDDriver *nandp,
|
||||||
uint32_t block, uint32_t page);
|
uint32_t block, uint32_t page);
|
||||||
uint8_t emcnandErase(EMCNANDDriver *emcnandp, uint32_t block);
|
uint8_t nandErase(NANDDriver *nandp, uint32_t block);
|
||||||
bool emcnandIsBad(EMCNANDDriver *emcnandp, uint32_t block);
|
bool nandIsBad(NANDDriver *nandp, uint32_t block);
|
||||||
|
|
||||||
#if EMCNAND_USE_MUTUAL_EXCLUSION
|
#if NAND_USE_MUTUAL_EXCLUSION
|
||||||
void emcnandAcquireBus(EMCNANDDriver *emcnandp);
|
void nandAcquireBus(NANDDriver *nandp);
|
||||||
void emcnandReleaseBus(EMCNANDDriver *emcnandp);
|
void nandReleaseBus(NANDDriver *nandp);
|
||||||
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
|
#endif /* NAND_USE_MUTUAL_EXCLUSION */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* HAL_USE_EMCNAND */
|
#endif /* HAL_USE_NAND */
|
||||||
|
|
||||||
#endif /* _EMCNAND_H_ */
|
#endif /* _NAND_H_ */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
|
@ -19,16 +19,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file emc_lld.c
|
* @file fsmc.c
|
||||||
* @brief EMC Driver subsystem low level driver source template.
|
* @brief FSMC Driver subsystem low level driver source template.
|
||||||
*
|
*
|
||||||
* @addtogroup EMC
|
* @addtogroup FSMC
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
|
|
||||||
#if HAL_USE_EMC || defined(__DOXYGEN__)
|
#if HAL_USE_NAND || defined(__DOXYGEN__)
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver local definitions. */
|
/* Driver local definitions. */
|
||||||
|
@ -39,10 +39,10 @@
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMC1 driver identifier.
|
* @brief FSMC1 driver identifier.
|
||||||
*/
|
*/
|
||||||
#if STM32_EMC_USE_FSMC1 || defined(__DOXYGEN__)
|
#if STM32_FSMC_USE_FSMC1 || defined(__DOXYGEN__)
|
||||||
EMCDriver EMCD1;
|
FSMCDriver FSMCD1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -66,89 +66,90 @@ EMCDriver EMCD1;
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Low level EMC driver initialization.
|
* @brief Low level FSMC driver initialization.
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
void emc_lld_init(void) {
|
void fsmc_lld_init(void) {
|
||||||
|
|
||||||
#if STM32_EMC_USE_FSMC1
|
FSMCD1.state = FSMC_STOP;
|
||||||
emcObjectInit(&EMCD1);
|
|
||||||
|
|
||||||
#if STM32_EMCNAND_USE_EMCNAND1
|
#if STM32_NAND_USE_FSMC_NAND1
|
||||||
EMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
|
FSMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if STM32_EMCNAND_USE_EMCNAND2
|
#if STM32_NAND_USE_FSMC_NAND2
|
||||||
EMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
|
FSMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if STM32_USE_EMC_PCCARD
|
#if STM32_USE_FSMC_PCCARD
|
||||||
EMCD1.pccard = (FSMC_PCCARD_TypeDef *)FSMC_Bank4_R_BASE;
|
FSMCD1.pccard = (FSMC_PCCARD_TypeDef *)FSMC_Bank4_R_BASE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* STM32_EMC_USE_EMC1 */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configures and activates the EMC peripheral.
|
* @brief Configures and activates the FSMC peripheral.
|
||||||
*
|
*
|
||||||
* @param[in] emcp pointer to the @p EMCDriver object
|
* @param[in] fsmcp pointer to the @p FSMCDriver object
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
void emc_lld_start(EMCDriver *emcp) {
|
void fsmc_lld_start(FSMCDriver *fsmcp) {
|
||||||
|
|
||||||
if (emcp->state == EMC_STOP) {
|
|
||||||
|
osalDbgAssert((fsmcp->state == FSMC_STOP) || (fsmcp->state == FSMC_READY),
|
||||||
|
"invalid state");
|
||||||
|
|
||||||
|
if (fsmcp->state == FSMC_STOP) {
|
||||||
/* Enables the peripheral.*/
|
/* Enables the peripheral.*/
|
||||||
#if STM32_EMC_USE_FSMC1
|
#if STM32_FSMC_USE_FSMC1
|
||||||
if (&EMCD1 == emcp) {
|
if (&FSMCD1 == fsmcp) {
|
||||||
rccResetFSMC();
|
rccResetFSMC();
|
||||||
rccEnableFSMC(FALSE);
|
rccEnableFSMC(FALSE);
|
||||||
#if STM32_EMC_USE_INT
|
#if STM32_NAND_USE_FSMC_INT
|
||||||
nvicEnableVector(FSMC_IRQn, STM32_EMC_FSMC1_IRQ_PRIORITY);
|
nvicEnableVector(FSMC_IRQn, STM32_FSMC_FSMC1_IRQ_PRIORITY);
|
||||||
#endif /* STM32_EMC_USE_INT */
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* PLATFORM_STM32_USE_EMC1 */
|
#endif /* STM32_FSMC_USE_FSMC1 */
|
||||||
|
|
||||||
emcp->state = EMC_READY;
|
fsmcp->state = FSMC_READY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deactivates the EMC peripheral.
|
* @brief Deactivates the FSMC peripheral.
|
||||||
*
|
*
|
||||||
* @param[in] emcp pointer to the @p EMCDriver object
|
* @param[in] emcp pointer to the @p FSMCDriver object
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
void emc_lld_stop(EMCDriver *emcp) {
|
void fsmc_lld_stop(FSMCDriver *fsmcp) {
|
||||||
|
|
||||||
if (emcp->state == EMC_READY) {
|
if (fsmcp->state == FSMC_READY) {
|
||||||
/* Resets the peripheral.*/
|
/* Resets the peripheral.*/
|
||||||
rccResetFSMC();
|
rccResetFSMC();
|
||||||
|
|
||||||
/* Disables the peripheral.*/
|
/* Disables the peripheral.*/
|
||||||
#if STM32_EMC_USE_FSMC1
|
#if STM32_FSMC_USE_FSMC1
|
||||||
if (&EMCD1 == emcp) {
|
if (&FSMCD1 == fsmcp) {
|
||||||
#if STM32_EMC_USE_INT
|
#if STM32_NAND_USE_FSMC_INT
|
||||||
nvicDisableVector(FSMC_IRQn);
|
nvicDisableVector(FSMC_IRQn);
|
||||||
#endif
|
#endif
|
||||||
rccDisableFSMC(FALSE);
|
rccDisableFSMC(FALSE);
|
||||||
}
|
}
|
||||||
#endif /* PLATFORM_STM32_USE_EMC1 */
|
#endif /* PLATFORM_STM32_USE_FSMC1 */
|
||||||
|
|
||||||
emcp->state = EMC_STOP;
|
fsmcp->state = FSMC_STOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if STM32_EMC_USE_INT
|
#if STM32_NAND_USE_FSMC_INT
|
||||||
/**
|
/**
|
||||||
* @brief Serve common interrupt.
|
* @brief Serve common interrupt.
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
void emc_lld_serve_interrupt(void) {
|
void fsmc_lld_serve_interrupt(void) {
|
||||||
|
|
||||||
osalSysHalt("Unrealized");
|
osalSysHalt("Unrealized");
|
||||||
}
|
}
|
||||||
|
@ -162,20 +163,20 @@ CH_IRQ_HANDLER(FSMC_IRQHandler) {
|
||||||
osalSysHalt("This functionality untested");
|
osalSysHalt("This functionality untested");
|
||||||
|
|
||||||
CH_IRQ_PROLOGUE();
|
CH_IRQ_PROLOGUE();
|
||||||
#if STM32_EMCNAND_USE_EMCNAND1
|
#if STM32_NAND_USE_FSMC_NAND1
|
||||||
if (EMCD1.nand1->SR & FSMC_SR_ISR_MASK){
|
if (FSMCD1.nand1->SR & FSMC_SR_ISR_MASK){
|
||||||
EMCNANDD1.isr_handler(&EMCNANDD1, EMCD1.nand1->SR);
|
NANDD1.isr_handler(&NANDD1, FSMCD1.nand1->SR);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if STM32_EMCNAND_USE_EMCNAND2
|
#if STM32_NAND_USE_FSMC_NAND2
|
||||||
if (EMCD1.nand2->SR & FSMC_SR_ISR_MASK){
|
if (FSMCD1.nand2->SR & FSMC_SR_ISR_MASK){
|
||||||
EMCNANDD2.isr_handler(&EMCNANDD2, EMCD1.nand2->SR);
|
NANDD2.isr_handler(&NANDD2, FSMCD1.nand2->SR);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
CH_IRQ_EPILOGUE();
|
CH_IRQ_EPILOGUE();
|
||||||
}
|
}
|
||||||
#endif /* STM32_EMC_USE_INT */
|
#endif /* STM32_FSMC_USE_INT */
|
||||||
|
|
||||||
#endif /* HAL_USE_EMC */
|
#endif /* HAL_USE_FSMC */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
|
@ -19,18 +19,18 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file emc_lld.h
|
* @file fsmc.h
|
||||||
* @brief EMC Driver subsystem low level driver header template.
|
* @brief FSMC Driver subsystem low level driver header template.
|
||||||
*
|
*
|
||||||
* @addtogroup EMC
|
* @addtogroup FSMC
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _EMC_LLD_H_
|
#ifndef _FSMC_H_
|
||||||
#define _EMC_LLD_H_
|
#define _FSMC_H_
|
||||||
|
|
||||||
#if HAL_USE_EMC || defined(__DOXYGEN__)
|
#if HAL_USE_NAND || defined(__DOXYGEN__)
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver constants. */
|
/* Driver constants. */
|
||||||
|
@ -146,11 +146,11 @@ typedef struct {
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @brief EMC driver enable switch.
|
* @brief FSMC driver enable switch.
|
||||||
* @details If set to @p TRUE the support for EMC is included.
|
* @details If set to @p TRUE the support for FSMC is included.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMC_USE_FSMC1) || defined(__DOXYGEN__)
|
#if !defined(STM32_FSMC_USE_FSMC1) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMC_USE_FSMC1 FALSE
|
#define STM32_FSMC_USE_FSMC1 FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -158,10 +158,8 @@ typedef struct {
|
||||||
* @details MCUs in 100-pin package has no dedicated interrupt pin for FSMC.
|
* @details MCUs in 100-pin package has no dedicated interrupt pin for FSMC.
|
||||||
* You have to use EXTI module instead to workaround this issue.
|
* You have to use EXTI module instead to workaround this issue.
|
||||||
*/
|
*/
|
||||||
#if STM32_EMC_EMCNAND_USE_FSMC_INT
|
#if !defined(STM32_NAND_USE_FSMC_INT) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMC_USE_INT TRUE
|
#define STM32_NAND_USE_FSMC_INT FALSE
|
||||||
#else
|
|
||||||
#define STM32_EMC_USE_INT FALSE
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -169,8 +167,8 @@ typedef struct {
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Derived constants and error checks. */
|
/* Derived constants and error checks. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
#if !STM32_EMC_USE_FSMC1
|
#if !STM32_FSMC_USE_FSMC1
|
||||||
#error "EMC driver activated but no EMC peripheral assigned"
|
#error "FSMC driver activated but no FSMC peripheral assigned"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -178,9 +176,18 @@ typedef struct {
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type of a structure representing an EMC driver.
|
* @brief Type of a structure representing an FSMC driver.
|
||||||
*/
|
*/
|
||||||
typedef struct EMCDriver EMCDriver;
|
typedef struct FSMCDriver FSMCDriver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Driver state machine possible states.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
FSMC_UNINIT = 0, /**< Not initialized. */
|
||||||
|
FSMC_STOP = 1, /**< Stopped. */
|
||||||
|
FSMC_READY = 2, /**< Ready. */
|
||||||
|
} fsmcstate_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Driver configuration structure.
|
* @brief Driver configuration structure.
|
||||||
|
@ -188,28 +195,24 @@ typedef struct EMCDriver EMCDriver;
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
} EMCConfig;
|
} FSMCConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure representing an EMC driver.
|
* @brief Structure representing an FSMC driver.
|
||||||
*/
|
*/
|
||||||
struct EMCDriver {
|
struct FSMCDriver {
|
||||||
/**
|
/**
|
||||||
* @brief Driver state.
|
* @brief Driver state.
|
||||||
*/
|
*/
|
||||||
emcstate_t state;
|
fsmcstate_t state;
|
||||||
/**
|
|
||||||
* @brief Current configuration data.
|
|
||||||
*/
|
|
||||||
const EMCConfig *config;
|
|
||||||
/* End of the mandatory fields.*/
|
/* End of the mandatory fields.*/
|
||||||
#if STM32_EMCNAND_USE_EMCNAND1
|
#if STM32_NAND_USE_FSMC_NAND1
|
||||||
FSMC_NAND_TypeDef *nand1;
|
FSMC_NAND_TypeDef *nand1;
|
||||||
#endif
|
#endif
|
||||||
#if STM32_EMCNAND_USE_EMCNAND2
|
#if STM32_NAND_USE_FSMC_NAND2
|
||||||
FSMC_NAND_TypeDef *nand2;
|
FSMC_NAND_TypeDef *nand2;
|
||||||
#endif
|
#endif
|
||||||
#if STM32_USE_EMC_PCCARD
|
#if STM32_USE_FSMC_PCCARD
|
||||||
FSMC_PCCard_TypeDef *pccard;
|
FSMC_PCCard_TypeDef *pccard;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -222,22 +225,22 @@ struct EMCDriver {
|
||||||
/* External declarations. */
|
/* External declarations. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
#if STM32_EMC_USE_FSMC1 && !defined(__DOXYGEN__)
|
#if STM32_FSMC_USE_FSMC1 && !defined(__DOXYGEN__)
|
||||||
extern EMCDriver EMCD1;
|
extern FSMCDriver FSMCD1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
void emc_lld_init(void);
|
void fsmc_lld_init(void);
|
||||||
void emc_lld_start(EMCDriver *emcp);
|
void fsmc_lld_start(FSMCDriver *fsmcp);
|
||||||
void emc_lld_stop(EMCDriver *emcp);
|
void fsmc_lld_stop(FSMCDriver *fsmcp);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* HAL_USE_EMC */
|
#endif /* HAL_USE_NAND */
|
||||||
|
|
||||||
#endif /* _EMC_LLD_H_ */
|
#endif /* _FSMC_H_ */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
|
@ -0,0 +1,547 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/HAL - Copyright (C) 2006-2014 Giovanni Di Sirio
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
|
||||||
|
aka barthess.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file nand_lld.c
|
||||||
|
* @brief NAND Driver subsystem low level driver source template.
|
||||||
|
*
|
||||||
|
* @addtogroup NAND
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if HAL_USE_NAND || defined(__DOXYGEN__)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local definitions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
#define NAND_DMA_CHANNEL \
|
||||||
|
STM32_DMA_GETCHANNEL(STM32_NAND_DMA_STREAM, \
|
||||||
|
STM32_FSMC_DMA_CHN)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAND1 driver identifier.
|
||||||
|
*/
|
||||||
|
#if STM32_NAND_USE_FSMC_NAND1 || defined(__DOXYGEN__)
|
||||||
|
NANDDriver NANDD1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief NAND2 driver identifier.
|
||||||
|
*/
|
||||||
|
#if STM32_NAND_USE_FSMC_NAND2 || defined(__DOXYGEN__)
|
||||||
|
NANDDriver NANDD2;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local variables and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/**
|
||||||
|
* @brief Wakes up the waiting thread.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
* @param[in] msg wakeup message
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void wakeup_isr(NANDDriver *nandp){
|
||||||
|
|
||||||
|
osalDbgCheck(nandp->thread != NULL);
|
||||||
|
osalThreadResumeI(&nandp->thread, MSG_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put calling thread in suspend and switch driver state
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*/
|
||||||
|
static void nand_lld_suspend_thread(NANDDriver *nandp) {
|
||||||
|
|
||||||
|
//nandp->thread = chThdGetSelfX();
|
||||||
|
osalThreadSuspendS(&nandp->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Caclulate ECCPS register value
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*/
|
||||||
|
static uint32_t calc_eccps(NANDDriver *nandp){
|
||||||
|
|
||||||
|
uint32_t i = 0;
|
||||||
|
uint32_t eccps = nandp->config->page_data_size;
|
||||||
|
|
||||||
|
eccps = eccps >> 9;
|
||||||
|
while (eccps > 0){
|
||||||
|
i++;
|
||||||
|
eccps >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i << 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver interrupt handlers. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if STM32_NAND_USE_FSMC_INT
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupts from FSMC
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_ready_isr_enable(NANDDriver *nandp) {
|
||||||
|
nandp->nand->SR |= FSMC_SR_IREN;
|
||||||
|
osalSysHalt("Function untested");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable interrupts from FSMC
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_ready_isr_disable(NANDDriver *nandp) {
|
||||||
|
nandp->nand->SR &= ~FSMC_SR_IREN;
|
||||||
|
osalSysHalt("Function untested");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ready interrupt handler
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
* @param[in] flags flags passed from FSMC intrrupt handler
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_isr_handler (NANDDriver *nandp,
|
||||||
|
nandflags_t flags){
|
||||||
|
(void)nandp;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
|
osalSysHalt("Unrealized");
|
||||||
|
}
|
||||||
|
#else /* STM32_NAND_USE_FSMC_INT */
|
||||||
|
/**
|
||||||
|
* @brief Disable interrupts from EXTI
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_ready_isr_enable(NANDDriver *nandp) {
|
||||||
|
nandp->config->ext_isr_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupts from EXTI
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_ready_isr_disable(NANDDriver *nandp) {
|
||||||
|
nandp->config->ext_isr_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Ready pin interrupt handler.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_isr_handler(NANDDriver *nandp){
|
||||||
|
|
||||||
|
osalSysLockFromISR();
|
||||||
|
|
||||||
|
switch (nandp->state){
|
||||||
|
case NAND_READ:
|
||||||
|
nandp->state = NAND_DMA_RX;
|
||||||
|
dmaStartMemCopy(nandp->dma, nandp->dmamode,
|
||||||
|
nandp->map_data, nandp->rxdata, nandp->datalen);
|
||||||
|
/* thread will be woked up from DMA ISR */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAND_ERASE:
|
||||||
|
/* NAND reports about erase finish */
|
||||||
|
nandp->state = NAND_READY;
|
||||||
|
wakeup_isr(nandp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAND_PROGRAM:
|
||||||
|
/* NAND reports about page programming finish */
|
||||||
|
nandp->state = NAND_READY;
|
||||||
|
wakeup_isr(nandp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
osalSysHalt("Unhandled case");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
#endif /* STM32_NAND_USE_FSMC_INT */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief DMA RX end IRQ handler.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
* @param[in] flags pre-shifted content of the ISR register
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
static void nand_lld_serve_transfer_end_irq(NANDDriver *nandp,
|
||||||
|
uint32_t flags) {
|
||||||
|
/* DMA errors handling.*/
|
||||||
|
#if defined(STM32_NAND_DMA_ERROR_HOOK)
|
||||||
|
if ((flags & (STM32_DMA_ISR_TEIF | STM32_DMA_ISR_DMEIF)) != 0) {
|
||||||
|
STM32_NAND_DMA_ERROR_HOOK(nandp);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)flags;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
osalSysLockFromISR();
|
||||||
|
|
||||||
|
dmaStreamDisable(nandp->dma);
|
||||||
|
|
||||||
|
switch (nandp->state){
|
||||||
|
case NAND_DMA_TX:
|
||||||
|
nandp->state = NAND_PROGRAM;
|
||||||
|
nandp->map_cmd[0] = NAND_CMD_PAGEPROG;
|
||||||
|
/* thread will be woken from ready_isr() */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAND_DMA_RX:
|
||||||
|
nandp->state = NAND_READY;
|
||||||
|
nandp->rxdata = NULL;
|
||||||
|
nandp->datalen = 0;
|
||||||
|
wakeup_isr(nandp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
osalSysHalt("Unhandled case");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osalSysUnlockFromISR();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level NAND driver initialization.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void nand_lld_init(void) {
|
||||||
|
|
||||||
|
#if STM32_NAND_USE_FSMC_NAND1
|
||||||
|
/* Driver initialization.*/
|
||||||
|
nandObjectInit(&NANDD1);
|
||||||
|
NANDD1.rxdata = NULL;
|
||||||
|
NANDD1.datalen = 0;
|
||||||
|
NANDD1.thread = NULL;
|
||||||
|
NANDD1.dma = STM32_DMA_STREAM(STM32_NAND_NAND1_DMA_STREAM);
|
||||||
|
NANDD1.nand = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
|
||||||
|
NANDD1.map_data = (uint8_t*)FSMC_Bank2_MAP_COMMON_DATA;
|
||||||
|
NANDD1.map_cmd = (uint8_t*)FSMC_Bank2_MAP_COMMON_CMD;
|
||||||
|
NANDD1.map_addr = (uint8_t*)FSMC_Bank2_MAP_COMMON_ADDR;
|
||||||
|
#endif /* STM32_NAND_USE_FSMC_NAND1 */
|
||||||
|
|
||||||
|
#if STM32_NAND_USE_FSMC_NAND2
|
||||||
|
/* Driver initialization.*/
|
||||||
|
nandObjectInit(&NANDD2);
|
||||||
|
NANDD2.rxdata = NULL;
|
||||||
|
NANDD2.datalen = 0;
|
||||||
|
NANDD2.thread = NULL;
|
||||||
|
NANDD2.dma = STM32_DMA_STREAM(STM32_NAND_NAND2_DMA_STREAM);
|
||||||
|
NANDD2.nand = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
|
||||||
|
NANDD2.map_data = (uint8_t*)FSMC_Bank3_MAP_COMMON_DATA;
|
||||||
|
NANDD2.map_cmd = (uint8_t*)FSMC_Bank3_MAP_COMMON_CMD;
|
||||||
|
NANDD2.map_addr = (uint8_t*)FSMC_Bank3_MAP_COMMON_ADDR;
|
||||||
|
#endif /* STM32_NAND_USE_FSMC_NAND2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures and activates the NAND peripheral.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void nand_lld_start(NANDDriver *nandp) {
|
||||||
|
|
||||||
|
bool b;
|
||||||
|
|
||||||
|
if (FSMCD1.state == FSMC_STOP)
|
||||||
|
fsmc_lld_start(&FSMCD1);
|
||||||
|
|
||||||
|
if (nandp->state == NAND_STOP) {
|
||||||
|
b = dmaStreamAllocate(nandp->dma,
|
||||||
|
STM32_EMC_FSMC1_IRQ_PRIORITY,
|
||||||
|
(stm32_dmaisr_t)nand_lld_serve_transfer_end_irq,
|
||||||
|
(void *)nandp);
|
||||||
|
osalDbgAssert(!b, "stream already allocated");
|
||||||
|
nandp->dmamode = STM32_DMA_CR_CHSEL(NAND_DMA_CHANNEL) |
|
||||||
|
STM32_DMA_CR_PL(STM32_NAND_NAND1_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(nandp->dma,
|
||||||
|
STM32_DMA_FCR_DMDIS | NAND_STM32_DMA_FCR_FTH_LVL); */
|
||||||
|
nandp->nand->PCR = calc_eccps(nandp) | FSMC_PCR_PTYP | FSMC_PCR_PBKEN;
|
||||||
|
nandp->nand->PMEM = nandp->config->pmem;
|
||||||
|
nandp->nand->PATT = nandp->config->pmem;
|
||||||
|
nandp->isr_handler = nand_isr_handler;
|
||||||
|
nand_ready_isr_enable(nandp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deactivates the NAND peripheral.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void nand_lld_stop(NANDDriver *nandp) {
|
||||||
|
|
||||||
|
if (nandp->state == NAND_READY) {
|
||||||
|
dmaStreamRelease(nandp->dma);
|
||||||
|
nandp->nand->PCR &= ~FSMC_PCR_PBKEN;
|
||||||
|
nand_ready_isr_disable(nandp);
|
||||||
|
nandp->isr_handler = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from NAND.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver 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 nand_lld_read_data(NANDDriver *nandp, uint8_t *data,
|
||||||
|
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc){
|
||||||
|
|
||||||
|
nandp->state = NAND_READ;
|
||||||
|
nandp->rxdata = data;
|
||||||
|
nandp->datalen = datalen;
|
||||||
|
|
||||||
|
nand_lld_write_cmd (nandp, NAND_CMD_READ0);
|
||||||
|
nand_lld_write_addr(nandp, addr, addrlen);
|
||||||
|
osalSysLock();
|
||||||
|
nand_lld_write_cmd (nandp, 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((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0,
|
||||||
|
"State machine broken. ECCEN must be previously disabled.");
|
||||||
|
|
||||||
|
if (NULL != ecc){
|
||||||
|
nandp->nand->PCR |= FSMC_PCR_ECCEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
nand_lld_suspend_thread(nandp);
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
/* thread was woken up from DMA ISR */
|
||||||
|
if (NULL != ecc){
|
||||||
|
while (! (nandp->nand->SR & FSMC_SR_FEMPT))
|
||||||
|
;
|
||||||
|
*ecc = nandp->nand->ECCR;
|
||||||
|
nandp->nand->PCR &= ~FSMC_PCR_ECCEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write data to NAND.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver 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 nand_lld_write_data(NANDDriver *nandp, const uint8_t *data,
|
||||||
|
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc){
|
||||||
|
|
||||||
|
nandp->state = NAND_WRITE;
|
||||||
|
|
||||||
|
nand_lld_write_cmd (nandp, NAND_CMD_WRITE);
|
||||||
|
osalSysLock();
|
||||||
|
nand_lld_write_addr(nandp, addr, addrlen);
|
||||||
|
|
||||||
|
/* Now start DMA transfer to NAND buffer and put thread in sleep state.
|
||||||
|
Tread will we woken up from ready ISR. */
|
||||||
|
nandp->state = NAND_DMA_TX;
|
||||||
|
osalDbgAssert((nandp->nand->PCR & FSMC_PCR_ECCEN) == 0,
|
||||||
|
"State machine broken. ECCEN must be previously disabled.");
|
||||||
|
|
||||||
|
if (NULL != ecc){
|
||||||
|
nandp->nand->PCR |= FSMC_PCR_ECCEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmaStartMemCopy(nandp->dma, nandp->dmamode,
|
||||||
|
data, nandp->map_data, datalen);
|
||||||
|
|
||||||
|
nand_lld_suspend_thread(nandp);
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
if (NULL != ecc){
|
||||||
|
while (! (nandp->nand->SR & FSMC_SR_FEMPT))
|
||||||
|
;
|
||||||
|
*ecc = nandp->nand->ECCR;
|
||||||
|
nandp->nand->PCR &= ~FSMC_PCR_ECCEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nand_lld_read_status(nandp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erase block.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver 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 nand_lld_erase(NANDDriver *nandp,
|
||||||
|
uint8_t *addr, size_t addrlen){
|
||||||
|
|
||||||
|
nandp->state = NAND_ERASE;
|
||||||
|
|
||||||
|
nand_lld_write_cmd (nandp, NAND_CMD_ERASE);
|
||||||
|
nand_lld_write_addr(nandp, addr, addrlen);
|
||||||
|
osalSysLock();
|
||||||
|
nand_lld_write_cmd (nandp, NAND_CMD_ERASE_CONFIRM);
|
||||||
|
nand_lld_suspend_thread(nandp);
|
||||||
|
osalSysUnlock();
|
||||||
|
|
||||||
|
return nand_lld_read_status(nandp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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] nandp pointer to the @p NANDDriver object
|
||||||
|
* @param[out] data pointer to output buffer
|
||||||
|
* @param[in] len length of data to be read
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void nand_lld_polled_read_data(NANDDriver *nandp,
|
||||||
|
uint8_t *data, size_t len){
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (i=0; i<len; i++)
|
||||||
|
data[i] = nandp->map_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send addres to NAND.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
* @param[in] len length of address array
|
||||||
|
* @param[in] addr pointer to address array
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void nand_lld_write_addr(NANDDriver *nandp,
|
||||||
|
const uint8_t *addr, size_t len){
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (i=0; i<len; i++)
|
||||||
|
nandp->map_addr[i] = addr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send command to NAND.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
* @param[in] cmd command value
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd){
|
||||||
|
nandp->map_cmd[0] = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read status byte from NAND.
|
||||||
|
*
|
||||||
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
|
*
|
||||||
|
* @return Status byte.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
uint8_t nand_lld_read_status(NANDDriver *nandp) {
|
||||||
|
|
||||||
|
uint8_t status[1] = {0x01}; /* presume worse */
|
||||||
|
|
||||||
|
nand_lld_write_cmd(nandp, NAND_CMD_STATUS);
|
||||||
|
nand_lld_polled_read_data(nandp, status, 1);
|
||||||
|
|
||||||
|
return status[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAL_USE_NAND */
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
|
@ -19,24 +19,26 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file emcnand_lld.h
|
* @file nand_lld.h
|
||||||
* @brief EMCNAND Driver subsystem low level driver header template.
|
* @brief NAND Driver subsystem low level driver header template.
|
||||||
*
|
*
|
||||||
* @addtogroup EMCNAND
|
* @addtogroup NAND
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _EMCNAND_LLD_H_
|
#ifndef _NAND_LLD_H_
|
||||||
#define _EMCNAND_LLD_H_
|
#define _NAND_LLD_H_
|
||||||
|
|
||||||
#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
|
#include "fsmc.h"
|
||||||
|
|
||||||
|
#if HAL_USE_NAND || defined(__DOXYGEN__)
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver constants. */
|
/* Driver constants. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
#define EMCNAND_MIN_PAGE_SIZE 256
|
#define NAND_MIN_PAGE_SIZE 256
|
||||||
#define EMCNAND_MAX_PAGE_SIZE 8192
|
#define NAND_MAX_PAGE_SIZE 8192
|
||||||
#define EMCNAND_BAD_MAP_END_MARK ((uint16_t)0xFFFF)
|
#define NAND_BAD_MAP_END_MARK ((uint16_t)0xFFFF)
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver pre-compile time settings. */
|
/* Driver pre-compile time settings. */
|
||||||
|
@ -54,66 +56,66 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND driver enable switch.
|
* @brief NAND driver enable switch.
|
||||||
* @details If set to @p TRUE the support for EMCNAND1 is included.
|
* @details If set to @p TRUE the support for NAND1 is included.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_USE_EMCNAND1) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_USE_NAND1) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_USE_EMCNAND1 FALSE
|
#define STM32_NAND_USE_NAND1 FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND driver enable switch.
|
* @brief NAND driver enable switch.
|
||||||
* @details If set to @p TRUE the support for EMCNAND2 is included.
|
* @details If set to @p TRUE the support for NAND2 is included.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_USE_EMCNAND2) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_USE_NAND2) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_USE_EMCNAND2 FALSE
|
#define STM32_NAND_USE_NAND2 FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND DMA error hook.
|
* @brief NAND DMA error hook.
|
||||||
* @note The default action for DMA errors is a system halt because DMA
|
* @note The default action for DMA errors is a system halt because DMA
|
||||||
* error can only happen because programming errors.
|
* error can only happen because programming errors.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_DMA_ERROR_HOOK(emcnandp) osalSysHalt("DMA failure")
|
#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND interrupt enable switch.
|
* @brief NAND interrupt enable switch.
|
||||||
* @details If set to @p TRUE the support for internal FSMC interrupt included.
|
* @details If set to @p TRUE the support for internal FSMC interrupt included.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_USE_INT) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_USE_INT) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_USE_INT FALSE
|
#define STM32_NAND_USE_INT FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND1 DMA priority (0..3|lowest..highest).
|
* @brief NAND1 DMA priority (0..3|lowest..highest).
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_EMCNAND1_DMA_PRIORITY) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_NAND1_DMA_PRIORITY) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_EMCNAND1_DMA_PRIORITY 0
|
#define STM32_NAND_NAND1_DMA_PRIORITY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND2 DMA priority (0..3|lowest..highest).
|
* @brief NAND2 DMA priority (0..3|lowest..highest).
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_EMCNAND2_DMA_PRIORITY) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_NAND2_DMA_PRIORITY) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_EMCNAND2_DMA_PRIORITY 0
|
#define STM32_NAND_NAND2_DMA_PRIORITY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DMA stream used for EMCNAND1 operations.
|
* @brief DMA stream used for NAND1 operations.
|
||||||
* @note This option is only available on platforms with enhanced DMA.
|
* @note This option is only available on platforms with enhanced DMA.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_EMCNAND1_DMA_STREAM) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_NAND1_DMA_STREAM) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_EMCNAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
|
#define STM32_NAND_NAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DMA stream used for EMCNAND2 operations.
|
* @brief DMA stream used for NAND2 operations.
|
||||||
* @note This option is only available on platforms with enhanced DMA.
|
* @note This option is only available on platforms with enhanced DMA.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_EMCNAND_EMCNAND2_DMA_STREAM) || defined(__DOXYGEN__)
|
#if !defined(STM32_NAND_NAND2_DMA_STREAM) || defined(__DOXYGEN__)
|
||||||
#define STM32_EMCNAND_EMCNAND2_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
#define STM32_NAND_NAND2_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
@ -122,28 +124,26 @@
|
||||||
/* Derived constants and error checks. */
|
/* Derived constants and error checks. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
#if !STM32_EMCNAND_USE_EMCNAND1 && !STM32_EMCNAND_USE_EMCNAND2
|
#if !STM32_NAND_USE_FSMC_NAND1 && !STM32_NAND_USE_FSMC_NAND2
|
||||||
#error "EMCNAND driver activated but no EMCNAND peripheral assigned"
|
#error "NAND driver activated but no NAND peripheral assigned"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if STM32_EMCNAND_USE_EMCNAND1 && !STM32_HAS_EMC
|
#if STM32_NAND_USE_FSMC_NAND1 && !STM32_HAS_FSMC
|
||||||
#error "EMC not present in the selected device"
|
#error "FSMC not present in the selected device"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !STM32_EMCNAND_USE_INT && !HAL_USE_EXT
|
#if STM32_NAND_USE_FSMC_NAND2 && !STM32_HAS_FSMC
|
||||||
|
#error "FSMC not present in the selected device"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !STM32_NAND_USE_FSMC_INT && !HAL_USE_EXT
|
||||||
#error "External interrupt controller must be enabled to use this feature"
|
#error "External interrupt controller must be enabled to use this feature"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if STM32_EMCNAND_USE_EMCNAND1 && \
|
#if (STM32_NAND_USE_FSMC_NAND2 || STM32_NAND_USE_FSMC_NAND1) && \
|
||||||
!STM32_DMA_IS_VALID_ID(STM32_EMCNAND_EMCNAND1_DMA_STREAM, \
|
!STM32_DMA_IS_VALID_ID(STM32_NAND_DMA_STREAM, \
|
||||||
STM32_EMC_DMA_MSK)
|
STM32_FSMC_DMA_MSK)
|
||||||
#error "invalid DMA stream associated to EMCNAND"
|
#error "invalid DMA stream associated to NAND"
|
||||||
#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
|
#endif
|
||||||
|
|
||||||
#if !defined(STM32_DMA_REQUIRED)
|
#if !defined(STM32_DMA_REQUIRED)
|
||||||
|
@ -157,30 +157,30 @@
|
||||||
/**
|
/**
|
||||||
* @brief NAND driver condition flags type.
|
* @brief NAND driver condition flags type.
|
||||||
*/
|
*/
|
||||||
typedef uint32_t emcnandflags_t;
|
typedef uint32_t nandflags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type of a structure representing an EMCNAND driver.
|
* @brief Type of a structure representing an NAND driver.
|
||||||
*/
|
*/
|
||||||
typedef struct EMCNANDDriver EMCNANDDriver;
|
typedef struct NANDDriver NANDDriver;
|
||||||
|
|
||||||
#if STM32_EMC_USE_INT
|
#if STM32_NAND_USE_FSMC_INT
|
||||||
/**
|
/**
|
||||||
* @brief Type of interrupt handler function
|
* @brief Type of interrupt handler function
|
||||||
*/
|
*/
|
||||||
typedef void (*emcnandisrhandler_t)
|
typedef void (*nandisrhandler_t)
|
||||||
(EMCNANDDriver *emcnandp, emcnandflags_t flags);
|
(NANDDriver *nandp, nandflags_t flags);
|
||||||
#else
|
#else
|
||||||
/**
|
/**
|
||||||
* @brief Type of interrupt handler function
|
* @brief Type of interrupt handler function
|
||||||
*/
|
*/
|
||||||
typedef void (*emcnandisrhandler_t)(EMCNANDDriver *emcnandp);
|
typedef void (*nandisrhandler_t)(NANDDriver *nandp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Type of function switching external interrupts on and off.
|
* @brief Type of function switching external interrupts on and off.
|
||||||
*/
|
*/
|
||||||
typedef void (*emcnandisrswitch_t)(void);
|
typedef void (*nandisrswitch_t)(void);
|
||||||
#endif /* STM32_EMC_USE_INT */
|
#endif /* STM32_NAND_USE_FSMC_INT */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Driver configuration structure.
|
* @brief Driver configuration structure.
|
||||||
|
@ -190,7 +190,7 @@ typedef struct {
|
||||||
/**
|
/**
|
||||||
* @brief Pointer to lower level driver.
|
* @brief Pointer to lower level driver.
|
||||||
*/
|
*/
|
||||||
EMCDriver *emcp;
|
FSMCDriver *fsmcp;
|
||||||
/**
|
/**
|
||||||
* @brief Number of erase blocks in NAND device.
|
* @brief Number of erase blocks in NAND device.
|
||||||
*/
|
*/
|
||||||
|
@ -207,13 +207,13 @@ typedef struct {
|
||||||
* @brief Number of pages in block.
|
* @brief Number of pages in block.
|
||||||
*/
|
*/
|
||||||
uint32_t pages_per_block;
|
uint32_t pages_per_block;
|
||||||
#if EMCNAND_USE_BAD_MAP
|
#if NAND_USE_BAD_MAP
|
||||||
/**
|
/**
|
||||||
* @brief Pointer to bad block map.
|
* @brief Pointer to bad block map.
|
||||||
* @details One bit per block. Memory for map must be allocated by user.
|
* @details One bit per block. Memory for map must be allocated by user.
|
||||||
*/
|
*/
|
||||||
uint32_t *bb_map;
|
uint32_t *bb_map;
|
||||||
#endif /* EMCNAND_USE_BAD_MAP */
|
#endif /* NAND_USE_BAD_MAP */
|
||||||
/**
|
/**
|
||||||
* @brief Number of write cycles for row addressing.
|
* @brief Number of write cycles for row addressing.
|
||||||
*/
|
*/
|
||||||
|
@ -232,34 +232,34 @@ typedef struct {
|
||||||
* from STMicroelectronics.
|
* from STMicroelectronics.
|
||||||
*/
|
*/
|
||||||
uint32_t pmem;
|
uint32_t pmem;
|
||||||
#if !STM32_EMC_USE_INT
|
#if !STM32_NAND_USE_FSMC_INT
|
||||||
/**
|
/**
|
||||||
* @brief Function enabling interrupts from EXTI
|
* @brief Function enabling interrupts from EXTI
|
||||||
*/
|
*/
|
||||||
emcnandisrswitch_t ext_isr_enable;
|
nandisrswitch_t ext_isr_enable;
|
||||||
/**
|
/**
|
||||||
* @brief Function disabling interrupts from EXTI
|
* @brief Function disabling interrupts from EXTI
|
||||||
*/
|
*/
|
||||||
emcnandisrswitch_t ext_isr_disable;
|
nandisrswitch_t ext_isr_disable;
|
||||||
#endif /* !STM32_EMC_USE_INT */
|
#endif /* !STM32_NAND_USE_FSMC_INT */
|
||||||
} EMCNANDConfig;
|
} NANDConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Structure representing an EMCNAND driver.
|
* @brief Structure representing an NAND driver.
|
||||||
*/
|
*/
|
||||||
struct EMCNANDDriver {
|
struct NANDDriver {
|
||||||
/**
|
/**
|
||||||
* @brief Driver state.
|
* @brief Driver state.
|
||||||
*/
|
*/
|
||||||
emcnandstate_t state;
|
nandstate_t state;
|
||||||
/**
|
/**
|
||||||
* @brief Current configuration data.
|
* @brief Current configuration data.
|
||||||
*/
|
*/
|
||||||
const EMCNANDConfig *config;
|
const NANDConfig *config;
|
||||||
/**
|
/**
|
||||||
* @brief Array to store bad block map.
|
* @brief Array to store bad block map.
|
||||||
*/
|
*/
|
||||||
#if EMCNAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
#if NAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||||
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
|
||||||
/**
|
/**
|
||||||
* @brief Mutex protecting the bus.
|
* @brief Mutex protecting the bus.
|
||||||
|
@ -268,12 +268,12 @@ struct EMCNANDDriver {
|
||||||
#elif CH_CFG_USE_SEMAPHORES
|
#elif CH_CFG_USE_SEMAPHORES
|
||||||
semaphore_t semaphore;
|
semaphore_t semaphore;
|
||||||
#endif
|
#endif
|
||||||
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
|
#endif /* NAND_USE_MUTUAL_EXCLUSION */
|
||||||
/* End of the mandatory fields.*/
|
/* End of the mandatory fields.*/
|
||||||
/**
|
/**
|
||||||
* @brief Function enabling interrupts from FSMC
|
* @brief Function enabling interrupts from FSMC
|
||||||
*/
|
*/
|
||||||
emcnandisrhandler_t isr_handler;
|
nandisrhandler_t isr_handler;
|
||||||
/**
|
/**
|
||||||
* @brief Pointer to current transaction buffer
|
* @brief Pointer to current transaction buffer
|
||||||
*/
|
*/
|
||||||
|
@ -320,38 +320,38 @@ struct EMCNANDDriver {
|
||||||
/* External declarations. */
|
/* External declarations. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
#if STM32_EMCNAND_USE_EMCNAND1 && !defined(__DOXYGEN__)
|
#if STM32_NAND_USE_FSMC_NAND1 && !defined(__DOXYGEN__)
|
||||||
extern EMCNANDDriver EMCNANDD1;
|
extern NANDDriver NANDD1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if STM32_EMCNAND_USE_EMCNAND2 && !defined(__DOXYGEN__)
|
#if STM32_NAND_USE_FSMC_NAND2 && !defined(__DOXYGEN__)
|
||||||
extern EMCNANDDriver EMCNANDD2;
|
extern NANDDriver NANDD2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
void emcnand_lld_init(void);
|
void nand_lld_init(void);
|
||||||
void emcnand_lld_start(EMCNANDDriver *emcnandp);
|
void nand_lld_start(NANDDriver *nandp);
|
||||||
void emcnand_lld_stop(EMCNANDDriver *emcnandp);
|
void nand_lld_stop(NANDDriver *nandp);
|
||||||
uint8_t emcnand_lld_write_data(EMCNANDDriver *emcnandp, const uint8_t *data,
|
uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data,
|
||||||
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
|
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
|
||||||
void emcnand_lld_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
|
void nand_lld_read_data(NANDDriver *nandp, uint8_t *data,
|
||||||
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
|
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
|
||||||
void emcnand_lld_polled_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
|
void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data,
|
||||||
size_t len);
|
size_t len);
|
||||||
uint8_t emcnand_lld_erase(EMCNANDDriver *emcnandp, uint8_t *addr,
|
uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr,
|
||||||
size_t addrlen);
|
size_t addrlen);
|
||||||
void emcnand_lld_write_addr(EMCNANDDriver *emcnandp,
|
void nand_lld_write_addr(NANDDriver *nandp,
|
||||||
const uint8_t *addr, size_t len);
|
const uint8_t *addr, size_t len);
|
||||||
void emcnand_lld_write_cmd(EMCNANDDriver *emcnandp, uint8_t cmd);
|
void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd);
|
||||||
uint8_t emcnand_lld_read_status(EMCNANDDriver *emcnandp);
|
uint8_t nand_lld_read_status(NANDDriver *nandp);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* HAL_USE_EMCNAND */
|
#endif /* HAL_USE_NAND */
|
||||||
|
|
||||||
#endif /* _EMCNAND_LLD_H_ */
|
#endif /* _NAND_LLD_H_ */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
|
@ -1,545 +0,0 @@
|
||||||
/*
|
|
||||||
ChibiOS/HAL - Copyright (C) 2006-2014 Giovanni Di Sirio
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
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){
|
|
||||||
|
|
||||||
osalDbgCheck(emcnandp->thread != NULL);
|
|
||||||
osalThreadResumeI(&emcnandp->thread, MSG_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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();
|
|
||||||
osalThreadSuspendS(&emcnandp->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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;
|
|
||||||
osalSysHalt("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;
|
|
||||||
osalSysHalt("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;
|
|
||||||
|
|
||||||
osalSysHalt("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);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EMCNAND_PROGRAM:
|
|
||||||
/* NAND reports about page programming finish */
|
|
||||||
emcnandp->state = EMCNAND_READY;
|
|
||||||
wakeup_isr(emcnandp);
|
|
||||||
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);
|
|
||||||
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 */
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
|
||||||
${CHIBIOS}/os/hal/ports/STM32/LLD/TIMv1/st_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/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/FSMCv1/fsmc.c \
|
||||||
${CHIBIOS}/os/hal/ports/STM32/LLD/emcnand_lld.c
|
${CHIBIOS}/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c
|
||||||
|
|
||||||
# Required include directories
|
# Required include directories
|
||||||
PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \
|
PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \
|
||||||
|
@ -35,4 +35,5 @@ PLATFORMINC = ${CHIBIOS}/os/hal/ports/common/ARMCMx \
|
||||||
${CHIBIOS}/os/hal/ports/STM32/LLD/RTCv2 \
|
${CHIBIOS}/os/hal/ports/STM32/LLD/RTCv2 \
|
||||||
${CHIBIOS}/os/hal/ports/STM32/LLD/SPIv1 \
|
${CHIBIOS}/os/hal/ports/STM32/LLD/SPIv1 \
|
||||||
${CHIBIOS}/os/hal/ports/STM32/LLD/TIMv1 \
|
${CHIBIOS}/os/hal/ports/STM32/LLD/TIMv1 \
|
||||||
${CHIBIOS}/os/hal/ports/STM32/LLD/USARTv1
|
${CHIBIOS}/os/hal/ports/STM32/LLD/USARTv1 \
|
||||||
|
${CHIBIOS}/os/hal/ports/STM32/LLD/FSMCv1
|
||||||
|
|
|
@ -327,16 +327,16 @@
|
||||||
#endif /* defined(STM32F401xx) */
|
#endif /* defined(STM32F401xx) */
|
||||||
|
|
||||||
/* EMC attributes.*/
|
/* EMC attributes.*/
|
||||||
#define STM32_HAS_EMC TRUE
|
#define STM32_HAS_FSMC TRUE
|
||||||
#define STM32_EMC_DMA_MSK (STM32_DMA_STREAM_ID_MSK(2, 0) | \
|
#define STM32_FSMC_DMA_MSK (STM32_DMA_STREAM_ID_MSK(2, 0) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 1) | \
|
STM32_DMA_STREAM_ID_MSK(2, 1) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 2) | \
|
STM32_DMA_STREAM_ID_MSK(2, 2) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 3) | \
|
STM32_DMA_STREAM_ID_MSK(2, 3) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 4) | \
|
STM32_DMA_STREAM_ID_MSK(2, 4) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 5) | \
|
STM32_DMA_STREAM_ID_MSK(2, 5) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 6) | \
|
STM32_DMA_STREAM_ID_MSK(2, 6) |\
|
||||||
STM32_DMA_STREAM_ID_MSK(2, 7))
|
STM32_DMA_STREAM_ID_MSK(2, 7))
|
||||||
#define STM32_EMC_DMA_CHN 0x03010201
|
#define STM32_FSMC_DMA_CHN 0x03010201
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
#endif /* _STM32_REGISTRY_H_ */
|
#endif /* _STM32_REGISTRY_H_ */
|
||||||
|
|
128
os/hal/src/emc.c
128
os/hal/src/emc.c
|
@ -1,128 +0,0 @@
|
||||||
/*
|
|
||||||
ChibiOS/HAL - Copyright (C) 2006,2007,2008,2009,2010,
|
|
||||||
2011,2012,2013,2014 Giovanni Di Sirio.
|
|
||||||
|
|
||||||
This file is part of ChibiOS/HAL
|
|
||||||
|
|
||||||
ChibiOS/HAL 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.c
|
|
||||||
* @brief EMC Driver code.
|
|
||||||
*
|
|
||||||
* @addtogroup EMC
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hal.h"
|
|
||||||
|
|
||||||
#if HAL_USE_EMC || defined(__DOXYGEN__)
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver local definitions. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver exported variables. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver local types. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver local variables. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver local functions. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/*===========================================================================*/
|
|
||||||
/* Driver exported functions. */
|
|
||||||
/*===========================================================================*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief EMC Driver initialization.
|
|
||||||
* @note This function is implicitly invoked by @p halInit(), there is
|
|
||||||
* no need to explicitly initialize the driver.
|
|
||||||
*
|
|
||||||
* @init
|
|
||||||
*/
|
|
||||||
void emcInit(void) {
|
|
||||||
|
|
||||||
emc_lld_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initializes the standard part of a @p EMCDriver structure.
|
|
||||||
*
|
|
||||||
* @param[out] emcp pointer to the @p EMCDriver object
|
|
||||||
*
|
|
||||||
* @init
|
|
||||||
*/
|
|
||||||
void emcObjectInit(EMCDriver *emcp) {
|
|
||||||
|
|
||||||
emcp->state = EMC_STOP;
|
|
||||||
emcp->config = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Configures and activates the EMC peripheral.
|
|
||||||
*
|
|
||||||
* @param[in] emcp pointer to the @p EMCDriver object
|
|
||||||
* @param[in] config pointer to the @p EMCConfig object
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void emcStart(EMCDriver *emcp, const EMCConfig *config) {
|
|
||||||
|
|
||||||
osalDbgCheck((emcp != NULL) && (config != NULL));
|
|
||||||
|
|
||||||
osalSysLock();
|
|
||||||
osalDbgAssert((emcp->state == EMC_STOP) || (emcp->state == EMC_READY),
|
|
||||||
"invalid state");
|
|
||||||
emcp->config = config;
|
|
||||||
emc_lld_start(emcp);
|
|
||||||
emcp->state = EMC_READY;
|
|
||||||
osalSysUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Deactivates the EMC peripheral.
|
|
||||||
*
|
|
||||||
* @param[in] emcp pointer to the @p EMCDriver object
|
|
||||||
*
|
|
||||||
* @api
|
|
||||||
*/
|
|
||||||
void emcStop(EMCDriver *emcp) {
|
|
||||||
|
|
||||||
osalDbgCheck(emcp != NULL);
|
|
||||||
|
|
||||||
osalSysLock();
|
|
||||||
osalDbgAssert((emcp->state == EMC_STOP) || (emcp->state == EMC_READY),
|
|
||||||
"invalid state");
|
|
||||||
emc_lld_stop(emcp);
|
|
||||||
emcp->state = EMC_STOP;
|
|
||||||
osalSysUnlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAL_USE_EMC */
|
|
||||||
|
|
||||||
/** @} */
|
|
|
@ -23,16 +23,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file emcnand.c
|
* @file nand.c
|
||||||
* @brief EMCNAND Driver code.
|
* @brief NAND Driver code.
|
||||||
*
|
*
|
||||||
* @addtogroup EMCNAND
|
* @addtogroup NAND
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
|
|
||||||
#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
|
#if HAL_USE_NAND || defined(__DOXYGEN__)
|
||||||
|
|
||||||
#include "string.h" /* for memset */
|
#include "string.h" /* for memset */
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@
|
||||||
static void pagesize_check(size_t page_data_size){
|
static void pagesize_check(size_t page_data_size){
|
||||||
|
|
||||||
/* Page size out of bounds.*/
|
/* Page size out of bounds.*/
|
||||||
osalDbgCheck((page_data_size >= EMCNAND_MIN_PAGE_SIZE) &&
|
osalDbgCheck((page_data_size >= NAND_MIN_PAGE_SIZE) &&
|
||||||
(page_data_size <= EMCNAND_MAX_PAGE_SIZE));
|
(page_data_size <= NAND_MAX_PAGE_SIZE));
|
||||||
|
|
||||||
/* Page size must be power of 2.*/
|
/* Page size must be power of 2.*/
|
||||||
osalDbgCheck(((page_data_size - 1) & page_data_size) == 0);
|
osalDbgCheck(((page_data_size - 1) & page_data_size) == 0);
|
||||||
|
@ -76,7 +76,7 @@ static void pagesize_check(size_t page_data_size){
|
||||||
/**
|
/**
|
||||||
* @brief Translate block-page-offset scheme to NAND internal address.
|
* @brief Translate block-page-offset scheme to NAND internal address.
|
||||||
*
|
*
|
||||||
* @param[in] cfg pointer to the @p EMCNANDConfig from
|
* @param[in] cfg pointer to the @p NANDConfig from
|
||||||
* corresponding NAND driver
|
* corresponding NAND driver
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
|
@ -86,7 +86,7 @@ static void pagesize_check(size_t page_data_size){
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
static void calc_addr(const EMCNANDConfig *cfg,
|
static void calc_addr(const NANDConfig *cfg,
|
||||||
uint32_t block, uint32_t page, uint32_t offset,
|
uint32_t block, uint32_t page, uint32_t offset,
|
||||||
uint8_t *addr, size_t addr_len){
|
uint8_t *addr, size_t addr_len){
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
@ -114,7 +114,7 @@ static void calc_addr(const EMCNANDConfig *cfg,
|
||||||
* @brief Translate block number to NAND internal address.
|
* @brief Translate block number to NAND internal address.
|
||||||
* @note This function designed for erasing purpose.
|
* @note This function designed for erasing purpose.
|
||||||
*
|
*
|
||||||
* @param[in] cfg pointer to the @p EMCNANDConfig from
|
* @param[in] cfg pointer to the @p NANDConfig from
|
||||||
* corresponding NAND driver
|
* corresponding NAND driver
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[out] addr buffer to store calculated address
|
* @param[out] addr buffer to store calculated address
|
||||||
|
@ -122,7 +122,7 @@ static void calc_addr(const EMCNANDConfig *cfg,
|
||||||
*
|
*
|
||||||
* @notapi
|
* @notapi
|
||||||
*/
|
*/
|
||||||
static void calc_blk_addr(const EMCNANDConfig *cfg,
|
static void calc_blk_addr(const NANDConfig *cfg,
|
||||||
uint32_t block, uint8_t *addr, size_t addr_len){
|
uint32_t block, uint8_t *addr, size_t addr_len){
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
uint32_t row = 0;
|
uint32_t row = 0;
|
||||||
|
@ -140,23 +140,23 @@ static void calc_blk_addr(const EMCNANDConfig *cfg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EMCNAND_USE_BAD_MAP
|
#if NAND_USE_BAD_MAP
|
||||||
/**
|
/**
|
||||||
* @brief Add new bad block to map.
|
* @brief Add new bad block to map.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] map pointer to bad block map
|
* @param[in] map pointer to bad block map
|
||||||
*/
|
*/
|
||||||
static void bad_map_update(EMCNANDDriver *emcnandp, size_t block) {
|
static void bad_map_update(NANDDriver *nandp, size_t block) {
|
||||||
|
|
||||||
uint32_t *map = emcnandp->config->bb_map;
|
uint32_t *map = nandp->config->bb_map;
|
||||||
const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */
|
const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t shift;
|
size_t shift;
|
||||||
|
|
||||||
/* Nand device overflow.*/
|
/* Nand device overflow.*/
|
||||||
osalDbgCheck(emcnandp->config->blocks > block);
|
osalDbgCheck(nandp->config->blocks > block);
|
||||||
|
|
||||||
i = block / BPMC;
|
i = block / BPMC;
|
||||||
shift = block % BPMC;
|
shift = block % BPMC;
|
||||||
|
@ -168,11 +168,11 @@ static void bad_map_update(EMCNANDDriver *emcnandp, size_t block) {
|
||||||
/**
|
/**
|
||||||
* @brief Scan for bad blocks and fill map with their numbers.
|
* @brief Scan for bad blocks and fill map with their numbers.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
*/
|
*/
|
||||||
static void scan_bad_blocks(EMCNANDDriver *emcnandp) {
|
static void scan_bad_blocks(NANDDriver *nandp) {
|
||||||
|
|
||||||
const size_t blocks = emcnandp->config->blocks;
|
const size_t blocks = nandp->config->blocks;
|
||||||
const size_t maplen = blocks / 32;
|
const size_t maplen = blocks / 32;
|
||||||
|
|
||||||
size_t b;
|
size_t b;
|
||||||
|
@ -181,104 +181,104 @@ static void scan_bad_blocks(EMCNANDDriver *emcnandp) {
|
||||||
|
|
||||||
/* clear map just to be safe */
|
/* clear map just to be safe */
|
||||||
for (b=0; b<maplen; b++)
|
for (b=0; b<maplen; b++)
|
||||||
emcnandp->config->bb_map[b] = 0;
|
nandp->config->bb_map[b] = 0;
|
||||||
|
|
||||||
/* now write numbers of bad block to map */
|
/* now write numbers of bad block to map */
|
||||||
for (b=0; b<blocks; b++){
|
for (b=0; b<blocks; b++){
|
||||||
m0 = emcnandReadBadMark(emcnandp, b, 0);
|
m0 = nandReadBadMark(nandp, b, 0);
|
||||||
m1 = emcnandReadBadMark(emcnandp, b, 1);
|
m1 = nandReadBadMark(nandp, b, 1);
|
||||||
if ((0xFF != m0) || (0xFF != m1)){
|
if ((0xFF != m0) || (0xFF != m1)){
|
||||||
bad_map_update(emcnandp, b);
|
bad_map_update(nandp, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* EMCNAND_USE_BAD_MAP */
|
#endif /* NAND_USE_BAD_MAP */
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver exported functions. */
|
/* Driver exported functions. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EMCNAND Driver initialization.
|
* @brief NAND Driver initialization.
|
||||||
* @note This function is implicitly invoked by @p halInit(), there is
|
* @note This function is implicitly invoked by @p halInit(), there is
|
||||||
* no need to explicitly initialize the driver.
|
* no need to explicitly initialize the driver.
|
||||||
*
|
*
|
||||||
* @init
|
* @init
|
||||||
*/
|
*/
|
||||||
void emcnandInit(void) {
|
void nandInit(void) {
|
||||||
|
|
||||||
emcnand_lld_init();
|
nand_lld_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes the standard part of a @p EMCNANDDriver structure.
|
* @brief Initializes the standard part of a @p NANDDriver structure.
|
||||||
*
|
*
|
||||||
* @param[out] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[out] nandp pointer to the @p NANDDriver object
|
||||||
*
|
*
|
||||||
* @init
|
* @init
|
||||||
*/
|
*/
|
||||||
void emcnandObjectInit(EMCNANDDriver *emcnandp) {
|
void nandObjectInit(NANDDriver *nandp) {
|
||||||
|
|
||||||
#if EMCNAND_USE_MUTUAL_EXCLUSION
|
#if NAND_USE_MUTUAL_EXCLUSION
|
||||||
#if CH_CFG_USE_MUTEXES
|
#if CH_CFG_USE_MUTEXES
|
||||||
chMtxObjectInit(&emcnandp->mutex);
|
chMtxObjectInit(&nandp->mutex);
|
||||||
#else
|
#else
|
||||||
chSemObjectInit(&emcnandp->semaphore, 1);
|
chSemObjectInit(&nandp->semaphore, 1);
|
||||||
#endif /* CH_CFG_USE_MUTEXES */
|
#endif /* CH_CFG_USE_MUTEXES */
|
||||||
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
|
#endif /* NAND_USE_MUTUAL_EXCLUSION */
|
||||||
|
|
||||||
emcnandp->state = EMCNAND_STOP;
|
nandp->state = NAND_STOP;
|
||||||
emcnandp->config = NULL;
|
nandp->config = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Configures and activates the EMCNAND peripheral.
|
* @brief Configures and activates the NAND peripheral.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] config pointer to the @p EMCNANDConfig object
|
* @param[in] config pointer to the @p NANDConfig object
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandStart(EMCNANDDriver *emcnandp, const EMCNANDConfig *config) {
|
void nandStart(NANDDriver *nandp, const NANDConfig *config) {
|
||||||
|
|
||||||
osalDbgCheck((emcnandp != NULL) && (config != NULL));
|
osalDbgCheck((nandp != NULL) && (config != NULL));
|
||||||
osalDbgAssert(config->emcp->state == EMC_READY,
|
osalDbgAssert(config->fsmcp->state == FSMC_READY,
|
||||||
"lower level driver not ready");
|
"lower level driver not ready");
|
||||||
osalDbgAssert((emcnandp->state == EMCNAND_STOP) ||
|
osalDbgAssert((nandp->state == NAND_STOP) ||
|
||||||
(emcnandp->state == EMCNAND_READY),
|
(nandp->state == NAND_READY),
|
||||||
"invalid state");
|
"invalid state");
|
||||||
|
|
||||||
emcnandp->config = config;
|
nandp->config = config;
|
||||||
pagesize_check(emcnandp->config->page_data_size);
|
pagesize_check(nandp->config->page_data_size);
|
||||||
emcnand_lld_start(emcnandp);
|
nand_lld_start(nandp);
|
||||||
emcnandp->state = EMCNAND_READY;
|
nandp->state = NAND_READY;
|
||||||
|
|
||||||
#if EMCNAND_USE_BAD_MAP
|
#if NAND_USE_BAD_MAP
|
||||||
scan_bad_blocks(emcnandp);
|
scan_bad_blocks(nandp);
|
||||||
#endif /* EMCNAND_USE_BAD_MAP */
|
#endif /* NAND_USE_BAD_MAP */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deactivates the EMCNAND peripheral.
|
* @brief Deactivates the NAND peripheral.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandStop(EMCNANDDriver *emcnandp) {
|
void nandStop(NANDDriver *nandp) {
|
||||||
|
|
||||||
osalDbgCheck(emcnandp != NULL);
|
osalDbgCheck(nandp != NULL);
|
||||||
osalDbgAssert((emcnandp->state == EMCNAND_STOP) ||
|
osalDbgAssert((nandp->state == NAND_STOP) ||
|
||||||
(emcnandp->state == EMCNAND_READY),
|
(nandp->state == NAND_READY),
|
||||||
"invalid state");
|
"invalid state");
|
||||||
emcnand_lld_stop(emcnandp);
|
nand_lld_stop(nandp);
|
||||||
emcnandp->state = EMCNAND_STOP;
|
nandp->state = NAND_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read whole page.
|
* @brief Read whole page.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
* @param[out] data buffer to store data
|
* @param[out] data buffer to store data
|
||||||
|
@ -286,25 +286,25 @@ void emcnandStop(EMCNANDDriver *emcnandp) {
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandReadPageWhole(EMCNANDDriver *emcnandp, uint32_t block,
|
void nandReadPageWhole(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, uint8_t *data, size_t datalen) {
|
uint32_t page, uint8_t *data, size_t datalen) {
|
||||||
|
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addrbuf[8];
|
uint8_t addrbuf[8];
|
||||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||||
|
|
||||||
osalDbgCheck((emcnandp != NULL) && (data != NULL));
|
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||||
osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size)));
|
osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size)));
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_addr(cfg, block, page, 0, addrbuf, addrlen);
|
calc_addr(cfg, block, page, 0, addrbuf, addrlen);
|
||||||
emcnand_lld_read_data(emcnandp, data, datalen, addrbuf, addrlen, NULL);
|
nand_lld_read_data(nandp, data, datalen, addrbuf, addrlen, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write whole page.
|
* @brief Write whole page.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
* @param[in] data buffer with data to be written
|
* @param[in] data buffer with data to be written
|
||||||
|
@ -314,27 +314,27 @@ void emcnandReadPageWhole(EMCNANDDriver *emcnandp, uint32_t block,
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
uint8_t emcnandWritePageWhole(EMCNANDDriver *emcnandp, uint32_t block,
|
uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, const uint8_t *data, size_t datalen) {
|
uint32_t page, const uint8_t *data, size_t datalen) {
|
||||||
|
|
||||||
uint8_t retval;
|
uint8_t retval;
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addr[8];
|
uint8_t addr[8];
|
||||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||||
|
|
||||||
osalDbgCheck((emcnandp != NULL) && (data != NULL));
|
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||||
osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size)));
|
osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size)));
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_addr(cfg, block, page, 0, addr, addrlen);
|
calc_addr(cfg, block, page, 0, addr, addrlen);
|
||||||
retval = emcnand_lld_write_data(emcnandp, data, datalen, addr, addrlen, NULL);
|
retval = nand_lld_write_data(nandp, data, datalen, addr, addrlen, NULL);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read page data without spare area.
|
* @brief Read page data without spare area.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
* @param[out] data buffer to store data
|
* @param[out] data buffer to store data
|
||||||
|
@ -343,25 +343,25 @@ uint8_t emcnandWritePageWhole(EMCNANDDriver *emcnandp, uint32_t block,
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandReadPageData(EMCNANDDriver *emcnandp, uint32_t block, uint32_t page,
|
void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||||
uint8_t *data, size_t datalen, uint32_t *ecc) {
|
uint8_t *data, size_t datalen, uint32_t *ecc) {
|
||||||
|
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addrbuf[8];
|
uint8_t addrbuf[8];
|
||||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||||
|
|
||||||
osalDbgCheck((emcnandp != NULL) && (data != NULL));
|
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||||
osalDbgCheck((datalen <= cfg->page_data_size));
|
osalDbgCheck((datalen <= cfg->page_data_size));
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_addr(cfg, block, page, 0, addrbuf, addrlen);
|
calc_addr(cfg, block, page, 0, addrbuf, addrlen);
|
||||||
emcnand_lld_read_data(emcnandp, data, datalen, addrbuf, addrlen, ecc);
|
nand_lld_read_data(nandp, data, datalen, addrbuf, addrlen, ecc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write page data without spare area.
|
* @brief Write page data without spare area.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
* @param[in] data buffer with data to be written
|
* @param[in] data buffer with data to be written
|
||||||
|
@ -372,27 +372,27 @@ void emcnandReadPageData(EMCNANDDriver *emcnandp, uint32_t block, uint32_t page,
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
uint8_t emcnandWritePageData(EMCNANDDriver *emcnandp, uint32_t block,
|
uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, const uint8_t *data, size_t datalen, uint32_t *ecc) {
|
uint32_t page, const uint8_t *data, size_t datalen, uint32_t *ecc) {
|
||||||
|
|
||||||
uint8_t retval;
|
uint8_t retval;
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addr[8];
|
uint8_t addr[8];
|
||||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||||
|
|
||||||
osalDbgCheck((emcnandp != NULL) && (data != NULL));
|
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||||
osalDbgCheck((datalen <= cfg->page_data_size));
|
osalDbgCheck((datalen <= cfg->page_data_size));
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_addr(cfg, block, page, 0, addr, addrlen);
|
calc_addr(cfg, block, page, 0, addr, addrlen);
|
||||||
retval = emcnand_lld_write_data(emcnandp, data, datalen, addr, addrlen, ecc);
|
retval = nand_lld_write_data(nandp, data, datalen, addr, addrlen, ecc);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read page spare area.
|
* @brief Read page spare area.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
* @param[out] spare buffer to store data
|
* @param[out] spare buffer to store data
|
||||||
|
@ -400,25 +400,25 @@ uint8_t emcnandWritePageData(EMCNANDDriver *emcnandp, uint32_t block,
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandReadPageSpare(EMCNANDDriver *emcnandp, uint32_t block,
|
void nandReadPageSpare(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, uint8_t *spare, size_t sparelen) {
|
uint32_t page, uint8_t *spare, size_t sparelen) {
|
||||||
|
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addr[8];
|
uint8_t addr[8];
|
||||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||||
|
|
||||||
osalDbgCheck((NULL != spare) && (emcnandp != NULL));
|
osalDbgCheck((NULL != spare) && (nandp != NULL));
|
||||||
osalDbgCheck(sparelen <= cfg->page_spare_size);
|
osalDbgCheck(sparelen <= cfg->page_spare_size);
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_addr(cfg, block, page, cfg->page_data_size, addr, addrlen);
|
calc_addr(cfg, block, page, cfg->page_data_size, addr, addrlen);
|
||||||
emcnand_lld_read_data(emcnandp, spare, sparelen, addr, addrlen, NULL);
|
nand_lld_read_data(nandp, spare, sparelen, addr, addrlen, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write page spare area.
|
* @brief Write page spare area.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
* @param[in] spare buffer with spare data to be written
|
* @param[in] spare buffer with spare data to be written
|
||||||
|
@ -428,49 +428,49 @@ void emcnandReadPageSpare(EMCNANDDriver *emcnandp, uint32_t block,
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
uint8_t emcnandWritePageSpare(EMCNANDDriver *emcnandp, uint32_t block,
|
uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block,
|
||||||
uint32_t page, const uint8_t *spare, size_t sparelen) {
|
uint32_t page, const uint8_t *spare, size_t sparelen) {
|
||||||
|
|
||||||
uint8_t retVal;
|
uint8_t retVal;
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addr[8];
|
uint8_t addr[8];
|
||||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||||
|
|
||||||
osalDbgCheck((NULL != spare) && (emcnandp != NULL));
|
osalDbgCheck((NULL != spare) && (nandp != NULL));
|
||||||
osalDbgCheck(sparelen <= cfg->page_spare_size);
|
osalDbgCheck(sparelen <= cfg->page_spare_size);
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_addr(cfg, block, page, cfg->page_data_size, addr, addrlen);
|
calc_addr(cfg, block, page, cfg->page_data_size, addr, addrlen);
|
||||||
retVal = emcnand_lld_write_data(emcnandp, spare, sparelen, addr, addrlen, NULL);
|
retVal = nand_lld_write_data(nandp, spare, sparelen, addr, addrlen, NULL);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Mark block as bad.
|
* @brief Mark block as bad.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandMarkBad(EMCNANDDriver *emcnandp, uint32_t block) {
|
void nandMarkBad(NANDDriver *nandp, uint32_t block) {
|
||||||
|
|
||||||
uint8_t bb_mark[2] = {0, 0};
|
uint8_t bb_mark[2] = {0, 0};
|
||||||
uint8_t op_status;
|
uint8_t op_status;
|
||||||
op_status = emcnandWritePageSpare(emcnandp, block, 0, bb_mark, sizeof(bb_mark));
|
op_status = nandWritePageSpare(nandp, block, 0, bb_mark, sizeof(bb_mark));
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed*/
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed*/
|
||||||
op_status = emcnandWritePageSpare(emcnandp, block, 1, bb_mark, sizeof(bb_mark));
|
op_status = nandWritePageSpare(nandp, block, 1, bb_mark, sizeof(bb_mark));
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed*/
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed*/
|
||||||
|
|
||||||
#if EMCNAND_USE_BAD_MAP
|
#if NAND_USE_BAD_MAP
|
||||||
bad_map_update(emcnandp, block);
|
bad_map_update(nandp, block);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read bad mark out.
|
* @brief Read bad mark out.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
* @param[in] page page number related to begin of block
|
* @param[in] page page number related to begin of block
|
||||||
*
|
*
|
||||||
|
@ -478,42 +478,42 @@ void emcnandMarkBad(EMCNANDDriver *emcnandp, uint32_t block) {
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
uint8_t emcnandReadBadMark(EMCNANDDriver *emcnandp,
|
uint8_t nandReadBadMark(NANDDriver *nandp,
|
||||||
uint32_t block, uint32_t page) {
|
uint32_t block, uint32_t page) {
|
||||||
uint8_t bb_mark[1];
|
uint8_t bb_mark[1];
|
||||||
emcnandReadPageSpare(emcnandp, block, page, bb_mark, sizeof(bb_mark));
|
nandReadPageSpare(nandp, block, page, bb_mark, sizeof(bb_mark));
|
||||||
return bb_mark[0];
|
return bb_mark[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Erase block.
|
* @brief Erase block.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
*
|
*
|
||||||
* @return The operation status reported by NAND IC (0x70 command).
|
* @return The operation status reported by NAND IC (0x70 command).
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
uint8_t emcnandErase(EMCNANDDriver *emcnandp, uint32_t block){
|
uint8_t nandErase(NANDDriver *nandp, uint32_t block){
|
||||||
|
|
||||||
uint8_t retVal;
|
uint8_t retVal;
|
||||||
const EMCNANDConfig *cfg = emcnandp->config;
|
const NANDConfig *cfg = nandp->config;
|
||||||
uint8_t addr[4];
|
uint8_t addr[4];
|
||||||
size_t addrlen = cfg->rowcycles;
|
size_t addrlen = cfg->rowcycles;
|
||||||
|
|
||||||
osalDbgCheck(emcnandp != NULL);
|
osalDbgCheck(nandp != NULL);
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
calc_blk_addr(cfg, block, addr, addrlen);
|
calc_blk_addr(cfg, block, addr, addrlen);
|
||||||
retVal = emcnand_lld_erase(emcnandp, addr, addrlen);
|
retVal = nand_lld_erase(nandp, addr, addrlen);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Report block badness.
|
* @brief Report block badness.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
* @param[in] block block number
|
* @param[in] block block number
|
||||||
*
|
*
|
||||||
* @return block condition
|
* @return block condition
|
||||||
|
@ -522,13 +522,13 @@ uint8_t emcnandErase(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
bool emcnandIsBad(EMCNANDDriver *emcnandp, uint32_t block){
|
bool nandIsBad(NANDDriver *nandp, uint32_t block){
|
||||||
|
|
||||||
osalDbgCheck(emcnandp != NULL);
|
osalDbgCheck(nandp != NULL);
|
||||||
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
|
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||||
|
|
||||||
#if EMCNAND_USE_BAD_MAP
|
#if NAND_USE_BAD_MAP
|
||||||
uint32_t *map = emcnandp->config->bb_map;
|
uint32_t *map = nandp->config->bb_map;
|
||||||
const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */
|
const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t shift;
|
size_t shift;
|
||||||
|
@ -541,60 +541,60 @@ bool emcnandIsBad(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
uint8_t m0, m1;
|
uint8_t m0, m1;
|
||||||
m0 = emcnandReadBadMark(emcnandp, block, 0);
|
m0 = nandReadBadMark(nandp, block, 0);
|
||||||
m1 = emcnandReadBadMark(emcnandp, block, 1);
|
m1 = nandReadBadMark(nandp, block, 1);
|
||||||
if ((0xFF != m0) || (0xFF != m1))
|
if ((0xFF != m0) || (0xFF != m1))
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
#endif /* EMCNAND_USE_BAD_MAP */
|
#endif /* NAND_USE_BAD_MAP */
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EMCNAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
#if NAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||||
/**
|
/**
|
||||||
* @brief Gains exclusive access to the EMCNAND bus.
|
* @brief Gains exclusive access to the NAND bus.
|
||||||
* @details This function tries to gain ownership to the EMCNAND bus, if the bus
|
* @details This function tries to gain ownership to the NAND bus, if the bus
|
||||||
* is already being used then the invoking thread is queued.
|
* is already being used then the invoking thread is queued.
|
||||||
* @pre In order to use this function the option
|
* @pre In order to use this function the option
|
||||||
* @p EMCNAND_USE_MUTUAL_EXCLUSION must be enabled.
|
* @p NAND_USE_MUTUAL_EXCLUSION must be enabled.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandAcquireBus(EMCNANDDriver *emcnandp) {
|
void nandAcquireBus(NANDDriver *nandp) {
|
||||||
|
|
||||||
osalDbgCheck(emcnandp != NULL);
|
osalDbgCheck(nandp != NULL);
|
||||||
|
|
||||||
#if CH_CFG_USE_MUTEXES
|
#if CH_CFG_USE_MUTEXES
|
||||||
chMtxLock(&emcnandp->mutex);
|
chMtxLock(&nandp->mutex);
|
||||||
#elif CH_CFG_USE_SEMAPHORES
|
#elif CH_CFG_USE_SEMAPHORES
|
||||||
chSemWait(&emcnandp->semaphore);
|
chSemWait(&nandp->semaphore);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Releases exclusive access to the EMCNAND bus.
|
* @brief Releases exclusive access to the NAND bus.
|
||||||
* @pre In order to use this function the option
|
* @pre In order to use this function the option
|
||||||
* @p EMCNAND_USE_MUTUAL_EXCLUSION must be enabled.
|
* @p NAND_USE_MUTUAL_EXCLUSION must be enabled.
|
||||||
*
|
*
|
||||||
* @param[in] emcnandp pointer to the @p EMCNANDDriver object
|
* @param[in] nandp pointer to the @p NANDDriver object
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
void emcnandReleaseBus(EMCNANDDriver *emcnandp) {
|
void nandReleaseBus(NANDDriver *nandp) {
|
||||||
|
|
||||||
osalDbgCheck(emcnandp != NULL);
|
osalDbgCheck(nandp != NULL);
|
||||||
|
|
||||||
#if CH_CFG_USE_MUTEXES
|
#if CH_CFG_USE_MUTEXES
|
||||||
chMtxUnlock(&emcnandp->mutex);
|
chMtxUnlock(&nandp->mutex);
|
||||||
#elif CH_CFG_USE_SEMAPHORES
|
#elif CH_CFG_USE_SEMAPHORES
|
||||||
chSemSignal(&emcnandp->semaphore);
|
chSemSignal(&nandp->semaphore);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
|
#endif /* NAND_USE_MUTUAL_EXCLUSION */
|
||||||
|
|
||||||
#endif /* HAL_USE_EMCNAND */
|
#endif /* HAL_USE_NAND */
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -157,17 +157,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables the EMC subsystem.
|
* @brief Enables the NAND subsystem.
|
||||||
*/
|
*/
|
||||||
#if !defined(HAL_USE_EMC) || defined(__DOXYGEN__)
|
#if !defined(HAL_USE_NAND) || defined(__DOXYGEN__)
|
||||||
#define HAL_USE_EMC TRUE
|
#define HAL_USE_NAND TRUE
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enables the NAND over EMC subsystem.
|
|
||||||
*/
|
|
||||||
#if !defined(HAL_USE_EMCNAND) || defined(__DOXYGEN__)
|
|
||||||
#define HAL_USE_EMCNAND TRUE
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -326,19 +319,19 @@
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables the @p emcnandAcquireBus() and @p emcnanReleaseBus() APIs.
|
* @brief Enables the @p nandAcquireBus() and @p nanReleaseBus() APIs.
|
||||||
* @note Disabling this option saves both code and data space.
|
* @note Disabling this option saves both code and data space.
|
||||||
*/
|
*/
|
||||||
#if !defined(EMCNAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
#if !defined(NAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
|
||||||
#define EMCNAND_USE_MUTUAL_EXCLUSION TRUE
|
#define NAND_USE_MUTUAL_EXCLUSION TRUE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enables internal driver map for bad blocks.
|
* @brief Enables internal driver map for bad blocks.
|
||||||
* @note Disabling this option saves both code and data space.
|
* @note Disabling this option saves both code and data space.
|
||||||
*/
|
*/
|
||||||
#if !defined(EMCNAND_USE_BAD_MAP) || defined(__DOXYGEN__)
|
#if !defined(NAND_USE_BAD_MAP) || defined(__DOXYGEN__)
|
||||||
#define EMCNAND_USE_BAD_MAP TRUE
|
#define NAND_USE_BAD_MAP TRUE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _HALCONF_H_ */
|
#endif /* _HALCONF_H_ */
|
||||||
|
|
|
@ -51,12 +51,12 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define USE_KILL_BLOCK_TEST FALSE
|
#define USE_KILL_BLOCK_TEST TRUE
|
||||||
|
|
||||||
#define EMCNAND_TIME_SET ((uint32_t) 2) //(8nS)
|
#define FSMCNAND_TIME_SET ((uint32_t) 2) //(8nS)
|
||||||
#define EMCNAND_TIME_WAIT ((uint32_t) 6) //(30nS)
|
#define FSMCNAND_TIME_WAIT ((uint32_t) 6) //(30nS)
|
||||||
#define EMCNAND_TIME_HOLD ((uint32_t) 1) //(5nS)
|
#define FSMCNAND_TIME_HOLD ((uint32_t) 1) //(5nS)
|
||||||
#define EMCNAND_TIME_HIZ ((uint32_t) 4) //(20nS)
|
#define FSMCNAND_TIME_HIZ ((uint32_t) 4) //(20nS)
|
||||||
|
|
||||||
#define NAND_BLOCKS_COUNT 8192
|
#define NAND_BLOCKS_COUNT 8192
|
||||||
#define NAND_PAGE_DATA_SIZE 2048
|
#define NAND_PAGE_DATA_SIZE 2048
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
* PROTOTYPES
|
* PROTOTYPES
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
|
#if !STM32_NAND_USE_FSMC_INT
|
||||||
static void ready_isr_enable(void);
|
static void ready_isr_enable(void);
|
||||||
static void ready_isr_disable(void);
|
static void ready_isr_disable(void);
|
||||||
static void nand_ready_cb(EXTDriver *extp, expchannel_t channel);
|
static void nand_ready_cb(EXTDriver *extp, expchannel_t channel);
|
||||||
|
@ -108,33 +108,28 @@ static uint8_t ref_buf[NAND_PAGE_SIZE];
|
||||||
//static TimeMeasurement tmu_read_data;
|
//static TimeMeasurement tmu_read_data;
|
||||||
//static TimeMeasurement tmu_read_spare;
|
//static TimeMeasurement tmu_read_spare;
|
||||||
|
|
||||||
/*
|
#if NAND_USE_BAD_MAP
|
||||||
*
|
|
||||||
*/
|
|
||||||
static const EMCConfig emccfg = {};
|
|
||||||
|
|
||||||
#if EMCNAND_USE_BAD_MAP
|
|
||||||
static uint32_t badblock_map[NAND_BLOCKS_COUNT / 32];
|
static uint32_t badblock_map[NAND_BLOCKS_COUNT / 32];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static const EMCNANDConfig nandcfg = {
|
static const NANDConfig nandcfg = {
|
||||||
&EMCD1,
|
&FSMCD1,
|
||||||
NAND_BLOCKS_COUNT,
|
NAND_BLOCKS_COUNT,
|
||||||
NAND_PAGE_DATA_SIZE,
|
NAND_PAGE_DATA_SIZE,
|
||||||
NAND_PAGE_SPARE_SIZE,
|
NAND_PAGE_SPARE_SIZE,
|
||||||
NAND_PAGES_PER_BLOCK,
|
NAND_PAGES_PER_BLOCK,
|
||||||
#if EMCNAND_USE_BAD_MAP
|
#if NAND_USE_BAD_MAP
|
||||||
badblock_map,
|
badblock_map,
|
||||||
#endif
|
#endif
|
||||||
NAND_ROW_WRITE_CYCLES,
|
NAND_ROW_WRITE_CYCLES,
|
||||||
NAND_COL_WRITE_CYCLES,
|
NAND_COL_WRITE_CYCLES,
|
||||||
/* stm32 specific fields */
|
/* stm32 specific fields */
|
||||||
((EMCNAND_TIME_HIZ << 24) | (EMCNAND_TIME_HOLD << 16) | \
|
((FSMCNAND_TIME_HIZ << 24) | (FSMCNAND_TIME_HOLD << 16) | \
|
||||||
(EMCNAND_TIME_WAIT << 8) | EMCNAND_TIME_SET),
|
(FSMCNAND_TIME_WAIT << 8) | FSMCNAND_TIME_SET),
|
||||||
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
|
#if !STM32_NAND_USE_FSMC_INT
|
||||||
ready_isr_enable,
|
ready_isr_enable,
|
||||||
ready_isr_disable
|
ready_isr_disable
|
||||||
#endif
|
#endif
|
||||||
|
@ -143,7 +138,7 @@ static const EMCNANDConfig nandcfg = {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
|
#if !STM32_NAND_USE_FSMC_INT
|
||||||
static const EXTConfig extcfg = {
|
static const EXTConfig extcfg = {
|
||||||
{
|
{
|
||||||
{EXT_CH_MODE_DISABLED, NULL}, //0
|
{EXT_CH_MODE_DISABLED, NULL}, //0
|
||||||
|
@ -171,7 +166,7 @@ static const EXTConfig extcfg = {
|
||||||
{EXT_CH_MODE_DISABLED, NULL},
|
{EXT_CH_MODE_DISABLED, NULL},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif /* !STM32_EMC_EMCNAND_USE_FSMC_INT */
|
#endif /* !STM32_NAND_USE_FSMC_INT */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
|
@ -191,12 +186,12 @@ volatile uint32_t KillCycle = 0;
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
|
#if !STM32_NAND_USE_FSMC_INT
|
||||||
static void nand_ready_cb(EXTDriver *extp, expchannel_t channel){
|
static void nand_ready_cb(EXTDriver *extp, expchannel_t channel){
|
||||||
(void)extp;
|
(void)extp;
|
||||||
(void)channel;
|
(void)channel;
|
||||||
|
|
||||||
EMCNANDD1.isr_handler(&EMCNANDD1);
|
NANDD1.isr_handler(&NANDD1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ready_isr_enable(void) {
|
static void ready_isr_enable(void) {
|
||||||
|
@ -206,7 +201,7 @@ static void ready_isr_enable(void) {
|
||||||
static void ready_isr_disable(void) {
|
static void ready_isr_disable(void) {
|
||||||
extChannelDisable(&EXTD1, GPIOD_NAND_RB);
|
extChannelDisable(&EXTD1, GPIOD_NAND_RB);
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* STM32_NAND_USE_FSMC_INT */
|
||||||
|
|
||||||
static void nand_wp_assert(void) {
|
static void nand_wp_assert(void) {
|
||||||
palClearPad(GPIOB, GPIOB_NAND_WP);
|
palClearPad(GPIOB, GPIOB_NAND_WP);
|
||||||
|
@ -237,13 +232,13 @@ static THD_FUNCTION(fsmcIdleThread, arg) {
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static bool isErased(EMCNANDDriver *dp, size_t block){
|
static bool is_erased(NANDDriver *dp, size_t block){
|
||||||
uint32_t page = 0;
|
uint32_t page = 0;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for (page=0; page<EMCNANDD1.config->pages_per_block; page++){
|
for (page=0; page<NANDD1.config->pages_per_block; page++){
|
||||||
emcnandReadPageData(dp, block, page, nand_buf, EMCNANDD1.config->page_data_size, NULL);
|
nandReadPageData(dp, block, page, nand_buf, NANDD1.config->page_data_size, NULL);
|
||||||
emcnandReadPageSpare(dp, block, page, &nand_buf[2048], EMCNANDD1.config->page_spare_size);
|
nandReadPageSpare(dp, block, page, &nand_buf[2048], NANDD1.config->page_spare_size);
|
||||||
for (i=0; i<sizeof(nand_buf); i++) {
|
for (i=0; i<sizeof(nand_buf); i++) {
|
||||||
if (nand_buf[i] != 0xFF)
|
if (nand_buf[i] != 0xFF)
|
||||||
return false;
|
return false;
|
||||||
|
@ -278,37 +273,37 @@ static void pattern_fill(void) {
|
||||||
osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE));
|
osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if EMCNAND_USE_KILL_TEST
|
#if USE_KILL_BLOCK_TEST
|
||||||
static void kill_block(EMCNANDDriver *emcnandp, uint32_t block){
|
static void kill_block(NANDDriver *nandp, uint32_t block){
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
size_t page = 0;
|
size_t page = 0;
|
||||||
uint8_t op_status;
|
uint8_t op_status;
|
||||||
|
|
||||||
/* This test require good block.*/
|
/* This test require good block.*/
|
||||||
osalDbgCheck(!emcnandIsBad(emcnandp, block));
|
osalDbgCheck(!nandIsBad(nandp, block));
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
op_status = emcnandErase(&EMCNANDD1, block);
|
op_status = nandErase(&NANDD1, block);
|
||||||
if (0 != (op_status & 1)){
|
if (0 != (op_status & 1)){
|
||||||
if(!isErased(emcnandp, block))
|
if(!is_erased(nandp, block))
|
||||||
osalSysHalt("Block successfully killed");
|
osalSysHalt("Block successfully killed");
|
||||||
}
|
}
|
||||||
if(!isErased(emcnandp, block))
|
if(!is_erased(nandp, block))
|
||||||
osalSysHalt("Block block not erased, but erase operation report success");
|
osalSysHalt("Block block not erased, but erase operation report success");
|
||||||
|
|
||||||
for (page=0; page<emcnandp->config->pages_per_block; page++){
|
for (page=0; page<nandp->config->pages_per_block; page++){
|
||||||
memset(nand_buf, 0, NAND_PAGE_SIZE);
|
memset(nand_buf, 0, NAND_PAGE_SIZE);
|
||||||
op_status = emcnandWritePageWhole(emcnandp, block, page, nand_buf, NAND_PAGE_SIZE);
|
op_status = nandWritePageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE);
|
||||||
if (0 != (op_status & 1)){
|
if (0 != (op_status & 1)){
|
||||||
emcnandReadPageWhole(emcnandp, block, page, nand_buf, NAND_PAGE_SIZE);
|
nandReadPageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE);
|
||||||
for (i=0; i<NAND_PAGE_SIZE; i++){
|
for (i=0; i<NAND_PAGE_SIZE; i++){
|
||||||
if (nand_buf[i] != 0)
|
if (nand_buf[i] != 0)
|
||||||
osalSysHalt("Block successfully killed");
|
osalSysHalt("Block successfully killed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emcnandReadPageWhole(emcnandp, block, page, nand_buf, NAND_PAGE_SIZE);
|
nandReadPageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE);
|
||||||
for (i=0; i<NAND_PAGE_SIZE; i++){
|
for (i=0; i<NAND_PAGE_SIZE; i++){
|
||||||
if (nand_buf[i] != 0)
|
if (nand_buf[i] != 0)
|
||||||
osalSysHalt("Page write failed, but write operation report success");
|
osalSysHalt("Page write failed, but write operation report success");
|
||||||
|
@ -317,7 +312,7 @@ static void kill_block(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
KillCycle++;
|
KillCycle++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* EMCNAND_USE_KILL_TEST */
|
#endif /* USE_KILL_BLOCK_TEST */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ECC_NO_ERROR = 0,
|
ECC_NO_ERROR = 0,
|
||||||
|
@ -370,7 +365,7 @@ static void invert_bit(uint8_t *buf, uint32_t byte, uint32_t bit){
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
static void ecc_test(NANDDriver *nandp, uint32_t block){
|
||||||
|
|
||||||
uint32_t corrupted;
|
uint32_t corrupted;
|
||||||
uint32_t byte, bit;
|
uint32_t byte, bit;
|
||||||
|
@ -380,18 +375,18 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
ecc_result_t ecc_result = ECC_NO_ERROR;
|
ecc_result_t ecc_result = ECC_NO_ERROR;
|
||||||
|
|
||||||
/* This test requires good block.*/
|
/* This test requires good block.*/
|
||||||
osalDbgCheck(!emcnandIsBad(emcnandp, block));
|
osalDbgCheck(!nandIsBad(nandp, block));
|
||||||
if (!isErased(emcnandp, block))
|
if (!is_erased(nandp, block))
|
||||||
emcnandErase(&EMCNANDD1, block);
|
nandErase(&NANDD1, block);
|
||||||
|
|
||||||
pattern_fill();
|
pattern_fill();
|
||||||
|
|
||||||
/*** Correctable errors ***/
|
/*** Correctable errors ***/
|
||||||
op_status = emcnandWritePageData(emcnandp, block, 0,
|
op_status = nandWritePageData(nandp, block, 0,
|
||||||
nand_buf, emcnandp->config->page_data_size, &ecc_ref);
|
nand_buf, nandp->config->page_data_size, &ecc_ref);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
emcnandReadPageData(emcnandp, block, 0,
|
nandReadPageData(nandp, block, 0,
|
||||||
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
|
nand_buf, nandp->config->page_data_size, &ecc_broken);
|
||||||
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
||||||
osalDbgCheck(ECC_NO_ERROR == ecc_result); /* unexpected error */
|
osalDbgCheck(ECC_NO_ERROR == ecc_result); /* unexpected error */
|
||||||
|
|
||||||
|
@ -399,8 +394,8 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
byte = 0;
|
byte = 0;
|
||||||
bit = 7;
|
bit = 7;
|
||||||
invert_bit(nand_buf, byte, bit);
|
invert_bit(nand_buf, byte, bit);
|
||||||
op_status = emcnandWritePageData(emcnandp, block, 1,
|
op_status = nandWritePageData(nandp, block, 1,
|
||||||
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
|
nand_buf, nandp->config->page_data_size, &ecc_broken);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
invert_bit(nand_buf, byte, bit);
|
invert_bit(nand_buf, byte, bit);
|
||||||
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
||||||
|
@ -411,8 +406,8 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
byte = 2047;
|
byte = 2047;
|
||||||
bit = 0;
|
bit = 0;
|
||||||
invert_bit(nand_buf, byte, bit);
|
invert_bit(nand_buf, byte, bit);
|
||||||
op_status = emcnandWritePageData(emcnandp, block, 2,
|
op_status = nandWritePageData(nandp, block, 2,
|
||||||
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
|
nand_buf, nandp->config->page_data_size, &ecc_broken);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
invert_bit(nand_buf, byte, bit);
|
invert_bit(nand_buf, byte, bit);
|
||||||
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
||||||
|
@ -423,8 +418,8 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
byte = 1027;
|
byte = 1027;
|
||||||
bit = 3;
|
bit = 3;
|
||||||
invert_bit(nand_buf, byte, bit);
|
invert_bit(nand_buf, byte, bit);
|
||||||
op_status = emcnandWritePageData(emcnandp, block, 3,
|
op_status = nandWritePageData(nandp, block, 3,
|
||||||
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
|
nand_buf, nandp->config->page_data_size, &ecc_broken);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
invert_bit(nand_buf, byte, bit);
|
invert_bit(nand_buf, byte, bit);
|
||||||
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
|
||||||
|
@ -435,8 +430,8 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
byte = 1027;
|
byte = 1027;
|
||||||
invert_bit(nand_buf, byte, 3);
|
invert_bit(nand_buf, byte, 3);
|
||||||
invert_bit(nand_buf, byte, 4);
|
invert_bit(nand_buf, byte, 4);
|
||||||
op_status = emcnandWritePageData(emcnandp, block, 4,
|
op_status = nandWritePageData(nandp, block, 4,
|
||||||
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
|
nand_buf, nandp->config->page_data_size, &ecc_broken);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
invert_bit(nand_buf, byte, 3);
|
invert_bit(nand_buf, byte, 3);
|
||||||
invert_bit(nand_buf, byte, 4);
|
invert_bit(nand_buf, byte, 4);
|
||||||
|
@ -444,13 +439,13 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
|
||||||
osalDbgCheck(ECC_UNCORRECTABLE_ERROR == ecc_result); /* This error must be NOT correctable */
|
osalDbgCheck(ECC_UNCORRECTABLE_ERROR == ecc_result); /* This error must be NOT correctable */
|
||||||
|
|
||||||
/*** make clean ***/
|
/*** make clean ***/
|
||||||
emcnandErase(&EMCNANDD1, block);
|
nandErase(&NANDD1, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static void general_test (EMCNANDDriver *emcnandp, size_t first,
|
static void general_test (NANDDriver *nandp, size_t first,
|
||||||
size_t last, size_t read_rounds){
|
size_t last, size_t read_rounds){
|
||||||
|
|
||||||
size_t block, page, round;
|
size_t block, page, round;
|
||||||
|
@ -470,9 +465,9 @@ static void general_test (EMCNANDDriver *emcnandp, size_t first,
|
||||||
|
|
||||||
/* perform basic checks */
|
/* perform basic checks */
|
||||||
for (block=first; block<last; block++){
|
for (block=first; block<last; block++){
|
||||||
if (!emcnandIsBad(emcnandp, block)){
|
if (!nandIsBad(nandp, block)){
|
||||||
if (!isErased(emcnandp, block)){
|
if (!is_erased(nandp, block)){
|
||||||
op_status = emcnandErase(emcnandp, block);
|
op_status = nandErase(nandp, block);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,20 +475,20 @@ static void general_test (EMCNANDDriver *emcnandp, size_t first,
|
||||||
|
|
||||||
/* write block with pattern, read it back and compare */
|
/* write block with pattern, read it back and compare */
|
||||||
for (block=first; block<last; block++){
|
for (block=first; block<last; block++){
|
||||||
if (!emcnandIsBad(emcnandp, block)){
|
if (!nandIsBad(nandp, block)){
|
||||||
for (page=0; page<emcnandp->config->pages_per_block; page++){
|
for (page=0; page<nandp->config->pages_per_block; page++){
|
||||||
pattern_fill();
|
pattern_fill();
|
||||||
|
|
||||||
//tmStartMeasurement(&tmu_write_data);
|
//tmStartMeasurement(&tmu_write_data);
|
||||||
op_status = emcnandWritePageData(emcnandp, block, page,
|
op_status = nandWritePageData(nandp, block, page,
|
||||||
nand_buf, emcnandp->config->page_data_size, &wecc);
|
nand_buf, nandp->config->page_data_size, &wecc);
|
||||||
//tmStopMeasurement(&tmu_write_data);
|
//tmStopMeasurement(&tmu_write_data);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
|
|
||||||
//tmStartMeasurement(&tmu_write_spare);
|
//tmStartMeasurement(&tmu_write_spare);
|
||||||
op_status = emcnandWritePageSpare(emcnandp, block, page,
|
op_status = nandWritePageSpare(nandp, block, page,
|
||||||
nand_buf + emcnandp->config->page_data_size,
|
nand_buf + nandp->config->page_data_size,
|
||||||
emcnandp->config->page_spare_size);
|
nandp->config->page_spare_size);
|
||||||
//tmStopMeasurement(&tmu_write_spare);
|
//tmStopMeasurement(&tmu_write_spare);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
|
|
||||||
|
@ -502,15 +497,15 @@ static void general_test (EMCNANDDriver *emcnandp, size_t first,
|
||||||
memset(nand_buf, 0, NAND_PAGE_SIZE);
|
memset(nand_buf, 0, NAND_PAGE_SIZE);
|
||||||
|
|
||||||
//tmStartMeasurement(&tmu_read_data);
|
//tmStartMeasurement(&tmu_read_data);
|
||||||
emcnandReadPageData(emcnandp, block, page,
|
nandReadPageData(nandp, block, page,
|
||||||
nand_buf, emcnandp->config->page_data_size, &recc);
|
nand_buf, nandp->config->page_data_size, &recc);
|
||||||
//tmStopMeasurement(&tmu_read_data);
|
//tmStopMeasurement(&tmu_read_data);
|
||||||
osalDbgCheck(0 == (recc ^ wecc)); /* ECC error detected */
|
osalDbgCheck(0 == (recc ^ wecc)); /* ECC error detected */
|
||||||
|
|
||||||
//tmStartMeasurement(&tmu_read_spare);
|
//tmStartMeasurement(&tmu_read_spare);
|
||||||
emcnandReadPageSpare(emcnandp, block, page,
|
nandReadPageSpare(nandp, block, page,
|
||||||
nand_buf + emcnandp->config->page_data_size,
|
nand_buf + nandp->config->page_data_size,
|
||||||
emcnandp->config->page_spare_size);
|
nandp->config->page_spare_size);
|
||||||
//tmStopMeasurement(&tmu_read_spare);
|
//tmStopMeasurement(&tmu_read_spare);
|
||||||
|
|
||||||
osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE)); /* Read back failed */
|
osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE)); /* Read back failed */
|
||||||
|
@ -519,13 +514,13 @@ static void general_test (EMCNANDDriver *emcnandp, size_t first,
|
||||||
|
|
||||||
/* make clean */
|
/* make clean */
|
||||||
//tmStartMeasurement(&tmu_erase);
|
//tmStartMeasurement(&tmu_erase);
|
||||||
op_status = emcnandErase(emcnandp, block);
|
op_status = nandErase(nandp, block);
|
||||||
//tmStopMeasurement(&tmu_erase);
|
//tmStopMeasurement(&tmu_erase);
|
||||||
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
|
||||||
|
|
||||||
status = isErased(emcnandp, block);
|
status = is_erased(nandp, block);
|
||||||
osalDbgCheck(true == status); /* blocks was not erased successfully */
|
osalDbgCheck(true == status); /* blocks was not erased successfully */
|
||||||
}/* if (!emcnandIsBad(emcnandp, block)){ */
|
}/* if (!nandIsBad(nandp, block)){ */
|
||||||
}
|
}
|
||||||
red_led_off();
|
red_led_off();
|
||||||
}
|
}
|
||||||
|
@ -552,7 +547,7 @@ int main(void) {
|
||||||
volatile int32_t uart_its_idle = 0;
|
volatile int32_t uart_its_idle = 0;
|
||||||
volatile uint32_t idle_thread_cnt = 0;
|
volatile uint32_t idle_thread_cnt = 0;
|
||||||
|
|
||||||
#if EMCNAND_USE_KILL_TEST
|
#if USE_KILL_BLOCK_TEST
|
||||||
size_t kill = 8000;
|
size_t kill = 8000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -566,11 +561,10 @@ int main(void) {
|
||||||
halInit();
|
halInit();
|
||||||
chSysInit();
|
chSysInit();
|
||||||
|
|
||||||
emcStart(&EMCD1, &emccfg);
|
#if !STM32_NAND_USE_FSMC_INT
|
||||||
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
|
|
||||||
extStart(&EXTD1, &extcfg);
|
extStart(&EXTD1, &extcfg);
|
||||||
#endif
|
#endif
|
||||||
emcnandStart(&EMCNANDD1, &nandcfg);
|
nandStart(&NANDD1, &nandcfg);
|
||||||
|
|
||||||
chThdSleepMilliseconds(4000);
|
chThdSleepMilliseconds(4000);
|
||||||
|
|
||||||
|
@ -586,7 +580,7 @@ int main(void) {
|
||||||
dma_storm_uart_start();
|
dma_storm_uart_start();
|
||||||
dma_storm_spi_start();
|
dma_storm_spi_start();
|
||||||
T = chVTGetSystemTimeX();
|
T = chVTGetSystemTimeX();
|
||||||
general_test(&EMCNANDD1, start, end, 1);
|
general_test(&NANDD1, start, end, 1);
|
||||||
T = chVTGetSystemTimeX() - T;
|
T = chVTGetSystemTimeX() - T;
|
||||||
adc_its = dma_storm_adc_stop();
|
adc_its = dma_storm_adc_stop();
|
||||||
uart_its = dma_storm_uart_stop();
|
uart_its = dma_storm_uart_stop();
|
||||||
|
@ -609,10 +603,10 @@ int main(void) {
|
||||||
osalDbgCheck(abs(uart_its - uart_its_idle) < (uart_its_idle / 20));
|
osalDbgCheck(abs(uart_its - uart_its_idle) < (uart_its_idle / 20));
|
||||||
osalDbgCheck(abs(spi_its - spi_its_idle) < (spi_its_idle / 10));
|
osalDbgCheck(abs(spi_its - spi_its_idle) < (spi_its_idle / 10));
|
||||||
|
|
||||||
ecc_test(&EMCNANDD1, end);
|
ecc_test(&NANDD1, end);
|
||||||
|
|
||||||
#if EMCNAND_USE_KILL_TEST
|
#if USE_KILL_BLOCK_TEST
|
||||||
kill_block(&EMCNANDD1, kill);
|
kill_block(&NANDD1, kill);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nand_wp_assert();
|
nand_wp_assert();
|
||||||
|
|
|
@ -304,13 +304,13 @@
|
||||||
#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
|
#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EMC driver system settings.
|
* FSMC driver system settings.
|
||||||
*/
|
*/
|
||||||
#define STM32_EMC_USE_FSMC1 TRUE
|
#define STM32_FSMC_USE_FSMC1 TRUE
|
||||||
#define STM32_EMC_FSMC1_IRQ_PRIORITY 10
|
#define STM32_FSMC_FSMC1_IRQ_PRIORITY 10
|
||||||
#define STM32_EMC_EMCNAND_USE_FSMC_INT FALSE
|
|
||||||
|
|
||||||
#define STM32_EMCNAND_USE_EMCNAND1 TRUE
|
#define STM32_NAND_USE_FSMC_NAND1 TRUE
|
||||||
#define STM32_EMCNAND_EMCNAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
#define STM32_NAND_USE_FSMC_INT FALSE
|
||||||
#define STM32_EMCNAND_EMCNAND1_DMA_PRIORITY 0
|
#define STM32_NAND_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
|
||||||
#define STM32_EMCNAND_DMA_ERROR_HOOK(emcnandp) osalSysHalt("DMA failure")
|
#define STM32_NAND_DMA_PRIORITY 0
|
||||||
|
#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure")
|
||||||
|
|
Loading…
Reference in New Issue