stm32f103zet6 기반 FAT16 파일 시스템 학습 0(SD 카드 섹터 읽기)

SD카드를 본 지 이틀이 되었는데 주로 테스트된 카드의 용량이 맞지 않아서 계속 원인을 찾았는데 결국은 단위 위에 문제가 생겼을 뿐입니다. 아마도 이전에 SD를 접하지 못했기 때문일 것입니다. 그래서 그 중의 일부 레지스터에 대해 잘 모릅니다. 모든 것이 다시 시작되었습니다. 이 레지스터 매뉴얼을 대조하고 프로그램을 이해하고 프로그램을 수정합니다.한 걸음 한 걸음 정리해 보자!
우선SD카드에 대한 협의는 이해할 필요가 있다. 나는 오늘 오전 수업 시간에 이 SD카드의 협의를 이해했다. 바로 이 문서를 바탕으로 한 것이다. 이 문서는 SD 협의에 입문하기에 적합하다고 생각한다(개인적으로).http://download.csdn.net/detail/king_bingge/5218183
SD를 처음 알게 되면 본격적으로 SD카드를 배우기 시작할 수 있습니다!
1. SD카드를 사용하려면 먼저 SD카드를 초기화해야 한다. 그러면 어떻게 초기화합니까?(명령의 매개 변수는 잠시 언급하지 않음)
1. 여기에는 많은 지령이 관련되어 있다.프로토콜은 SD카드에 전기를 넣은 후 최소 74개의 시계 펄스를 주어야만 관련 SD 초기화 작업을 할 수 있다고 규정했다. 비록 이렇게 말하지만 나는 74개의 시계를 주지 않는다. 그는 그대로 초기화할 수 있다. 봐봐.
	for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XF);

하지만 더 성공적으로 초기화할 수 있도록 이 규정이 있기 때문에 우리는 정직하게 74개의 시계를 주는 것이 좋습니다. 괜찮습니다!
2. 그 다음에 협의에서 우리가 리셋하거나 전기를 올릴 때 SD카드의SD제어 레지스터는 카드 식별 모드의 빈 모드에 있다고 말했는데 당분간 이렇게 하자.원래 우리는 리셋 명령을 보낼 필요가 없지만, 우리의SD가 지원하는 전압 범위를 모른다.그래서 우리는 먼저 복구 명령을 내린 다음에 작업 전압을 얻는 명령을 내리는 것이 가장 좋다. 이것도 비교적 안전하다. 만약에 다중SD카드의 작업 전압에 의문이 있다면 칩 매뉴얼을 보러 가야 한다.이 지식이 있으면 그 아래의 코드는 문제가 되지 않는다
retry=20;
	do
	{
		r1=SD_SendCmd(CMD0,0,0x95);//  IDLE  
	}while((r1!=0X01) && retry--);
 	SD_Type=0;//    
	if(r1==0X01)
	{
		if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
		{
			for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);	//Get trailing return value of R7 resp
			if(buf[2]==0X01&&buf[3]==0XAA)//     2.7~3.6V
3. 협의에 언급된 ACMD41 명령의 목적은 SD카드 컨트롤러에 SD카드가 주어진 Vdd 범위에서 작동할 수 있는지 식별하는 메커니즘을 주는 것이다. 만약에 SD카드가 지정된 Vdd 범위에서 작동하지 못하면 비활성 상태(Inactive state)에 들어가기 때문에 우리는 다음에 이 명령을 보내야 한다. 그러나 이 명령을 보내기 전에 이것은 응용형 명령임을 알아야 한다.그래서 CMD55 명령을 붙여야 하기 때문에 아래 코드가 있습니다.
		if(buf[2]==0X01&&buf[3]==0XAA)//     2.7~3.6V
			{
				retry=0XFFFE;
				do
				{
					SD_SendCmd(CMD55,0,0X01);	//  CMD55
					r1=SD_SendCmd(CMD41,0x40000000,0X01);//  CMD41
				}while(r1&&retry--);
				if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//  SD2.0     		//      
				{
					for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//  OCR 
					if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //  CCS
					else SD_Type=SD_TYPE_V2;   
				}

이렇게 하면 카드의 유형을 얻을 수 있다. 이로써 카드의 초기화는 기본적으로 완성되었다. 물론 협의에 따라 우리는 여기서 상대 주소 같은 것을 수정할 수 있다.필요하다면 이렇게 해도 돼!
2. SD카드를 초기화합니다. 다음에 저희 SD의 용량을 보고 싶으면 이렇게 하세요!
아까부터 카드 용량 문제로 답답해서 대충 이해했어요!여기 함수 이름은 읽기 섹터 수입니다. 실제로 되돌아오는 값은 카드의 용량입니다. 주의해야 합니다.
1. 먼저 코드를 본다
u32 SD_GetSectorCount(void)
{
    u8 csd[16];
    u32 Capacity_KB,Capacity_MB ;
    u8 n;
		u16 csize;  					    
	// CSD  ,      ,  0
    if(SD_GetCSD(csd)!=0) return 0;	    
		n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
		csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
	
		Capacity_KB= (u32)csize << (n - 10);//      ,      KB
		Capacity_MB = Capacity_KB/1024;
    return Capacity_MB;
}

이 계산의 문제는 128비트의 CSD 레지스터인 SD카드의 매뉴얼을 보아야 한다.여기에서 나는 내가 분석하는 과정을 붙였다. 나는 어쩔 수 없이 비교적 어지럽다고 말했다. 어쩌면 나만 알아볼 수 있을지도 모른다. 정리하는 것이 귀찮다. 참고만 하자!
My SD_Card
CSD        :
00 7f ff 32    bit(127-96)			csd0 - csd3
5f 59 83 cb    bit(95--64)			csd4 - csd7	    0101 1111 0101 1001 1000 0011 1100 1011
76 db df ff    bit(63--32)			csd8 - csd11        0111 0110 1101 1011 1101 1111 1111 1111
96 40 00 97    bit(31---0)			csd12 -csd15

csize  {62,73}
csize_muti{47,49}
read {80,83}
csize = 1111 0010 1101 = 3885
csize_muti = 111 = 7
read = 1001 = 9 
    :
blocknr = (csize+1)*mult	= 
mult = (csize_muti < 8)*(2^(csize_muti + 2))   
block_len = (read < 12)*(2^(read)) 
capacity = blocknr * block_len = 13*4*3516*98304
             :
		n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
		csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
			
		Capacity_KB= (u32)csize << (n - 10);//      ,      KB  // 00 7f ff 32 5f 59 83 cb  76 db df ff 96 40 00 97
		Capacity_MB = Capacity_KB/1024;
		
		
		1、(csd[8] >> 6)      bit62 bit63  				  2 
		2、((u16)csd[7] << 2)    bit64--bit69  			  6 
		3、((u16)(csd[6] & 3) << 10)    bit70--bit73  	
사실 제 문제는 직장에 있어요!
이렇게 하면 우리는 표시된 용량치를 볼 수 있다. 나는 1G이다.출력은 971M으로 윈도우즈 아래에 있는 것과 일치합니다.사실 우리는 SD카드의 안내 섹터를 읽어서 관련 정보를 읽을 수 있으며, 레지스터를 사용할 필요가 없다.그렇다면 지금 우리의 계산 공식은 바로 (이것은 단지 내가 직접 쓴 것일 뿐이다. 이해하려면 부채의 내용을 보아야 한다. 나는 그 MBR을 대조해서 쓴 것이다)
			x=(((buf_read[34])*64*1024+(buf_read[33])*256+(buf_read[32])))*512/1024/1024;	//    
			printf("
SD Sector Size:%d Mb
",x);

비록 그다지 고상하지는 않지만, 쓸 수 있으면 그만이다.
2、다음은 SPI로 섹터를 어떻게 읽는지 봅시다. 코드부터 봅시다.
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
	u8 r1;
	if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//       
	if(cnt==1)
	{
		r1=SD_SendCmd(CMD17,sector,0X01);//   
		if(r1==0)//      
		{
			r1=SD_RecvData(buf,512);//  512   	   
		}
	}else
	{
		r1=SD_SendCmd(CMD18,sector,0X01);//     
		do
		{
			r1=SD_RecvData(buf,512);//  512   	 
			buf+=512;  
		}while(--cnt && r1==0); 	
		SD_SendCmd(CMD12,0,0X01);	//      
	}   
	SD_DisSelect();//    
	return r1;//
}

이 몇 줄의 코드는 단일과 여러 개의 섹터의 읽기와 쓰기를 실현할 수 있으며, 추적해 들어가면 이 함수를 볼 수 있다
//SPIx       
//TxData:      
//   :      
u8 SPIx_ReadWriteByte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //     SPI       :        
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI1, TxData); 															 //    SPIx      
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); //     SPI       :         
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); 																//    SPIx       					    
}

이 함수의 기능은 발송도 할 수 있고 읽기도 할 수 있다. 이제 총괄해 보자!
하나의 섹터를 읽는 과정
1、선발명령 r1=SDSendCmd(CMD17,sector,0X01);//단일 섹터 읽기 명령
2. 그 다음에 받은 데이터를 임시 그룹에 저장한다.
u8 SD_RecvData(u8*buf,u16 len)
{			  	  
	if(SD_GetResponse(0xFE))return 1;//  SD         0xFE
    while(len--)//      
    {
        *buf=SPIx_ReadWriteByte(0xFF);
        buf++;
    }
    //   2  CRC(dummy CRC)
    SD_SPI_ReadWriteByte(0xFF);
    SD_SPI_ReadWriteByte(0xFF);									  					    
    return 0;//    
}
그러면 대응하는 섹터도 비슷해요.
1、단일 섹터를 먼저 쓰는 명령 r1=SDSendCmd(CMD24,sector,0X01);//명령을 쓰다
2. Buffer의 내용을 해당 섹터에 쓰기
u8 SD_SendBlock(u8*buf,u8 cmd)
{	
	u16 t;		  	  
	if(SD_WaitReady())return 1;//      
	SD_SPI_ReadWriteByte(cmd);
	if(cmd!=0XFD)//      
	{
		for(t=0;t<512;t++)SPIx_ReadWriteByte(buf[t]);//    ,        
	    SD_SPI_ReadWriteByte(0xFF);//  crc
	    SD_SPI_ReadWriteByte(0xFF);
		t=SD_SPI_ReadWriteByte(0xFF);//    
		if((t&0x1F)!=0x05)return 2;//    									  					    
	}						 									  					    
    return 0;//    
}

이제 읽기와 쓰기 섹터가 완성되었습니다. 다음 단계는 파일 시스템을 사용해서 조작하는 것입니다.

좋은 웹페이지 즐겨찾기