NBOOT - 串口与NAND FLASH功能实现
一、串口功能配置
在调试过程中,通过串口输出信息可以有效帮助定位问题。以下是实现方法:
- 修改默认的UART设置:打开
\SRC\INC\bsp_cfg.h文件,调整为使用UART0。
#define BSP_UART0_ULCON 0x03 // 配置数据位、停止位和校验
#define BSP_UART0_UCON 0x0005 // 池模式,PCLK作为UART时钟源
#define BSP_UART0_UFCON 0x00 // 禁用FIFO
#define BSP_UART0_UMCON 0x00 // 禁用自动流控
#define BSP_UART0_UBRDIV (S3C2410X_PCLK/(115200*16) - 1) // 波特率分频器
- 创建并实现串口初始化及字符串输出功能:在nboot目录下新建
debug.c文件,并将其加入工程中。
#include <bsp.h>
VOID UART_Init() {
volatile S3C2410X_IOPORT_REG *ioPort = (S3C2410X_IOPORT_REG*)(S3C2410X_BASE_REG_PA_IOPORT);
volatile S3C2410X_UART_REG *uartReg = (S3C2410X_UART_REG *)(S3C2410X_BASE_REG_PA_UART0);
ioPort->GPHCON &= ~((3 << 4)|(3 << 6)); // 清除原有配置
ioPort->GPHCON |= (2 << 4)|(2 << 6); // 设置GPH2/GHP3为UART0 Tx/Rx
ioPort->GPHUP |= (1 << 2)|(1 << 3); // 禁用TXD0和RXD0的上拉电阻
uartReg->UFCON = BSP_UART0_UFCON; // 禁用FIFO
uartReg->UMCON = BSP_UART0_UMCON; // 禁用自动流控
uartReg->ULCON = BSP_UART0_ULCON; // 数据格式配置
uartReg->UCON = BSP_UART0_UCON; // UART控制寄存器配置
uartReg->UBRDIV = BSP_UART0_UBRDIV; // 波特率分频器设置
}
static VOID Send_Char(UINT8 ch) {
volatile S3C2410X_UART_REG *uartReg = (S3C2410X_UART_REG *)(S3C2410X_BASE_REG_PA_UART0);
while (!(uartReg->UTRSTAT & 0x02)); // 等待发送缓冲区为空
uartReg->UTXH = ch; // 发送字符
}
VOID Print_String(LPWSTR str) {
while (*str != L'\0') {
Send_Char((UINT8)*str++);
}
}
完成上述步骤后,可以通过调用 Print_String(TEXT("Hello World!\\r\\n")) 来测试串口输出。
二、NAND FLASH功能配置
NAND FLASH读取代码较为复杂,但通常BSP中已有现成代码可供参考。以下是实现步骤:
- 在nboot目录下新建
flash.c文件,并加入工程;同时复制相关文件:nand.s和nand.h。
void Init_NAND_Controller() {
s2410NAND = (S3C2410X_NAND_REG *)NAND_BASE;
s2410NAND->NFCONF =
(1 << 15) | // 启用控制器
(1 << 14) | // 页面大小:512字节
(1 << 13) | // 地址步数:4步
(1 << 12) | // 初始化ECC
(1 << 11) | // nFCE控制:高电平
(TACLS << 0) | // CLE/ALE延迟
(TWRPH0 << 3) | // 写周期第一阶段延迟
(TWRPH1 << 0); // 写周期第二阶段延迟
NF_nFCE_L(); // 选中芯片
NF_CMD(CMD_RESET); // 发送复位命令
NF_WAITRB(); // 等待操作完成
NF_nFCE_H(); // 取消选中芯片
}
BOOL Read_Sector(DWORD addr, LPBYTE buffer, DWORD count) {
ULONG sectorAddr = (ULONG)addr;
ULONG blockPage;
NF_RSTECC(); // 初始化ECC
NF_nFCE_L(); // 选中芯片
NF_CMD(CMD_RESET); // 发送复位命令
while (count--) {
blockPage = (((sectorAddr / NAND_PAGE_CNT) * NAND_PAGE_CNT) | (sectorAddr % NAND_PAGE_CNT));
NF_WAITRB(); // 等待命令完成
if (buffer) {
NF_CMD(CMD_READ); // 发送读命令
NF_ADDR(0); // 列地址
NF_ADDR(blockPage & 0xff); // 页地址低位
NF_ADDR((blockPage >> 8) & 0xff); // 中间位
NF_ADDR((blockPage >> 16) & 0xff); // 高位
NF_WAITRB(); // 等待命令完成
RdPage512(buffer); // 读取页面数据
NF_RDDATA(); // 读取状态
NF_RDDATA();
buffer += NAND_PAGE_SIZE;
}
++sectorAddr;
}
NF_nFCE_H(); // 取消选中芯片
return TRUE;
}
- 确保NAND控制器寄存器地址正确,例如
#define NAND_BASE 0x4e000000,并在nand.s文件中同步更新。
三、主程序整合
在main函数中按顺序调用以下函数:
UART_Init();
Init_NAND_Controller();
Read_Sector(0x30021000, buffer, 0x00040000 / 512); // 加载EBOOT到RAM
Launch(0x30021000); // 启动EBOOT
