SD卡引导WinCE启动引发的种种问题

nevin007 2011-12-12 11:27:14
前几天在调试SD卡引导WinCE内核的Bootloader,功能调试成功后系统可以从SD卡启动,但是发现有以下问题:

SD卡只能工作在5MHz以下,确切的说SDIPRE的预分频值只能是13,如果换成其它频率,那么在Bootloader运行完毕跳转到内核启动地址(比如0x30200000)的时候会卡死,不知道是什么原因。这样的话从上电开机到内核初始化大约需要一分钟的时间,其中大部分时间应该是消耗在了内核拷贝的过程上。接着,内核初始化完毕以后又需要等待大约2分钟才能在LCD上看到桌面,这是为什么?我回忆了一下,如果是Nand引导的话,会事先通过EBOOT将TOC写到Nand的Block1中,启动的时候Bootloader会根据TOC的指示加载内核镜像,这样从内核初始化完毕到看到系统桌面大约2秒,不知道上面的现象是不是这个原因,如果是的话如何解决?如何在SD卡中实现?

请教各位指点~

我的SD卡容量128MB,支持的最高工作频率是50MHz(从CSD读出来的),我的程序是参照坛里一位前辈的修改的:
http://topic.csdn.net/u/20090811/16/B0924B18-F28D-41FA-8656-3450C331D40A.html

我把主要代码再贴一遍:

void xmain(void)
{
INT8U ret;
U32 j;

MMU_EnableICache();
ChangeClockDivider(3, 1);
ChangeMPllValue(127, 2, 1); //405MHZ

Isr_Init();
Uart_Init(0, 115200);
Uart_Select(0);

Delay100us(12000);

Uart_Printf("The main is running\n");

NF_Init();

ret = SD_Initialize();

if (ret == NO_ERR)
{
//初始化SD卡成功
Uart_Printf("SD_Initalize Success\n");

ret = FAT_Init();

if (ret == NO_ERR)
{
//初始化FAT成功
Uart_Printf("\nFAT Initalize Success\n");

FAT_DisDir("\\");

RunByBootFile("\\BOOT.TXT");
}
else
{
//初始化FAT失败
Uart_Printf("\nFAT Initalize error:%d\n", ret);
}
}
else
{
//初始化SD卡失败
Uart_Printf("SD_initalize error:%d\n", ret);
}

Uart_Printf("\nPress Key 'U' Enter USBMON\n");

for (j = 0;j < 10;j++)
{
Uart_Printf("*");
Delay100us(12000);

if (rUTRSTAT0 & 0x1) //UART 有数据输入
{
ret = RdURXH0();

if ((ret == 'U') || (ret == 'u'))
{
Uart_Printf("\nUSBMON\n");
Run_USBMON(); //启动USBMON
}
}
}

Uart_Printf("\n");
ret = RunImageFromNand(1, 0);
Uart_Printf("\nBoot ERROR:%d", ret);
while (1);

}



/*********************************************************************************************************
** Function name: SD_Initialize
** Descriptions: initialize SD/MMC card
** 初始化SD/MMC卡
** Input: sd_struct *sds: SD卡信息结构体 sd_struct *sds: the information structure of SD Card
** Output: 0: 正确 >0: 错误码 0: right >0: error code
** Created by: MingYuan Zheng 郑明远
** Created Date: 2006-01-09
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
INT8U SD_Initialize(void) //(sd_struct *sds)
{
INT8U response[16], ret;

SD_HardWareInit(); /* 1. 初始化SD/MMC接口硬件 Initialize the hardware of SD/MMC interface */

sds.timeout_erase = 0x7fffff;
sds.timeout_read = 0x7fffff;
sds.timeout_write = 0x7fffff;

Debug_Printf("\nSD_Initialize start");

ret = SD_ResetSD();

if (ret != NO_ERR) /* 2. 发出CMD0命令复位SD卡 send CMD0 command to reset SD/MMC card */
return ret;

sds.card_type = Card_Indentify(); /* 3. 判别卡的型号:SD或MMC卡 identify card type: SD or MMC card */

Debug_Printf("card_type:%d\n",sds.card_type);

ret = SD_ActiveCard(); //sds); /* 4. 激活SD/MMC卡 active SD/MMC card */

if (ret != NO_ERR)
return ret;

ret = SD_ReadAllCID(16, response); /* 5. 请所有卡发送CID寄存器 ask all card send their CID number */

if (ret != NO_ERR)
return ret;

if (sds.RCA == 0)
{
card_id++;
sds.RCA = card_id; /* 给卡分配一个地址 assign a address */
}

ret = SD_GetRCA(sds.card_type, &sds.RCA); /* 6. 得到卡的RCA get the RCA of the card */

if (ret != NO_ERR)
return ret;

ret = SD_GetCardInfo(); //sds); /* 7. 读CSD寄存器,获取SD卡信息 read CSD register, get the information of SD card */

if (ret != NO_ERR)
return ret;

SD_ClkToMax(); /* 8. 设置读/写SD/MMC时钟到最大值 set clock of reading or writing SD/MMC to maximum */



return (SD_SetBlockLen(sds.RCA, SD_BLOCKSIZE)); /* 9. 设置块的长度: 512Bytes Set the block length: 512Bytes */
}


/*********************************************************************************************************
** Function name: SD_ReadBlock
** Descriptions: read a block from SD/MMC card
** 从SD/MMC卡中读出一个块
** Input: sd_struct *sds : SD/MMC卡信息结构体 sd_struct *sds : the information structure of SD/MMC Card
INT32U blockaddr: 块地址 INT32U blockaddr: the address of the block
INT8U *recbuf : 接收缓冲区,长度512Bytes INT8U *recbuf : the buffer of receive,length is 512Bytes
** Output: 1: 成功 > 0: 错误码 1: sucessfully > 0: error code
** Created by: MingYuan Zheng 郑明远
** Created Date: 2006-01-09
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
INT8U SD_ReadBlock(INT32U blockaddr, INT8U *recbuf)
{
INT8U ret, status[4];
// INT32U stat = 0;

// Debug_Printf("\nSD_ReadBlock start");

ret = SD_ReadCard_Status(sds.RCA, 4, status); /* 读取卡的状态 read the status of the card */

if (ret != NO_ERR)
return ret;

ret = SD_SelectCard(sds.RCA); /* CMD7,进入传输状态 CMD7, enter tranfer status */

if (ret != NO_ERR)
return ret;

if (sds.card_type == CARDTYPE_SD)
{ /* 卡为SD卡 card is SD card */
ret = SD_SetBusWidth(sds.RCA, 1); /* 设置卡为数据总线方式 set card to wide data bus */

if (ret != NO_ERR)
return ret;
}

#if SD_INTERRUPT_EN
rSDIIMSK = SDIIMSK_TOUT | SDIIMSK_DFIN | SDIIMSK_RX_LAST | SDIIMSK_RX_FULL;

reading = 1;

buffer = recbuf; /* 数据缓冲区指针 buffer pointer */

bufcnt = 0;

datalen = SD_BLOCKSIZE; /* 接收数据长度 receive data length */

error = SD_ERR_TIMEOUT_READ; /* be initialized to error code */

#endif

// if (sds.card_type == CARDTYPE_SD)
// stat = SDIDCON_RACMD_1 | SDIDCON_BLK | SDIDCON_RX | SDIDCON_WIDE | 1 << 0;
// else
// stat = SDIDCON_RACMD_1 | SDIDCON_BLK | SDIDCON_RX | 1 << 0;

rSDIBSIZE = SD_BLOCKSIZE; /* 块数据的长度 block data length */

rSDICON |= SDICON_FRESET; /* 复位 FIFO reset FIFO */

// rSDIDCON = stat; /* 写数据控制寄存器 write data control register */

rSDIFSTA = rSDIFSTA | (1 << 16); // FIFO reset

rSDIDCON = (2 << 22) | (1 << 19) | (1 << 17) | (1 << 16) | (1 << 14) | (2 << 12) | (1 << 0); //YH 040220

//Word Rx, Rx after cmd, blk, 4bit bus, Rx start, blk num, data start, data transmit mode

rSDICARG = 0x0; // CMD17/18(addr)

ret = SD_ReadSingleBlock(blockaddr); /* 读单块命令 read single blocks command */

if (ret != NO_ERR)
return ret;

#if SD_INTERRUPT_EN
interruptible_sleep_on(&wq); /* 进入可被中断的睡眠状态, 数据在中断中自动接收 */

#ifdef CHECK_CARD_EN
if (!card_insert)
{
return SD_ERR_NO_CARD; /* 卡未插入,返回错误 */
}
#endif /* CHECK_CARD_EN */

if (error)
{ /* there is error, return error code */
return error;
}

ret = NO_ERR;

#else /* 读出数据 read data from sd card */
ret = SD_ReadBlockData(SD_BLOCKSIZE, recbuf, sds.timeout_read);
#endif

if (ret != NO_ERR)
return ret;

ret = SD_DeSelectCard(); /* CMD7, 退出传输状态 */

return NO_ERR;
}



...全文
365 点赞 收藏 9
写回复
9 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
liuyue168168 2013-12-12
有哪位大侠,帮忙做一个USB进入WINCE引导文件。。怎么操作?? 把UsbUpdateOS.fge引导工具与凯立德导航软件拷贝到U盘中,然后插到主机的USB接口上,重启主机就可进入WIN CE 谢谢各位了 下载一个wince系统软件WinCE6.0_V2.0_SmartQ7,解压到U盘根目录下面,进入root文件夹,用记事本打开menu.lst文件,看里面的可选项,更改可选项指向你的wence浏览器,比如ToWinCe等,即可进入。 towince.exe放USB根目录下,或者放root文件夹里,请问menu.lst要怎么改?多谢! 原文件是: #Linux boot entry reference: ##################################################### # title xxx (whatever your want but not "wince") # kernel /boot/xxx (zImage or SmartQx kernel image) # initrd /boot/xxx (if any) # param xxx xxx xxx (if needed) # logo /boot/foo.bmp4 ##################################################### # #NOTE: #1. Use "#" to comment out a whole line. #2. Use "title" as the first command line of an OS entry. #3. One command per line. #4. Any error, e.g. No SD card inserted, no menu.lst at /boot, invalid menu.lst will boot the default OS. #5. Use gbmp565 to convert image from 24-bit Windows Bitmap to bmp4 format; logo size is 96x96 pixels. # Transparent color: R 0x00, G 0x00, B 0x66. # # SmartQ WinCE 6.0 title wince kernel /boot/NK.nb0
回复
wjcapple 2012-07-02
D4VAL EQU 0 ; 1.3V
D3VAL EQU 1
D2VAL EQU 0
D1VAL EQU 0
D0VAL EQU 1
这些代码是什么意思?
回复
swanmsg 2011-12-19
有做C#的没?
回复
nevin007 2011-12-15
[Quote=引用 2 楼 paul_chao 的回复:]
1. Copy SD->RAM 這段資料對不對, 可以寫個CHECKSUM程式確定.
2. EBOOT -> NK, 通常NK不會再重設P……
[/Quote]

我现在的Bootloader除了初始化平台外主要就是完成拷贝SD卡中的NK.nb0到RAM,然后跳转到RAM中的地址加载内核。也就是说没有用到EBOOT,也就不涉及按照TOC中的记录加载内核。

我的CE是4.2的BSP升级到5.0的,在fw.s中有如下代码,应该是又初始化了一遍系统时钟。
[ CLKVAL = 400
FCLK EQU (400)
[ S2440A = 1 ; S2440A
PLLVAL EQU (((92 << 12) + (1 << 4) + 1))
| ; S2440X
PLLVAL EQU (((92 << 12) + (1 << 4) + 0))
]
CLKDIVVAL EQU 7 ; 0x0 = 1:1:1, 0x1 = 1:1:2, 0x2 = 1:2:2, 0x3 = 1:2:4, 0x4 = 1:4:4, 0x5 = 1:4:8, 0x6 = 1:3:3, 0x7 = 1:3:6
D4VAL EQU 0 ; 1.3V
D3VAL EQU 1
D2VAL EQU 0
D1VAL EQU 0
D0VAL EQU 1
]

同时我也觉得在改变了SD卡的频率后,拷贝RAM的过程有问题,否则也不会在跳转之后系统加载不起来。我觉得问题的源头很有可能出在SD卡的初始化部分,我再去研究研究SD卡的协议~
回复
当我遇上-你 2011-12-14
频率的问题,可以使用示波器测试下对不
回复
northcan 2011-12-14
[Quote=引用 2 楼 paul_chao 的回复:]
引用楼主 nevin007 的回复:
SD卡只能工作在5MHz以下,确切的说SDIPRE的预分频值只能是13,如果换成其它频率,那么在Bootloader运行完毕跳转到内核启动地址(比如0x30200000)的时候会卡死,不知道是什么原因。...


1. Copy SD->RAM 這段資料對不對, 可以寫個CHECKSUM程式確定.
2. EBOOT -> NK, 通常NK不會再重設P……
[/Quote]

高手来了,好久不见paul_chao 的精彩回帖了。
回复
paul_chao 2011-12-14
[Quote=引用楼主 nevin007 的回复:]
SD卡只能工作在5MHz以下,确切的说SDIPRE的预分频值只能是13,如果换成其它频率,那么在Bootloader运行完毕跳转到内核启动地址(比如0x30200000)的时候会卡死,不知道是什么原因。...
[/Quote]

1. Copy SD->RAM 這段資料對不對, 可以寫個CHECKSUM程式確定.
2. EBOOT -> NK, 通常NK不會再重設PLL, 若NK跑太慢, LZ的PLL在離開EBOOT前有沒有設對.

Paul, Chao @ Techware
回复
nevin007 2011-12-13
怎么没人关注一下呢?是不是初始化的时候有什么问题?
回复
发帖
嵌入开发(WinCE)
创建于2007-09-28

1.9w+

社区成员

硬件/嵌入开发 嵌入开发(WinCE)
申请成为版主
帖子事件
创建了帖子
2011-12-12 11:27
社区公告
暂无公告