#include "systemInit.h" #include "sd.h" #include "myfun.h" #include "pin_define.h" #include "uart_init.h"
//定义初始化变量标志 unsigned char is_init; //在初始化的时候设置此变量为1,同步数据传输(SPI)会放慢
unsigned char _dat; /******************************************************************************** - 功能描述:向SD卡以SPI模式写数据 - 隶属模块:SD卡模块 - 参数说明:无 - 返回说明:返回类型为void --形参说明:该参数为写向SD卡的数据 ********************************************************************************/ void SD_spi_write(unsigned char x) { unsigned char i; for(i=0;i<8;i++) { if((x>>(7-i)&0x01)==0x01) GPIOPinWrite(SD_COM_PORT,SD_DIN_F_SO,0x04); else GPIOPinWrite(SD_COM_PORT,SD_DIN_F_SO,0x00); GPIOPinWrite(SD_COM_PORT,SD_CLK_F_CLK,0X00); if(is_init) SysCtlDelay(DELAY_TIME1*TheSysClock/DELAY_TIME);//delay(DELAY_TIME); GPIOPinWrite(SD_COM_PORT,SD_CLK_F_CLK,0X02); if(is_init) SysCtlDelay(DELAY_TIME1*TheSysClock/DELAY_TIME);//delay(DELAY_TIME); } }
/****************************************************************** - 功能描述:IO模拟SPI,读取一个字节 - 隶属模块:SD卡模块 - 函数属性:内部 - 参数说明:无 - 返回说明:返回读到的字节 ******************************************************************/ unsigned char SD_spi_read() //SPI读一个字节 { unsigned char ulStatus; unsigned char i; _dat=0x00;
for(i=0;i<8;i++) { GPIOPinWrite(SD_COM_PORT,SD_OUT_F_SI,0X01); ulStatus=GPIOPinRead(SD_COM_PORT,SD_OUT_F_SI);
GPIOPinWrite(SD_COM_PORT,SD_CLK_F_CLK,0X02); if(is_init) SysCtlDelay(DELAY_TIME1*TheSysClock/DELAY_TIME);//delay(DELAY_TIME); GPIOPinWrite(SD_COM_PORT,SD_CLK_F_CLK,0X00); if(is_init) SysCtlDelay(DELAY_TIME1*TheSysClock/DELAY_TIME);//delay(DELAY_TIME);
if(ulStatus&0x01) _dat|=0x01<<(7-i); else _dat&=0xfe<<(7-i); } return (_dat); }
/****************************************************************** - 功能描述:向SD卡写命令 - 隶属模块:SD卡模块 - 函数属性:内部 - 参数说明:SD卡的命令是6个字节,pcmd是指向命令字节序列的指针 - 返回说明:命令写入后,SD卡的回应值,调用不成功,将返回0xff ******************************************************************/ //向SD卡写命令,pcmd是命令字节序列的首地址 unsigned char SD_Write_Cmd(unsigned char *pcmd) { unsigned char temp,time=0;
GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); SD_spi_write(0xff); //提高兼容性,如果没有这里,有些SD卡可能不支持 GPIOPinWrite(SD_COM_PORT,SD_CS,0X00);
SD_spi_write(pcmd[0]); SD_spi_write(pcmd[1]); SD_spi_write(pcmd[2]); SD_spi_write(pcmd[3]); SD_spi_write(pcmd[4]); SD_spi_write(pcmd[5]); do { temp = SD_spi_read();//一直读,直到读到的不是0xff或超时 time++; }while((temp==0xff)&&(time<TRY_TIME)); UARTprintf("is ok read cmd.\r\n"); return(temp); }
/******************************************************************************** - 功能描述:复位SD卡,用到CMD0,使用SD卡切换到SPI模式 - 隶属模块:SD卡模块 - 参数说明:无 - 返回说明:调用成功,返回0x00,否则返回INIT_CMD0_ERROR (Pin_Define.h中有定义) ********************************************************************************/ unsigned char SD_Reset(void)//SD卡复位,进入SPI模式,使用CMD0(0号命令) { unsigned char time,temp,i; unsigned char pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; UARTprintf("go into sd_reset.\r\n"); is_init=0x01; //设置初始化标志位 GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); for(i=0;i<0xff;i++) //初始时,首先要发送最少74个时钟信号,这是必须的!!! { SD_spi_write(0xff); //120个时钟周期 } GPIOPinWrite(SD_COM_PORT,SD_CS,0X00); time=0; do { temp=SD_Write_Cmd(pcmd); //写入CMD0 time++; if(time==TRY_TIME) { GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); UARTprintf("INIT_CMD0_ERROR\r\n"); return(INIT_CMD0_ERROR); //CMD0写入失败 } }while(temp!=0x01); GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); SD_spi_write(0xff); //按照SD卡的操作时序在这里补8个时钟 UARTprintf("go out sd_reset.\r\n"); return 0; //返回0,说明复位操作成功 }
/****************************************************************************** - 功能描述:初始化SD卡,使用CMD1 - 隶属模块:SD卡模块 - 函数属性:内部 - 参数说明:无 - 返回说明:调用成功,返回0x00,否则返回INIT_CMD1_ERROR (Pin_Define.h中有定义) ******************************************************************************/ unsigned char SD_Init(void) //初始化,使用CMD1(1号命令) { unsigned char time,temp; unsigned char pcmd[] = {0x41,0x00,0x00,0x00,0x00,0xff}; UARTprintf("go into sd_init.\r\n"); GPIOPinWrite(SD_COM_PORT,SD_CS,0X00);
time=0; do { temp=SD_Write_Cmd(pcmd); time++; if(time==TRY_TIME) { GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); return(INIT_CMD1_ERROR); //CMD1写入失败 } }while(temp!=0); is_init=0; //初始化完毕,将is_init设置为0,为了提高以后的数据传输速度 GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); //关装SD卡的片选
SD_spi_write(0xff); //按照SD卡的操作时序在这里补8个时钟 UARTprintf("go out sd_init.\r\n"); return(0); //返回0,说明初始化操作成功 }
/*********************************************************************************************** - 功能描述:将buffer指向的512个字节的数据写入到SD卡的addr扇区中 - 隶属模块:SD卡模块 - 函数属性:内部 - 参数说明:addr:扇区地址 buffer:指向数据缓冲区的指针 - 返回说明:调用成功,返回0x00,否则返回WRITE_BLOCK_ERROR (Pin_Define.h中有定义) - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率,is_init不为0时可提高SPI速度 ***********************************************************************************************/ //向SD卡中的指定地址的扇区写入512个字节,使用CMD24(24号命令) unsigned char SD_Write_Sector(unsigned long addr,unsigned char *Buffer) { unsigned char temp,time; unsigned int i; //向SD卡中单个块(512字节,一个扇区)写入数据,用CMD24 unsigned char pcmd[] = {0x58,0x00,0x00,0x00,0x00,0xff}; //addr = addr * 512 将块地址(扇区地址)转为字节地址 [这里就限制了SD卡的最大容量为4G] addr<<=9; //将字节地址写入到CMD24字节序列中 pcmd[1]=((addr&0xff000000)>>24); pcmd[2]=((addr&0x00ff0000)>>16); pcmd[3]=((addr&0x0000ff00)>>8); //打开SD卡片选 GPIOPinWrite(SD_COM_PORT,SD_CS,0X00);
time=0; do { temp=SD_Write_Cmd(pcmd); time++; if(time==TRY_TIME) { GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); //命令写入失败 return(temp); } }while(temp!=0); //这里要插入若干时钟信号 for(i=0;i<100;i++) { SD_spi_read(); } //写入开始字节 0xfe,后面就是要写入的512个字节的数据 SD_spi_write(0xfe); //将缓冲区中要写入的512个字节写入SD卡 for (i=0;i<512;i++) { SD_spi_write(*Buffer++); } //两个字节的CRC校验码,不用关心 SD_spi_write(0xFF); SD_spi_write(0xFF); //读取返回值 temp=SD_spi_read(); //如果返回值是 XXX00DELAY_TIME1 说明数据已经被SD卡接受了 if((temp & 0x1F)!=0x05) { GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); //写块数据失败 return(WRITE_BLOCK_ERROR); } //等到SD卡不忙(数据被接受以后,SD卡要将这些数据写入到自身的FLASH中,需要一个时间) while(SD_spi_read()!=0xff); //忙时,读回来的值为0x00,不忙时,为0xff //关闭片选 GPIOPinWrite(SD_COM_PORT,SD_CS,0X08);
SD_spi_write(0xFF);//按照SD卡的操作时序在这里补8个时钟 return(0); //返回0,说明写扇区操作成功 }
/**************************************************************************** - 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区 - 隶属模块:SD卡模块 - 函数属性:内部 - 参数说明:addr:扇区地址 buffer:指向数据缓冲区的指针 - 返回说明:调用成功,返回0x00,否则返回READ_BLOCK_ERROR (sd.h中有定义) - 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率 ****************************************************************************/ //从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令) unsigned char SD_Read_Sector(unsigned long addr,unsigned char *buffer) { unsigned int j; unsigned char time,temp; unsigned char pcmd[]={0x51,0x00,0x00,0x00,0x00,0xFF}; //CMD17的字节序列 //sector = sector * 512 将块地址(扇区地址)转为字节地址 addr<<=9;
pcmd[1]=((addr&0xFF000000)>>24); pcmd[2]=((addr&0x00FF0000)>>16); pcmd[3]=((addr&0x0000FF00)>>8); //打开片选 GPIOPinWrite(SD_COM_PORT,SD_CS,0X00);
time=0; do { //写入CMD17 ,写入17号命令 temp=SD_Write_Cmd(pcmd); time++; if(time==TRY_TIME) { return(READ_BLOCK_ERROR); //读块失败 } }while(temp!=0); //一直读,当读到0xfe时,说明后面的是512字节的数据了 while (SD_spi_read() != 0xfe); //将数据写入到数据缓冲区中 for(j=0;j<512;j++) { buffer[j]=SD_spi_read(); } //读取两个字节的CRC校验码,不用关心它们 SD_spi_read(); SD_spi_read(); //SD卡关闭片选 GPIOPinWrite(SD_COM_PORT,SD_CS,0X08); //按照SD卡的操作时序在这里补8个时钟 SD_spi_write(0xFF);
return 0; }
|