TF卡的SPI驱动 硬件连接关系SD采用SPI模式时的引脚连接关系 硬件系统设计图如下所示: SPI模式的TF卡引脚连接关系图如下。 这里需要特别提醒,CS引脚默认是不焊接的,如果需要测试必须先短接后PA3引脚才能生效。在这里绕了好几天。 软件驱动 1) IO口配置 这里默认配置SPI的CS引脚为软件控制。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_SCK; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_MISO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init( GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_MOSI; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_NSS; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init( GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_SDCMD; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init( GPIOA, &GPIO_InitStructure); 2) SPI设备配置 SPI设备采用SPI1,全双工2线方式,软件控制CS信号。 SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //SPI_CPOL_High SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_256; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init( SPI1, &SPI_InitStructure ); SPI_Cmd( SPI1, ENABLE ); 3) TF卡驱动 向SD卡写入一个CMD或者ACMD指令的过程是这样的: 首先使CS为低电平,SD卡使能;其次在SD卡的Din写入指令;写入指令后还要附加8个填充时钟,是SD卡完成内部操作;之后在SD卡的Dout上接受回应;回应接受完毕使CS为低电平,再附加8个填充时钟。 注意:在SD卡的Din没有数据写入时,应使Din保持高电平。 l SD卡复位: 1.拉高CS,发送至少74个clk周期来使SD卡达到正常工作电压和进行同步 2.选低CS,发送CMD0,需要收到回应0x01表示成功进入idle状态 3.拉高CS,发送8个时钟 实现代码: for(i=0;i<10;i++) SPI_ReadWrite_Byte(0XFF);//发送至少74个脉冲 retry=20; do { r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态 }while((r1!=0X01) && retry--); l SD卡初始化: 复位成功后,SD卡就进入了SPI模式,接着应该进行初始化。发送CMD55+ACMD41完成初始化。 时序图如下: 程序代码实现: SD_SendCmd(CMD55,0,0X01); //发送CMD55 r1=SD_SendCmd(CMD41,0,0X01); //发送CMD41 l SDK卡读操作 操作流程: 1.发送CMD18读,收到0x00表示成功 2.连续读直到读到开始字节0xFE 3.读512字节 4.读两个CRC字节 5.如果还想读下一扇区,重复2-4 6.发送CMD12来停止读多块操作 时序图如下: 程序实现: r1=SD_SendCmd(CMD18,sector,0X01); do { r1=SD_RecvData(buf,512); buf+=512; }while(--cnt && r1==0); SD_SendCmd(CMD12,0,0X01) l SDK卡写操作 操作走流程: 1.发送CMD24(写单块),CMD25(写多块)收到0x00表示成功 2.发送若干时钟 3.发送写单块开始字节0xFE,写多块开始字节0xFC 4.发送512个字节数据 5.发送2字节CRC(可以均为0xff) 6.连续读直到读到XXX00101表示数据写入成功 7.继续读进行忙检测(读到0x00表示SD卡正忙),当读到0xff表示写操作完成 8.如果想写下一扇区重复2-7步骤 9.发送写多块停止字节0xFD来停止写操作 10.进行忙检测直到读到0xFF 时序图: 程序代码实现: r1=SD_SendCmd(CMD25,sector,0X01); if(r1==0) { do { r1=SD_SendBlock(buf,0xFC); buf+=512; }while(--cnt && r1==0); r1=SD_SendBlock(0,0xFD); } 测试效果成功的完成SD卡初始化,并且读到了SD卡容量。
|
程序源码可以放出来看看吗
感谢分享