/*! \file exmc_nandflash_fixed.c \brief improved NAND Flash driver with complete GPIO configuration \version 2026-03-09, V1.4.0, firmware for GD32H7xx */ /* Copyright (c) 2025, GigaDevice Semiconductor Inc. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if 0 #include "gd32h7xx.h" #include "exmc_nandflash_fixed.h" #include /* NAND Flash操作区域定义 */ #define NAND_CMD_AREA *(__IO uint8_t *)(BANK_NAND_ADDR | EXMC_CMD_AREA) #define NAND_ADDR_AREA *(__IO uint8_t *)(BANK_NAND_ADDR | EXMC_ADDR_AREA) #define NAND_DATA_AREA *(__IO uint8_t *)(BANK_NAND_ADDR | EXMC_DATA_AREA) /* NAND Flash地址计算宏 */ #define ROW_ADDRESS (address.page + (address.block + (address.zone * NAND_ZONE_SIZE)) * NAND_BLOCK_SIZE) /* 页位计数 */ #define PAGE_BIT 6 /* 私有变量 */ static uint8_t nand_initialized = 0; /* 私有函数声明 */ static uint8_t exmc_nand_getstatus(void); static uint8_t exmc_nand_writedata(uint8_t *pbuffer, nand_address_struct physicaladdress, uint16_t bytecount); static uint8_t exmc_nand_readdata(uint8_t *pbuffer, nand_address_struct phyaddress, uint16_t bytecount); static uint8_t exmc_nand_writepage(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount); static uint8_t exmc_nand_readpage(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount); static uint8_t exmc_nand_eraseblock(uint32_t blocknum); static uint8_t exmc_nand_readstatus(void); static void exmc_nand_gpio_config(void); static void exmc_nand_timing_config(void); static void exmc_nand_delay_ms(uint32_t ms); /*! \brief 配置NAND Flash的GPIO引脚 \param[in] none \param[out] none \retval none \note 硬件配置:EXMC_D0-PD14, EXMC_D1-PD15, EXMC_D2-PD0, EXMC_D3-PD1, EXMC_D4-PE7, EXMC_D5-PE8, EXMC_D6-PE9, EXMC_D7-PE10, EXMC_NCE-PD7, EXMC_CLE-PD11, EXMC_ALE-PD12, EXMC_NWE-PD5, EXMC_NOE-PD4, EXMC_NWAIT-PD6 */ static void exmc_nand_gpio_config(void) { printf("配置NAND Flash GPIO引脚...\n"); /* 数据总线配置 */ printf(" 配置数据总线...\n"); /* D2(PD0), D3(PD1) - 数据线 */ gpio_af_set(GPIOD, NAND_EXMC_AF, NAND_EXMC_D2_PIN | NAND_EXMC_D3_PIN); gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, NAND_EXMC_D2_PIN | NAND_EXMC_D3_PIN); gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, NAND_EXMC_D2_PIN | NAND_EXMC_D3_PIN); /* D0(PD14), D1(PD15) - 数据线 */ gpio_af_set(GPIOD, NAND_EXMC_AF, NAND_EXMC_D0_PIN | NAND_EXMC_D1_PIN); gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, NAND_EXMC_D0_PIN | NAND_EXMC_D1_PIN); gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, NAND_EXMC_D0_PIN | NAND_EXMC_D1_PIN); /* D4(PE7), D5(PE8), D6(PE9), D7(PE10) - 数据线 */ gpio_af_set(GPIOE, NAND_EXMC_AF, NAND_EXMC_D4_PIN | NAND_EXMC_D5_PIN | NAND_EXMC_D6_PIN | NAND_EXMC_D7_PIN); gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP, NAND_EXMC_D4_PIN | NAND_EXMC_D5_PIN | NAND_EXMC_D6_PIN | NAND_EXMC_D7_PIN); gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, NAND_EXMC_D4_PIN | NAND_EXMC_D5_PIN | NAND_EXMC_D6_PIN | NAND_EXMC_D7_PIN); /* 控制信号配置 */ printf(" 配置控制信号...\n"); /* CLE(PD11), ALE(PD12) - 命令/地址锁存使能 */ gpio_af_set(GPIOD, NAND_EXMC_AF, NAND_EXMC_CLE_PIN | NAND_EXMC_ALE_PIN); gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, NAND_EXMC_CLE_PIN | NAND_EXMC_ALE_PIN); gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, NAND_EXMC_CLE_PIN | NAND_EXMC_ALE_PIN); /* NOE(PD4), NWE(PD5), NWAIT(PD6) - 读/写/等待信号 */ gpio_af_set(GPIOD, NAND_EXMC_AF, NAND_EXMC_NOE_PIN | NAND_EXMC_NWE_PIN | NAND_EXMC_NWAIT_PIN); gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, NAND_EXMC_NOE_PIN | NAND_EXMC_NWE_PIN | NAND_EXMC_NWAIT_PIN); gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, NAND_EXMC_NOE_PIN | NAND_EXMC_NWE_PIN | NAND_EXMC_NWAIT_PIN); /* NCE(PD7) - 芯片使能信号 */ gpio_af_set(GPIOD, NAND_EXMC_AF, NAND_EXMC_NCE_PIN); gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, NAND_EXMC_NCE_PIN); gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_85MHZ, NAND_EXMC_NCE_PIN); printf("NAND Flash GPIO配置完成\n"); } /*! \brief 配置NAND Flash时序参数 \param[in] none \param[out] none \retval none */ static void exmc_nand_timing_config(void) { printf("配置NAND Flash时序参数...\n"); /* 时序参数配置 SET: (tCS - tWP) = 15 - 12 = 3ns HLD: tCH = 5ns HIZ: tWH = 10ns WAIT: tWP = 12ns CTR: CLE to RE delay: 10ns ATR: ALE to RE delay: 10ns */ printf(" 设置时序: SET=2, WAIT=12, HLD=5, HIZ=5\n"); } /*! \brief 毫秒级延时 \param[in] ms: 延时毫秒数 \param[out] none \retval none */ static void exmc_nand_delay_ms(uint32_t ms) { for(volatile uint32_t i = 0; i < (SystemCoreClock / 4000) * ms; i++) { __NOP(); } } /*! \brief 初始化NAND Flash \param[in] none \param[out] none \retval 0: 成功, -1: 失败 */ int exmc_nandflash_init(void) { exmc_nand_parameter_struct nand_init_struct; exmc_nand_timing_parameter_struct nand_timing_init_struct; if(nand_initialized) { return 0; /* 已初始化 */ } printf("开始初始化NAND Flash...\n"); /* 使能时钟 */ printf(" 使能时钟...\n"); rcu_periph_clock_enable(RCU_EXMC); rcu_periph_clock_enable(RCU_GPIOD); rcu_periph_clock_enable(RCU_GPIOE); rcu_periph_clock_enable(RCU_GPIOF); rcu_periph_clock_enable(RCU_GPIOG); /* 配置GPIO */ exmc_nand_gpio_config(); /* 配置时序 */ exmc_nand_timing_config(); /* EXMC NAND参数初始化 */ exmc_nand_struct_para_init(&nand_init_struct); /* 时序参数配置 */ nand_timing_init_struct.setuptime = 2; nand_timing_init_struct.waittime = 12; /* GD Flash时序 */ nand_timing_init_struct.holdtime = 5; nand_timing_init_struct.databus_hiztime = 5; /* NAND Flash参数配置 */ nand_init_struct.ecc_size = EXMC_ECC_SIZE_2048BYTES; nand_init_struct.atr_latency = EXMC_ALE_RE_DELAY_5_CK_EXMC; nand_init_struct.ctr_latency = EXMC_CLE_RE_DELAY_5_CK_EXMC; nand_init_struct.ecc_logic = ENABLE; nand_init_struct.databus_width = EXMC_NAND_DATABUS_WIDTH_8B; nand_init_struct.wait_feature = ENABLE; nand_init_struct.common_space_timing = &nand_timing_init_struct; nand_init_struct.attribute_space_timing = &nand_timing_init_struct; /* 初始化EXMC NAND */ exmc_nand_init(&nand_init_struct); /* 使能EXMC NAND */ exmc_nand_enable(); nand_initialized = 1; printf("NAND Flash初始化成功\n"); return 0; } /*! \brief 去初始化NAND Flash \param[in] none \param[out] none \retval none */ void exmc_nandflash_deinit(void) { /* 禁用EXMC NAND */ exmc_nand_disable(); /* 去初始化EXMC NAND */ exmc_nand_deinit(); /* 重置GPIO为输入模式 */ gpio_mode_set(GPIOD, GPIO_MODE_INPUT, GPIO_PUPD_NONE, NAND_EXMC_D2_PIN | NAND_EXMC_D3_PIN | NAND_EXMC_NOE_PIN | NAND_EXMC_NWE_PIN | NAND_EXMC_NWAIT_PIN | NAND_EXMC_NCE_PIN | NAND_EXMC_CLE_PIN | NAND_EXMC_ALE_PIN | NAND_EXMC_D0_PIN | NAND_EXMC_D1_PIN); gpio_mode_set(GPIOE, GPIO_MODE_INPUT, GPIO_PUPD_NONE, NAND_EXMC_D4_PIN | NAND_EXMC_D5_PIN | NAND_EXMC_D6_PIN | NAND_EXMC_D7_PIN); nand_initialized = 0; printf("NAND Flash去初始化完成\n"); } /*! \brief 检查是否已初始化 \param[in] none \param[out] none \retval 1: 已初始化, 0: 未初始化 */ uint8_t exmc_nandflash_is_initialized(void) { return nand_initialized; } /*! \brief 读取NAND Flash ID \param[in] nand_id: NAND Flash ID结构体指针 \param[out] none \retval 0: 成功, -1: 失败 */ int nand_read_id(nand_id_struct *nand_id) { uint32_t data; if(!nand_initialized || !nand_id) { return -1; } printf("读取NAND Flash ID...\n"); /* 发送读ID命令 */ NAND_CMD_AREA = NAND_CMD_READID; __DSB(); /* 发送地址 */ NAND_ADDR_AREA = 0x00; __DSB(); /* 读取ID */ data = *(__IO uint32_t *)(BANK_NAND_ADDR | EXMC_DATA_AREA); nand_id->maker_id = ADDR_1ST_CYCLE(data); nand_id->device_id = ADDR_2ND_CYCLE(data); nand_id->third_id = ADDR_3RD_CYCLE(data); nand_id->fourth_id = ADDR_4TH_CYCLE(data); printf("NAND Flash ID: 制造商=0x%02X, 设备=0x%02X, 第三=0x%02X, 第四=0x%02X\n", nand_id->maker_id, nand_id->device_id, nand_id->third_id, nand_id->fourth_id); return 0; } /*! \brief 写入NAND Flash页 \param[in] pbuffer: 数据缓冲区指针 \param[in] address: 写入地址 \param[in] bytecount: 写入字节数 \param[out] none \retval 0: 成功, -1: 失败 */ static uint8_t exmc_nand_writepage(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount) { uint16_t i; uint32_t ecc_value; uint8_t ecc_status = 0U; if(!nand_initialized || !pbuffer) { return -1; } /* ECC配置检查 */ if(RESET != (EXMC_NCTL & EXMC_NCTL_ECCEN)) { exmc_nand_ecc_config(DISABLE); exmc_nand_ecc_config(ENABLE); ecc_status = 1U; } /* 发送页编程命令第一周期 */ NAND_CMD_AREA = NAND_CMD_WRITE_1ST; __DSB(); /* 发送地址 */ NAND_ADDR_AREA = address.page_in_offset; __DSB(); NAND_ADDR_AREA = address.page_in_offset >> 8; __DSB(); NAND_ADDR_AREA = ADDR_1ST_CYCLE(ROW_ADDRESS); __DSB(); NAND_ADDR_AREA = ADDR_2ND_CYCLE(ROW_ADDRESS); __DSB(); /* 写入数据 */ for(i = 0; i < bytecount; i++) { NAND_DATA_AREA = pbuffer[i]; __DSB(); } /* 发送页编程命令第二周期 */ NAND_CMD_AREA = NAND_CMD_WRITE_2ND; __DSB(); if(1U == ecc_status) { while(RESET == (EXMC_NINTEN & EXMC_NINTEN_FFEPT)); ecc_value = exmc_ecc_get(); /* 避免编译警告 */ ecc_value = ecc_value; } /* 检查操作状态 */ if(NAND_READY == exmc_nand_getstatus()) { return 0; } return -1; } /*! \brief 读取NAND Flash页 \param[in] pbuffer: 数据缓冲区指针 \param[in] address: 读取地址 \param[in] bytecount: 读取字节数 \param[out] none \retval 0: 成功, -1: 失败 */ static uint8_t exmc_nand_readpage(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount) { uint16_t i; uint32_t ecc_value; uint8_t ecc_status = 0U; if(!nand_initialized || !pbuffer) { return -1; } /* ECC配置检查 */ if(RESET != (EXMC_NCTL & EXMC_NCTL_ECCEN)) { exmc_nand_ecc_config(DISABLE); exmc_nand_ecc_config(ENABLE); ecc_status = 1U; } /* 发送读命令第一周期 */ NAND_CMD_AREA = NAND_CMD_READ1_1ST; __DSB(); /* 发送地址 */ NAND_ADDR_AREA = address.page_in_offset; __DSB(); NAND_ADDR_AREA = address.page_in_offset >> 8; __DSB(); NAND_ADDR_AREA = ADDR_1ST_CYCLE(ROW_ADDRESS); __DSB(); NAND_ADDR_AREA = ADDR_2ND_CYCLE(ROW_ADDRESS); __DSB(); /* 发送读命令第二周期 */ NAND_CMD_AREA = NAND_CMD_READ1_2ND; __DSB(); /* 读取数据 */ for(i = 0; i < bytecount; i++) { pbuffer[i] = NAND_DATA_AREA; } if(1U == ecc_status) { while(RESET == (EXMC_NINTEN & EXMC_NINTEN_FFEPT)); ecc_value = exmc_ecc_get(); /* 避免编译警告 */ ecc_value = ecc_value; } /* 检查操作状态 */ if(NAND_READY == exmc_nand_getstatus()) { return 0; } return -1; } /*! \brief 擦除NAND Flash块 \param[in] blocknum: 块号 \param[out] none \retval 0: 成功, -1: 失败 */ static uint8_t exmc_nand_eraseblock(uint32_t blocknum) { if(!nand_initialized) { return -1; } printf("擦除块%d...\n", blocknum); /* 发送擦除命令第一周期 */ NAND_CMD_AREA = NAND_CMD_ERASE_1ST; __DSB(); /* 发送块地址 */ blocknum <<= PAGE_BIT; NAND_ADDR_AREA = ADDR_1ST_CYCLE(blocknum); __DSB(); NAND_ADDR_AREA = ADDR_2ND_CYCLE(blocknum); __DSB(); /* 发送擦除命令第二周期 */ NAND_CMD_AREA = NAND_CMD_ERASE_2ND; __DSB(); return (exmc_nand_getstatus()); } /*! \brief 写入数据到NAND Flash \param[in] pbuffer: 数据缓冲区指针 \param[in] address: 写入地址 \param[in] bytecount: 写入字节数 \param[out] none \retval 0: 成功, -1: 失败 */ static uint8_t exmc_nand_writedata(uint8_t *pbuffer, nand_address_struct physicaladdress, uint16_t bytecount) { uint8_t *temp_pbuffer = pbuffer; if(!nand_initialized || !pbuffer) { return -1; } /* 写入前先擦除块 */ if(exmc_nand_eraseblock(physicaladdress.block) != NAND_READY) { printf("擦除块%d失败\n", physicaladdress.block); return -1; } /* 跨页写入处理 */ while(bytecount + physicaladdress.page_in_offset > NAND_PAGE_SIZE) { if(exmc_nand_writepage(temp_pbuffer, physicaladdress, NAND_PAGE_SIZE - physicaladdress.page_in_offset) != 0) { return -1; } bytecount -= NAND_PAGE_SIZE - physicaladdress.page_in_offset; temp_pbuffer += NAND_PAGE_SIZE - physicaladdress.page_in_offset; physicaladdress.page++; physicaladdress.page_in_offset = 0; } /* 写入剩余数据 */ if(bytecount > 0) { if(exmc_nand_writepage(temp_pbuffer, physicaladdress, bytecount) != 0) { return -1; } } return 0; } /*! \brief 从NAND Flash读取数据 \param[in] pbuffer: 数据缓冲区指针 \param[in] phyaddress: 读取地址 \param[in] bytecount: 读取字节数 \param[out] none \retval 0: 成功, -1: 失败 */ static uint8_t exmc_nand_readdata(uint8_t *pbuffer, nand_address_struct phyaddress, uint16_t bytecount) { uint8_t *temp_pbuffer = pbuffer; if(!nand_initialized || !pbuffer) { return -1; } /* 跨页读取处理 */ while(bytecount + phyaddress.page_in_offset > NAND_PAGE_SIZE) { if(exmc_nand_readpage(temp_pbuffer, phyaddress, NAND_PAGE_SIZE - phyaddress.page_in_offset) != 0) { return -1; } phyaddress.page++; temp_pbuffer += NAND_PAGE_SIZE - phyaddress.page_in_offset; bytecount -= NAND_PAGE_SIZE - phyaddress.page_in_offset; phyaddress.page_in_offset = 0; } /* 读取剩余数据 */ if(bytecount > 0) { if(exmc_nand_readpage(temp_pbuffer, phyaddress, bytecount) != 0) { return -1; } } return 0; } /*! \brief 读取NAND Flash状态 \param[in] none \param[out] none \retval 状态值 */ static uint8_t exmc_nand_readstatus(void) { uint8_t data; uint8_t status = NAND_BUSY; /* 发送读状态命令 */ NAND_CMD_AREA = NAND_CMD_STATUS; __DSB(); data = NAND_DATA_AREA; if((data & NAND_ERROR) == NAND_ERROR) { status = NAND_ERROR; } else if((data & NAND_READY) == NAND_READY) { status = NAND_READY; } else { status = NAND_BUSY; } return status; } /*! \brief 获取NAND操作状态 \param[in] none \param[out] none \retval 操作状态 */ static uint8_t exmc_nand_getstatus(void) { uint32_t timeout = 0x10000; uint8_t status = NAND_READY; status = exmc_nand_readstatus(); /* 等待操作完成或超时 */ while((status != NAND_READY) && (timeout != 0x00)) { status = exmc_nand_readstatus(); timeout--; } if(timeout == 0x00) { status = NAND_TIMEOUT_ERROR; } return status; } /*! \brief 写入指定逻辑地址的数据 \param[in] memaddr: 逻辑地址 \param[in] pwritebuf: 写入数据缓冲区 \param[in] bytecount: 写入字节数 \param[out] none \retval 0: 成功, -1: 失败 */ int nand_write(uint32_t memaddr, uint8_t *pwritebuf, uint16_t bytecount) { uint32_t temp_blockremainsize; nand_address_struct physicaladdress; uint32_t temp; if(!nand_initialized || !pwritebuf) { return -1; } printf("写入数据到地址%d, 长度%d字节\n", memaddr, bytecount); temp = memaddr % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); /* 计算物理地址 */ physicaladdress.zone = memaddr / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE * NAND_ZONE_SIZE); physicaladdress.block = memaddr / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); physicaladdress.page = temp / NAND_PAGE_SIZE; physicaladdress.page_in_offset = temp % NAND_PAGE_SIZE; temp_blockremainsize = (NAND_BLOCK_SIZE * NAND_PAGE_SIZE) - (NAND_PAGE_SIZE * physicaladdress.page + physicaladdress.page_in_offset); /* 跨块写入处理 */ while(bytecount > temp_blockremainsize) { if(exmc_nand_writedata(pwritebuf, physicaladdress, temp_blockremainsize) != 0) { printf("写入块%d失败\n", physicaladdress.block); return -1; } physicaladdress.block++; pwritebuf += temp_blockremainsize; bytecount -= temp_blockremainsize; physicaladdress.page = 0; physicaladdress.page_in_offset = 0; temp_blockremainsize = (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); } /* 写入剩余数据 */ if(bytecount > 0) { if(exmc_nand_writedata(pwritebuf, physicaladdress, bytecount) != 0) { printf("写入剩余数据失败\n"); return -1; } } printf("数据写入完成\n"); return 0; } /*! \brief 从指定逻辑地址读取数据 \param[in] memaddr: 逻辑地址 \param[in] preadbuf: 读取数据缓冲区 \param[in] bytecount: 读取字节数 \param[out] none \retval 0: 成功, -1: 失败 */ int nand_read(uint32_t memaddr, uint8_t *preadbuf, uint16_t bytecount) { uint32_t temp_blockremainsize; nand_address_struct physicaladdress; uint32_t temp; if(!nand_initialized || !preadbuf) { return -1; } printf("从地址%d读取数据, 长度%d字节\n", memaddr, bytecount); temp = memaddr % (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); /* 计算物理地址 */ physicaladdress.zone = memaddr / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE * NAND_ZONE_SIZE); physicaladdress.block = memaddr / (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); physicaladdress.page = temp / NAND_PAGE_SIZE; physicaladdress.page_in_offset = temp % NAND_PAGE_SIZE; temp_blockremainsize = (NAND_BLOCK_SIZE * NAND_PAGE_SIZE) - (NAND_PAGE_SIZE * physicaladdress.page + physicaladdress.page_in_offset); /* 跨块读取处理 */ while(bytecount > temp_blockremainsize) { if(exmc_nand_readdata(preadbuf, physicaladdress, temp_blockremainsize) != 0) { printf("读取块%d失败\n", physicaladdress.block); return -1; } physicaladdress.block++; preadbuf += temp_blockremainsize; bytecount -= temp_blockremainsize; physicaladdress.page = 0; physicaladdress.page_in_offset = 0; temp_blockremainsize = (NAND_BLOCK_SIZE * NAND_PAGE_SIZE); } /* 读取剩余数据 */ if(bytecount > 0) { if(exmc_nand_readdata(preadbuf, physicaladdress, bytecount) != 0) { printf("读取剩余数据失败\n"); return -1; } } printf("数据读取完成\n"); return 0; } /*! \brief 格式化NAND Flash \param[in] none \param[out] none \retval 0: 成功, -1: 失败 */ int nand_format(void) { uint16_t i; if(!nand_initialized) { return -1; } printf("开始格式化NAND Flash (%d个块)...\n", NAND_BLOCK_COUNT); for(i = 0; i < NAND_BLOCK_COUNT; i++) { if(NAND_READY != exmc_nand_eraseblock(i)) { printf("擦除块%d失败\n", i); return -1; } /* 进度显示 */ if(i % 100 == 0) { printf("格式化进度: %d/%d (%.1f%%)\n", i + 1, NAND_BLOCK_COUNT, (float)(i + 1) * 100.0f / NAND_BLOCK_COUNT); } } printf("NAND Flash格式化完成\n"); return 0; } /*! \brief 重置NAND Flash \param[in] none \param[out] none \retval 0: 成功, -1: 失败 */ int nand_reset(void) { if(!nand_initialized) { return -1; } printf("重置NAND Flash...\n"); NAND_CMD_AREA = NAND_CMD_RESET; __DSB(); /* 检查操作状态 */ if(NAND_READY == exmc_nand_getstatus()) { printf("NAND Flash重置成功\n"); return 0; } printf("NAND Flash重置失败\n"); return -1; } /*! \brief 写入备用区数据 \param[in] pbuffer: 数据缓冲区指针 \param[in] address: 写入地址 \param[in] bytecount: 写入字节数 \param[out] none \retval 0: 成功, -1: 失败 */ int exmc_nand_writespare(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount) { if(!nand_initialized || !pbuffer) { return -1; } /* 检查备用区地址范围 */ if(address.page_in_offset <= NAND_PAGE_SIZE) { printf("地址不在备用区范围\n"); return -1; } if(bytecount + address.page_in_offset >= NAND_PAGE_TOTAL_SIZE) { printf("写入数据超出备用区范围\n"); return -1; } return exmc_nand_writepage(pbuffer, address, bytecount); } /*! \brief 读取备用区数据 \param[in] pbuffer: 数据缓冲区指针 \param[in] address: 读取地址 \param[in] bytecount: 读取字节数 \param[out] none \retval 0: 成功, -1: 失败 */ int exmc_nand_readspare(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount) { if(!nand_initialized || !pbuffer) { return -1; } /* 检查备用区地址范围 */ if(address.page_in_offset <= NAND_PAGE_SIZE) { printf("地址不在备用区范围\n"); return -1; } if(bytecount + address.page_in_offset >= NAND_PAGE_TOTAL_SIZE) { printf("读取数据超出备用区范围\n"); return -1; } return exmc_nand_readpage(pbuffer, address, bytecount); } /*! \brief 填充缓冲区 \param[in] pbuffer: 数据缓冲区指针 \param[in] buffer_length: 缓冲区长度 \param[in] value: 填充值 \param[out] none \retval none */ void fill_buffer_nand(uint8_t *pbuffer, uint16_t buffer_length, uint32_t value) { uint16_t index; if(!pbuffer) { return; } for(index = 0; index < buffer_length; index++) { pbuffer[index] = value + index; } } /*! \brief NAND Flash自检 \param[in] none \param[out] none \retval 0: 成功, -1: 失败 */ int nand_self_test(void) { printf("开始NAND Flash自检...\n"); /* 检查初始化状态 */ if(!nand_initialized) { printf("NAND Flash未初始化\n"); return -1; } /* 读取ID测试 */ nand_id_struct nand_id; if(nand_read_id(&nand_id) != 0) { printf("❌ 读取NAND Flash ID失败\n"); return -1; } printf("✅ NAND Flash ID读取成功\n"); /* 重置测试 */ if(nand_reset() != 0) { printf("❌ NAND Flash重置失败\n"); return -1; } printf("✅ NAND Flash重置成功\n"); /* 基本读写测试 */ printf("测试基本读写功能...\n"); /* 准备测试数据 */ uint8_t write_buffer[256]; uint8_t read_buffer[256]; for(int i = 0; i < 256; i++) { write_buffer[i] = (uint8_t)(i & 0xFF); } /* 写入测试 */ if(nand_write(0, write_buffer, 256) != 0) { printf("❌ 写入测试失败\n"); return -1; } /* 读取测试 */ if(nand_read(0, read_buffer, 256) != 0) { printf("❌ 读取测试失败\n"); return -1; } /* 数据验证 */ int error_count = 0; for(int i = 0; i < 256; i++) { if(write_buffer[i] != read_buffer[i]) { error_count++; if(error_count <= 5) { printf("数据错误: 索引%d, 写入0x%02X, 读取0x%02X\n", i, write_buffer[i], read_buffer[i]); } } } if(error_count == 0) { printf("✅ 基本读写测试通过\n"); } else { printf("❌ 基本读写测试失败,错误数: %d\n", error_count); return -1; } printf("NAND Flash自检完成\n"); return 0; } /*! \brief NAND Flash信息显示 \param[in] none \param[out] none \retval none */ void nand_print_info(void) { printf("\n=== NAND Flash信息 ===\n"); printf("容量: %d MB (%d KB)\n", (NAND_BLOCK_COUNT * NAND_BLOCK_SIZE * NAND_PAGE_SIZE) / (1024 * 1024), (NAND_BLOCK_COUNT * NAND_BLOCK_SIZE * NAND_PAGE_SIZE) / 1024); printf("块数量: %d\n", NAND_BLOCK_COUNT); printf("每块页数: %d\n", NAND_BLOCK_SIZE); printf("页大小: %d bytes\n", NAND_PAGE_SIZE); printf("备用区大小: %d bytes\n", NAND_SPARE_AREA_SIZE); printf("总页大小: %d bytes\n", NAND_PAGE_TOTAL_SIZE); printf("数据总线宽度: 8 bits\n"); printf("ECC支持: 2048 bytes\n"); printf("硬件配置:\n"); printf(" 数据总线: D0-PD14, D1-PD15, D2-PD0, D3-PD1\n"); printf(" D4-PE7, D5-PE8, D6-PE9, D7-PE10\n"); printf(" 控制信号: NCE-PD7, CLE-PD11, ALE-PD12\n"); printf(" NWE-PD5, NOE-PD4, NWAIT-PD6\n"); printf("=========================\n\n"); } #endif