Using an ESP32-WROOM.
How can the HSPI pins be initialized as the default SPI instead of the VSPI? (apparently the VSPI pins are used by default)
Thanks
Using an ESP32-WROOM.
How can the HSPI pins be initialized as the default SPI instead of the VSPI? (apparently the VSPI pins are used by default)
Thanks
I don't quite understand your need, but see if this link helps.
" ESP32 SPI Communication: Pins, Multiple SPI, Peripherals (Arduino) | Random Nerd Tutorials
Per the Note from the link you gave:
" Note: usually, when not specified, the board will use the VSPI pins when initializing an SPI communication with the default settings."
How do I specify HSPI to be used instead?
I found this:
SPI.begin(SCK, MISO, MOSI, SS);
It seems to work using the HSPI pins.
Question: How does the ESP32 use this? As a software or hardware SPI?
If you scroll all the way down you will actually find the section that covers how to use both SPI simultaniously, and that should explain it sufficiently in detail.
this is the example referred to, mind you whether that will work with any library straight away i am not sure, since most libraries call make the calls to SPI themselves.
Thanks for that.
I'm also concerned about the individual Librarys overriding any SPI setting I try to make. I reached out to Paul, so hopefully he'll see this and help me understand.
Since i am looking into using both VSPI & HSPI in a project myself i did some more research because it didn't quite make sense, Now i have a working example for an SD card on an ESP32, and i have succeeded doing that with the default VSPI pins 23, 19 & 18 and an SS pin which is not so relevant which one to use but since i haven't specified it in the example, it must have been pin 5
#define LED_YELLOW 2
#define LED_BUILTIN 1
#define RXD0 12
#define TXD0 14
#include "FS.h"
#include "SD.h"
#include "SPI.h"
void setup(){
Serial.begin(115200,SERIAL_8N1,RXD0,TXD0);
pinMode(LED_YELLOW,OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW); // active LOW
digitalWrite(LED_YELLOW, HIGH); // active LOW
if(!SD.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
digitalWrite(LED_YELLOW, LOW); // active LOW
digitalWrite(LED_BUILTIN, HIGH); // active LOW
}
void loop(){
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
I know it worked, or i wouldn't have saved it in my ESP32 sketch folder.
Now in the SD.h there is the reference to SsFat.h and in there, there is reference to Sd2Card.h
in which i find a few lines like this
#ifndef SDCARD_SPI
#define SDCARD_SPI SPI
#endif
#include <SPI.h>
Now looking at the multiple SPI tutorial part i see
vspi = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
which would mean that both VSPI & HSPI are actually defined macros in the ESP32 core, and that the solution may be as simple as
#define SPI HSPI
after which the compiler should throw a warning about SPI having been defined before and where that was (and it's definition)
Clearly to make the sd library use HSPI, a simple
#define SDCARD_SPI HSPI
should do the trick.
Now where these new macor definitoons go exactly is always a bit mysterious to me, if you put them in the .h file it almost for sure works, but that can't be what we want to do, it would also break the sd library for all other boards anyway i am just not quite sure, i do some trial and error remove the #ifndef to see if the definition has actually is valid where i want it and the compiler warns me, pragma messages may also be a helpful strategy. Anyway enough for me for today.
I think you might be right... or at least that the same assessment I had looking through the files.
Have you tested the "#define SPI HSPI" yet?
No i haven't tested anything yet. No time i was working most the day and i have projects for the weekend, but maybe some time to try things in the evening.
Well i decided to test to see if i could get the SD card working on HSPI, but i ran into a few things. First of all if i connect the SD card to HSPI default pins, connecting Miso results in the ESP32 to crash at boot.
I guess it has something to do with MISO being pulled up, but i am not sure.
Then i found the ESP32 specific SPI.h and i found something odd
in SPI.h
SPIClass(uint8_t spi_bus=HSPI);
so that means that for any pointer tot the class it will take HSPI as default, anyway probably not relevant.
Doing some trial and error and not getting anywhere (hehe just error) i realized that i had not been looking at the proper SD library to begin with, ESP32 has it's own, and reading the readme i found
**What is the difference between SD and SD_MMC libraries?**
SD runs on SPI, and SD_MMC uses the SDMMC hardware bus on the ESP32.
Huh ? so i went into the SD_MMC library and that uses HSPI
/*
* Connect the SD card to the following pins:
*
* SD Card | ESP32
* D2 12
* D3 13
* CMD 15
* VSS GND
* VDD 3.3V
* CLK 14
* VSS GND
* D0 2 (add 1K pull up after flashing)
* D1 4
*/
But that is a different matter.
Anyway i haven't got it to work so far, but the sd module i use has a 10K pullup on MISO and that does need to be resolved.
What are you planning to connect to HSPI ?
Of course for what i intend to do the most obvious solution is in SD.h
the prototype for SD.begin()
bool begin(uint8_t ssPin=SS, SPIClass &spi=SPI, uint32_t frequency=4000000, const char * mountpoint="/sd", uint8_t max_files=5, bool format_if_empty=false)
which allows the passing of an SPIClass.
Now later i can see if i can get it connected to the default pins or will need to re-arrange them.
Ok, i got the SD card working on HSPI like this
#define LED_YELLOW 2
#define HSPI_SCK 4
#define HSPI_MISO 16
#define HSPI_MOSI 17
#define SD_CS 15
#include "FS.h"
#include "SD.h"
#include "SPI.h"
SPIClass * hspi = NULL;
void setup(){
Serial.begin(115200);
pinMode(LED_YELLOW,OUTPUT);
digitalWrite(LED_YELLOW, LOW); // active LOW
hspi = new SPIClass(HSPI);
hspi->begin(HSPI_SCK, HSPI_MISO, HSPI_MOSI, SD_CS);
//hspi->begin();
if(!SD.begin(SD_CS, *hspi)){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
listDir(SD, "/", 0);
createDir(SD, "/mydir");
listDir(SD, "/", 0);
removeDir(SD, "/mydir");
listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
appendFile(SD, "/hello.txt", "World!\n");
readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
digitalWrite(LED_YELLOW, HIGH); // active LOW
}
void loop(){
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
With the pin 13 causing a crash and i have had issues with pin 14 before as well i went for some alternate pins.
Calling begin() on a SPI object setting the pins, works, simply because if begin() gets called again
void SPIClass::begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss)
{
if(_spi) {
return;
}
the private pointer is no longer NULL and therefore the rest of begin() doesn't get executed. This means that once those pins are defined in a sketch you can not set the pins to something else unless you start to make modifications to the library, but why would one want to, you would normally use just the change of the CS/SS pin for that, but you'd do that manually. I have seen no SPI device library that actually changes the CS/SS pin state, so that would be manual job anyway.
Now if you pass the pointer to the SPIClass with begin, you do have to include the CS pin, and the SD library sets it to output mode for us already, I haven't changed the speed yet, i think the default SPI speed if 4MHz if the SD library controls it, but the SPI library defaults to 1MHz, i am not sure which one actually get used in the end. I suspect the SD Library actually sets the clockspeed in the end, but i guess one could pass the same argument to both constructors rather than betting on the default.
Hope this helps, clearly setting the default SPI to HSPI is not really that easy to do, unless you find where it is set initially.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.