四、增加串口功能
串口在调试时,打印调试信息是很有用的;在nboot过程中,打印些信息,若是发生crash,也可判断是否在nboot阶段。
串口采用UART0,115200波特率。
1、Clone过来的bsp默认是采用UART1,修改"/SRC/INC/bsp_cfg.h"文件
代码 1 // ------------------------------------------------------------------------------ 2 // Debug UART0 3 // ------------------------------------------------------------------------------ 4 5 #define BSP_UART0_ULCON 0x03 // 8 bits, 1 stop, no parity 6 #define BSP_UART0_UCON 0x0005 // pool mode, PCLK for UART 7 #define BSP_UART0_UFCON 0x00 // disable FIFO 8 #define BSP_UART0_UMCON 0x00 // disable auto flow control 9 #define BSP_UART0_UBRDIV (S3C2410X_PCLK/(115200*16) - 1)
2、在nboot目录下新建debug.c文件,并加入工程。debug.c文件完成串口的初始化和字符串输出功能,其代码可copy
"/SRC/OAL/OALLIB/debug.c"文件,稍微修改即可,包括两个函数 VOID OEMInitDebugSerial()和VOID OEMWriteDebugString(LPWSTR string) 代码 1 #include < bsp.h > 2 3 4 5 VOID OEMInitDebugSerial() 6 { 7 8 volatile S3C2410X_IOPORT_REG * pIOPortReg = (S3C2410X_IOPORT_REG * )(S3C2410X_BASE_REG_PA_IOPORT); 9 volatile S3C2410X_UART_REG * pUARTReg = (S3C2410X_UART_REG * )(S3C2410X_BASE_REG_PA_UART0); 10 11 // GPH2 and GHP3 are UART0 Tx and Rx, respectively. 12 // 13 14 pIOPortReg -> GPHCON &= ~ (( 3 << 4 ) | ( 3 << 6 )); 15 pIOPortReg -> GPHCON |= ( 2 << 4 ) | ( 2 << 6 ); 16 17 // Disable pull-up on TXD0 and RXD0. 18 pIOPortReg -> GPHUP |= ( 1 << 2 ) | ( 1 << 3 ); 19 20 // Configure the UART. 21 pUARTReg -> UFCON = BSP_UART0_UFCON; // FIFO disable 22 pUARTReg -> UMCON = BSP_UART0_UMCON; // AFC disable 23 24 pUARTReg -> ULCON = BSP_UART0_ULCON; // Normal,No parity,1 stop,8 bits 25 pUARTReg -> UCON = BSP_UART0_UCON; 26 27 pUARTReg -> UBRDIV = BSP_UART0_UBRDIV; 28 29 30 } 31 32 // ------------------------------------------------------------------------------ 33 // 34 // Function: OEMWriteDebugByte 35 // 36 // Transmits a character out the debug serial port. 37 // 38 static VOID OEMWriteDebugByte(UINT8 ch) 39 { 40 volatile S3C2410X_UART_REG * pUARTReg = (S3C2410X_UART_REG * )(S3C2410X_BASE_REG_PA_UART0); 41 42 // Wait for transmit buffer to be empty 43 while (((pUARTReg -> UTRSTAT) & 0x02 ) == 0 ); 44 45 // Send character 46 pUARTReg -> UTXH = ch; 47 48 } 49 50 51 52 // ------------------------------------------------------------------------------ 53 // 54 // Function: OEMWriteDebugString 55 // 56 // Output unicode string to debug serial port 57 // 58 VOID OEMWriteDebugString(LPWSTR string ) 59 { 60 while ( * string != L ' /0 ' ) 61 OEMWriteDebugByte((UINT8) * string ++ ); 62 }
3、以上两步已将串口功能实现,通过OEMWriteDebugString(TEXT("Hello World!/r/n"))这样的语句来打印debug信息了。
五、NAND FLASH部分
NAND FLASH 读代码复杂,不过在BSP都基本有现成代码,拷贝过来修改即可。主要包含两个函数,初始化NANDFLASH和读NANDFLASH。
1、nboot目录新建个Flash.c文件并加入工程,copy"/SRC/COMMON/SMARTMEDIA/FMD/ARM/nand.s"到nboot目录并加入工程;
copy"/SRC/COMMON/SMARTMEDIA/FMD/nand.h"文件到目录下,并include到Flash.c文件。
2、Flash_Iint ()函数实现。Flash.c
代码 1 2 void Flash_Init() 3 { 4 // Caller should have specified NAND controller address. 5 // 6 s2410NAND = (S3C2410X_NAND_REG * )NAND_BASE; 7 8 // Set up initial flash controller configuration. 9 // 10 s2410NAND -> NFCONF = ( 1 << 15 ) | /* Enable/Disable */ 11 ( 1 << 14 ) | /* Page Size : 512Bytes */ 12 ( 1 << 13 ) | /* 4 Step Address */ 13 ( 1 << 12 ) | /* Initialize ECC */ 14 ( 1 << 11 ) | /* nFCE control nFCE = HIGH */ 15 (TACLS << 0 ) | /* CLE & ALE = HCLK * (TACLS + 1) */ 16 (TWRPH0 << 3 ) | /* TWRPH0 = HCLK * (TWRPH0 + 1) */ 17 (TWRPH1 << 0 ); /* TWRPH1 = HCLK * (TWRPH1 + 1) */ 18 19 NF_nFCE_L(); // Select the flash chip. 20 NF_CMD(CMD_RESET); // Send reset command. 21 NF_WAITRB(); // Wait for flash to complete command. 22 // Get manufacturer and device codes. 23 24 NF_nFCE_H(); // Deselect the flash chip. 25 }
3、Flash读函数,Flash_ReadSector()函数实现。Flash.c
代码 1 2 /* 3 @func BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash. 4 @rdesc TRUE = Success, FALSE = Failure. 5 @comm 6 @xref 7 */ 8 BOOL Flash_ReadSector(DWORD startSectorAddr, LPBYTE pSectorBuff, DWORD dwNumSectors) 9 { 10 ULONG SectorAddr = (ULONG)startSectorAddr; 11 ULONG blockPage; 12 13 NF_RSTECC(); // Initialize ECC. 14 NF_nFCE_L(); // Select the flash chip. 15 NF_CMD(CMD_RESET); // Send reset command. 16 17 while (dwNumSectors -- ) 18 { 19 blockPage = (((SectorAddr / NAND_PAGE_CNT) * NAND_PAGE_CNT) | (SectorAddr % NAND_PAGE_CNT)); 20 21 NF_WAITRB(); // Wait for flash to complete command. 22 23 if (pSectorBuff) 24 { 25 NF_CMD(CMD_READ); // Send read command. 26 NF_ADDR( 0 ); // Column = 0. 27 NF_ADDR(blockPage & 0xff ); // Page address. 28 NF_ADDR((blockPage >> 8 ) & 0xff ); 29 NF_ADDR((blockPage >> 16 ) & 0xff ); 30 NF_WAITRB(); // Wait for command to complete. 31 32 // Handle unaligned buffer pointer 33 RdPage512(pSectorBuff); // Read page/sector data. 34 35 NF_RDDATA(); // Read/clear status. 36 NF_RDDATA(); // 37 } 38 39 ++ SectorAddr; 40 pSectorBuff += NAND_PAGE_SIZE; 41 } 42 43 NF_nFCE_H(); // Deselect the flash chip. 44 45 return (TRUE); 46 }
4、修改Flash Controller的寄存器地址,#define NAND_BASE 0x4e000000。另外nand.s文件内,也要改过来(NFDATA)。nand.s文件内除了Rdpage512()之外函数都可以删除。
这样,NAND FLASH 部分也就完成了。
六、main文件,完成
经过以上工作,nboot差不多就完成了,在main函数中调用就可了
1、在main函数内,按顺序调用下面的函数
OEMInitDebugSerial(); Flash_Init(); Flash_ReadSector(0x30021000,32,0x00040000/512)); //0x3002_1000是EBOOT的ram地址,0x00040000的大小, //32是FlashPage Bloack-1的地址(也即Eboot烧到block-0)2、运行EBOOT。copy eboot目录下的ulit.s文件,删除两句语句,
; ldr r3, = (VIR_RAM_START - PHY_RAM_START) ; sub r2, r2, r3然后再main函数内调用Launch(0x300021000)即可启动EBOOT了。
七、完结
将nboot编译,烧进Flash,并烧录eboot,上电,看到EBOOT启动了。