⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd.c

📁 SD和FAT文件系统.rar
💻 C
字号:

#include "..\inc\sd.h"
#include "..\inc\44b.h"

SD_INFO g_SDInfo;

volatile char endSioTR=0;
//启用中断传输模式
void __irq Sio_Int(void)			//SPI中断函数
{
	rI_ISPC = BIT_SIO;				//清零中断标志位
	endSioTR = 1;
}

/*************************************************************************
* 名称: void SPI_MasterTransmit(INT8U u8Data)				 									 
* 功能: SPI主机模式传送数据				       									
* 参数: cData 要传输的字节数据    		                   									
* 返回: SPI接收值		                           								
*************************************************************************/
INT8U SPI_MasterTransmit(INT8U u8Data)
{
	rSIODAT = u8Data;
	rSIOCON |= (1 << 3);  //启动数据传输 
	while (!endSioTR); 	//等待传输结束
	endSioTR = 0;
	return rSIODAT;  //返回SPI接收的数据
}
/*************************************************************************
*名称: SD_SendCMD													 
*功能: 向SD卡发送命令	       									
*参数: u8Cmd 命令 u32Arg 参数					          									
*返回: SD卡状态值		                           								
*************************************************************************/	
INT8U SD_SendCMD(INT8U u8Cmd, INT32U u32Arg)
{
	INT8U r1;
	INT16U Temp = 0;
	SPI_CS_ASSERT;
	SPI_MasterTransmit(u8Cmd | 0x40);	//分别写入命令	
	SPI_MasterTransmit(u32Arg >> 24);
	SPI_MasterTransmit(u32Arg >> 16);
	SPI_MasterTransmit(u32Arg >> 8);
	SPI_MasterTransmit(u32Arg);
	SPI_MasterTransmit(0x95);
	do{
		r1 = SPI_MasterTransmit(0xFF);
		if(Temp++ > 100) 
		{
			break; 						//超时退出
		}	
	}while(r1 == 0xFF);
	SPI_CS_DEASSERT;
	SPI_MasterTransmit(0xFF); 			//发送8个填充时钟
	return r1; 							//返回状态值	
}
/*************************************************************************
*名称: SD_GetOCR
*功能: 获取OCR寄存器数据	       									
*参数: *pu8Buff 数据缓存区指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetOCR(INT8U *pu8Buff)
{
	INT8U i;
	INT8U r1=0;
	r1 = SD_SendCMD(CMD_SD_SEND_OP_COND, 0);
	if(r1 != 0) //响应错误
	{
		return 1;
	}
	SPI_CS_ASSERT;	
    for (i = 0; i < 4; i++)
    {
    	pu8Buff[i] = SPI_MasterTransmit(0xFF);
    }
	SPI_CS_DEASSERT;	
	return 0;
}
/*************************************************************************
*名称: SD_GetCID
*功能: 获取CID寄存器数据	       									
*参数: *pu8Buff 数据缓存区指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetCID(INT8U *pu8Buff)
{
	INT8U i;
	INT8U Temp = 0;
	INT8U r1=0;
	r1 = SD_SendCMD(CMD_SEND_CID,0);//发送读CSD寄存器命令
	if(r1 != 0) //响应错误
	{
		return 1;
	}
	SPI_CS_ASSERT;
	do{
		r1 = SPI_MasterTransmit(0xFF);
		if(Temp++ > 100)
		{
			return 1;
		}
	}while(r1 != 0xFE); //等待数据起始令牌
    for (i = 0; i < 16; i++)
    {
    	pu8Buff[i] = SPI_MasterTransmit(0xFF);
    }
  SPI_MasterTransmit(0xFF); //发送8个填充时钟
	SPI_CS_DEASSERT;	
	return 0;	
}
/*************************************************************************
*名称: SD_GetCSD
*功能: 获取CSD寄存器数据	       									
*参数: *pu8Buff 数据缓存区指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetCSD(INT8U *pu8Buff)
{
	INT8U i;
	INT8U Temp = 0;
	INT8U r1=0;
	r1 = SD_SendCMD(CMD_SEND_CSD ,0);
	r1 = SD_SendCMD(CMD_SEND_CSD ,0);//发送读CSD寄存器命令
	if(r1 != 0) //响应错误
	{
		return 1;
	}
	SPI_CS_ASSERT;
	do{
		r1 = SPI_MasterTransmit(0xFF);
		if(Temp++ > 100)
		{
			return 1;
		}
	}while(r1 != 0xFE); //等待数据起始令牌
		
    for (i = 0; i < 16; i++)
    {
    	pu8Buff[i] = SPI_MasterTransmit(0xFF);
    }
  SPI_MasterTransmit(0xFF); //发送8个填充时钟
	SPI_CS_DEASSERT;	
	return 0;	
}
/*************************************************************************
*名称: SD_GetCardInfo
*功能: 获取卡片信息
*参数: 
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetCardInfo(SD_INFO *pg_SDInfo)
{
	INT8U Temp[16];
    if(SD_GetCID(Temp) == 0)		//获取CID信息
    {
       	INT8U i;
       	pg_SDInfo->mid = Temp[0];
		pg_SDInfo->oid[0] = Temp[1];
		pg_SDInfo->oid[1] = Temp[2];  
		for(i = 0; i < 5; i++)
		{
			pg_SDInfo->pnm[i] = Temp[i + 3];
		}
        pg_SDInfo->prv = Temp[1];
		pg_SDInfo->psn = ((INT32U)Temp[9] << 24) + ((INT32U)Temp[10] << 16)
				+ ((INT32U)Temp[11] << 8) + (INT32U)Temp[12];
				//计算32位串号
		pg_SDInfo->mdt = Temp[14];
    }
    else
    {
        return 3;       
    }
	if(SD_GetCSD(Temp) == 0)		//获取CSD信息
	{
		INT32U j;
		pg_SDInfo->bl = 1 << (Temp[5] & 0x0F);	//计算块长度
	
		 
		pg_SDInfo->bn = ((Temp[6] & 0x03) << 10) +
						(Temp[7] << 2) + ((Temp[8] & 0xC0) >> 6);	
                							//计算C_SIZE + 1
		j = ((Temp[9] & 0x03) << 1) + ((Temp[10] & 0x80) >> 7);
	      									//计算C_SIZE_MULT	
    	
		pg_SDInfo->bn = (pg_SDInfo->bn + 1) * (1 << (j + 2));	
        		//计算BLOCKNR = (C_SIZE + 1) * 2 ^ (C_SIZE_MULT + 2)	
        pg_SDInfo->cap = pg_SDInfo->bl * pg_SDInfo->bn; //计算容量大小
        pg_SDInfo->cap >>= 20;
	}
	else
	{
		return 4;
	}
	return 0;
}
/*************************************************************************
*名称: SD_Init													 
*功能: SD卡初始化	       									
*参数: 无					          									
*返回: 0成功 非零是失败		                           								
*************************************************************************/	
INT8U SD_Init(PSD_INFO psdi)
{
	INT8U i;
	INT8U Temp = 0;
	INT8U r1=0;
	
	pISR_SIO = (unsigned)Sio_Int;      //中断入口地址
	rINTMSK = ~(BIT_GLOBAL | BIT_SIO);
	//-- SPI(SIO) port initialize
	rPCONF = (rPCONF & 0x3ff) + (3 << 19) + (3 << 16) + (3 << 13) + (3 << 10);
	rPUPF |= 0x160; //Rx must pullup

	//-- SPI(SIO) controller & card initialize
	rSIOCON = (0x0 << 7) | (0x0 << 6) | (0x1 << 5) | (0x0 << 4) | (0x0 << 3) | (0x0 << 2) | 0x1;
	//inter clk, MSB 1st, Tx/Rx, falling, no action, auto run, SIO int
	rSBRDR = 99; //MCLK=60MHz,SIOCK=300KHz(in initialize time)
	rIVTCNT = 0;
	
	for (i = 0;i < 20;i++) 		//至少发送74个脉冲 
	{
		SPI_MasterTransmit(0xFF);
	}
	
	do								//复位存储卡
	{
		r1 = SD_SendCMD(CMD_GO_IDLE_STATE , 0); //发IDLE命令	
		if(Temp++ > 20)
		{
			return 1;				//超时退出
		}		
	} while(r1 != 0x01);
	
	Temp = 0;
	do								//激活存储卡
	{
		r1 = SD_SendCMD(CMD_SEND_OP_COND , 0); 	//发CMD1命令激活卡	
		if(Temp++ > 20)
		{
			return 1;					//超时退出
		}		
	} while(r1 != 0x01);
	do 									//判断卡片类型
	{
		r1 = SD_SendCMD(CMD_APP, 0); 	//发CMD55命令	
		if(r1 == 0x01) 					//响应正确
		{
			r1 = SD_SendCMD(CMD_SD_SEND_OP_COND, 0);//发ACMD41命令
			if(r1 == 0x00) 				//SD卡
			{
				psdi->ct = SD_TYPE_SD	; 
			}
		}
		
		else							//响应错误
		{
			r1 = SD_SendCMD(CMD_SEND_OP_COND , 0); //发CMD1命令激活卡
			if(r1 == 0x00)				//MMC卡
			{
				psdi->ct = SD_TYPE_MMC;
			}
		}
	//	Uart_Printf("卡的类型\n",&psdi->ct);
/*		if(Temp++ > 20)
		{
			return 1;				//超时退出
		}	*/
	} while(r1 != 0x00);
	Uart_Printf("SD卡的类型\n");
	
	if(SD_GetCardInfo(psdi) != 0)	// 获取存储卡信息失败
	{
		return 1;
	}
	Uart_Printf("获取存储卡信息\n");
	r1 = SD_SendCMD(CMD_CRC_ON_OFF, 0);   // 关闭crc16
	r1 = SD_SendCMD(CMD_CRC_ON_OFF, 0);
	if(r1 != 0 )
	{
		return 1;
	}
	Uart_Printf("关闭crc16\n");
	r1 = SD_SendCMD(CMD_SET_BLOCKLEN, 512); 	// 设扇区大小512
	if(r1 != 0 )
	{
		return 1;
	}
	Uart_Printf("\nIn ready state\n");
	rSIOCON = (0x0 << 7) | (0x0 << 6) | (0x1 << 5) | (0x0 << 4) | (0x0 << 3) | (0x0 << 2) | 0x1;
	rSBRDR = 5; 	//MCLK=60MHz,SIOCK=5MHz
	rIVTCNT = 0;
	return 0;	
}
/*************************************************************************
*名称: SD_ReadBlockSingle
*功能: 读取单块数据
*参数: u32Sector扇区地址, *pBuff读取数据存饭缓存指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_ReadBlockSingle(INT32U u32Sector, INT8U *pu8Buff)
{

	INT16U Temp = 0;
	INT8U r1 = 0;
	INT16U i = 0;
	do{
		r1 = SD_SendCMD(CMD_READ_SINGLE_BLOCK, u32Sector << 9);
											 //发送读BLOCK命令
		if(Temp++ > 10) //超时返回
		{
             return 1;
		}
	}while(r1 != 0x00);
	Temp = 0;
	SPI_CS_ASSERT;
	while( SPI_MasterTransmit(0xFF) != 0xFE); //等待数据起始令牌
  for (i = 0; i < 512; i++) //读取一整块数据
  {
  	pu8Buff[i] = SPI_MasterTransmit(0xFF);
  }
  SPI_MasterTransmit(0xFF); //接收伪CRC16
  SPI_MasterTransmit(0xFF); 
	SPI_CS_DEASSERT;
  SPI_MasterTransmit(0xFF); //发送8个填充时钟

	return 0;	
}
/*************************************************************************
*名称: SD_WriteBlockSingle
*功能: 写取单块数据
*参数: u32Sector扇区地址, *pBuff指向写入数据
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_WriteBlockSingle(INT32U u32Sector, INT8U *pu8Buff)
{
	INT16U i;
	INT8U Temp = 0;
	INT8U r1 = 0;
	do{
		r1 = SD_SendCMD(CMD_WRITE_SINGLE_BLOCK, u32Sector << 9); 
								//发送读BLOCK命令
		if(Temp++ > 10)
		{
            return 1;
		}
	}while(r1 != 0);
	SPI_CS_ASSERT;
    SPI_MasterTransmit(0xFF);
    SPI_MasterTransmit(0xFE); //发送数据起始令牌
    for (i = 0; i < 512; i++)
    {
    	SPI_MasterTransmit(*pu8Buff++);
    }
    SPI_MasterTransmit(0xFF); //发送伪CRC16
    SPI_MasterTransmit(0xFF);
    r1 = SPI_MasterTransmit(0xFF);
    if((r1 & 0x0F) != 0x05) //等待是否成功
    {
        SPI_MasterTransmit(0xFF);
        SPI_CS_DEASSERT;
        return 1;
    }
    while(SPI_MasterTransmit(0xFF) != 0xFF); //等待是否完成
    SPI_MasterTransmit(0xFF);
	SPI_CS_DEASSERT;	
	return 0;	
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -