# [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

## STM32CubeIDE設定
### PIN 設定

---
### GPIO設定
PA5 設定INPUT

---
### RCC設定

---
### SYS設定

---
### SDIO設定
CMD D0 啟用pull up

開啟DMA

---
### USART設定

### NVIC 設定

---
### Clock設定

---
### FatFS設定

input 選PA5這是用來檢查SD卡插入的

---
### 外設檔案分開+生成

#### 生成程式碼

---
### Nucleo_Pinou

---
### 電路圖

---
## 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)