Initial commit: CCU621_M firmware project with BLE debug link support.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,940 @@
|
||||
/*!
|
||||
\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 <stdio.h>
|
||||
|
||||
/* 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
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*!
|
||||
\file exmc_nandflash_fixed.h
|
||||
\brief header file of improved NAND Flash driver
|
||||
|
||||
\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.
|
||||
*/
|
||||
|
||||
#ifndef EXMC_NANDFLASH_FIXED_H
|
||||
#define EXMC_NANDFLASH_FIXED_H
|
||||
|
||||
#include "gd32h7xx.h"
|
||||
|
||||
/* EXMC NAND Flash区域定义 */
|
||||
#define EXMC_CMD_AREA (uint32_t)(1<<16) /* A16 = CLE high command area */
|
||||
#define EXMC_ADDR_AREA (uint32_t)(1<<17) /* A17 = ALE high address area */
|
||||
#define EXMC_DATA_AREA ((uint32_t)0x00000000) /* data area */
|
||||
|
||||
/* NAND Flash命令定义 */
|
||||
#define NAND_CMD_READ1_1ST ((uint8_t)0x00)
|
||||
#define NAND_CMD_READ1_2ND ((uint8_t)0x30)
|
||||
#define NAND_CMD_WRITE_1ST ((uint8_t)0x80)
|
||||
#define NAND_CMD_WRITE_2ND ((uint8_t)0x10)
|
||||
#define NAND_CMD_ERASE_1ST ((uint8_t)0x60)
|
||||
#define NAND_CMD_ERASE_2ND ((uint8_t)0xD0)
|
||||
#define NAND_CMD_READID ((uint8_t)0x90)
|
||||
#define NAND_CMD_STATUS ((uint8_t)0x70)
|
||||
#define NAND_CMD_LOCK_STATUS ((uint8_t)0x7A)
|
||||
#define NAND_CMD_RESET ((uint8_t)0xFF)
|
||||
|
||||
/* NAND Flash状态定义 */
|
||||
#define NAND_BUSY ((uint8_t)0x00)
|
||||
#define NAND_ERROR ((uint8_t)0x01)
|
||||
#define NAND_READY ((uint8_t)0x40)
|
||||
#define NAND_TIMEOUT_ERROR ((uint8_t)0x80)
|
||||
|
||||
/* NAND Flash参数定义 */
|
||||
#define NAND_ZONE_COUNT ((uint16_t)0x0001) /* 区域数量 */
|
||||
#define NAND_ZONE_SIZE ((uint16_t)0x0400) /* 每区块数 (1024) */
|
||||
#define NAND_BLOCK_SIZE ((uint16_t)0x0040) /* 每块页数 (64) */
|
||||
#define NAND_PAGE_SIZE ((uint16_t)0x0800) /* 页大小 (2048字节) */
|
||||
#define NAND_SPARE_AREA_SIZE ((uint16_t)0x0080) /* 备用区大小 (128字节) */
|
||||
#define NAND_PAGE_TOTAL_SIZE (NAND_PAGE_SIZE + NAND_SPARE_AREA_SIZE) /* 总页大小 */
|
||||
#define NAND_MAX_ADDRESS (((NAND_ZONE_COUNT*NAND_ZONE_SIZE)*NAND_BLOCK_SIZE)*NAND_PAGE_SIZE) /* 最大地址 */
|
||||
#define NAND_BLOCK_COUNT 1024 /* 块总数 */
|
||||
|
||||
/* NAND Flash地址计算宏 */
|
||||
#define ADDR_1ST_CYCLE(ADDR) (uint8_t)((ADDR)& 0xFF)
|
||||
#define ADDR_2ND_CYCLE(ADDR) (uint8_t)(((ADDR)& 0xFF00) >> 8)
|
||||
#define ADDR_3RD_CYCLE(ADDR) (uint8_t)(((ADDR)& 0xFF0000) >> 16)
|
||||
#define ADDR_4TH_CYCLE(ADDR) (uint8_t)(((ADDR)& 0xFF000000) >> 24)
|
||||
|
||||
/* 返回值定义 */
|
||||
#define NAND_OK 0
|
||||
#define NAND_FAIL 1
|
||||
|
||||
/* EXMC NAND Flash基地址 */
|
||||
#define BANK_NAND_ADDR ((uint32_t)0x80000000)
|
||||
|
||||
/* 硬件引脚定义 */
|
||||
#define NAND_EXMC_D0_PIN GPIO_PIN_14 /* PD14 */
|
||||
#define NAND_EXMC_D1_PIN GPIO_PIN_15 /* PD15 */
|
||||
#define NAND_EXMC_D2_PIN GPIO_PIN_0 /* PD0 */
|
||||
#define NAND_EXMC_D3_PIN GPIO_PIN_1 /* PD1 */
|
||||
#define NAND_EXMC_D4_PIN GPIO_PIN_7 /* PE7 */
|
||||
#define NAND_EXMC_D5_PIN GPIO_PIN_8 /* PE8 */
|
||||
#define NAND_EXMC_D6_PIN GPIO_PIN_9 /* PE9 */
|
||||
#define NAND_EXMC_D7_PIN GPIO_PIN_10 /* PE10 */
|
||||
#define NAND_EXMC_NCE_PIN GPIO_PIN_7 /* PD7 */
|
||||
#define NAND_EXMC_CLE_PIN GPIO_PIN_11 /* PD11 */
|
||||
#define NAND_EXMC_ALE_PIN GPIO_PIN_12 /* PD12 */
|
||||
#define NAND_EXMC_NWE_PIN GPIO_PIN_5 /* PD5 */
|
||||
#define NAND_EXMC_NOE_PIN GPIO_PIN_4 /* PD4 */
|
||||
#define NAND_EXMC_NWAIT_PIN GPIO_PIN_6 /* PD6 */
|
||||
|
||||
/* 硬件端口定义 */
|
||||
#define NAND_EXMC_D0_PORT GPIOD
|
||||
#define NAND_EXMC_D1_PORT GPIOD
|
||||
#define NAND_EXMC_D2_PORT GPIOD
|
||||
#define NAND_EXMC_D3_PORT GPIOD
|
||||
#define NAND_EXMC_D4_PORT GPIOE
|
||||
#define NAND_EXMC_D5_PORT GPIOE
|
||||
#define NAND_EXMC_D6_PORT GPIOE
|
||||
#define NAND_EXMC_D7_PORT GPIOE
|
||||
#define NAND_EXMC_NCE_PORT GPIOD
|
||||
#define NAND_EXMC_CLE_PORT GPIOD
|
||||
#define NAND_EXMC_ALE_PORT GPIOD
|
||||
#define NAND_EXMC_NWE_PORT GPIOD
|
||||
#define NAND_EXMC_NOE_PORT GPIOD
|
||||
#define NAND_EXMC_NWAIT_PORT GPIOD
|
||||
|
||||
/* 复用功能定义 */
|
||||
#define NAND_EXMC_AF GPIO_AF_12
|
||||
|
||||
/* NAND Flash ID结构体 */
|
||||
typedef struct {
|
||||
uint8_t maker_id; /* 制造商ID */
|
||||
uint8_t device_id; /* 设备ID */
|
||||
uint8_t third_id; /* 第三字节ID */
|
||||
uint8_t fourth_id; /* 第四字节ID */
|
||||
} nand_id_struct;
|
||||
|
||||
/* NAND Flash地址结构体 */
|
||||
typedef struct {
|
||||
uint16_t zone; /* 区域号 */
|
||||
uint16_t block; /* 块号 */
|
||||
uint16_t page; /* 页号 */
|
||||
uint16_t page_in_offset; /* 页内偏移 */
|
||||
} nand_address_struct;
|
||||
|
||||
/* 新的API函数声明 */
|
||||
/* 初始化和配置 */
|
||||
int exmc_nandflash_init(void); /* 完整初始化 */
|
||||
void exmc_nandflash_deinit(void); /* 完整去初始化 */
|
||||
uint8_t exmc_nandflash_is_initialized(void); /* 检查初始化状态 */
|
||||
|
||||
/* 基本操作 */
|
||||
int nand_read_id(nand_id_struct *nand_id); /* 读取NAND Flash ID */
|
||||
int nand_reset(void); /* 重置NAND Flash */
|
||||
int nand_format(void); /* 格式化NAND Flash */
|
||||
|
||||
/* 数据读写 */
|
||||
int nand_write(uint32_t memaddr, uint8_t *pwritebuf, uint16_t bytecount); /* 写入数据 */
|
||||
int nand_read(uint32_t memaddr, uint8_t *preadbuf, uint16_t bytecount); /* 读取数据 */
|
||||
|
||||
/* 备用区操作 */
|
||||
int exmc_nand_writespare(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount); /* 写入备用区 */
|
||||
int exmc_nand_readspare(uint8_t *pbuffer, nand_address_struct address, uint16_t bytecount); /* 读取备用区 */
|
||||
|
||||
/* 工具函数 */
|
||||
void fill_buffer_nand(uint8_t *pbuffer, uint16_t buffer_length, uint32_t value); /* 填充缓冲区 */
|
||||
int nand_self_test(void); /* 自检测试 */
|
||||
void nand_print_info(void); /* 显示NAND Flash信息 */
|
||||
|
||||
/* 兼容原有接口已统一到新API中,无需重复声明 */
|
||||
|
||||
#endif /* EXMC_NANDFLASH_FIXED_H */
|
||||
|
||||
Reference in New Issue
Block a user