# Phần 4: Thẻ nhớ

Ok tiếp theo là lắp đặt thẻ nhớ.

Trong dự án này thẻ nhớ sẽ là nơi lưu trữ dữ liệu chính như hình gif, audio...

<span style="color: rgb(241, 196, 15);">Trước khi bắt đầu thì có một điều cần chú ý</span>

### Xử lý conflict phần cứng

Thẻ nhớ sử dụng giao tiếp SPI. Với ESP32 khi sử dụng nhiều thiết bị giao tiếp chung SPI thì cần có chân CS để điều khiển.

Trong trường hợp hiện tại chúng ta có 2 thiết bị giao tiếp SPI là thẻ nhớ và màn hình. Khi cần giao tiếp với thẻ nhớ thì tín hiệu CS trên thẻ nhớ được bật và tắt đối với màn hình.

Thế nhưng trong phần trước. Màn hình chúng ta sử dụng có 7 pin và không có chân CS. Điều này là do chân CS được nhà sản xuất nối trực tiếp với GND. Tín hiệu CS trên màn hình sẽ luôn ở trạng thái bật. Vì vậy chúng ta có 2 hướng giải quyết:

- Kiểu người có tiền: Thay màn mới cho đẹp
- Kiểu người hết tiền chúng ta có những bước sau:
    - Xác định chân CS đã bị hàn với GND trên màn hình. Là chân thứ 8 trên dây nối màn hình với PCB
    - Rã hàn để thấy được phần kết nối CS với GND
    - Ngắt kết nối của chân CS với GND bằng cách cắt qua lớp đồng trên PCB
    - Hàn lại dây nối màn hình với PCB
    - Hàn chân CS ra một chân mới và kết nối với ESP32.
    - <span style="white-space: pre-wrap;">Trong phần khai báo thư viện TFT\_eSPI phần </span>`<span class="editor-theme-code">#define TFT_CS -1</span>`<span style="white-space: pre-wrap;"> sửa thành </span>`<span class="editor-theme-code"> #define TFT_CS   <pin đã kết nối trên ESP32></span>`

[![ESP32_TheCube_Phan4_1.png](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/scaled-1680-/BB4esp32-thecube-phan4-1.png)](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/BB4esp32-thecube-phan4-1.png)[![ESP32_TheCube_Phan4_2.png](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/scaled-1680-/jl6esp32-thecube-phan4-2.png)](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/jl6esp32-thecube-phan4-2.png)[![ESP32_TheCube_Phan4_3.png](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/scaled-1680-/WDeesp32-thecube-phan4-3.png)](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/WDeesp32-thecube-phan4-3.png)

Ok vậy là xong. Đừng làm chết màn hình là được :)))

### Lắp đặt

<table id="bkmrk-m%C3%A0n-h%C3%ACnhesp32-c3ch%E1%BA%AFc"><colgroup><col></col><col></col><col></col><col></col></colgroup><tbody><tr><td>**Màn hình**

</td><td>**ESP32-C3**

</td><td>**Chắc năng**

</td><td>**Ghi chú**

</td></tr><tr><td>VCC (3.3)

</td><td>**3.3V** hoặc 5V

</td><td>Cấp nguồn cho màn hình.

</td><td>Nguồn vào từ USB qua ESP32 có thể đẩy ra thành 2 nguồn 3.3V hoặc 5V.

</td></tr><tr><td>GND

</td><td>GND

</td><td>Nối đất

</td><td>Tạo một điểm tham chiếu chung cho toàn bộ thiết bị trên hệ thống

</td></tr><tr><td>SCK

</td><td>GPIO4

</td><td>Clock (SPI)

</td><td>Dùng chung với Màn hình

</td></tr><tr><td>MOSI

</td><td>GPIO6

</td><td>Data out

</td><td>Dùng chung với Màn hình

</td></tr><tr><td>MISO

</td><td>GPIO5

</td><td>Data in

</td><td>Dùng chân chuyên dụng của ESP32

</td></tr><tr><td>CS

</td><td>GPIO7

</td><td>Điều khiển khi giao tiếp SPI

</td><td>Chọn bất kỳ chân GPIO còn trống thuận tiện cho đi dây

</td></tr></tbody></table>

### Kiểm tra

#### `<span class="editor-theme-code">platformio.ini</span>`

<span style="white-space: pre-wrap;">Trong phần thiết lập này chúng ta cần khai báo thêm thư viện SD trong </span>`<span class="editor-theme-code">lib_deps</span>`

```c++
[env:esp32-c3-devkitm-1]
platform = platformio/espressif32 @ 6.6.0
board = esp32-c3-devkitm-1
framework = arduino
platform_packages =
  framework-arduinoespressif32 @ ~3.20014.0
lib_deps = 
	SD // Khai báo thêm thư viện này
	SPI
	bodmer/TFT_eSPI@^2.5.43
monitor_speed = 115200
build_flags = 
	-D ARDUINO_USB_MODE=1
	-D ARDUINO_USB_CDC_ON_BOOT=1
```

#### Code and Test

```c++
#include <Arduino.h>
#include <TFT_eSPI.h>
#include <SD.h> // Thêm khai báo thư viện

// Tạo đối tượng tft từ thư viện // Để hiển thị kết quả test
TFT_eSPI tft = TFT_eSPI();

// Khai báo phần cứng cho SDCard
const int SDCARD_PIN_CS = 7;
const int SDCARD_PIN_SCK = 4;
const int SDCARD_PIN_MISO = 5;
const int SDCARD_PIN_MOSI = 6;

// Khai báo hàm
void initTFT(); // Khởi tạo màn hình
void initSD(); // Khởi tạo SDCard
void listDir(fs::FS &fs, const char * dirname, uint8_t levels); // Hàm hiển thị các tệp trong SD // Dùng để test chưa cần quan tâm nhiều

void setup() {
  initTFT();
  initSD();
}

int count = 0;
void loop() {}

void initTFT()
{
  tft.init(); 
  tft.setRotation(0);
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_GREEN);
  tft.setTextSize(1);
  tft.setCursor(0, 0);
  tft.println("Init TFT success!!!");
}

void initSD()
{
  SPI.end();
  SPI.begin(SDCARD_PIN_SCK, SDCARD_PIN_MISO, SDCARD_PIN_MOSI, SDCARD_PIN_CS); // Khởi tạo giao tiếp SPI

  tft.print("Initializing SD card using CS pin: ");
  tft.println(SDCARD_PIN_CS);

  if (!SD.begin(SDCARD_PIN_CS, SPI)) {
    tft.setTextColor(TFT_RED);
    tft.println("SD mount failed (wiring/freq).");
    return;
  }

  tft.setTextColor(TFT_GREEN);
  tft.println("SD card initialized.");

  uint8_t type = SD.cardType();
  if (type == CARD_NONE) {
    tft.setTextColor(TFT_RED);
    tft.println("No SD card detected.");
    return;
  }
  tft.printf("Type: %s\n", type == CARD_MMC ? "MMC" :
                         type == CARD_SD  ? "SDSC" :
                         type == CARD_SDHC? "SDHC/SDXC" : "UNKNOWN");
  tft.printf("Size: %llu MB\n", SD.cardSize() / (1024ULL * 1024ULL));

  tft.println("Filesystem Content:");
  listDir(SD, "/", 0);
  tft.println("\n--- Test Complete ---");
}

// Hàm liệt kê nội dung thư mục (lấy từ ví dụ của thư viện SD)
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
  tft.printf("Listing directory: %s\n", dirname);

  File root = fs.open(dirname);
  if (!root) {
    tft.println("Failed to open directory");
    return;
  }
  if (!root.isDirectory()) {
    tft.println("Not a directory");
    return;
  }

  File file = root.openNextFile();
  while (file) {
    if (file.isDirectory()) {
      tft.print("  DIR : ");
      tft.println(file.name());
      if (levels) {
        listDir(fs, file.path(), levels - 1);
      }
    } else {
      tft.print("  FILE: ");
      tft.print(file.name());
      tft.print("\tSIZE: ");
      tft.println(file.size());
    }
    file = root.openNextFile();
  }
}
```

Upload and Monitor

Kết quả hiển thị như hình dưới (hoặc tương tự toàn màu green) là OK

Nếu chỉ hiển thị đến "Initializing SD card using CS pin: " thì cần check thêm terminal để kiểm tra lỗi

- Có thể conflict phần cứng nhắc tới ở trên chưa được xử lý
- Thẻ nhớ chưa được format đúng (ESP32)
- Lỗi thẻ nhớ hoặc module thẻ nhớ

[![1000048897.jpg](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/scaled-1680-/1000048897.jpg)](https://knowledge.thanhdv.com/uploads/images/gallery/2025-10/scaled-1680-/1000048897.jpg)