打印

关于使用STR912的SPI访问SD卡的问题

[复制链接]
4728|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
foodeyun|  楼主 | 2007-6-4 20:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位大虾:
    小弟近日调试SD,使用912的SPI访问,遇到了麻烦!自己修改了一个网上下的驱动(周立功的),修改了相关的接口函数.可是,SD就是没有回应.
    谁有相关的经验,帮帮我!或者把你的源代码发到我邮箱:fdy_001@163.com
    不甚感激!
沙发
浪淘沙| | 2007-6-4 20:36 | 只看该作者

还是说说你是如何做的吧;不然自己用示波器看看波形自己

即使有人给了你个源程序,你还是可能遇到这样的问题,到时候可能还是不知所措;不如趁这个机会提高一下自己。

另STF好像做过,你不妨提出些问题,也许它能帮你。

使用特权

评论回复
板凳
foodeyun|  楼主 | 2007-6-5 16:23 | 只看该作者

spi访问SD,用什么模式?

我访问EEPROM m95080可以,但是访问SD卡不行,SD没有回应,估计是数据格式不对!需要怎么设置?
我没有找到SD协议的时序.

使用特权

评论回复
地板
香水城| | 2007-6-5 21:26 | 只看该作者

你不是有源程序吗?分析跟踪一下应该能找到答案吧

我们还没有做过,暂时帮不上忙。

有其他网友做过吗?

使用特权

评论回复
5
hq1025| | 2007-6-6 13:41 | 只看该作者

问题应该不大!

我们的SD卡接口已经调试成功了,用SSP接口(SPI模式),移植的是ZLG的SD卡模块.配置
的时候要注意的几个问题.
1.配置SSP时SSP0_CLK,SSP0_MOSI不要设置GPIO_IPConnected_Enable,而SSP0_MISO一定要设置.否则收发数据可能会有问题.这个问题在用nSS线去做SD卡片选时肯定会有.
2.SD卡初始化时要按要求设低SSP的速率<400K
3.SSP收数据时要注意先清除FIFO,因为ZLG的SD卡读写模块是用于LPC系列,而LPC系列SPI接口很多都是没有FIFO的,所以他们的软件包里没有这个问题.
4.可以参考Keil for ARM工具附带的例程中的一个SD文件系统的例程.在下面这个目录
C:KeilARMRV30RTLBoardsKeilMCBSTR9SD_File
希望你把问题描述更清楚一些,是初始化不成功?命令无响应?还是其他的现象.这样他们STF的人就好分析问题.

使用特权

评论回复
6
foodeyun|  楼主 | 2007-6-6 15:34 | 只看该作者

高手帮忙看看,我把代码贴出来,具体现象也描述了一下

我采用买开发板自带的SSP访问SPI口EEPROM的例子时,可以正确访问EEPROM.说明SSP口正常.
当我接上SD卡,发送CMD0,应该收到0x01,实际收到的尽是0xFF.
于是不停的发数据,用示波器观察,SCLK为328KHz,MOSI有数据输出.波形为时钟的上升沿数据稳定,便于SD卡锁存.
硬件是这样连接的:SCLK,MISO,MOSI分别对应接SD.5,SD.7,SD.2, NSS接到SD.1.
我是将NSS配置为普通IO片选的.

是不是应该将 NSS配置为NSS,接到3.3V,然后用另外的一个IO来做片选?

IO配置程序如下:
/* SSP0 pins Config */
  GPIO_DeInit(GPIO5);
  /*Gonfigure SSP0_CLK, SSP0_MOSI pins */
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
  //GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable;
  GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt2  ;
  GPIO_Init (GPIO5, &GPIO_InitStructure);
  
  /*Configure P5.7*/
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Direction = GPIO_PinOutput;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull ;
  GPIO_InitStructure.GPIO_Alternate = GPIO_OutputAlt1  ;
  GPIO_Init (GPIO5, &GPIO_InitStructure);
  GPIO_WriteBit(GPIO5,GPIO_Pin_7,(BitAction)1);
  
  /*Gonfigure SSP0_MISO pin GPIO5.6*/
  GPIO_StructInit(&GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Direction = GPIO_PinInput;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Type = GPIO_Type_PushPull;
  GPIO_InitStructure.GPIO_IPConnected = GPIO_IPConnected_Enable;
  GPIO_InitStructure.GPIO_Alternate = GPIO_InputAlt1;
  GPIO_Init (GPIO5, &GPIO_InitStructure);

SSP配置:
  /* SSP0 configuration */
  SSP_DeInit(SSP0);
  SSP_InitStructure.SSP_FrameFormat = SSP_FrameFormat_Motorola;
  SSP_InitStructure.SSP_Mode = SSP_Mode_Master;
  SSP_InitStructure.SSP_CPOL = SSP_CPOL_High;
 // SSP_InitStructure.SSP_CPOL = SSP_CPOL_Low;
  SSP_InitStructure.SSP_CPHA = SSP_CPHA_2Edge;
  SSP_InitStructure.SSP_DataSize = SSP_DataSize_8b;
  SSP_InitStructure.SSP_ClockRate = 100;
  SSP_InitStructure.SSP_ClockPrescaler = 2; // must be even
  SSP_Init(SSP0, &SSP_InitStructure);

  /* SSP0 enable */
  SSP_Cmd(SSP0, ENABLE); 

SYSCLK配置:
  SCU_MCLKSourceConfig(SCU_MCLK_OSC);
  SCU_PLLFactorsConfig(N,M,P);
  SCU_PLLCmd(ENABLE);
  while(!(SCU->SYSSTATUS&SCU_FLAG_LOCK));
  SCU_MCLKSourceConfig(SCU_MCLK_PLL);//MCLK=48M
  SCU_RCLKDivisorConfig(SCU_RCLK_Div4);//RCLK=12M
  SCU_PCLKDivisorConfig(SCU_PCLK_Div8);//PCLK=12M/8

使用特权

评论回复
7
hq1025| | 2007-6-6 16:47 | 只看该作者

很奇怪了!

很奇怪了!在使用SSP功能时,NSS线可以做普通IO来用.如果你确定你的SCLK为328KHz
的话,可能就是SSP的读写出现了问题.不知到你对它的Rx FIFO是怎么处理的,如果想
收一个数据,最好先清除Rx FIFO再发送一个0xFF后读SSP0->DR就收到数据了.也有可
能是你对SD的初始化操作出现了问题,不知你是否曾经调试过SPI模式下的SD卡?先确认你的读写程序是否是对的?我在发送CMD0命令前有一个置位CS线的操作(见下).在
SD_SPIDelay()函数中不断发送0XFF,还有你可以试着将SPI的速率调得更低一点.

SPI_CS_Assert();    /* 1. 置CS为低 assert CS */  
SD_SPIDelay(25);    /* 2. 至少延时 74 clock delay more than 74clock*/
SPI_CS_Deassert();    /* 3. 置CS为高 dessert CS */
SD_SPIDelay(2);        /* 4. 延时2(8 clock) delay 2(8 clock) */

发送CMD0命令

使用特权

评论回复
8
hq1025| | 2007-6-6 16:59 | 只看该作者

可以用口线模拟SPI口试一下!

如果怀疑是SSP导致的问题的话,可以考虑用I/O口线模拟SPI试一下!我也是用这种方法找到问题的.

使用特权

评论回复
9
hq1025| | 2007-6-6 17:11 | 只看该作者

我的配置!

我们的CPHA CPOL和速率跟你不一样.你的初始速率有些高
/* SSP0 configuration */
SSP_DeInit(SSP0);
SSP_InitStructure.SSP_FrameFormat = SSP_FrameFormat_Motorola;    
SSP_InitStructure.SSP_Mode = SSP_Mode_Master;        // 主从选择
SSP_InitStructure.SSP_CPOL = SSP_CPOL_High;            // CPOL 时钟输出极性,仅SPI模式有效
SSP_InitStructure.SSP_CPHA = SSP_CPHA_2Edge;        // CPHA 时钟输出相位,仅SPI模式有效
SSP_InitStructure.SSP_DataSize = SSP_DataSize_8b;    // 数据长度为8位
SSP_InitStructure.SSP_SlaveOutput = SSP_SlaveOutput_Enable;
SSP_InitStructure.SSP_ClockPrescaler = 0xFE;
SSP_Init(SSP0, &SSP_InitStructure);
SSP_Cmd(SSP0, ENABLE);

使用特权

评论回复
10
foodeyun|  楼主 | 2007-6-7 10:49 | 只看该作者

可以初始化,写数据还是有问题!

使用特权

评论回复
11
foodeyun|  楼主 | 2007-6-7 11:39 | 只看该作者

可以初始化,写数据还是有问题!

非常的感谢hq1025,stf的帮助!

我更改了端口的初始化程序,使用周立功的代码,可以读出SD的容量,扇区数等信息,可是写了数据读出来全是0xFF或者0x00.这是为什么?

1,关于NSS,如hq1025说的,初始化为NSS后,它可做普通的IO来实现CS.这一点已
证明可以.

2,如hq1025说的,我改了接收函数为:

INT8U SPI_RecByte(void)
{                        
    SSP_ClearFlag(SSP0, SSP_FLAG_RxTimeOut);
    SSP_ClearFlag(SSP0,SSP_FLAG_RxOverrun);
    
    SSPx->SR &=  0xFB;    // 
    
    SPI_SendByte(0xFF);
    
    /* loop while Receive FIFO is empty */
    while(SSP_GetFlagStatus(SSP0,SSP_FLAG_RxFifoNotEmpty) == RESET);    
  //for(u16 i=0; i<65535; i++);
  
    /* return the byte read from the SPI bus */
    return((u8)SSP_ReceiveData(SSP0));//>>8);     
}

3,按照STF的修改了IO口的设置.

4,初始化成功说明,通信应该没有问题.问题在于命令!
我写了512个字节到第0 块,然后读出来总是0或者0xFF.不明白究竟是写有问题,还是读有问题.我没有使用CRC.
程序如下:
for(i=0; i<512; i++)
{
    Tx_Buffer = i;
}
SD_WriteBlock(0,Tx_Buffer);
//此函数发送CMD24.
    
SD_ReadBlock(0,Rx_Buffer);
//此函数发送CMD17.


请问:读写的时候,还应该注意什么?

使用特权

评论回复
12
hq1025| | 2007-6-7 13:18 | 只看该作者

是不是WP的问题?

我好像没有碰到这样的问题,是不是WP的问题?ZLG_SD软件包里面的SD_ChkCardWP()会检测WP信号,写块时如果不通过的话就会跳出来,写操作不会完成.你读出来的数据是不是一直固定为0xFF或0x00?还是不确定的数据?如果前面的初始化命令可以成功,那么同样的软件包里面的其他命令没有理由不能操作.试一下这个SPI操作函数:
void SPI_SendByte(INT8U byte)
{
   while ((SSP0->SR & TNF) == 0);
   SSP0->DR = byte;
   /* Wait if RNE cleared, Rx FIFO is empty. */
   while ((SSP0->SR & RNE) == 0);
   byte = SSP0->DR;
}

INT8U SPI_RecByte(void)
{
   u8 byte;

   /* Wait if TNF cleared, Tx FIFO is full. */
   while ((SSP0->SR & TNF) == 0);
   SSP0->DR = 0xFF;
   /* Wait if RNE cleared, Rx FIFO is empty. */
   while ((SSP0->SR & RNE) == 0);
   byte = SSP0->DR;

   return (byte);
}

使用特权

评论回复
13
foodeyun|  楼主 | 2007-6-7 14:57 | 只看该作者

已经成功了,谢谢啊!

现在已经可以读写了!
哎,原来还是发送接受函数的问题!多谢多谢!

再请教一下:
现在没有用CRC,我在读数据的时候,有时候读出来的数据是错误的,差不多3到4次错一次.这正常吗?
应该怎么办? 使用CRC校验吗?

使用特权

评论回复
14
hq1025| | 2007-6-7 15:14 | 只看该作者

不用客气!

不用客气!读写偶尔有错误的情况我还没有碰到过.而且我们以前用文件系统操作等等也没有出现过.可能像你说的一样与CRC有关,你可以打开CRC校验试一下.

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

113

主题

147

帖子

0

粉丝