STM32开发板入门教程(十三) - SPI模式读写SD卡
生活随笔
收集整理的這篇文章主要介紹了
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卡的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用win10小娜
- 下一篇: (2)stm32开发之使用Keil MD