日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STM32开发板入门教程(十三) - SPI模式读写SD卡

發布時間:2023/12/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STM32开发板入门教程(十三) - SPI模式读写SD卡 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
功能介紹 :使用SPI模式 讀寫SD卡block數據 可通過串口發送到PC機查看

SD卡是Secure Digital Card卡的簡稱,直譯成漢語就是“安全數字卡”,是由日本松下公司、東芝公司和美國SANDISK公司共同開發研制的全新的存儲卡產品。SD存儲卡是一個完全開放的標準(系統),多用于MP3、數碼攝像機、數碼相機、電子圖書、AV器材等等,尤其是被廣泛應用在超薄數碼相機上。呵呵 現在偶們做東西也喜歡用sd卡了 為啥? 容量大啊 價格便宜啊 讀寫次數100000次以上(也有資料說是300000次 呵呵) 這個次數夠猛了啊 讀寫的速度也很快 現在高速的SD卡寫速度可以達到20M/S 呵呵 如果你買的SD卡達不到這個速度?? 就應該考慮一下是不是買到假貨了?? 呵呵 現在SD卡都是白菜價了啊 貌似4G的也就50塊錢一個啦



嗯 不扯遠了 繼續正題?? SD卡讀寫有2種方式 一種是SD模式 一種是SPI模式 SD模式操作時序復雜 使用的IO口也多 呵呵 常用的一般是SPI模式 我們今天介紹的也是SPI模式 接口簡單 移植也方便 速度也不慢了啊 使用高速的SPI模式 1M/S應該是很容易達到的 剛剛把STM32下的SD卡讀寫移植好 也沒測試讀寫速度 呵呵 下回有時間把讀寫速度測試了發上來 呵呵



SD卡初始化過程:

1. 初始化STM32的SPI接口 使用低速模式
2. 延時至少74clock
3. 發送CMD0,需要返回0x01,進入Idle狀態
4. 循環發送CMD55+ACMD41,直到返回0x00,進入Ready狀態

5. 設置讀寫block大小為512byte
5. 把STM32的SPI設置為高速模式




讀一個block塊的過程

1. 發送CMD17(單塊)或CMD18(多塊)讀命令,返回0x00
2. 接收數據開始令牌0xfe + 正式數據512Bytes + CRC 校驗2Bytes

寫一個block塊的過程

1. 發送CMD24(單塊)或CMD25(多塊)寫命令,返回0x00
2. 發送數據開始令牌0xfe + 正式數據512Bytes + CRC校驗2Bytes



附上一個datasheet上的標準 spi mode initialization flow





初始化函數
/*******************************************************************************
* Function Name?? : SD_MMC_SPI_Init
* Description ?? ??? : SD_MMC_SPI_Init
* Input ?? ?? ?? ?? ?? : None
* Output ?? ?? ?? ?? : None
* Return ?? ?? ?? ?? : zero init success, non-zero init error
*******************************************************************************/
u8 SD_MMC_SPI_Init(void)
{
?? GPIO_InitTypeDef GPIO_InitStructure;

?? /* Enable SPI1 and GPIO clocks */
?? RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA |
?? ?? ?? ?? ?? ?? ?? RCC_APB2Periph_SD_MMC_SPI_CS, ENABLE);

?? /* Configure SPI1 pins: SCK, MISO and MOSI */
?? GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
?? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
?? GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
?? GPIO_Init(GPIOA, &GPIO_InitStructure);

?? /* Configure SD_MMC_SPI_CS */
?? GPIO_InitStructure.GPIO_Pin = SD_MMC_SPI_CS_Pin_CS;
?? GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
?? GPIO_Init(SD_MMC_SPI_CS, &GPIO_InitStructure);
??
??
/* initialize SPI with lowest frequency */
SD_MMC_Low_Speed();

/* card needs 74 cycles minimum to start up */
for(u8 i = 0; i < 10; ++i)
{
?? ??? /* wait 8 clock cycles */
?? ??? SD_MMC_ReadWrite_Byte(0x00);
}

/* address card */
SD_MMC_SPI_SELECT();

/* reset card */
u8 response;
for(u16 i = 0; ; ++i)
{
?? ??? response = SD_MMC_Send_Command(CMD_GO_IDLE_STATE , 0 );
?? ??? if( response == 0x01 )
?? ?? ?? break;

?? ??? if(i == 0x1ff)
?? ??? {
?? ?? ?? SD_MMC_SPI_DESELECT();
?? ?? ?? return 1;
?? ??? }
}

/* wait for card to get ready */
for(u16 i = 0; ; ++i)
{
?? ??? response = SD_MMC_Send_Command(CMD_SEND_OP_COND, 0);
?? ??? if(!(response & (1 << R1_IDLE_STATE)))
?? ?? ?? break;

?? ??? if(i == 0x7fff)
?? ??? {
?? ?? ?? SD_MMC_SPI_DESELECT();
?? ?? ?? return 1;
?? ??? }
}

/* set block size to 512 bytes */
if(SD_MMC_Send_Command(CMD_SET_BLOCKLEN, 512))
{
?? ??? SD_MMC_SPI_DESELECT();
?? ??? return 1;
}

/* deaddress card */
SD_MMC_SPI_DESELECT();

/* switch to highest SPI frequency possible */
SD_MMC_High_Speed();

return 0;
}


發送一個命令
/*******************************************************************************
* Function Name?? : SD_MMC_Send_Command
* Description ?? ??? : SD_MMC_Send_Command
* Input ?? ?? ?? ?? ?? : None
* Output ?? ?? ?? ?? : None
* Return ?? ?? ?? ?? : None
*******************************************************************************/
u8 SD_MMC_Send_Command(u8 cmd, u32 arg)
{
?? ??? u8 Response;
?? ??? u8 Retry = 0;

?? ??? SD_MMC_ReadWrite_Byte(0xff);
?? ??? SD_MMC_SPI_SELECT();
?? ??? //分別寫入命令
?? ??? SD_MMC_ReadWrite_Byte(cmd | 0x40);
?? ??? SD_MMC_ReadWrite_Byte(arg >> 24);
?? ??? SD_MMC_ReadWrite_Byte(arg >> 16);
?? ??? SD_MMC_ReadWrite_Byte(arg >> 8);
?? ??? SD_MMC_ReadWrite_Byte(arg);
?? ??? SD_MMC_ReadWrite_Byte(0x95);


?? ??? do{
?? ?? ?? ?? // 等待響應,響應的開始位為0
?? ?? ?? ?? Response = SD_MMC_ReadWrite_Byte(0xff);
?? ?? ?? ?? Retry++;
?? ??? }while( ((Response&0x80)!=0) && (Retry < 200) );

?? ??? SD_MMC_SPI_DESELECT();
?? ??? return Response;?? //返回狀態值
}


讀一個block塊 讀取成功返回0 非0 則讀取失敗
/*******************************************************************************
* Function Name?? : SD_MMC_Read_Single_Block
* Description ?? ??? : SD_MMC_Read_Single_Block
* Input ?? ?? ?? ?? ?? : sector number and buffer data point
* Output ?? ?? ?? ?? : None
* Return ?? ?? ?? ?? : zero success, non-zero error
*******************************************************************************/
u8 SD_MMC_Read_Single_Block(u32 sector, u8* buffer)
{
?? ??? u8 Response;
?? ??? u16 i;
?? ??? u16 Retry = 0;

?? ?? //讀命令 send read command
?? ??? Response = SD_MMC_Send_Command(CMD_READ_SINGLE_BLOCK, sector<<9);

?? ??? if(Response != 0x00)
?? ?? ?? ?? return Response;

?? ??? SD_MMC_SPI_SELECT();
?? ??? // start byte 0xfe
?? ??? while(SD_MMC_ReadWrite_Byte(0xff) != 0xfe)
?? ??? {
?? ?? if(++Retry > 0xfffe)
?? ?? {
?? ?? ?? ??? SD_MMC_SPI_DESELECT();
?? ?? ?? ??? return 1; //timeout
?? ?? }
?? ??? }

?? ??? for(i = 0; i < 512; ++i)
?? ??? {
?? ?? ?? ?? //讀512個數據
?? ?? ?? ?? *buffer++ = SD_MMC_ReadWrite_Byte(0xff);
?? ??? }

?? ??? SD_MMC_ReadWrite_Byte(0xff);?? //偽crc
?? ??? SD_MMC_ReadWrite_Byte(0xff);?? //偽crc

?? ??? SD_MMC_SPI_DESELECT();
?? ??? SD_MMC_ReadWrite_Byte(0xff);?? // extra 8 CLK

?? ??? return 0;
}



寫一個block塊 成功返回0 非0 則寫入失敗
/*******************************************************************************
* Function Name?? : SD_MMC_Write_Single_Block
* Description ?? ??? : SD_MMC_Write_Single_Block
* Input ?? ?? ?? ?? ?? : sector number and buffer data point
* Output ?? ?? ?? ?? : None
* Return ?? ?? ?? ?? : zero success, non-zero error.
*******************************************************************************/
u8 SD_MMC_Write_Single_Block(u32 sector, u8* buffer)
{
u8 Response;
u16 i;
u16 retry=0;

?? ??? //寫命令?? send write command
Response = SD_MMC_Send_Command(CMD_WRITE_SINGLE_BLOCK, sector<<9);
if(Response != 0x00)
return Response;

SD_MMC_SPI_SELECT();

SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);
SD_MMC_ReadWrite_Byte(0xff);

?? ??? //發開始符 start byte 0xfe
SD_MMC_ReadWrite_Byte(0xfe);

?? ??? //送512字節數據 send 512 bytes data
for(i=0; i<512; i++)
{
?? SD_MMC_ReadWrite_Byte(*buffer++);
}

SD_MMC_ReadWrite_Byte(0xff); //dummy crc
SD_MMC_ReadWrite_Byte(0xff); //dummy crc

Response = SD_MMC_ReadWrite_Byte(0xff);

//等待是否成功 judge if it successful
if( (Response&0x1f) != 0x05)
{
?? SD_MMC_SPI_DESELECT();
?? return Response;
}
//等待操作完?? wait no busy
while(SD_MMC_ReadWrite_Byte(0xff) != 0x00)
{
?? if(retry++ > 0xfffe)
?? {
SD_MMC_SPI_DESELECT();
return 1;
?? }
}
SD_MMC_SPI_DESELECT();
SD_MMC_ReadWrite_Byte(0xff);// extra 8 CLK

return 0;
}

總結

以上是生活随笔為你收集整理的STM32开发板入门教程(十三) - SPI模式读写SD卡的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。