FSMC NAND improvements.
1) Implemented 16 bit bus width support 2) Added workaround errata in STM32
This commit is contained in:
parent
d2aaea434a
commit
88c55f1aaa
|
@ -107,21 +107,21 @@ extern "C" {
|
|||
void nandObjectInit(NANDDriver *nandp);
|
||||
void nandStart(NANDDriver *nandp, const NANDConfig *config, bitmap_t *bb_map);
|
||||
void nandStop(NANDDriver *nandp);
|
||||
void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
uint8_t *data, size_t datalen);
|
||||
void nandMarkBad(NANDDriver *nandp, uint32_t block);
|
||||
void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
uint8_t *data, size_t datalen, uint32_t *ecc);
|
||||
void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
uint8_t *spare, size_t sparelen);
|
||||
uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const uint8_t *data, size_t datalen);
|
||||
uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const uint8_t *data, size_t datalen, uint32_t *ecc);
|
||||
uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const uint8_t *spare, size_t sparelen);
|
||||
uint8_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page);
|
||||
uint8_t nandErase(NANDDriver *nandp, uint32_t block);
|
||||
void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
void *data, size_t datalen);
|
||||
void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
void *data, size_t datalen, uint32_t *ecc);
|
||||
void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
void *spare, size_t sparelen);
|
||||
uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const void *data, size_t datalen);
|
||||
uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const void *data, size_t datalen, uint32_t *ecc);
|
||||
uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const void *spare, size_t sparelen);
|
||||
uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page);
|
||||
void nandMarkBad(NANDDriver *nandp, uint32_t block);
|
||||
bool nandIsBad(NANDDriver *nandp, uint32_t block);
|
||||
#if NAND_USE_MUTUAL_EXCLUSION
|
||||
void nandAcquireBus(NANDDriver *nandp);
|
||||
|
|
|
@ -177,10 +177,15 @@ typedef struct {
|
|||
/**
|
||||
* @brief PCR register
|
||||
*/
|
||||
#define FSMC_PCR_PWAITEN ((uint32_t)0x00000002)
|
||||
#define FSMC_PCR_PBKEN ((uint32_t)0x00000004)
|
||||
#define FSMC_PCR_PTYP ((uint32_t)0x00000008)
|
||||
#define FSMC_PCR_ECCEN ((uint32_t)0x00000040)
|
||||
#define FSMC_PCR_PWAITEN ((uint32_t)1 << 1)
|
||||
#define FSMC_PCR_PBKEN ((uint32_t)1 << 2)
|
||||
#define FSMC_PCR_PTYP ((uint32_t)1 << 3)
|
||||
#define FSMC_PCR_PWID_8 ((uint32_t)0 << 4)
|
||||
#define FSMC_PCR_PWID_16 ((uint32_t)1 << 4)
|
||||
#define FSMC_PCR_PWID_RESERVED1 ((uint32_t)2 << 4)
|
||||
#define FSMC_PCR_PWID_RESERVED2 ((uint32_t)3 << 4)
|
||||
#define FSMC_PCR_PWID_MASK ((uint32_t)3 << 4)
|
||||
#define FSMC_PCR_ECCEN ((uint32_t)1 << 6)
|
||||
#define FSMC_PCR_PTYP_PCCARD 0
|
||||
#define FSMC_PCR_PTYP_NAND FSMC_PCR_PTYP
|
||||
|
||||
|
|
|
@ -33,6 +33,19 @@
|
|||
STM32_DMA_GETCHANNEL(STM32_NAND_DMA_STREAM, \
|
||||
STM32_FSMC_DMA_CHN)
|
||||
|
||||
/**
|
||||
* @brief Bus width of NAND IC.
|
||||
* @details Must be 8 or 16
|
||||
*/
|
||||
#if ! defined(STM32_NAND_BUS_WIDTH) || defined(__DOXYGEN__)
|
||||
#define STM32_NAND_BUS_WIDTH 8
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief DMA transaction width on AHB bus in bytes
|
||||
*/
|
||||
#define AHB_TRANSACTION_WIDTH 2
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
@ -62,6 +75,47 @@ NANDDriver NANDD2;
|
|||
/*===========================================================================*/
|
||||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Helper function.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void align_check(const void *ptr, uint32_t len) {
|
||||
osalDbgCheck((((uint32_t)ptr % AHB_TRANSACTION_WIDTH) == 0) &&
|
||||
((len % AHB_TRANSACTION_WIDTH) == 0) &&
|
||||
(len >= AHB_TRANSACTION_WIDTH));
|
||||
(void)ptr;
|
||||
(void)len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Work around errata in STM32's FSMC core.
|
||||
* @details Constant output clock (if enabled) disappears when CLKDIV value
|
||||
* sets to 1 (FMC_CLK period = 2 × HCLK periods) AND 8-bit async
|
||||
* transaction generated on AHB. This workaround eliminates 8-bit
|
||||
* transactions on bus when you use 8-bit memory. It suitable only
|
||||
* for 8-bit memory (i.e. PWID bits in PCR register must be set
|
||||
* to 8-bit mode).
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void set_16bit_bus(NANDDriver *nandp) {
|
||||
#if STM32_NAND_BUS_WIDTH
|
||||
nandp->nand->PCR |= FSMC_PCR_PWID_16;
|
||||
#else
|
||||
(void)nandp;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_8bit_bus(NANDDriver *nandp) {
|
||||
#if STM32_NAND_BUS_WIDTH
|
||||
nandp->nand->PCR &= ~FSMC_PCR_PWID_16;
|
||||
#else
|
||||
(void)nandp;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wakes up the waiting thread.
|
||||
*
|
||||
|
@ -142,7 +196,7 @@ static void nand_ready_isr_disable(NANDDriver *nandp) {
|
|||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void nand_isr_handler (NANDDriver *nandp) {
|
||||
static void nand_isr_handler(NANDDriver *nandp) {
|
||||
|
||||
osalSysLockFromISR();
|
||||
|
||||
|
@ -152,8 +206,8 @@ static void nand_isr_handler (NANDDriver *nandp) {
|
|||
switch (nandp->state){
|
||||
case NAND_READ:
|
||||
nandp->state = NAND_DMA_RX;
|
||||
dmaStartMemCopy(nandp->dma, nandp->dmamode,
|
||||
nandp->map_data, nandp->rxdata, nandp->datalen);
|
||||
dmaStartMemCopy(nandp->dma, nandp->dmamode, nandp->map_data, nandp->rxdata,
|
||||
nandp->datalen/AHB_TRANSACTION_WIDTH);
|
||||
/* thread will be waked up from DMA ISR */
|
||||
break;
|
||||
|
||||
|
@ -197,7 +251,7 @@ static void nand_lld_serve_transfer_end_irq(NANDDriver *nandp, uint32_t flags) {
|
|||
case NAND_DMA_TX:
|
||||
nandp->state = NAND_PROGRAM;
|
||||
nandp->map_cmd[0] = NAND_CMD_PAGEPROG;
|
||||
/* thread will be woken from ready_isr() */
|
||||
/* thread will be woken up from ready_isr() */
|
||||
break;
|
||||
|
||||
case NAND_DMA_RX:
|
||||
|
@ -236,9 +290,9 @@ void nand_lld_init(void) {
|
|||
NANDD1.thread = NULL;
|
||||
NANDD1.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM);
|
||||
NANDD1.nand = FSMCD1.nand1;
|
||||
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;
|
||||
NANDD1.map_data = (void *)FSMC_Bank2_MAP_COMMON_DATA;
|
||||
NANDD1.map_cmd = (uint16_t *)FSMC_Bank2_MAP_COMMON_CMD;
|
||||
NANDD1.map_addr = (uint16_t *)FSMC_Bank2_MAP_COMMON_ADDR;
|
||||
NANDD1.bb_map = NULL;
|
||||
#endif /* STM32_NAND_USE_FSMC_NAND1 */
|
||||
|
||||
|
@ -250,9 +304,9 @@ void nand_lld_init(void) {
|
|||
NANDD2.thread = NULL;
|
||||
NANDD2.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM);
|
||||
NANDD2.nand = FSMCD1.nand2;
|
||||
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;
|
||||
NANDD2.map_data = (void *)FSMC_Bank3_MAP_COMMON_DATA;
|
||||
NANDD2.map_cmd = (uint16_t *)FSMC_Bank3_MAP_COMMON_CMD;
|
||||
NANDD2.map_addr = (uint16_t *)FSMC_Bank3_MAP_COMMON_ADDR;
|
||||
NANDD2.bb_map = NULL;
|
||||
#endif /* STM32_NAND_USE_FSMC_NAND2 */
|
||||
}
|
||||
|
@ -267,6 +321,8 @@ void nand_lld_init(void) {
|
|||
void nand_lld_start(NANDDriver *nandp) {
|
||||
|
||||
bool b;
|
||||
uint32_t dmasize;
|
||||
uint32_t pcr_bus_width;
|
||||
|
||||
if (FSMCD1.state == FSMC_STOP)
|
||||
fsmc_start(&FSMCD1);
|
||||
|
@ -277,16 +333,34 @@ void nand_lld_start(NANDDriver *nandp) {
|
|||
(stm32_dmaisr_t)nand_lld_serve_transfer_end_irq,
|
||||
(void *)nandp);
|
||||
osalDbgAssert(!b, "stream already allocated");
|
||||
|
||||
#if AHB_TRANSACTION_WIDTH == 4
|
||||
dmasize = STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD;
|
||||
#elif AHB_TRANSACTION_WIDTH == 2
|
||||
dmasize = STM32_DMA_CR_PSIZE_HWORD | STM32_DMA_CR_MSIZE_HWORD;
|
||||
#elif AHB_TRANSACTION_WIDTH == 1
|
||||
dmasize = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE;
|
||||
#else
|
||||
#error "Incorrect AHB_TRANSACTION_WIDTH"
|
||||
#endif
|
||||
|
||||
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 |
|
||||
dmasize |
|
||||
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;
|
||||
|
||||
#if STM32_NAND_BUS_WIDTH == 8
|
||||
pcr_bus_width = FSMC_PCR_PWID_8;
|
||||
#elif
|
||||
STM32_NAND_BUS_WIDTH == 16
|
||||
pcr_bus_width = FSMC_PCR_PWID_16;
|
||||
#else
|
||||
#error "Bus width must be 8 or 16 bits"
|
||||
#endif
|
||||
nandp->nand->PCR = pcr_bus_width | calc_eccps(nandp) |
|
||||
FSMC_PCR_PTYP_NAND | FSMC_PCR_PBKEN;
|
||||
nandp->nand->PMEM = nandp->config->pmem;
|
||||
nandp->nand->PATT = nandp->config->pmem;
|
||||
nandp->isr_handler = nand_isr_handler;
|
||||
|
@ -316,24 +390,28 @@ void nand_lld_stop(NANDDriver *nandp) {
|
|||
*
|
||||
* @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] datalen size of data buffer in bytes
|
||||
* @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,
|
||||
void nand_lld_read_data(NANDDriver *nandp, uint16_t *data, size_t datalen,
|
||||
uint8_t *addr, size_t addrlen, uint32_t *ecc){
|
||||
|
||||
align_check(data, datalen);
|
||||
|
||||
nandp->state = NAND_READ;
|
||||
nandp->rxdata = data;
|
||||
nandp->datalen = datalen;
|
||||
|
||||
nand_lld_write_cmd (nandp, NAND_CMD_READ0);
|
||||
set_16bit_bus(nandp);
|
||||
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);
|
||||
nand_lld_write_cmd(nandp, NAND_CMD_READ0_CONFIRM);
|
||||
set_8bit_bus(nandp);
|
||||
|
||||
/* Here NAND asserts busy signal and starts transferring from memory
|
||||
array to page buffer. After the end of transmission ready_isr functions
|
||||
|
@ -362,7 +440,7 @@ void nand_lld_read_data(NANDDriver *nandp, uint8_t *data, size_t datalen,
|
|||
*
|
||||
* @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] datalen size of data buffer in bytes
|
||||
* @param[in] addr pointer to address buffer
|
||||
* @param[in] addrlen length of address
|
||||
* @param[out] ecc pointer to store computed ECC. Ignored when NULL.
|
||||
|
@ -371,14 +449,18 @@ void nand_lld_read_data(NANDDriver *nandp, uint8_t *data, size_t datalen,
|
|||
*
|
||||
* @notapi
|
||||
*/
|
||||
uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data,
|
||||
uint8_t nand_lld_write_data(NANDDriver *nandp, const uint16_t *data,
|
||||
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc) {
|
||||
|
||||
align_check(data, datalen);
|
||||
|
||||
nandp->state = NAND_WRITE;
|
||||
|
||||
nand_lld_write_cmd (nandp, NAND_CMD_WRITE);
|
||||
set_16bit_bus(nandp);
|
||||
nand_lld_write_cmd(nandp, NAND_CMD_WRITE);
|
||||
osalSysLock();
|
||||
nand_lld_write_addr(nandp, addr, addrlen);
|
||||
set_8bit_bus(nandp);
|
||||
|
||||
/* Now start DMA transfer to NAND buffer and put thread in sleep state.
|
||||
Tread will be woken up from ready ISR. */
|
||||
|
@ -390,7 +472,8 @@ uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data,
|
|||
nandp->nand->PCR |= FSMC_PCR_ECCEN;
|
||||
}
|
||||
|
||||
dmaStartMemCopy(nandp->dma, nandp->dmamode, data, nandp->map_data, datalen);
|
||||
dmaStartMemCopy(nandp->dma, nandp->dmamode, data, nandp->map_data,
|
||||
datalen/AHB_TRANSACTION_WIDTH);
|
||||
|
||||
nand_lld_suspend_thread(nandp);
|
||||
osalSysUnlock();
|
||||
|
@ -416,7 +499,10 @@ void nand_lld_reset(NANDDriver *nandp) {
|
|||
|
||||
nandp->state = NAND_RESET;
|
||||
|
||||
nand_lld_write_cmd (nandp, NAND_CMD_RESET);
|
||||
set_16bit_bus(nandp);
|
||||
nand_lld_write_cmd(nandp, NAND_CMD_RESET);
|
||||
set_8bit_bus(nandp);
|
||||
|
||||
osalSysLock();
|
||||
nand_lld_suspend_thread(nandp);
|
||||
osalSysUnlock();
|
||||
|
@ -437,35 +523,19 @@ 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);
|
||||
set_16bit_bus(nandp);
|
||||
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_write_cmd(nandp, NAND_CMD_ERASE_CONFIRM);
|
||||
set_8bit_bus(nandp);
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -505,13 +575,14 @@ void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd) {
|
|||
*/
|
||||
uint8_t nand_lld_read_status(NANDDriver *nandp) {
|
||||
|
||||
uint8_t status;
|
||||
status = 1; /* presume worse */
|
||||
uint16_t status;
|
||||
|
||||
set_16bit_bus(nandp);
|
||||
nand_lld_write_cmd(nandp, NAND_CMD_STATUS);
|
||||
nand_lld_polled_read_data(nandp, &status, 1);
|
||||
set_8bit_bus(nandp);
|
||||
status = nandp->map_data[0];
|
||||
|
||||
return status;
|
||||
return status & 0xFF;
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_NAND */
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
typedef struct NANDDriver NANDDriver;
|
||||
|
||||
/**
|
||||
* @brief Type of interrupt handler function
|
||||
* @brief Type of interrupt handler function.
|
||||
*/
|
||||
typedef void (*nandisrhandler_t)(NANDDriver *nandp);
|
||||
|
||||
|
@ -206,15 +206,15 @@ struct NANDDriver {
|
|||
#endif /* NAND_USE_MUTUAL_EXCLUSION */
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Function enabling interrupts from FSMC
|
||||
* @brief Function enabling interrupts from FSMC.
|
||||
*/
|
||||
nandisrhandler_t isr_handler;
|
||||
/**
|
||||
* @brief Pointer to current transaction buffer
|
||||
* @brief Pointer to current transaction buffer.
|
||||
*/
|
||||
uint8_t *rxdata;
|
||||
void *rxdata;
|
||||
/**
|
||||
* @brief Current transaction length
|
||||
* @brief Current transaction length in bytes.
|
||||
*/
|
||||
size_t datalen;
|
||||
/**
|
||||
|
@ -236,15 +236,15 @@ struct NANDDriver {
|
|||
/**
|
||||
* @brief Memory mapping for data.
|
||||
*/
|
||||
uint8_t *map_data;
|
||||
uint16_t *map_data;
|
||||
/**
|
||||
* @brief Memory mapping for commands.
|
||||
*/
|
||||
uint8_t *map_cmd;
|
||||
uint16_t *map_cmd;
|
||||
/**
|
||||
* @brief Memory mapping for addresses.
|
||||
*/
|
||||
uint8_t *map_addr;
|
||||
uint16_t *map_addr;
|
||||
/**
|
||||
* @brief Pointer to bad block map.
|
||||
* @details One bit per block. All memory allocation is user's responsibility.
|
||||
|
@ -274,13 +274,12 @@ extern "C" {
|
|||
void nand_lld_init(void);
|
||||
void nand_lld_start(NANDDriver *nandp);
|
||||
void nand_lld_stop(NANDDriver *nandp);
|
||||
void nand_lld_read_data(NANDDriver *nandp, uint8_t *data,
|
||||
uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen);
|
||||
void nand_lld_read_data(NANDDriver *nandp, uint16_t *data,
|
||||
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
|
||||
void nand_lld_polled_read_data(NANDDriver *nandp, uint8_t *data, size_t len);
|
||||
void nand_lld_write_addr(NANDDriver *nandp, const uint8_t *addr, size_t len);
|
||||
void nand_lld_write_cmd(NANDDriver *nandp, uint8_t cmd);
|
||||
uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen);
|
||||
uint8_t nand_lld_write_data(NANDDriver *nandp, const uint8_t *data,
|
||||
uint8_t nand_lld_write_data(NANDDriver *nandp, const uint16_t *data,
|
||||
size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc);
|
||||
uint8_t nand_lld_read_status(NANDDriver *nandp);
|
||||
void nand_lld_reset(NANDDriver *nandp);
|
||||
|
|
|
@ -139,12 +139,13 @@ static void calc_blk_addr(const NANDConfig *cfg, uint32_t block,
|
|||
*/
|
||||
static bool read_is_block_bad(NANDDriver *nandp, size_t block) {
|
||||
|
||||
if (0xFF != nandReadBadMark(nandp, block, 0))
|
||||
return true;
|
||||
if (0xFF != nandReadBadMark(nandp, block, 1))
|
||||
return true;
|
||||
uint16_t badmark0 = nandReadBadMark(nandp, block, 0);
|
||||
uint16_t badmark1 = nandReadBadMark(nandp, block, 1);
|
||||
|
||||
return false;
|
||||
if ((0xFFFF != badmark0) || (0xFFFF != badmark1))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -260,24 +261,24 @@ void nandStop(NANDDriver *nandp) {
|
|||
* @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
|
||||
* @param[in] datalen length of data buffer
|
||||
* @param[out] data buffer to store data, half word aligned
|
||||
* @param[in] datalen length of data buffer in bytes, half word aligned
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
uint8_t *data, size_t datalen) {
|
||||
void *data, size_t datalen) {
|
||||
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addrbuf[8];
|
||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
const size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||
osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size)));
|
||||
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||
|
||||
calc_addr(cfg, block, page, 0, addrbuf, addrlen);
|
||||
nand_lld_read_data(nandp, data, datalen, addrbuf, addrlen, NULL);
|
||||
calc_addr(cfg, block, page, 0, addr, addrlen);
|
||||
nand_lld_read_data(nandp, data, datalen, addr, addrlen, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,20 +287,20 @@ void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
* @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
|
||||
* @param[in] datalen length of data buffer
|
||||
* @param[in] data buffer with data to be written, half word aligned
|
||||
* @param[in] datalen length of data buffer in bytes, half word aligned
|
||||
*
|
||||
* @return The operation status reported by NAND IC (0x70 command).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const uint8_t *data, size_t datalen) {
|
||||
const void *data, size_t datalen) {
|
||||
|
||||
uint8_t retval;
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addr[8];
|
||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
const size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||
osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size)));
|
||||
|
@ -316,25 +317,25 @@ uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
* @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
|
||||
* @param[in] datalen length of data buffer
|
||||
* @param[out] data buffer to store data, half word aligned
|
||||
* @param[in] datalen length of data buffer in bytes, half word aligned
|
||||
* @param[out] ecc pointer to calculated ECC. Ignored when NULL.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
uint8_t *data, size_t datalen, uint32_t *ecc) {
|
||||
void *data, size_t datalen, uint32_t *ecc) {
|
||||
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addrbuf[8];
|
||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
const size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||
osalDbgCheck((datalen <= cfg->page_data_size));
|
||||
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||
|
||||
calc_addr(cfg, block, page, 0, addrbuf, addrlen);
|
||||
nand_lld_read_data(nandp, data, datalen, addrbuf, addrlen, ecc);
|
||||
calc_addr(cfg, block, page, 0, addr, addrlen);
|
||||
nand_lld_read_data(nandp, data, datalen, addr, addrlen, ecc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,8 +344,8 @@ void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
* @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
|
||||
* @param[in] datalen length of data buffer
|
||||
* @param[in] data buffer with data to be written, half word aligned
|
||||
* @param[in] datalen length of data buffer in bytes, half word aligned
|
||||
* @param[out] ecc pointer to calculated ECC. Ignored when NULL.
|
||||
*
|
||||
* @return The operation status reported by NAND IC (0x70 command).
|
||||
|
@ -352,12 +353,12 @@ void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
* @api
|
||||
*/
|
||||
uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const uint8_t *data, size_t datalen, uint32_t *ecc) {
|
||||
const void *data, size_t datalen, uint32_t *ecc) {
|
||||
|
||||
uint8_t retval;
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addr[8];
|
||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
const size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck((nandp != NULL) && (data != NULL));
|
||||
osalDbgCheck((datalen <= cfg->page_data_size));
|
||||
|
@ -374,17 +375,17 @@ uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
* @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
|
||||
* @param[in] sparelen length of data buffer
|
||||
* @param[out] spare buffer to store data, half word aligned
|
||||
* @param[in] sparelen length of data buffer in bytes, half word aligned
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
uint8_t *spare, size_t sparelen) {
|
||||
void *spare, size_t sparelen) {
|
||||
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addr[8];
|
||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
const size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck((NULL != spare) && (nandp != NULL));
|
||||
osalDbgCheck(sparelen <= cfg->page_spare_size);
|
||||
|
@ -400,19 +401,19 @@ void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
* @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
|
||||
* @param[in] sparelen length of data buffer
|
||||
* @param[in] spare buffer with spare data to be written, half word aligned
|
||||
* @param[in] sparelen length of data buffer in bytes, half word aligned
|
||||
*
|
||||
* @return The operation status reported by NAND IC (0x70 command).
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
||||
const uint8_t *spare, size_t sparelen) {
|
||||
const void *spare, size_t sparelen) {
|
||||
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addr[8];
|
||||
size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
const size_t addrlen = cfg->rowcycles + cfg->colcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck((NULL != spare) && (nandp != NULL));
|
||||
osalDbgCheck(sparelen <= cfg->page_spare_size);
|
||||
|
@ -432,10 +433,10 @@ uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page,
|
|||
*/
|
||||
void nandMarkBad(NANDDriver *nandp, uint32_t block) {
|
||||
|
||||
uint8_t bb_mark[2] = {0, 0};
|
||||
uint16_t bb_mark = 0;
|
||||
|
||||
nandWritePageSpare(nandp, block, 0, bb_mark, sizeof(bb_mark));
|
||||
nandWritePageSpare(nandp, block, 1, bb_mark, sizeof(bb_mark));
|
||||
nandWritePageSpare(nandp, block, 0, &bb_mark, sizeof(bb_mark));
|
||||
nandWritePageSpare(nandp, block, 1, &bb_mark, sizeof(bb_mark));
|
||||
|
||||
if (NULL != nandp->bb_map)
|
||||
bitmapSet(nandp->bb_map, block);
|
||||
|
@ -452,11 +453,11 @@ void nandMarkBad(NANDDriver *nandp, uint32_t block) {
|
|||
*
|
||||
* @api
|
||||
*/
|
||||
uint8_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page) {
|
||||
uint8_t bb_mark[1];
|
||||
uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page) {
|
||||
uint16_t bb_mark;
|
||||
|
||||
nandReadPageSpare(nandp, block, page, bb_mark, sizeof(bb_mark));
|
||||
return bb_mark[0];
|
||||
nandReadPageSpare(nandp, block, page, &bb_mark, sizeof(bb_mark));
|
||||
return bb_mark;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -472,8 +473,8 @@ uint8_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page) {
|
|||
uint8_t nandErase(NANDDriver *nandp, uint32_t block) {
|
||||
|
||||
const NANDConfig *cfg = nandp->config;
|
||||
uint8_t addr[4];
|
||||
size_t addrlen = cfg->rowcycles;
|
||||
const size_t addrlen = cfg->rowcycles;
|
||||
uint8_t addr[addrlen];
|
||||
|
||||
osalDbgCheck(nandp != NULL);
|
||||
osalDbgAssert(nandp->state == NAND_READY, "invalid state");
|
||||
|
|
|
@ -509,10 +509,8 @@ static void nand_test(bool use_badblock_map) {
|
|||
|
||||
/* performance counters */
|
||||
int32_t adc_ints = 0;
|
||||
int32_t spi_ints = 0;
|
||||
int32_t uart_ints = 0;
|
||||
int32_t adc_idle_ints = 0;
|
||||
int32_t spi_idle_ints = 0;
|
||||
int32_t uart_idle_ints = 0;
|
||||
uint32_t background_cnt = 0;
|
||||
systime_t T = 0;
|
||||
|
@ -540,13 +538,11 @@ static void nand_test(bool use_badblock_map) {
|
|||
*/
|
||||
dma_storm_adc_start();
|
||||
dma_storm_uart_start();
|
||||
dma_storm_spi_start();
|
||||
T = chVTGetSystemTimeX();
|
||||
general_test(&NAND, NAND_TEST_START_BLOCK, NAND_TEST_END_BLOCK, 1);
|
||||
T = chVTGetSystemTimeX() - T;
|
||||
adc_ints = dma_storm_adc_stop();
|
||||
uart_ints = dma_storm_uart_stop();
|
||||
spi_ints = dma_storm_spi_stop();
|
||||
chSysLock();
|
||||
background_cnt = BackgroundThdCnt;
|
||||
BackgroundThdCnt = 0;
|
||||
|
@ -557,11 +553,9 @@ static void nand_test(bool use_badblock_map) {
|
|||
*/
|
||||
dma_storm_adc_start();
|
||||
dma_storm_uart_start();
|
||||
dma_storm_spi_start();
|
||||
chThdSleep(T);
|
||||
adc_idle_ints = dma_storm_adc_stop();
|
||||
uart_idle_ints = dma_storm_uart_stop();
|
||||
spi_idle_ints = dma_storm_spi_stop();
|
||||
|
||||
/*
|
||||
* ensure that NAND code have negligible impact on other subsystems
|
||||
|
@ -569,7 +563,6 @@ static void nand_test(bool use_badblock_map) {
|
|||
osalDbgCheck(background_cnt > (BackgroundThdCnt / 4));
|
||||
osalDbgCheck(abs(adc_ints - adc_idle_ints) < (adc_idle_ints / 20));
|
||||
osalDbgCheck(abs(uart_ints - uart_idle_ints) < (uart_idle_ints / 20));
|
||||
osalDbgCheck(abs(spi_ints - spi_idle_ints) < (spi_idle_ints / 10));
|
||||
|
||||
/*
|
||||
* perform ECC calculation test
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#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")
|
||||
#define STM32_NAND_BUS_WIDTH 8
|
||||
|
||||
/*
|
||||
* FSMC SRAM driver system settings.
|
||||
|
|
Loading…
Reference in New Issue