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:
barthess 2014-08-06 21:17:02 +00:00
parent 2a6b156390
commit 156ff76940
16 changed files with 1014 additions and 1247 deletions

View File

@ -23,8 +23,7 @@ HALSRC = ${CHIBIOS}/os/hal/src/hal.c \
${CHIBIOS}/os/hal/src/st.c \
${CHIBIOS}/os/hal/src/uart.c \
${CHIBIOS}/os/hal/src/usb.c \
${CHIBIOS}/os/hal/src/emc.c \
${CHIBIOS}/os/hal/src/emcnand.c
${CHIBIOS}/os/hal/src/nand.c
# Required include directories
HALINC = ${CHIBIOS}/os/hal/include

View File

@ -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_ */
/** @} */

View File

@ -64,8 +64,7 @@
#include "st.h"
#include "uart.h"
#include "usb.h"
#include "emc.h"
#include "emcnand.h"
#include "nand.h"
/* Complex drivers.*/
#include "mmc_spi.h"

View File

@ -23,17 +23,17 @@
*/
/**
* @file emcnand.h
* @brief EMCNAND Driver macros and structures.
* @file nand.h
* @brief NAND Driver macros and structures.
*
* @addtogroup EMCNAND
* @addtogroup NAND
* @{
*/
#ifndef _EMCNAND_H_
#define _EMCNAND_H_
#ifndef _NAND_H_
#define _NAND_H_
#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
#if HAL_USE_NAND || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@ -62,19 +62,15 @@
/**
* @brief Enables the mutual exclusion APIs on the NAND.
*/
#if !defined(EMCNAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define EMCNAND_USE_MUTUAL_EXCLUSION FALSE
#if !defined(NAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define NAND_USE_MUTUAL_EXCLUSION FALSE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if EMCNAND_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"
#endif
#if !HAL_USE_EMC
#error "This driver requires EMC controller"
#if NAND_USE_MUTUAL_EXCLUSION && !CH_CFG_USE_MUTEXES && !CH_CFG_USE_SEMAPHORES
#error "NAND_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
#endif
/*===========================================================================*/
@ -85,23 +81,23 @@
* @brief Driver state machine possible states.
*/
typedef enum {
EMCNAND_UNINIT = 0, /**< Not initialized. */
EMCNAND_STOP = 1, /**< Stopped. */
EMCNAND_READY = 2, /**< Ready. */
EMCNAND_PROGRAM = 3, /**< Programming in progress. */
EMCNAND_ERASE = 4, /**< Erasing in progress. */
EMCNAND_WRITE = 5, /**< Writing to NAND buffer. */
EMCNAND_READ = 6, /**< Reading from NAND. */
EMCNAND_DMA_TX = 7, /**< DMA transmitting. */
EMCNAND_DMA_RX = 8, /**< DMA receiving. */
} emcnandstate_t;
NAND_UNINIT = 0, /**< Not initialized. */
NAND_STOP = 1, /**< Stopped. */
NAND_READY = 2, /**< Ready. */
NAND_PROGRAM = 3, /**< Programming in progress. */
NAND_ERASE = 4, /**< Erasing in progress. */
NAND_WRITE = 5, /**< Writing to NAND buffer. */
NAND_READ = 6, /**< Reading from NAND. */
NAND_DMA_TX = 7, /**< DMA transmitting. */
NAND_DMA_RX = 8, /**< DMA receiving. */
} 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. */
@ -114,39 +110,39 @@ typedef struct EMCNANDDriver EMCNANDDriver;
#ifdef __cplusplus
extern "C" {
#endif
void emcnandInit(void);
void emcnandObjectInit(EMCNANDDriver *emcnandp);
void emcnandStart(EMCNANDDriver *emcnandp, const EMCNANDConfig *config);
void emcnandStop(EMCNANDDriver *emcnandp);
void emcnandReadPageWhole(EMCNANDDriver *emcnandp, uint32_t block,
void nandInit(void);
void nandObjectInit(NANDDriver *nandp);
void nandStart(NANDDriver *nandp, const NANDConfig *config);
void nandStop(NANDDriver *nandp);
void nandReadPageWhole(NANDDriver *nandp, uint32_t block,
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);
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);
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);
void emcnandReadPageSpare(EMCNANDDriver *emcnandp, uint32_t block,
void nandReadPageSpare(NANDDriver *nandp, uint32_t block,
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);
void emcnandMarkBad(EMCNANDDriver *emcnandp, uint32_t block);
uint8_t emcnandReadBadMark(EMCNANDDriver *emcnandp,
void nandMarkBad(NANDDriver *nandp, uint32_t block);
uint8_t nandReadBadMark(NANDDriver *nandp,
uint32_t block, uint32_t page);
uint8_t emcnandErase(EMCNANDDriver *emcnandp, uint32_t block);
bool emcnandIsBad(EMCNANDDriver *emcnandp, uint32_t block);
uint8_t nandErase(NANDDriver *nandp, uint32_t block);
bool nandIsBad(NANDDriver *nandp, uint32_t block);
#if EMCNAND_USE_MUTUAL_EXCLUSION
void emcnandAcquireBus(EMCNANDDriver *emcnandp);
void emcnandReleaseBus(EMCNANDDriver *emcnandp);
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
#if NAND_USE_MUTUAL_EXCLUSION
void nandAcquireBus(NANDDriver *nandp);
void nandReleaseBus(NANDDriver *nandp);
#endif /* NAND_USE_MUTUAL_EXCLUSION */
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_EMCNAND */
#endif /* HAL_USE_NAND */
#endif /* _EMCNAND_H_ */
#endif /* _NAND_H_ */
/** @} */

View File

@ -19,16 +19,16 @@
*/
/**
* @file emc_lld.c
* @brief EMC Driver subsystem low level driver source template.
* @file fsmc.c
* @brief FSMC Driver subsystem low level driver source template.
*
* @addtogroup EMC
* @addtogroup FSMC
* @{
*/
#include "hal.h"
#if HAL_USE_EMC || defined(__DOXYGEN__)
#if HAL_USE_NAND || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
@ -39,10 +39,10 @@
/*===========================================================================*/
/**
* @brief EMC1 driver identifier.
* @brief FSMC1 driver identifier.
*/
#if STM32_EMC_USE_FSMC1 || defined(__DOXYGEN__)
EMCDriver EMCD1;
#if STM32_FSMC_USE_FSMC1 || defined(__DOXYGEN__)
FSMCDriver FSMCD1;
#endif
/*===========================================================================*/
@ -66,89 +66,90 @@ EMCDriver EMCD1;
/*===========================================================================*/
/**
* @brief Low level EMC driver initialization.
* @brief Low level FSMC driver initialization.
*
* @notapi
*/
void emc_lld_init(void) {
void fsmc_lld_init(void) {
#if STM32_EMC_USE_FSMC1
emcObjectInit(&EMCD1);
FSMCD1.state = FSMC_STOP;
#if STM32_EMCNAND_USE_EMCNAND1
EMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
#if STM32_NAND_USE_FSMC_NAND1
FSMCD1.nand1 = (FSMC_NAND_TypeDef *)FSMC_Bank2_R_BASE;
#endif
#if STM32_EMCNAND_USE_EMCNAND2
EMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
#if STM32_NAND_USE_FSMC_NAND2
FSMCD1.nand2 = (FSMC_NAND_TypeDef *)FSMC_Bank3_R_BASE;
#endif
#if STM32_USE_EMC_PCCARD
EMCD1.pccard = (FSMC_PCCARD_TypeDef *)FSMC_Bank4_R_BASE;
#if STM32_USE_FSMC_PCCARD
FSMCD1.pccard = (FSMC_PCCARD_TypeDef *)FSMC_Bank4_R_BASE;
#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
*/
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.*/
#if STM32_EMC_USE_FSMC1
if (&EMCD1 == emcp) {
#if STM32_FSMC_USE_FSMC1
if (&FSMCD1 == fsmcp) {
rccResetFSMC();
rccEnableFSMC(FALSE);
#if STM32_EMC_USE_INT
nvicEnableVector(FSMC_IRQn, STM32_EMC_FSMC1_IRQ_PRIORITY);
#endif /* STM32_EMC_USE_INT */
#if STM32_NAND_USE_FSMC_INT
nvicEnableVector(FSMC_IRQn, STM32_FSMC_FSMC1_IRQ_PRIORITY);
#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
*/
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.*/
rccResetFSMC();
/* Disables the peripheral.*/
#if STM32_EMC_USE_FSMC1
if (&EMCD1 == emcp) {
#if STM32_EMC_USE_INT
#if STM32_FSMC_USE_FSMC1
if (&FSMCD1 == fsmcp) {
#if STM32_NAND_USE_FSMC_INT
nvicDisableVector(FSMC_IRQn);
#endif
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.
*
* @notapi
*/
void emc_lld_serve_interrupt(void) {
void fsmc_lld_serve_interrupt(void) {
osalSysHalt("Unrealized");
}
@ -162,20 +163,20 @@ CH_IRQ_HANDLER(FSMC_IRQHandler) {
osalSysHalt("This functionality untested");
CH_IRQ_PROLOGUE();
#if STM32_EMCNAND_USE_EMCNAND1
if (EMCD1.nand1->SR & FSMC_SR_ISR_MASK){
EMCNANDD1.isr_handler(&EMCNANDD1, EMCD1.nand1->SR);
#if STM32_NAND_USE_FSMC_NAND1
if (FSMCD1.nand1->SR & FSMC_SR_ISR_MASK){
NANDD1.isr_handler(&NANDD1, FSMCD1.nand1->SR);
}
#endif
#if STM32_EMCNAND_USE_EMCNAND2
if (EMCD1.nand2->SR & FSMC_SR_ISR_MASK){
EMCNANDD2.isr_handler(&EMCNANDD2, EMCD1.nand2->SR);
#if STM32_NAND_USE_FSMC_NAND2
if (FSMCD1.nand2->SR & FSMC_SR_ISR_MASK){
NANDD2.isr_handler(&NANDD2, FSMCD1.nand2->SR);
}
#endif
CH_IRQ_EPILOGUE();
}
#endif /* STM32_EMC_USE_INT */
#endif /* STM32_FSMC_USE_INT */
#endif /* HAL_USE_EMC */
#endif /* HAL_USE_FSMC */
/** @} */

View File

@ -19,18 +19,18 @@
*/
/**
* @file emc_lld.h
* @brief EMC Driver subsystem low level driver header template.
* @file fsmc.h
* @brief FSMC Driver subsystem low level driver header template.
*
* @addtogroup EMC
* @addtogroup FSMC
* @{
*/
#ifndef _EMC_LLD_H_
#define _EMC_LLD_H_
#ifndef _FSMC_H_
#define _FSMC_H_
#if HAL_USE_EMC || defined(__DOXYGEN__)
#if HAL_USE_NAND || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@ -146,11 +146,11 @@ typedef struct {
* @{
*/
/**
* @brief EMC driver enable switch.
* @details If set to @p TRUE the support for EMC is included.
* @brief FSMC driver enable switch.
* @details If set to @p TRUE the support for FSMC is included.
*/
#if !defined(STM32_EMC_USE_FSMC1) || defined(__DOXYGEN__)
#define STM32_EMC_USE_FSMC1 FALSE
#if !defined(STM32_FSMC_USE_FSMC1) || defined(__DOXYGEN__)
#define STM32_FSMC_USE_FSMC1 FALSE
#endif
/**
@ -158,10 +158,8 @@ typedef struct {
* @details MCUs in 100-pin package has no dedicated interrupt pin for FSMC.
* You have to use EXTI module instead to workaround this issue.
*/
#if STM32_EMC_EMCNAND_USE_FSMC_INT
#define STM32_EMC_USE_INT TRUE
#else
#define STM32_EMC_USE_INT FALSE
#if !defined(STM32_NAND_USE_FSMC_INT) || defined(__DOXYGEN__)
#define STM32_NAND_USE_FSMC_INT FALSE
#endif
/** @} */
@ -169,8 +167,8 @@ typedef struct {
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !STM32_EMC_USE_FSMC1
#error "EMC driver activated but no EMC peripheral assigned"
#if !STM32_FSMC_USE_FSMC1
#error "FSMC driver activated but no FSMC peripheral assigned"
#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.
@ -188,28 +195,24 @@ typedef struct EMCDriver EMCDriver;
*/
typedef struct {
} EMCConfig;
} FSMCConfig;
/**
* @brief Structure representing an EMC driver.
* @brief Structure representing an FSMC driver.
*/
struct EMCDriver {
struct FSMCDriver {
/**
* @brief Driver state.
*/
emcstate_t state;
/**
* @brief Current configuration data.
*/
const EMCConfig *config;
fsmcstate_t state;
/* End of the mandatory fields.*/
#if STM32_EMCNAND_USE_EMCNAND1
#if STM32_NAND_USE_FSMC_NAND1
FSMC_NAND_TypeDef *nand1;
#endif
#if STM32_EMCNAND_USE_EMCNAND2
#if STM32_NAND_USE_FSMC_NAND2
FSMC_NAND_TypeDef *nand2;
#endif
#if STM32_USE_EMC_PCCARD
#if STM32_USE_FSMC_PCCARD
FSMC_PCCard_TypeDef *pccard;
#endif
};
@ -222,22 +225,22 @@ struct EMCDriver {
/* External declarations. */
/*===========================================================================*/
#if STM32_EMC_USE_FSMC1 && !defined(__DOXYGEN__)
extern EMCDriver EMCD1;
#if STM32_FSMC_USE_FSMC1 && !defined(__DOXYGEN__)
extern FSMCDriver FSMCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void emc_lld_init(void);
void emc_lld_start(EMCDriver *emcp);
void emc_lld_stop(EMCDriver *emcp);
void fsmc_lld_init(void);
void fsmc_lld_start(FSMCDriver *fsmcp);
void fsmc_lld_stop(FSMCDriver *fsmcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_EMC */
#endif /* HAL_USE_NAND */
#endif /* _EMC_LLD_H_ */
#endif /* _FSMC_H_ */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -19,24 +19,26 @@
*/
/**
* @file emcnand_lld.h
* @brief EMCNAND Driver subsystem low level driver header template.
* @file nand_lld.h
* @brief NAND Driver subsystem low level driver header template.
*
* @addtogroup EMCNAND
* @addtogroup NAND
* @{
*/
#ifndef _EMCNAND_LLD_H_
#define _EMCNAND_LLD_H_
#ifndef _NAND_LLD_H_
#define _NAND_LLD_H_
#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
#include "fsmc.h"
#if HAL_USE_NAND || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define EMCNAND_MIN_PAGE_SIZE 256
#define EMCNAND_MAX_PAGE_SIZE 8192
#define EMCNAND_BAD_MAP_END_MARK ((uint16_t)0xFFFF)
#define NAND_MIN_PAGE_SIZE 256
#define NAND_MAX_PAGE_SIZE 8192
#define NAND_BAD_MAP_END_MARK ((uint16_t)0xFFFF)
/*===========================================================================*/
/* Driver pre-compile time settings. */
@ -54,66 +56,66 @@
#endif
/**
* @brief EMCNAND driver enable switch.
* @details If set to @p TRUE the support for EMCNAND1 is included.
* @brief NAND driver enable switch.
* @details If set to @p TRUE the support for NAND1 is included.
*/
#if !defined(STM32_EMCNAND_USE_EMCNAND1) || defined(__DOXYGEN__)
#define STM32_EMCNAND_USE_EMCNAND1 FALSE
#if !defined(STM32_NAND_USE_NAND1) || defined(__DOXYGEN__)
#define STM32_NAND_USE_NAND1 FALSE
#endif
/**
* @brief EMCNAND driver enable switch.
* @details If set to @p TRUE the support for EMCNAND2 is included.
* @brief NAND driver enable switch.
* @details If set to @p TRUE the support for NAND2 is included.
*/
#if !defined(STM32_EMCNAND_USE_EMCNAND2) || defined(__DOXYGEN__)
#define STM32_EMCNAND_USE_EMCNAND2 FALSE
#if !defined(STM32_NAND_USE_NAND2) || defined(__DOXYGEN__)
#define STM32_NAND_USE_NAND2 FALSE
#endif
/**
* @brief EMCNAND DMA error hook.
* @brief NAND DMA error hook.
* @note The default action for DMA errors is a system halt because DMA
* error can only happen because programming errors.
*/
#if !defined(STM32_EMCNAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
#define STM32_EMCNAND_DMA_ERROR_HOOK(emcnandp) osalSysHalt("DMA failure")
#if !defined(STM32_NAND_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure")
#endif
/**
* @brief EMCNAND interrupt enable switch.
* @brief NAND interrupt enable switch.
* @details If set to @p TRUE the support for internal FSMC interrupt included.
*/
#if !defined(STM32_EMCNAND_USE_INT) || defined(__DOXYGEN__)
#define STM32_EMCNAND_USE_INT FALSE
#if !defined(STM32_NAND_USE_INT) || defined(__DOXYGEN__)
#define STM32_NAND_USE_INT FALSE
#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__)
#define STM32_EMCNAND_EMCNAND1_DMA_PRIORITY 0
#if !defined(STM32_NAND_NAND1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_NAND_NAND1_DMA_PRIORITY 0
#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__)
#define STM32_EMCNAND_EMCNAND2_DMA_PRIORITY 0
#if !defined(STM32_NAND_NAND2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_NAND_NAND2_DMA_PRIORITY 0
#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.
*/
#if !defined(STM32_EMCNAND_EMCNAND1_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_EMCNAND_EMCNAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
#if !defined(STM32_NAND_NAND1_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_NAND_NAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 6)
#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.
*/
#if !defined(STM32_EMCNAND_EMCNAND2_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_EMCNAND_EMCNAND2_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#if !defined(STM32_NAND_NAND2_DMA_STREAM) || defined(__DOXYGEN__)
#define STM32_NAND_NAND2_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#endif
/** @} */
@ -122,28 +124,26 @@
/* Derived constants and error checks. */
/*===========================================================================*/
#if !STM32_EMCNAND_USE_EMCNAND1 && !STM32_EMCNAND_USE_EMCNAND2
#error "EMCNAND driver activated but no EMCNAND peripheral assigned"
#if !STM32_NAND_USE_FSMC_NAND1 && !STM32_NAND_USE_FSMC_NAND2
#error "NAND driver activated but no NAND peripheral assigned"
#endif
#if STM32_EMCNAND_USE_EMCNAND1 && !STM32_HAS_EMC
#error "EMC not present in the selected device"
#if STM32_NAND_USE_FSMC_NAND1 && !STM32_HAS_FSMC
#error "FSMC not present in the selected device"
#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"
#endif
#if STM32_EMCNAND_USE_EMCNAND1 && \
!STM32_DMA_IS_VALID_ID(STM32_EMCNAND_EMCNAND1_DMA_STREAM, \
STM32_EMC_DMA_MSK)
#error "invalid DMA stream associated to EMCNAND"
#endif
#if STM32_EMCNAND_USE_EMCNAND2 && \
!STM32_DMA_IS_VALID_ID(STM32_EMCNAND_EMCNAND2_DMA_STREAM, \
STM32_EMC_DMA_MSK)
#error "invalid DMA stream associated to EMCNAND"
#if (STM32_NAND_USE_FSMC_NAND2 || STM32_NAND_USE_FSMC_NAND1) && \
!STM32_DMA_IS_VALID_ID(STM32_NAND_DMA_STREAM, \
STM32_FSMC_DMA_MSK)
#error "invalid DMA stream associated to NAND"
#endif
#if !defined(STM32_DMA_REQUIRED)
@ -157,30 +157,30 @@
/**
* @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
*/
typedef void (*emcnandisrhandler_t)
(EMCNANDDriver *emcnandp, emcnandflags_t flags);
typedef void (*nandisrhandler_t)
(NANDDriver *nandp, nandflags_t flags);
#else
/**
* @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.
*/
typedef void (*emcnandisrswitch_t)(void);
#endif /* STM32_EMC_USE_INT */
typedef void (*nandisrswitch_t)(void);
#endif /* STM32_NAND_USE_FSMC_INT */
/**
* @brief Driver configuration structure.
@ -190,7 +190,7 @@ typedef struct {
/**
* @brief Pointer to lower level driver.
*/
EMCDriver *emcp;
FSMCDriver *fsmcp;
/**
* @brief Number of erase blocks in NAND device.
*/
@ -207,13 +207,13 @@ typedef struct {
* @brief Number of pages in block.
*/
uint32_t pages_per_block;
#if EMCNAND_USE_BAD_MAP
#if NAND_USE_BAD_MAP
/**
* @brief Pointer to bad block map.
* @details One bit per block. Memory for map must be allocated by user.
*/
uint32_t *bb_map;
#endif /* EMCNAND_USE_BAD_MAP */
#endif /* NAND_USE_BAD_MAP */
/**
* @brief Number of write cycles for row addressing.
*/
@ -232,34 +232,34 @@ typedef struct {
* from STMicroelectronics.
*/
uint32_t pmem;
#if !STM32_EMC_USE_INT
#if !STM32_NAND_USE_FSMC_INT
/**
* @brief Function enabling interrupts from EXTI
*/
emcnandisrswitch_t ext_isr_enable;
nandisrswitch_t ext_isr_enable;
/**
* @brief Function disabling interrupts from EXTI
*/
emcnandisrswitch_t ext_isr_disable;
#endif /* !STM32_EMC_USE_INT */
} EMCNANDConfig;
nandisrswitch_t ext_isr_disable;
#endif /* !STM32_NAND_USE_FSMC_INT */
} NANDConfig;
/**
* @brief Structure representing an EMCNAND driver.
* @brief Structure representing an NAND driver.
*/
struct EMCNANDDriver {
struct NANDDriver {
/**
* @brief Driver state.
*/
emcnandstate_t state;
nandstate_t state;
/**
* @brief Current configuration data.
*/
const EMCNANDConfig *config;
const NANDConfig *config;
/**
* @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__)
/**
* @brief Mutex protecting the bus.
@ -268,12 +268,12 @@ struct EMCNANDDriver {
#elif CH_CFG_USE_SEMAPHORES
semaphore_t semaphore;
#endif
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
#endif /* NAND_USE_MUTUAL_EXCLUSION */
/* End of the mandatory fields.*/
/**
* @brief Function enabling interrupts from FSMC
*/
emcnandisrhandler_t isr_handler;
nandisrhandler_t isr_handler;
/**
* @brief Pointer to current transaction buffer
*/
@ -320,38 +320,38 @@ struct EMCNANDDriver {
/* External declarations. */
/*===========================================================================*/
#if STM32_EMCNAND_USE_EMCNAND1 && !defined(__DOXYGEN__)
extern EMCNANDDriver EMCNANDD1;
#if STM32_NAND_USE_FSMC_NAND1 && !defined(__DOXYGEN__)
extern NANDDriver NANDD1;
#endif
#if STM32_EMCNAND_USE_EMCNAND2 && !defined(__DOXYGEN__)
extern EMCNANDDriver EMCNANDD2;
#if STM32_NAND_USE_FSMC_NAND2 && !defined(__DOXYGEN__)
extern NANDDriver NANDD2;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void emcnand_lld_init(void);
void emcnand_lld_start(EMCNANDDriver *emcnandp);
void emcnand_lld_stop(EMCNANDDriver *emcnandp);
uint8_t emcnand_lld_write_data(EMCNANDDriver *emcnandp, const uint8_t *data,
void nand_lld_init(void);
void nand_lld_start(NANDDriver *nandp);
void nand_lld_stop(NANDDriver *nandp);
uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data,
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
void emcnand_lld_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
void nand_lld_read_data(NANDDriver *nandp, uint8_t *data,
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
void emcnand_lld_polled_read_data(EMCNANDDriver *emcnandp, uint8_t *data,
void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data,
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);
void emcnand_lld_write_addr(EMCNANDDriver *emcnandp,
void nand_lld_write_addr(NANDDriver *nandp,
const uint8_t *addr, size_t len);
void emcnand_lld_write_cmd(EMCNANDDriver *emcnandp, uint8_t cmd);
uint8_t emcnand_lld_read_status(EMCNANDDriver *emcnandp);
void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd);
uint8_t nand_lld_read_status(NANDDriver *nandp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_EMCNAND */
#endif /* HAL_USE_NAND */
#endif /* _EMCNAND_LLD_H_ */
#endif /* _NAND_LLD_H_ */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -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/USARTv1/serial_lld.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/USARTv1/uart_lld.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/emc_lld.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/emcnand_lld.c
${CHIBIOS}/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c \
${CHIBIOS}/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c
# Required include directories
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/SPIv1 \
${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

View File

@ -327,16 +327,16 @@
#endif /* defined(STM32F401xx) */
/* EMC attributes.*/
#define STM32_HAS_EMC TRUE
#define STM32_EMC_DMA_MSK (STM32_DMA_STREAM_ID_MSK(2, 0) | \
STM32_DMA_STREAM_ID_MSK(2, 1) | \
STM32_DMA_STREAM_ID_MSK(2, 2) | \
STM32_DMA_STREAM_ID_MSK(2, 3) | \
STM32_DMA_STREAM_ID_MSK(2, 4) | \
STM32_DMA_STREAM_ID_MSK(2, 5) | \
STM32_DMA_STREAM_ID_MSK(2, 6) | \
#define STM32_HAS_FSMC TRUE
#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, 2) |\
STM32_DMA_STREAM_ID_MSK(2, 3) |\
STM32_DMA_STREAM_ID_MSK(2, 4) |\
STM32_DMA_STREAM_ID_MSK(2, 5) |\
STM32_DMA_STREAM_ID_MSK(2, 6) |\
STM32_DMA_STREAM_ID_MSK(2, 7))
#define STM32_EMC_DMA_CHN 0x03010201
#define STM32_FSMC_DMA_CHN 0x03010201
/** @} */
#endif /* _STM32_REGISTRY_H_ */

View File

@ -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 */
/** @} */

View File

@ -23,16 +23,16 @@
*/
/**
* @file emcnand.c
* @brief EMCNAND Driver code.
* @file nand.c
* @brief NAND Driver code.
*
* @addtogroup EMCNAND
* @addtogroup NAND
* @{
*/
#include "hal.h"
#if HAL_USE_EMCNAND || defined(__DOXYGEN__)
#if HAL_USE_NAND || defined(__DOXYGEN__)
#include "string.h" /* for memset */
@ -66,8 +66,8 @@
static void pagesize_check(size_t page_data_size){
/* Page size out of bounds.*/
osalDbgCheck((page_data_size >= EMCNAND_MIN_PAGE_SIZE) &&
(page_data_size <= EMCNAND_MAX_PAGE_SIZE));
osalDbgCheck((page_data_size >= NAND_MIN_PAGE_SIZE) &&
(page_data_size <= NAND_MAX_PAGE_SIZE));
/* Page size must be power of 2.*/
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.
*
* @param[in] cfg pointer to the @p EMCNANDConfig from
* @param[in] cfg pointer to the @p NANDConfig from
* corresponding NAND driver
* @param[in] block block number
* @param[in] page page number related to begin of block
@ -86,7 +86,7 @@ static void pagesize_check(size_t page_data_size){
*
* @notapi
*/
static void calc_addr(const EMCNANDConfig *cfg,
static void calc_addr(const NANDConfig *cfg,
uint32_t block, uint32_t page, uint32_t offset,
uint8_t *addr, size_t addr_len){
size_t i = 0;
@ -114,7 +114,7 @@ static void calc_addr(const EMCNANDConfig *cfg,
* @brief Translate block number to NAND internal address.
* @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
* @param[in] block block number
* @param[out] addr buffer to store calculated address
@ -122,7 +122,7 @@ static void calc_addr(const EMCNANDConfig *cfg,
*
* @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){
size_t i = 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.
*
* @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] 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 */
size_t i;
size_t shift;
/* Nand device overflow.*/
osalDbgCheck(emcnandp->config->blocks > block);
osalDbgCheck(nandp->config->blocks > block);
i = 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.
*
* @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;
size_t b;
@ -181,104 +181,104 @@ static void scan_bad_blocks(EMCNANDDriver *emcnandp) {
/* clear map just to be safe */
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 */
for (b=0; b<blocks; b++){
m0 = emcnandReadBadMark(emcnandp, b, 0);
m1 = emcnandReadBadMark(emcnandp, b, 1);
m0 = nandReadBadMark(nandp, b, 0);
m1 = nandReadBadMark(nandp, b, 1);
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. */
/*===========================================================================*/
/**
* @brief EMCNAND Driver initialization.
* @brief NAND Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @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
*/
void emcnandObjectInit(EMCNANDDriver *emcnandp) {
void nandObjectInit(NANDDriver *nandp) {
#if EMCNAND_USE_MUTUAL_EXCLUSION
#if NAND_USE_MUTUAL_EXCLUSION
#if CH_CFG_USE_MUTEXES
chMtxObjectInit(&emcnandp->mutex);
chMtxObjectInit(&nandp->mutex);
#else
chSemObjectInit(&emcnandp->semaphore, 1);
chSemObjectInit(&nandp->semaphore, 1);
#endif /* CH_CFG_USE_MUTEXES */
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
#endif /* NAND_USE_MUTUAL_EXCLUSION */
emcnandp->state = EMCNAND_STOP;
emcnandp->config = NULL;
nandp->state = NAND_STOP;
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] config pointer to the @p EMCNANDConfig object
* @param[in] nandp pointer to the @p NANDDriver object
* @param[in] config pointer to the @p NANDConfig object
*
* @api
*/
void emcnandStart(EMCNANDDriver *emcnandp, const EMCNANDConfig *config) {
void nandStart(NANDDriver *nandp, const NANDConfig *config) {
osalDbgCheck((emcnandp != NULL) && (config != NULL));
osalDbgAssert(config->emcp->state == EMC_READY,
osalDbgCheck((nandp != NULL) && (config != NULL));
osalDbgAssert(config->fsmcp->state == FSMC_READY,
"lower level driver not ready");
osalDbgAssert((emcnandp->state == EMCNAND_STOP) ||
(emcnandp->state == EMCNAND_READY),
osalDbgAssert((nandp->state == NAND_STOP) ||
(nandp->state == NAND_READY),
"invalid state");
emcnandp->config = config;
pagesize_check(emcnandp->config->page_data_size);
emcnand_lld_start(emcnandp);
emcnandp->state = EMCNAND_READY;
nandp->config = config;
pagesize_check(nandp->config->page_data_size);
nand_lld_start(nandp);
nandp->state = NAND_READY;
#if EMCNAND_USE_BAD_MAP
scan_bad_blocks(emcnandp);
#endif /* EMCNAND_USE_BAD_MAP */
#if NAND_USE_BAD_MAP
scan_bad_blocks(nandp);
#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
*/
void emcnandStop(EMCNANDDriver *emcnandp) {
void nandStop(NANDDriver *nandp) {
osalDbgCheck(emcnandp != NULL);
osalDbgAssert((emcnandp->state == EMCNAND_STOP) ||
(emcnandp->state == EMCNAND_READY),
osalDbgCheck(nandp != NULL);
osalDbgAssert((nandp->state == NAND_STOP) ||
(nandp->state == NAND_READY),
"invalid state");
emcnand_lld_stop(emcnandp);
emcnandp->state = EMCNAND_STOP;
nand_lld_stop(nandp);
nandp->state = NAND_STOP;
}
/**
* @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] page page number related to begin of block
* @param[out] data buffer to store data
@ -286,25 +286,25 @@ void emcnandStop(EMCNANDDriver *emcnandp) {
*
* @api
*/
void emcnandReadPageWhole(EMCNANDDriver *emcnandp, uint32_t block,
void nandReadPageWhole(NANDDriver *nandp, uint32_t block,
uint32_t page, uint8_t *data, size_t datalen) {
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addrbuf[8];
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)));
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
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.
*
* @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] page page number related to begin of block
* @param[in] data buffer with data to be written
@ -314,27 +314,27 @@ void emcnandReadPageWhole(EMCNANDDriver *emcnandp, uint32_t block,
*
* @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) {
uint8_t retval;
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addr[8];
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)));
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
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;
}
/**
* @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] page page number related to begin of block
* @param[out] data buffer to store data
@ -343,25 +343,25 @@ uint8_t emcnandWritePageWhole(EMCNANDDriver *emcnandp, uint32_t block,
*
* @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) {
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addrbuf[8];
size_t addrlen = cfg->rowcycles + cfg->colcycles;
osalDbgCheck((emcnandp != NULL) && (data != NULL));
osalDbgCheck((nandp != NULL) && (data != NULL));
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);
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.
*
* @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] page page number related to begin of block
* @param[in] data buffer with data to be written
@ -372,27 +372,27 @@ void emcnandReadPageData(EMCNANDDriver *emcnandp, uint32_t block, uint32_t page,
*
* @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) {
uint8_t retval;
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addr[8];
size_t addrlen = cfg->rowcycles + cfg->colcycles;
osalDbgCheck((emcnandp != NULL) && (data != NULL));
osalDbgCheck((nandp != NULL) && (data != NULL));
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);
retval = emcnand_lld_write_data(emcnandp, data, datalen, addr, addrlen, ecc);
retval = nand_lld_write_data(nandp, data, datalen, addr, addrlen, ecc);
return retval;
}
/**
* @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] page page number related to begin of block
* @param[out] spare buffer to store data
@ -400,25 +400,25 @@ uint8_t emcnandWritePageData(EMCNANDDriver *emcnandp, uint32_t block,
*
* @api
*/
void emcnandReadPageSpare(EMCNANDDriver *emcnandp, uint32_t block,
void nandReadPageSpare(NANDDriver *nandp, uint32_t block,
uint32_t page, uint8_t *spare, size_t sparelen) {
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addr[8];
size_t addrlen = cfg->rowcycles + cfg->colcycles;
osalDbgCheck((NULL != spare) && (emcnandp != NULL));
osalDbgCheck((NULL != spare) && (nandp != NULL));
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);
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.
*
* @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] page page number related to begin of block
* @param[in] spare buffer with spare data to be written
@ -428,49 +428,49 @@ void emcnandReadPageSpare(EMCNANDDriver *emcnandp, uint32_t block,
*
* @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) {
uint8_t retVal;
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addr[8];
size_t addrlen = cfg->rowcycles + cfg->colcycles;
osalDbgCheck((NULL != spare) && (emcnandp != NULL));
osalDbgCheck((NULL != spare) && (nandp != NULL));
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);
retVal = emcnand_lld_write_data(emcnandp, spare, sparelen, addr, addrlen, NULL);
retVal = nand_lld_write_data(nandp, spare, sparelen, addr, addrlen, NULL);
return retVal;
}
/**
* @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
*
* @api
*/
void emcnandMarkBad(EMCNANDDriver *emcnandp, uint32_t block) {
void nandMarkBad(NANDDriver *nandp, uint32_t block) {
uint8_t bb_mark[2] = {0, 0};
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*/
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*/
#if EMCNAND_USE_BAD_MAP
bad_map_update(emcnandp, block);
#if NAND_USE_BAD_MAP
bad_map_update(nandp, block);
#endif
}
/**
* @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] page page number related to begin of block
*
@ -478,42 +478,42 @@ void emcnandMarkBad(EMCNANDDriver *emcnandp, uint32_t block) {
*
* @api
*/
uint8_t emcnandReadBadMark(EMCNANDDriver *emcnandp,
uint8_t nandReadBadMark(NANDDriver *nandp,
uint32_t block, uint32_t page) {
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];
}
/**
* @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
*
* @return The operation status reported by NAND IC (0x70 command).
*
* @api
*/
uint8_t emcnandErase(EMCNANDDriver *emcnandp, uint32_t block){
uint8_t nandErase(NANDDriver *nandp, uint32_t block){
uint8_t retVal;
const EMCNANDConfig *cfg = emcnandp->config;
const NANDConfig *cfg = nandp->config;
uint8_t addr[4];
size_t addrlen = cfg->rowcycles;
osalDbgCheck(emcnandp != NULL);
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
osalDbgCheck(nandp != NULL);
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
calc_blk_addr(cfg, block, addr, addrlen);
retVal = emcnand_lld_erase(emcnandp, addr, addrlen);
retVal = nand_lld_erase(nandp, addr, addrlen);
return retVal;
}
/**
* @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
*
* @return block condition
@ -522,13 +522,13 @@ uint8_t emcnandErase(EMCNANDDriver *emcnandp, uint32_t block){
*
* @api
*/
bool emcnandIsBad(EMCNANDDriver *emcnandp, uint32_t block){
bool nandIsBad(NANDDriver *nandp, uint32_t block){
osalDbgCheck(emcnandp != NULL);
osalDbgAssert(emcnandp->state == EMCNAND_READY, "invalid state");
osalDbgCheck(nandp != NULL);
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
#if EMCNAND_USE_BAD_MAP
uint32_t *map = emcnandp->config->bb_map;
#if NAND_USE_BAD_MAP
uint32_t *map = nandp->config->bb_map;
const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */
size_t i;
size_t shift;
@ -541,60 +541,60 @@ bool emcnandIsBad(EMCNANDDriver *emcnandp, uint32_t block){
return false;
#else
uint8_t m0, m1;
m0 = emcnandReadBadMark(emcnandp, block, 0);
m1 = emcnandReadBadMark(emcnandp, block, 1);
m0 = nandReadBadMark(nandp, block, 0);
m1 = nandReadBadMark(nandp, block, 1);
if ((0xFF != m0) || (0xFF != m1))
return true;
else
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.
* @details This function tries to gain ownership to the EMCNAND bus, if the bus
* @brief Gains exclusive access to the NAND 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.
* @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
*/
void emcnandAcquireBus(EMCNANDDriver *emcnandp) {
void nandAcquireBus(NANDDriver *nandp) {
osalDbgCheck(emcnandp != NULL);
osalDbgCheck(nandp != NULL);
#if CH_CFG_USE_MUTEXES
chMtxLock(&emcnandp->mutex);
chMtxLock(&nandp->mutex);
#elif CH_CFG_USE_SEMAPHORES
chSemWait(&emcnandp->semaphore);
chSemWait(&nandp->semaphore);
#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
* @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
*/
void emcnandReleaseBus(EMCNANDDriver *emcnandp) {
void nandReleaseBus(NANDDriver *nandp) {
osalDbgCheck(emcnandp != NULL);
osalDbgCheck(nandp != NULL);
#if CH_CFG_USE_MUTEXES
chMtxUnlock(&emcnandp->mutex);
chMtxUnlock(&nandp->mutex);
#elif CH_CFG_USE_SEMAPHORES
chSemSignal(&emcnandp->semaphore);
chSemSignal(&nandp->semaphore);
#endif
}
#endif /* EMCNAND_USE_MUTUAL_EXCLUSION */
#endif /* NAND_USE_MUTUAL_EXCLUSION */
#endif /* HAL_USE_EMCNAND */
#endif /* HAL_USE_NAND */
/** @} */

View File

@ -157,17 +157,10 @@
#endif
/**
* @brief Enables the EMC subsystem.
* @brief Enables the NAND subsystem.
*/
#if !defined(HAL_USE_EMC) || defined(__DOXYGEN__)
#define HAL_USE_EMC TRUE
#endif
/**
* @brief Enables the NAND over EMC subsystem.
*/
#if !defined(HAL_USE_EMCNAND) || defined(__DOXYGEN__)
#define HAL_USE_EMCNAND TRUE
#if !defined(HAL_USE_NAND) || defined(__DOXYGEN__)
#define HAL_USE_NAND TRUE
#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.
*/
#if !defined(EMCNAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define EMCNAND_USE_MUTUAL_EXCLUSION TRUE
#if !defined(NAND_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define NAND_USE_MUTUAL_EXCLUSION TRUE
#endif
/**
* @brief Enables internal driver map for bad blocks.
* @note Disabling this option saves both code and data space.
*/
#if !defined(EMCNAND_USE_BAD_MAP) || defined(__DOXYGEN__)
#define EMCNAND_USE_BAD_MAP TRUE
#if !defined(NAND_USE_BAD_MAP) || defined(__DOXYGEN__)
#define NAND_USE_BAD_MAP TRUE
#endif
#endif /* _HALCONF_H_ */

View File

@ -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 EMCNAND_TIME_WAIT ((uint32_t) 6) //(30nS)
#define EMCNAND_TIME_HOLD ((uint32_t) 1) //(5nS)
#define EMCNAND_TIME_HIZ ((uint32_t) 4) //(20nS)
#define FSMCNAND_TIME_SET ((uint32_t) 2) //(8nS)
#define FSMCNAND_TIME_WAIT ((uint32_t) 6) //(30nS)
#define FSMCNAND_TIME_HOLD ((uint32_t) 1) //(5nS)
#define FSMCNAND_TIME_HIZ ((uint32_t) 4) //(20nS)
#define NAND_BLOCKS_COUNT 8192
#define NAND_PAGE_DATA_SIZE 2048
@ -82,7 +82,7 @@
* PROTOTYPES
******************************************************************************
*/
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
#if !STM32_NAND_USE_FSMC_INT
static void ready_isr_enable(void);
static void ready_isr_disable(void);
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_spare;
/*
*
*/
static const EMCConfig emccfg = {};
#if EMCNAND_USE_BAD_MAP
#if NAND_USE_BAD_MAP
static uint32_t badblock_map[NAND_BLOCKS_COUNT / 32];
#endif
/*
*
*/
static const EMCNANDConfig nandcfg = {
&EMCD1,
static const NANDConfig nandcfg = {
&FSMCD1,
NAND_BLOCKS_COUNT,
NAND_PAGE_DATA_SIZE,
NAND_PAGE_SPARE_SIZE,
NAND_PAGES_PER_BLOCK,
#if EMCNAND_USE_BAD_MAP
#if NAND_USE_BAD_MAP
badblock_map,
#endif
NAND_ROW_WRITE_CYCLES,
NAND_COL_WRITE_CYCLES,
/* stm32 specific fields */
((EMCNAND_TIME_HIZ << 24) | (EMCNAND_TIME_HOLD << 16) | \
(EMCNAND_TIME_WAIT << 8) | EMCNAND_TIME_SET),
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
((FSMCNAND_TIME_HIZ << 24) | (FSMCNAND_TIME_HOLD << 16) | \
(FSMCNAND_TIME_WAIT << 8) | FSMCNAND_TIME_SET),
#if !STM32_NAND_USE_FSMC_INT
ready_isr_enable,
ready_isr_disable
#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 = {
{
{EXT_CH_MODE_DISABLED, NULL}, //0
@ -171,7 +166,7 @@ static const EXTConfig extcfg = {
{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){
(void)extp;
(void)channel;
EMCNANDD1.isr_handler(&EMCNANDD1);
NANDD1.isr_handler(&NANDD1);
}
static void ready_isr_enable(void) {
@ -206,7 +201,7 @@ static void ready_isr_enable(void) {
static void ready_isr_disable(void) {
extChannelDisable(&EXTD1, GPIOD_NAND_RB);
}
#endif
#endif /* STM32_NAND_USE_FSMC_INT */
static void nand_wp_assert(void) {
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;
size_t i = 0;
for (page=0; page<EMCNANDD1.config->pages_per_block; page++){
emcnandReadPageData(dp, block, page, nand_buf, EMCNANDD1.config->page_data_size, NULL);
emcnandReadPageSpare(dp, block, page, &nand_buf[2048], EMCNANDD1.config->page_spare_size);
for (page=0; page<NANDD1.config->pages_per_block; page++){
nandReadPageData(dp, block, page, nand_buf, NANDD1.config->page_data_size, NULL);
nandReadPageSpare(dp, block, page, &nand_buf[2048], NANDD1.config->page_spare_size);
for (i=0; i<sizeof(nand_buf); i++) {
if (nand_buf[i] != 0xFF)
return false;
@ -278,37 +273,37 @@ static void pattern_fill(void) {
osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE));
}
#if EMCNAND_USE_KILL_TEST
static void kill_block(EMCNANDDriver *emcnandp, uint32_t block){
#if USE_KILL_BLOCK_TEST
static void kill_block(NANDDriver *nandp, uint32_t block){
size_t i = 0;
size_t page = 0;
uint8_t op_status;
/* This test require good block.*/
osalDbgCheck(!emcnandIsBad(emcnandp, block));
osalDbgCheck(!nandIsBad(nandp, block));
while(true){
op_status = emcnandErase(&EMCNANDD1, block);
op_status = nandErase(&NANDD1, block);
if (0 != (op_status & 1)){
if(!isErased(emcnandp, block))
if(!is_erased(nandp, block))
osalSysHalt("Block successfully killed");
}
if(!isErased(emcnandp, block))
if(!is_erased(nandp, block))
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);
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)){
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++){
if (nand_buf[i] != 0)
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++){
if (nand_buf[i] != 0)
osalSysHalt("Page write failed, but write operation report success");
@ -317,7 +312,7 @@ static void kill_block(EMCNANDDriver *emcnandp, uint32_t block){
KillCycle++;
}
}
#endif /* EMCNAND_USE_KILL_TEST */
#endif /* USE_KILL_BLOCK_TEST */
typedef enum {
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 byte, bit;
@ -380,18 +375,18 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
ecc_result_t ecc_result = ECC_NO_ERROR;
/* This test requires good block.*/
osalDbgCheck(!emcnandIsBad(emcnandp, block));
if (!isErased(emcnandp, block))
emcnandErase(&EMCNANDD1, block);
osalDbgCheck(!nandIsBad(nandp, block));
if (!is_erased(nandp, block))
nandErase(&NANDD1, block);
pattern_fill();
/*** Correctable errors ***/
op_status = emcnandWritePageData(emcnandp, block, 0,
nand_buf, emcnandp->config->page_data_size, &ecc_ref);
op_status = nandWritePageData(nandp, block, 0,
nand_buf, nandp->config->page_data_size, &ecc_ref);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
emcnandReadPageData(emcnandp, block, 0,
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
nandReadPageData(nandp, block, 0,
nand_buf, nandp->config->page_data_size, &ecc_broken);
ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted);
osalDbgCheck(ECC_NO_ERROR == ecc_result); /* unexpected error */
@ -399,8 +394,8 @@ static void ecc_test(EMCNANDDriver *emcnandp, uint32_t block){
byte = 0;
bit = 7;
invert_bit(nand_buf, byte, bit);
op_status = emcnandWritePageData(emcnandp, block, 1,
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
op_status = nandWritePageData(nandp, block, 1,
nand_buf, nandp->config->page_data_size, &ecc_broken);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
invert_bit(nand_buf, byte, bit);
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;
bit = 0;
invert_bit(nand_buf, byte, bit);
op_status = emcnandWritePageData(emcnandp, block, 2,
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
op_status = nandWritePageData(nandp, block, 2,
nand_buf, nandp->config->page_data_size, &ecc_broken);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
invert_bit(nand_buf, byte, bit);
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;
bit = 3;
invert_bit(nand_buf, byte, bit);
op_status = emcnandWritePageData(emcnandp, block, 3,
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
op_status = nandWritePageData(nandp, block, 3,
nand_buf, nandp->config->page_data_size, &ecc_broken);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
invert_bit(nand_buf, byte, bit);
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;
invert_bit(nand_buf, byte, 3);
invert_bit(nand_buf, byte, 4);
op_status = emcnandWritePageData(emcnandp, block, 4,
nand_buf, emcnandp->config->page_data_size, &ecc_broken);
op_status = nandWritePageData(nandp, block, 4,
nand_buf, nandp->config->page_data_size, &ecc_broken);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
invert_bit(nand_buf, byte, 3);
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 */
/*** 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 block, page, round;
@ -470,9 +465,9 @@ static void general_test (EMCNANDDriver *emcnandp, size_t first,
/* perform basic checks */
for (block=first; block<last; block++){
if (!emcnandIsBad(emcnandp, block)){
if (!isErased(emcnandp, block)){
op_status = emcnandErase(emcnandp, block);
if (!nandIsBad(nandp, block)){
if (!is_erased(nandp, block)){
op_status = nandErase(nandp, block);
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 */
for (block=first; block<last; block++){
if (!emcnandIsBad(emcnandp, block)){
for (page=0; page<emcnandp->config->pages_per_block; page++){
if (!nandIsBad(nandp, block)){
for (page=0; page<nandp->config->pages_per_block; page++){
pattern_fill();
//tmStartMeasurement(&tmu_write_data);
op_status = emcnandWritePageData(emcnandp, block, page,
nand_buf, emcnandp->config->page_data_size, &wecc);
op_status = nandWritePageData(nandp, block, page,
nand_buf, nandp->config->page_data_size, &wecc);
//tmStopMeasurement(&tmu_write_data);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
//tmStartMeasurement(&tmu_write_spare);
op_status = emcnandWritePageSpare(emcnandp, block, page,
nand_buf + emcnandp->config->page_data_size,
emcnandp->config->page_spare_size);
op_status = nandWritePageSpare(nandp, block, page,
nand_buf + nandp->config->page_data_size,
nandp->config->page_spare_size);
//tmStopMeasurement(&tmu_write_spare);
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);
//tmStartMeasurement(&tmu_read_data);
emcnandReadPageData(emcnandp, block, page,
nand_buf, emcnandp->config->page_data_size, &recc);
nandReadPageData(nandp, block, page,
nand_buf, nandp->config->page_data_size, &recc);
//tmStopMeasurement(&tmu_read_data);
osalDbgCheck(0 == (recc ^ wecc)); /* ECC error detected */
//tmStartMeasurement(&tmu_read_spare);
emcnandReadPageSpare(emcnandp, block, page,
nand_buf + emcnandp->config->page_data_size,
emcnandp->config->page_spare_size);
nandReadPageSpare(nandp, block, page,
nand_buf + nandp->config->page_data_size,
nandp->config->page_spare_size);
//tmStopMeasurement(&tmu_read_spare);
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 */
//tmStartMeasurement(&tmu_erase);
op_status = emcnandErase(emcnandp, block);
op_status = nandErase(nandp, block);
//tmStopMeasurement(&tmu_erase);
osalDbgCheck(0 == (op_status & 1)); /* operation failed */
status = isErased(emcnandp, block);
status = is_erased(nandp, block);
osalDbgCheck(true == status); /* blocks was not erased successfully */
}/* if (!emcnandIsBad(emcnandp, block)){ */
}/* if (!nandIsBad(nandp, block)){ */
}
red_led_off();
}
@ -552,7 +547,7 @@ int main(void) {
volatile int32_t uart_its_idle = 0;
volatile uint32_t idle_thread_cnt = 0;
#if EMCNAND_USE_KILL_TEST
#if USE_KILL_BLOCK_TEST
size_t kill = 8000;
#endif
@ -566,11 +561,10 @@ int main(void) {
halInit();
chSysInit();
emcStart(&EMCD1, &emccfg);
#if !STM32_EMC_EMCNAND_USE_FSMC_INT
#if !STM32_NAND_USE_FSMC_INT
extStart(&EXTD1, &extcfg);
#endif
emcnandStart(&EMCNANDD1, &nandcfg);
nandStart(&NANDD1, &nandcfg);
chThdSleepMilliseconds(4000);
@ -586,7 +580,7 @@ int main(void) {
dma_storm_uart_start();
dma_storm_spi_start();
T = chVTGetSystemTimeX();
general_test(&EMCNANDD1, start, end, 1);
general_test(&NANDD1, start, end, 1);
T = chVTGetSystemTimeX() - T;
adc_its = dma_storm_adc_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(spi_its - spi_its_idle) < (spi_its_idle / 10));
ecc_test(&EMCNANDD1, end);
ecc_test(&NANDD1, end);
#if EMCNAND_USE_KILL_TEST
kill_block(&EMCNANDD1, kill);
#if USE_KILL_BLOCK_TEST
kill_block(&NANDD1, kill);
#endif
nand_wp_assert();

View File

@ -304,13 +304,13 @@
#define STM32_USB_OTGFIFO_FILL_BASEPRI 0
/*
* EMC driver system settings.
* FSMC driver system settings.
*/
#define STM32_EMC_USE_FSMC1 TRUE
#define STM32_EMC_FSMC1_IRQ_PRIORITY 10
#define STM32_EMC_EMCNAND_USE_FSMC_INT FALSE
#define STM32_FSMC_USE_FSMC1 TRUE
#define STM32_FSMC_FSMC1_IRQ_PRIORITY 10
#define STM32_EMCNAND_USE_EMCNAND1 TRUE
#define STM32_EMCNAND_EMCNAND1_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_EMCNAND_EMCNAND1_DMA_PRIORITY 0
#define STM32_EMCNAND_DMA_ERROR_HOOK(emcnandp) osalSysHalt("DMA failure")
#define STM32_NAND_USE_FSMC_NAND1 TRUE
#define STM32_NAND_USE_FSMC_INT FALSE
#define STM32_NAND_DMA_STREAM STM32_DMA_STREAM_ID(2, 7)
#define STM32_NAND_DMA_PRIORITY 0
#define STM32_NAND_DMA_ERROR_HOOK(nandp) osalSysHalt("DMA failure")