# [STM32]SDIO ## 🔌 SDIO 是什麼? **SDIO(Secure Digital Input Output)** 是一種擴充在 SD 記憶卡標準上的介面,支援 **資料儲存功能以外的 I/O 裝置**,例如: - Wi-Fi 模組 - 藍牙模組 - GPS 模組 - 通用 I/O 模組(GPIO) 👉 在嵌入式應用中,SDIO **最常用來做為 SD 卡的資料傳輸介面**,提供比 SPI 更快的速度。 --- ### 📶 SDIO 模式 vs SPI 模式 | 項目 | SDIO 模式 | SPI 模式 | |-----------------|-------------------------|------------------------| | 傳輸速度 | 高速(最高 50 MHz) | 低速(通常 20 MHz 以下) | | 傳輸資料寬度 | 1-bit / 4-bit 資料線 | 單線(MOSI/MISO) | | 效率 | 高 | 中等 | | 實作難度 | 較高(需 DMA) | 較低 | | 硬體資源占用 | 多(需 SDIO 外設) | 少(只要 SPI 控制器) | 🔧 若你的 MCU(例如 STM32)有內建 SDIO 介面,推薦使用 SDIO 模式搭配 **DMA(Direct Memory Access)** 傳輸,加快 SD 卡讀寫效率。 --- ### 🧩 SDIO 的資料線(4-bit 模式) | 腳位 | 功能 | |----------|--------------------| | CLK | 時鐘訊號 | | CMD | 指令傳輸線 | | D0–D3 | 資料線(1-bit / 4-bit) | 👉 實際使用中,**最少需 CMD、CLK、D0 三條線** 就能運作 1-bit 模式。若要跑 4-bit 模式,就要全部 D0~D3 都連接。 --- ### 🧪 在 STM32 中使用 SDIO 的典型流程: 1. 初始化 SDIO 硬體(設定時脈、模式、腳位) 2. 掛載 FATFS 檔案系統(如使用 `f_mount()`) 3. 開啟檔案 / 寫入 / 讀取 4. 卸載檔案系統(` f_mount(NULL, "", 0); `) 🧠 STM32 HAL 提供了 `HAL_SD_Init()`、`HAL_SD_ReadBlocks()`、`HAL_SD_WriteBlocks()` 等 API --- ### 📦 實際應用場景 - 📁 使用 SD 卡記錄 Log 檔案(像是車用資料記錄器) - 📸 儲存相機拍下的照片 - 🎮 從 SD 卡載入遊戲素材、音樂 - 📡 接 Wi-Fi 模組作資料上傳(藉由 SDIO I/O 擴充) --- ## 實作 ## Demo ![image](https://hackmd.io/_uploads/ryAdUsqnyl.png) ## STM32CubeIDE設定 ### PIN 設定 ![PinoutClear](https://imgur.com/VJNPOvV.png) --- ### GPIO設定 PA5 設定INPUT ![image](https://hackmd.io/_uploads/HJxin95h1l.png) --- ### RCC設定 ![RccSet](https://imgur.com/7kPTJ9A.png) --- ### SYS設定 ![SysSet](https://imgur.com/rNjjVDv.png) --- ### SDIO設定 CMD D0 啟用pull up ![image](https://hackmd.io/_uploads/B1gasq9hyl.png) 開啟DMA ![image](https://hackmd.io/_uploads/SkSWnq5nke.png) --- ### USART設定 ![image](https://hackmd.io/_uploads/Skw4nc531x.png) ### NVIC 設定 ![image](https://hackmd.io/_uploads/r1RSh552kl.png) --- ### Clock設定 ![ClockSet](https://imgur.com/SlT0y70.png) --- ### FatFS設定 ![image](https://hackmd.io/_uploads/HkcbTc5hJx.png) input 選PA5這是用來檢查SD卡插入的 ![image](https://hackmd.io/_uploads/S1v769chkg.png) --- ### 外設檔案分開+生成 ![GeneratorSet](https://imgur.com/Lo1x0Fc.png) #### 生成程式碼 ![CodeGenerator](https://imgur.com/LDLzPZb.png) --- ### Nucleo_Pinou ![nucleo_pinout](https://imgur.com/pW4VU4f.png) --- ### 電路圖 ![bse2025321](https://hackmd.io/_uploads/H1dT1s5hJx.png) --- ## SDIO+FATFS實作 ### :::spoiler 流程圖 ```mermaid flowchart TD A(開始) B[掛載 SD 卡 f_mount] C{掛載成功?} D[printf 錯誤訊息] E[開啟 test.txt 寫入模式] F{開啟成功?} G["寫入 TEST\\r\\n"] H[關閉檔案] I[開啟 test.txt 讀取模式] J{開啟成功?} K[讀取內容] L[關閉檔案] M[printf 輸出 buff] Z(結束) aa[卸載SD卡] A --> B B --> C C -- 否 --> D C -- 是 --> E E --> F F -- 否 --> D F -- 是 --> G --> H --> I I --> J J -- 否 --> D --> aa -->Z J -- 是 --> K --> L --> M --> aa ``` ::: --- ### 程式碼 #### :::spoiler usart.c ```c= /* USER CODE BEGIN 0 */ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); return ch; } /* USER CODE END 0 */ ``` ::: #### :::spoiler main.c ```c= /* USER CODE BEGIN Includes */ #include "stdio.h" /* USER CODE END Includes */ /* USER CODE BEGIN PV */ uint8_t buff[64]; /* USER CODE END PV */ /* USER CODE BEGIN 2 */ FRESULT res = f_mount(&SDFatFS, SDPath, 1);//掛載SD卡 if (res != FR_OK) { printf("File failed! Error code: %d\n", res); } else { // 嘗試開啟寫入檔案 res = f_open(&SDFile, "test.txt", FA_WRITE | FA_OPEN_ALWAYS); if (res != FR_OK) { printf("File failed! Error code: %d\n", res); } else { UINT i; f_write(&SDFile, "TEST\r\n", 6, &i); f_close(&SDFile); } // 再次開啟檔案以讀取 res = f_open(&SDFile, "test.txt", FA_READ); if (res != FR_OK) { printf("File failed! Error code: %d\n", res); } else { UINT i; f_read(&SDFile, buff, 6, &i); f_close(&SDFile); printf("%s\n", (char*)buff); // printf 輸出 } f_mount(NULL, "", 0); // 卸載SD卡 } /* USER CODE END 2 */ ``` ::: #### :::spoiler fatfs.c 設定fatfs時間 ```c=45 DWORD get_fattime(void) { /* USER CODE BEGIN get_fattime */ return ((DWORD)(2025 - 1980) << 25) // 年:2025 - 1980 = 45 | ((DWORD)3 << 21) // 月:3 月 | ((DWORD)21 << 16) // 日:21 號 | ((DWORD)14 << 11) // 時:14 點 | ((DWORD)55 << 5) // 分:55 分 | ((DWORD)25 >> 1); // 秒:50 秒(FAT 格式以 2 秒為單位) /* USER CODE END get_fattime */ } ``` ::: --- [📖參考資料](https://www.youtube.com/watch?v=1MxWZyayiTw)