spi初始化sd卡成功为什么读到的0扇区的数据都是0
初始化成功,读寄存器也正确,当读扇区的内容的时候读到的都是0 ,这是问什么呢? 你读的是物理扇区。用WINHEX看下,注意上面显示的逻辑扇区与物理扇区的值,如果两者相同就只显示一个。 有可能你初始化没成功,所以全是0 2 楼正解..因为你的SD卡在电脑上格式化后是带FAT系统的吧? 带系统的是不能这样读了..用winhex看下 对比一下..建议先熟悉一下fat 确定全是0。正常是只有16字节内容 其他是0 hefanghua 发表于 2012-5-11 18:17 static/image/common/back.gif你读的是物理扇区。用WINHEX看下,注意上面显示的逻辑扇区与物理扇区的值,如果两者相同就只显示一个。 ...
我是读卡的0扇区,是文件系统的启动扇区,可不应该都是0啊? byrin219 发表于 2012-5-11 19:00 static/image/common/back.gif
2 楼正解..因为你的SD卡在电脑上格式化后是带FAT系统的吧? 带系统的是不能这样读了..用winhex看下 对比一下 ...
不管带不带系统文件,启动扇区也是在0地址吧,我能读到其他一张sandisk的启动扇区,可是读这个卡就都是0. hhxb 发表于 2012-5-11 18:45 static/image/common/back.gif
有可能你初始化没成功,所以全是0
可是我初始化显示都成功了,而且能正确的读到寄存器的数值啊!那怎么才能确定我卡正常初始化了? 我读的是地址0,物理地址的开始。 我的一张2G卡,0扇区基本全为0,注意是基本为0,它在扇区快结束的字节有少量几个非0的数据,然后以55 AA结束该扇区。说明实际的引导扇区在刚才那几个字节所指的另一个扇区处。
如果还是调不出,建议用proteus仿真下SD(MMC)卡,并用SPI debugger查看通信过程。 楼上正解,SD卡的0扇区,如果你只把它分成一个区(就是没有多余的分区),那么0扇区前面的446字节的MBR基本上都是0x00,后面的DPT也只有第一个分区表项里面有些非零内容,然后结尾时0x55,0xAA;
这个也和不同的格式化软件有关系,有时候甚至没有MBR扇区,这时候0扇区就是DBR,前三个扇区通常是0xEB,0x58,0x90 0很正常。Windows格式化的MMC卡的第0扇区也是全0,我也读过。当我继续往后读约摸着十几个扇区才开始有非零值(好象是这样)。, wye11083 发表于 2012-5-12 14:31 static/image/common/back.gif
0很正常。Windows格式化的MMC卡的第0扇区也是全0,我也读过。当我继续往后读约摸着十几个扇区才开始有非零 ...
我记得上周5我测的时候不管读多少扇区一直都是0。 dudududu 发表于 2012-5-12 11:23 static/image/common/back.gif
楼上正解,SD卡的0扇区,如果你只把它分成一个区(就是没有多余的分区),那么0扇区前面的446字节的MBR基本 ...
我用WinHEX查看过了,没有MBR,直接就是DBR。 谁能提供我一份程序参考一下吗?
还有就是怎么做才能做到初始化、读sd卡的兼容性,才能保证我能识别所有的sd卡? 给你一个我正在用的程序,是在LM3S9B95上面用的,调用的是硬件SPI,所以你需要换用你自己的SPI函数,我实际使用,读扇区,写扇区,以及连续读扇区都没有问题,注释的话,有些地方可能还不是很准确,因为也是才写的,还没有完善到家
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD41 (0x40+41) /* SEND_OP_COND (ACMD) */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
UCHAR DISK_TYPE=0;
// 选择SD卡, SFLASH_CS_PIN置高,SDCARD_CS_PIN置低
static void SD_CS_ON (void)
{
GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN);
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, 0);
}
// 禁用SD卡,SDCARD_CS_PIN置高
static void SD_CS_OFF (void)
{
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, SDCARD_CS_PIN);
}
// 设置SPI运行速度
static void set_spi_speed(UINT speed)
{
unsigned long i;
SSIDisable(SDC_SSI_BASE);
if(speed > (SysCtlClockGet()/2000) ) i = SysCtlClockGet() / 2;
else i = speed;
if(i > 12500)
{ i = 12500; }
i=i*1000;
SSIConfigSetExpClk(SDC_SSI_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, i, 8);
SSIEnable(SDC_SSI_BASE);
}
//-----------------------------------------------------------------------
// 通过SPI向MMC发送一个字节数据
//-----------------------------------------------------------------------
static void spi_write_byte(BYTE dat)
{
DWORD rcvdat;
SSIDataPut(SDC_SSI_BASE, dat); /* 写一个字节到SPI的发送缓存 tx fifo */
SSIDataGet(SDC_SSI_BASE, &rcvdat); /* 写的同时,读取flush data */
}
//-----------------------------------------------------------------------
// 通过SPI接受来自MMC的一个字节数据
//-----------------------------------------------------------------------
static BYTE spi_read_byte (void)
{
DWORD rcvdat;
SSIDataPut(SDC_SSI_BASE, 0xFF); /* 写虚假数据 */
SSIDataGet(SDC_SSI_BASE, &rcvdat); /* 从SPI接受缓存中读取数据 rx fifo */
return (BYTE)rcvdat;
}
//等待disk准备就绪,超过50次则等待超时
static BYTE spi_wait_ready (void)
{
BYTE res;
UINT Timer = 20000;
do
res = spi_read_byte();
while ((res != 0xFF) && Timer--);
return res;
}
//-----------------------------------------------------------------------
// 发送80个时钟,CS和DI保持高电平
// SD卡上电后,转入SPI模式的时序要求
//-----------------------------------------------------------------------
static void write_initial_80_clock (void)
{
unsigned int i;
DWORD dat;
SD_CS_OFF();
//切换SPI_TX端口为普通GPIO,且输出高电平
GPIOPinTypeGPIOOutput(SDC_GPIO_PORT_BASE, SDC_SSI_TX);
GPIOPinWrite(SDC_GPIO_PORT_BASE, SDC_SSI_TX, SDC_SSI_TX);
//输出10字节0xff,使clock端口输出80个时钟信号
for(i = 0 ; i < 20 ; i++)
{
SSIDataPut(SDC_SSI_BASE, 0xFF); //传输虚拟数据
SSIDataGet(SDC_SSI_BASE, &dat); //结收虚拟数据
}
//切换SPI_TX端口为SPI模式
GPIOPinTypeSSI(SDC_GPIO_PORT_BASE, SDC_SSI_TX);
}
//---------------------------------------------------
// 函数名:spi_write_cmd
// 功能:发送卡命令
// 参数:uint8 Cmd: SD指令
// 参数:uint32 arg
// 返回值:uint8
//---------------------------------------------------
UINT8 spi_write_cmd(UINT8 Cmd, UINT32 arg, UINT8 CRC)
{
UINT8 r1;
UINT8 retry=0;
if (spi_wait_ready() != 0xFF) return 0xFF;
spi_write_byte(Cmd); //写入命令
spi_write_byte(arg>>24); //写入命令参数,有些命令没有参数,写00
spi_write_byte(arg>>16);
spi_write_byte(arg>>8);
spi_write_byte(arg);
spi_write_byte(CRC); //写入有效的 CRC值
retry = 10;
do
r1 = spi_read_byte();
while ((r1 & 0x80) && --retry); //等待响应, 超时退出
return r1; //返回状态值
}
//-----------------------------------------------------------------------
// 函数名:disk_read_sectors
// 功能:读扇区
// 参数:UINT32 start_sector 起始扇区地址
// 参数:BYTE sector_number连续读出的扇区数,有效值1-255
// 参数:BYTE *buff读出数据缓存区
// 返回值:TRUE/FALSE
//-----------------------------------------------------------------------
BYTE disk_read_sectors ( UINT32 sector, BYTE sector_number, BYTE *buff )
{
UINT8 r1;
UINT16 i;
SD_CS_ON (); //开片选
if(sector_number==1)
{
r1 = spi_write_cmd(CMD17, sector<<9, 0xff); // 发读扇区命令,读取有效返回值(0x00)
if(r1 != 0x00) return (0); // 如果写命令返回值无效,则返回失败
while(spi_read_byte() != 0xFE); // 等待数据的起始令牌号
for(i=0; i<512; i++) // 读512个数据
{
*buff = spi_read_byte();
buff++;
}
spi_read_byte(); // 丢弃两字节CRC校验位
spi_read_byte();
}
else if(sector_number>1)
{
r1 = spi_write_cmd(CMD18, sector<<9, 0xff); // 发读扇区命令,读取有效返回值(0x00)
if(r1 != 0x00) return (0); // 如果写命令返回值无效,则返回失败
do
{
while(spi_read_byte() != 0xFE); // 等待数据的起始令牌号
for(i=0; i<512; i++) // 读512个数据
{
*buff = spi_read_byte();
buff++;
}
spi_read_byte(); // 丢弃两字节CRC校验位
spi_read_byte();
} while(--sector_number);
spi_write_cmd(CMD12, 0, 0xff); // 发读扇区命令,读取有效返回值(0x00)
spi_read_byte(); // 丢弃两字节CRC校验位
spi_read_byte();
}
SD_CS_OFF(); // 关闭SD Card
return (1);
}
//-----------------------------------------------------------------------
// 函数名:disk_write_sectors
// 功能:写扇区
// 参数:UINT32 start_sector 起始扇区地址
// 参数:BYTE sector_number连续写入的扇区数,有效值1-255
// 参数:BYTE *buff等待写入的数据
// 返回值:TRUE/FALSE
//-----------------------------------------------------------------------
#ifREADONLY == 0
BYTE disk_write_sectors ( UINT32 sector, BYTE sector_number, BYTE *buff)
{
UINT8 r1=0;
UINT16 i=0;
SD_CS_ON (); //开片选
r1 = spi_write_cmd(CMD24, sector<<9, 0xff); // 发写扇区命令,读取有效返回值(0x00)
if(r1 != 0x00) return 0x00; // 如果写命令返回值无效,则返回失败
if(spi_wait_ready() != 0xFF) return 0x00;
spi_write_byte(0xFE); // 发送数据起始令牌号
for(i=0; i<512; i++) // 以扇区为单位写入数据
{
spi_write_byte(*buff);
buff++;
}
spi_write_byte(0xFF); // 发送两字节伪CRC
spi_write_byte(0xFF);
r1 = spi_read_byte(); // 读数据应答令牌号(有效令牌xxx00101B)
if( (r1&0x1F) != 0x05) // 判断令牌是否正确
{
SD_CS_OFF(); // 如果令牌错误,关闭SD Card
return 0x00; // 如果令牌错误,返回失败
}
while(spi_read_byte()==0); //--等待操作完成--
SD_CS_OFF(); // 关闭SD Card
return 0x01;
}
#endif
//SPI初始化
void spi_Interface_Init(void)
{
SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); //使能SSI模块
SysCtlPeripheralEnable(SDC_SSI_SYSCTL_PERIPH); //使能SSI0接口所在的GPIO端口
SysCtlPeripheralEnable(SDC_GPIO_SYSCTL_PERIPH);
SysCtlPeripheralEnable(SDCARD_CS_PERIPH);
SysCtlPeripheralEnable(SFLASH_CS_PERIPH);
GPIOPinTypeSSI(SDC_GPIO_PORT_BASE, SDC_SSI_TX | SDC_SSI_RX | SDC_SSI_CLK);//定义SPI端口
GPIOPinTypeGPIOOutput(SDCARD_CS_BASE, SDCARD_CS_PIN); //设置SDCARD_CS_PIN
GPIOPinTypeGPIOOutput(SFLASH_CS_BASE, SFLASH_CS_PIN); //设置SFLASH_CS_PIN
GPIOPadConfigSet(SDC_GPIO_PORT_BASE, SDC_SSI_PINS | SDC_SSI_TX | SDC_SSI_RX | SDC_SSI_CLK,
GPIO_STRENGTH_4MA, GPIO_PIN_TYPE_STD_WPU);
GPIOPadConfigSet(SDCARD_CS_BASE, SDCARD_CS_PIN, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU);
GPIOPadConfigSet(SFLASH_CS_BASE, SFLASH_CS_PIN, GPIO_STRENGTH_4MA,
GPIO_PIN_TYPE_STD_WPU);
GPIOPinWrite(SDCARD_CS_BASE, SDCARD_CS_PIN, SDCARD_CS_PIN); //SDCARD_CS_PIN 置1
GPIOPinWrite(SFLASH_CS_BASE, SFLASH_CS_PIN, SFLASH_CS_PIN); //SFLASH_CS_PIN 置1
//SSI配置:基址,协议格式,主/从模式,位速率,数据宽度
SSIConfigSetExpClk(SDC_SSI_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,
SSI_MODE_MASTER, 100000, 8);
SSIEnable(SSI0_BASE); //使能SSI收发
}
//---------------------------------------------------
// 函数名:MMC_SD_Init
// 功能:sd卡初始化
// 参数:无
// 返回值:uint8 type // 卡类型返回值: 0x10 SD, 0x20 MMC
//---------------------------------------------------
BYTE SD_Init(void)
{
UINT8 retry;
UINT8 r1=0;
spi_Interface_Init();
set_spi_speed(100); //低速 SPI=100k
retry = 0;
do
{
write_initial_80_clock(); // 发送80个时钟,使卡同步
SD_CS_ON(); // 使能Card
r1 = spi_write_cmd(CMD0, 0, 0x95); // 发Cmd0(复位)命令
retry++;
if(retry > 200) return (ERROR); //超时退出,个别卡需要更多次循环才有反应
} while(r1 != 0x01); // MMC、SD卡成功转到SPI模式
retry = 2;
while(retry--)spi_write_byte(0xFF);
do
{
r1 = spi_write_cmd(CMD55, 0, 0xff); // 先发送 Cmd55
if(r1 == 0x01) // 如果有反应
{
r1 = spi_write_cmd(CMD41,0, 0xff); // 再发送 Cmd41 进行激活
if(r1 == 0x00) DISK_TYPE = SD_CARD; // 激活成功就是SD卡
}
else { // 如果发送 Cmd55无反应,改发送 Cmd1
r1 = spi_write_cmd(CMD1,0, 0xff);
if(r1 == 0x00) DISK_TYPE = MMC_CARD; // 激活成功就是MMC卡
}
retry++;
if(retry > 255) return (TIME_OUT); // 超时退出, 个别卡需要更多次循环才有反应
} while(r1 != 0x00); // MMC、SD卡激活后的返回值均为0x00
r1 = spi_write_cmd(CMD16, 512, 0xff); //设置读取一次的字节数
if(r1!=0x00)return (TIME_OUT);
SD_CS_OFF(); // 关闭Card
spi_write_byte(0xFF); // 高速SPI前先发送8个时钟
if(DISK_TYPE!=0) set_spi_speed(12500); // 初始化成功,切换到高速 SPI 12.5M
return SUCCESS; //参数返回,1为初始化错误,10为SD卡,20为MMC卡
}
dudududu 发表于 2012-5-14 21:26 static/image/common/back.gif
给你一个我正在用的程序,是在LM3S9B95上面用的,调用的是硬件SPI,所以你需要换用你自己的SPI函数,我实际 ...
谢谢!我先参考一下。我现在的程序能完成sandisk2G卡的初始化和数据扇区的读取,但是其他的卡就很难初始化。我现在使用飞线的方式连接的会有问题吗? 飞线??
木有问题,我的也是飞线,然后目前只能读取小于4G的卡,因为32位的寻址限制(还不知道SD卡更大空间的寻址指令) dudududu 发表于 2012-5-16 11:04 static/image/common/back.gif
飞线??
木有问题,我的也是飞线,然后目前只能读取小于4G的卡,因为32位的寻址限制(还不知道SD卡更大空 ...
整合你的程序之后还是不能把4张卡都初始化,也只能完成2张。我将stm32开发板上用的一个程序(在开发板上可以识别4张卡)移植过来,出现同样的问题。
spi发送接收数据的过程如下正确吗?
u8 _spi_read_write(u8 data)
{
u8 temp;
SSI_DR = data; /* 发送数据放入SPI数据寄存器 */
while(0 == (SSI_SR & (1<<2))); /* 等待数据发送完毕 */
while(0 == (SSI_SR & (1<<3)));/* 等待数据接收完毕*/
temp = SSI_DR; /* 读取接收数据*/
while(SSI_SR&1); /* 等待spi操作完成毕*/
return temp;
}
对于sd卡的spi配置需要注意什么东西吗? 我勒个去模拟要同时搞四张SD卡,我就搞定一张而已哈。
关于SPI发送和接受数据,因为我用的LM3S9B96,有硬件SPI,只要把要发送的数据写到发送寄存器就可以发送,接受的话,只需要读取接受寄存器就可以,很简单的,你这个就不是很清楚了;
不过,好像SPI是同时收发数据的,所以我的程序里,接受的时候,也在发送无效的数据,而发送的时候,也是在接受数据的,只不过丢弃不用而已,
SD卡的配置,看我程序里面的初始化就可以,不过可能还不是很完善,可能有些卡不能很好的识别和兼容,我水平也有限哈,找找其他高手的例程,兼容性可能更好些!! 今天又测到,当我CMD0返回0x01------CMD8返回0x01(得到对应卡的类型)------发送CMD55返回0x01------发送ACMD41没有反应(命令超时,当我把时钟提高到400k以上之后可以得到响应但是数据不正确),如果ACMD41超时之后再去发送CMD55也回超时没有响应,谁知道这是为什么吗? 我对ADATA卡初始化正确,之后读任何扇区的数据都是0,能够正确得到数据的起始令牌0xfe,之后接受到的数据都是0,是什么原因? dudududu 发表于 2012-5-17 17:34 static/image/common/back.gif
我勒个去模拟要同时搞四张SD卡,我就搞定一张而已哈。
关于SPI发送和接受数据,因为我用的LM3S9B96,有硬件 ...
做芯片测试,做方案,当然要兼容所有的卡了,不能指定客户用什么卡啊。
我用的也是硬件spi,我的理解也是这样的,在发送的时候同时读取接受数据丢弃,在接受的时候同时发送无效数据。
我这有其他的程序在stm32开发板上就能识别这4张卡,但是同样的程序到我这里就只能识别2张,还有一张读出数据都是0. {:dizzy:}郁闷啊,搞了好久 注意在SDHC卡中的寻址方式,与一般的SD卡不同,一般的SD卡的方式是字节寻址,而SDHC寻址方式是块寻址,所以在SDHC中,32位地址线寻址范围可以达到(2^32)*512=2TB 请参考atmel的SD卡的初始化程序,它能够初始化各种类型的SD卡 学习了!!!!!!!!!!!!!!!!!!!!1 我读SD卡读了很多个扇区也全是0,郁闷,不知道是什么原因,
楼主解决了吗? 楼主,我的也是同样问题,初始化成功但读0扇区的数据全是0x00,用winhex看的0扇区不全是0啊,有正常的显示信息值,为什么呢
页:
[1]