Files
pyxis/lib/tdeck_ui/Hardware/TDeck/SDAccess.cpp
torlando-tech 0608af6d38 Unify all SPI peripherals on global FSPI to fix pin conflicts
Display and LoRa were creating separate SPIClass(HSPI) instances which
claimed GPIO pins via the matrix, preventing SD card (on FSPI) from
accessing MISO after Display init. Now all three peripherals use the
global SPI (FSPI) instance, eliminating GPIO routing conflicts.

- Display: use &SPI instead of new SPIClass(HSPI)
- SX1262Interface: use &SPI instead of new SPIClass(HSPI)
- SDAccess: enable format_if_empty for unformatted cards

Verified on device: SD (128GB SDHC), display, and LoRa all coexist.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 09:41:35 -05:00

123 lines
3.0 KiB
C++

// Copyright (c) 2024 microReticulum contributors
// SPDX-License-Identifier: MIT
#include "SDAccess.h"
#ifdef ARDUINO
#include <Log.h>
using namespace RNS;
namespace Hardware {
namespace TDeck {
SemaphoreHandle_t SDAccess::_spi_mutex = nullptr;
bool SDAccess::_ready = false;
bool SDAccess::init(SemaphoreHandle_t mutex) {
if (_ready) return true;
if (mutex == nullptr) {
Serial.println("[SDAccess] ERROR: null mutex");
return false;
}
_spi_mutex = mutex;
// Drive ALL SPI CS lines high to deselect other devices on the bus.
pinMode(Pin::DISPLAY_CS, OUTPUT);
digitalWrite(Pin::DISPLAY_CS, HIGH);
pinMode(Radio::LORA_CS, OUTPUT);
digitalWrite(Radio::LORA_CS, HIGH);
pinMode(SDCard::CS, OUTPUT);
digitalWrite(SDCard::CS, HIGH);
// Acquire mutex for SD.begin()
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(2000)) != pdTRUE) {
Serial.println("[SDAccess] Failed to acquire SPI mutex for init");
return false;
}
// SD card init: use global SPI (FSPI) before Display claims HSPI
SPI.begin(Pin::DISPLAY_SCK, Radio::SPI_MISO, Pin::DISPLAY_MOSI);
// format_if_empty=true auto-formats unformatted cards as FAT
bool ok = SD.begin(SDCard::CS, SPI, SD_SPI_FREQ, "/sd", 5, true);
xSemaphoreGive(_spi_mutex);
if (!ok) {
Serial.println("[SDAccess] SD card mount failed (no card?)");
return false;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("[SDAccess] No SD card detected");
return false;
}
_ready = true;
const char* type_str = "UNKNOWN";
switch (cardType) {
case CARD_MMC: type_str = "MMC"; break;
case CARD_SD: type_str = "SD"; break;
case CARD_SDHC: type_str = "SDHC"; break;
default: break;
}
Serial.printf("[SDAccess] Card type: %s, size: %lluMB\n",
type_str, SD.cardSize() / (1024 * 1024));
return true;
}
int SDAccess::read_file(const char* path, uint8_t* buf, size_t max_len) {
if (!_ready || !_spi_mutex) return -1;
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(500)) != pdTRUE) {
return -1;
}
File f = SD.open(path, FILE_READ);
if (!f) {
xSemaphoreGive(_spi_mutex);
return -1;
}
int bytes_read = f.read(buf, max_len);
f.close();
xSemaphoreGive(_spi_mutex);
return bytes_read;
}
bool SDAccess::file_exists(const char* path) {
if (!_ready || !_spi_mutex) return false;
if (xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(500)) != pdTRUE) {
return false;
}
bool exists = SD.exists(path);
xSemaphoreGive(_spi_mutex);
return exists;
}
bool SDAccess::acquire_bus(uint32_t timeout_ms) {
if (!_spi_mutex) return false;
return xSemaphoreTake(_spi_mutex, pdMS_TO_TICKS(timeout_ms)) == pdTRUE;
}
void SDAccess::release_bus() {
if (_spi_mutex) {
xSemaphoreGive(_spi_mutex);
}
}
} // namespace TDeck
} // namespace Hardware
#endif // ARDUINO