How can I use ESP32 Multiple Busses SPI (hspi) with TFT_eSPI library
Did you have a problem when you tried it ?
Yes, I don’t understand how to tell the library to use the hspi bus, if you just assign the hspi bus pins in the library configuration file, I see SPI packets for the TFT display on the vspi pins
Please show your config and your sketch
I have found it simpler to use VSPI for the TFT and HSPI for other SPI devices
what other SPI devices do you wish to connect to the ESP32?
SD Card, AD9833, MCP41010, MCP41050, MCP41100
which display are you using (in particular which display controller chip)?
have you tested any of the SPI devices as yet?
in the main it appears that sharing an SPI bus with an SD reader can cause problems - see Sharing the SPI bus among SD card and other SPI devices
EDIT:
AD9833 works OK with ESP32
not used MCP41010, etc but X9C103S Digital Potentiometer works OK with ESP32
ILI9341:
My sketch:
Спойлер
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
#include <FS.h>
#include "SD.h"
#include "SPIFFS.h"
#include <LittleFS.h>
#define SD_MISO 19
#define SD_MOSI 23
#define SD_SCK 18
#define SD_CS 5
#define AD9833_CS 15
#define MCP41x1_CS 16 // Define chipselect pin for MCP41010 (CS for Volume)
#define MCP41x1_ALC 17 // Define chipselect pin for MCP41050 (CS for ALC)
#define VSPI_MISO MISO
#define VSPI_MOSI MOSI
#define VSPI_SCLK SCK
#define VSPI_SS SS
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_SCLK 14
#define HSPI_SS 0
// G0 - TFT_CS 0 <-> TFT_CS
// G2 - TFT_RST 2 <-> TFT_RST
// G4 - TFT_DC 4 <-> TFT_DC
//
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define VSPI FSPI
#endif
//uninitalised pointers to SPI objects
SPIClass * vspi1 = NULL;
SPIClass * vspi2 = NULL;
SPIClass * vspi3 = NULL;
SPIClass * vspi4 = NULL;
SPIClass * hspi = NULL;
#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg = 0, mdeg = 0, hdeg = 0;
uint16_t osx = 120, osy = 120, omx = 120, omy = 120, ohx = 120, ohy = 120; // Saved H, M, S x & y coords
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0; // for next 1 second timeout
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
bool initial = 1;
void spiCommand(SPIClass *spi, byte data, int spiclk) {
//use it as you would the regular arduino SPI API
spi->beginTransaction(SPISettings(spiclk, MSBFIRST, SPI_MODE0));
digitalWrite(spi->pinSS(), LOW); //pull SS slow to prep other end for transfer
spi->transfer(data);
digitalWrite(spi->pinSS(), HIGH); //pull ss high to signify end of data transfer
spi->endTransaction();
}
void writeValueMCP41xxx(SPIClass *spi, byte data, int spiclk) {
spi->beginTransaction(SPISettings(spiclk, MSBFIRST, SPI_MODE0));
digitalWrite(spi->pinSS(), LOW);
byte MSb = 0x11; // 0b00010001 ; where x = 0, command bits for write
byte LSb = data & 0xFF; // No value greater than 255 ; send 0x0 otherwise
uint16_t transmission = MSb << 8 | LSb;
spi->transfer(transmission);
digitalWrite(spi->pinSS(), HIGH); // Disable chip select MCP41xxx
spi->endTransaction();
}
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.path(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void setup(void) {
Serial.begin(115200);
delay(3000);
vspi1 = new SPIClass(VSPI);
vspi2 = new SPIClass(VSPI);
vspi3 = new SPIClass(VSPI);
vspi4 = new SPIClass(VSPI);
vspi1->begin();
vspi2->begin(SCK, MISO, MOSI, AD9833_CS);
vspi3->begin(SCK, MISO, MOSI, MCP41x1_CS);
vspi4->begin(SCK, MISO, MOSI, MCP41x1_ALC);
pinMode(vspi1->pinSS(), OUTPUT); // VSPI SS - SD_CS (SD CARD)
pinMode(vspi2->pinSS(), OUTPUT); // VSPI SS - AD9833_CS (AD9833)
pinMode(vspi3->pinSS(), OUTPUT); // VSPI SS - MCP41x1_CS (Potenciometr)
pinMode(vspi4->pinSS(), OUTPUT); // VSPI SS - MCP41x1_ALS (Als)
if (!SD.begin(SD_CS, *vspi1, 4000000)) {
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);
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
tft.init();
tft.setRotation(0);
//tft.fillScreen(TFT_BLACK);
//tft.fillScreen(TFT_RED);
//tft.fillScreen(TFT_GREEN);
//tft.fillScreen(TFT_BLUE);
//tft.fillScreen(TFT_BLACK);
tft.fillScreen(TFT_GREY);
tft.setTextColor(TFT_WHITE, TFT_GREY); // Adding a background colour erases previous text automatically
// Draw clock face
tft.fillCircle(120, 120, 118, TFT_GREEN);
tft.fillCircle(120, 120, 110, TFT_BLACK);
// Draw 12 lines
for (int i = 0; i < 360; i += 30) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 114 + 120;
yy0 = sy * 114 + 120;
x1 = sx * 100 + 120;
yy1 = sy * 100 + 120;
tft.drawLine(x0, yy0, x1, yy1, TFT_GREEN);
}
// Draw 60 dots
for (int i = 0; i < 360; i += 6) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 102 + 120;
yy0 = sy * 102 + 120;
// Draw minute markers
tft.drawPixel(x0, yy0, TFT_WHITE);
// Draw main quadrant dots
if (i == 0 || i == 180) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
if (i == 90 || i == 270) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
}
tft.fillCircle(120, 121, 3, TFT_WHITE);
// Draw text at position 120,260 using fonts 4
// Only font numbers 2,4,6,7 are valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . - a p m
// Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
tft.drawCentreString("Time flies", 120, 260, 4);
targetTime = millis() + 1000;
}
void loop() {
// spiCommand(vspi1, 0b01010101, 1000000); // junk data to illustrate usage
// delay(10);
spiCommand(vspi2, 0b01110111, 1000000); // junk data to illustrate usage
delay(100);
static uint8_t pot = 0;
writeValueMCP41xxx(vspi3, pot, 1000000);
pot++;
delay(100);
static uint8_t alc = 255;
writeValueMCP41xxx(vspi4, alc, 1000000);
alc--;
delay(100);
if (targetTime < millis()) {
targetTime += 1000;
ss++; // Advance second
if (ss == 60) {
ss = 0;
mm++; // Advance minute
if (mm > 59) {
mm = 0;
hh++; // Advance hour
if (hh > 23) {
hh = 0;
}
}
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss * 6; // 0-59 -> 0-354
mdeg = mm * 6 + sdeg * 0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh * 30 + mdeg * 0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg - 90) * 0.0174532925);
hy = sin((hdeg - 90) * 0.0174532925);
mx = cos((mdeg - 90) * 0.0174532925);
my = sin((mdeg - 90) * 0.0174532925);
sx = cos((sdeg - 90) * 0.0174532925);
sy = sin((sdeg - 90) * 0.0174532925);
if (ss == 0 || initial) {
initial = 0;
// Erase hour and minute hand positions every minute
tft.drawLine(ohx, ohy, 120, 121, TFT_BLACK);
ohx = hx * 62 + 121;
ohy = hy * 62 + 121;
tft.drawLine(omx, omy, 120, 121, TFT_BLACK);
omx = mx * 84 + 120;
omy = my * 84 + 121;
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
tft.drawLine(osx, osy, 120, 121, TFT_BLACK);
osx = sx * 90 + 121;
osy = sy * 90 + 121;
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.drawLine(ohx, ohy, 120, 121, TFT_WHITE);
tft.drawLine(omx, omy, 120, 121, TFT_WHITE);
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.fillCircle(120, 121, 3, TFT_RED);
}
}
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
does the code work? if not what happens?
did you test each device in a separate program before attempting to implement the complete program?
the test code works, but on the oscillogram I see calls via the vspi channel to the TFT display, periodically the data on the display may disappear and not appear again
I found that reducing the SPI frequency in the TFT_eSPI setup file (where you specify the SPI pins) helps, e.g. 10MHz
#define SPI_FREQUENCY 10000000
- In principle, I don’t understand how the TFT_eSPI library can find out that it needs to work through the hspi class I defined
- Why do I see foreign debris on vspi pins?
- how to overcome it
Variant 2:
Спойлер
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library - https://github.com/Bodmer/TFT_eSPI
#include <FS.h>
#include "SD.h"
#include "SPIFFS.h"
#include <LittleFS.h>
#define SD_MISO 19
#define SD_MOSI 23
#define SD_SCK 18
#define SD_CS 5
#define AD9833_CS 15
#define MCP41x1_CS 16 // Define chipselect pin for MCP41010 (CS for Volume)
#define MCP41x1_ALC 17 // Define chipselect pin for MCP41050 (CS for ALC)
#define VSPI_MISO MISO
#define VSPI_MOSI MOSI
#define VSPI_SCLK SCK
#define VSPI_SS SS
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_SCLK 14
#define HSPI_SS 0
// G0 - TFT_CS 0 <-> TFT_CS
// G2 - TFT_RST 2 <-> TFT_RST
// G4 - TFT_DC 4 <-> TFT_DC
//
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define VSPI FSPI
#endif
//uninitalised pointers to SPI objects
SPIClass * vspi1 = NULL;
SPIClass * vspi2 = NULL;
SPIClass * vspi3 = NULL;
SPIClass * vspi4 = NULL;
SPIClass * hspi = NULL;
#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg = 0, mdeg = 0, hdeg = 0;
uint16_t osx = 120, osy = 120, omx = 120, omy = 120, ohx = 120, ohy = 120; // Saved H, M, S x & y coords
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0; // for next 1 second timeout
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
bool initial = 1;
void spiCommand(SPIClass *spi, byte data, int spiclk) {
//use it as you would the regular arduino SPI API
spi->beginTransaction(SPISettings(spiclk, MSBFIRST, SPI_MODE0));
digitalWrite(spi->pinSS(), LOW); //pull SS slow to prep other end for transfer
spi->transfer(data);
digitalWrite(spi->pinSS(), HIGH); //pull ss high to signify end of data transfer
spi->endTransaction();
}
void writeValueMCP41xxx(SPIClass *spi, byte data, int spiclk) {
spi->beginTransaction(SPISettings(spiclk, MSBFIRST, SPI_MODE0));
digitalWrite(spi->pinSS(), LOW);
byte MSb = 0x11; // 0b00010001 ; where x = 0, command bits for write
byte LSb = data & 0xFF; // No value greater than 255 ; send 0x0 otherwise
uint16_t transmission = MSb << 8 | LSb;
spi->transfer(transmission);
digitalWrite(spi->pinSS(), HIGH); // Disable chip select MCP41xxx
spi->endTransaction();
}
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.path(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void setup(void) {
Serial.begin(115200);
delay(3000);
vspi1 = new SPIClass(VSPI);
vspi2 = new SPIClass(VSPI);
vspi3 = new SPIClass(VSPI);
vspi4 = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
vspi1->begin();
vspi2->begin(SCK, MISO, MOSI, AD9833_CS);
vspi3->begin(SCK, MISO, MOSI, MCP41x1_CS);
vspi4->begin(SCK, MISO, MOSI, MCP41x1_ALC);
hspi->begin(HSPI_SCLK,HSPI_MISO,HSPI_MOSI,HSPI_SS);
pinMode(vspi1->pinSS(), OUTPUT); // VSPI SS - SD_CS (SD CARD)
digitalWrite(vspi1->pinSS(), HIGH);
pinMode(vspi2->pinSS(), OUTPUT); // VSPI SS - AD9833_CS (AD9833)
digitalWrite(vspi2->pinSS(), HIGH);
pinMode(vspi3->pinSS(), OUTPUT); // VSPI SS - MCP41x1_CS (Potenciometr)
digitalWrite(vspi3->pinSS(), HIGH);
pinMode(vspi4->pinSS(), OUTPUT); // VSPI SS - MCP41x1_ALS (Als)
digitalWrite(vspi4->pinSS(), HIGH);
pinMode(hspi->pinSS(), OUTPUT); // VSPI SS - MCP41x1_ALS (Als)
digitalWrite(hspi->pinSS(), HIGH);
if (!SD.begin(SD_CS, *vspi1, 4000000)) {
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);
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
tft.init();
tft.setRotation(0);
//tft.fillScreen(TFT_BLACK);
//tft.fillScreen(TFT_RED);
//tft.fillScreen(TFT_GREEN);
//tft.fillScreen(TFT_BLUE);
//tft.fillScreen(TFT_BLACK);
tft.fillScreen(TFT_GREY);
tft.setTextColor(TFT_WHITE, TFT_GREY); // Adding a background colour erases previous text automatically
// Draw clock face
tft.fillCircle(120, 120, 118, TFT_GREEN);
tft.fillCircle(120, 120, 110, TFT_BLACK);
// Draw 12 lines
for (int i = 0; i < 360; i += 30) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 114 + 120;
yy0 = sy * 114 + 120;
x1 = sx * 100 + 120;
yy1 = sy * 100 + 120;
tft.drawLine(x0, yy0, x1, yy1, TFT_GREEN);
}
// Draw 60 dots
for (int i = 0; i < 360; i += 6) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 102 + 120;
yy0 = sy * 102 + 120;
// Draw minute markers
tft.drawPixel(x0, yy0, TFT_WHITE);
// Draw main quadrant dots
if (i == 0 || i == 180) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
if (i == 90 || i == 270) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
}
tft.fillCircle(120, 121, 3, TFT_WHITE);
// Draw text at position 120,260 using fonts 4
// Only font numbers 2,4,6,7 are valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . - a p m
// Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
tft.drawCentreString("Time flies", 120, 260, 4);
targetTime = millis() + 1000;
}
void loop() {
// spiCommand(vspi1, 0b01010101, 1000000); // junk data to illustrate usage
// delay(10);
spiCommand(vspi2, 0b01110111, 1000000); // junk data to illustrate usage
delay(100);
static uint8_t pot = 0;
writeValueMCP41xxx(vspi3, pot, 1000000);
pot++;
delay(100);
static uint8_t alc = 255;
writeValueMCP41xxx(vspi4, alc, 1000000);
alc--;
delay(100);
if (targetTime < millis()) {
targetTime += 1000;
ss++; // Advance second
if (ss == 60) {
ss = 0;
mm++; // Advance minute
if (mm > 59) {
mm = 0;
hh++; // Advance hour
if (hh > 23) {
hh = 0;
}
}
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss * 6; // 0-59 -> 0-354
mdeg = mm * 6 + sdeg * 0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh * 30 + mdeg * 0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg - 90) * 0.0174532925);
hy = sin((hdeg - 90) * 0.0174532925);
mx = cos((mdeg - 90) * 0.0174532925);
my = sin((mdeg - 90) * 0.0174532925);
sx = cos((sdeg - 90) * 0.0174532925);
sy = sin((sdeg - 90) * 0.0174532925);
if (ss == 0 || initial) {
initial = 0;
// Erase hour and minute hand positions every minute
tft.drawLine(ohx, ohy, 120, 121, TFT_BLACK);
ohx = hx * 62 + 121;
ohy = hy * 62 + 121;
tft.drawLine(omx, omy, 120, 121, TFT_BLACK);
omx = mx * 84 + 120;
omy = my * 84 + 121;
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
tft.drawLine(osx, osy, 120, 121, TFT_BLACK);
osx = sx * 90 + 121;
osy = sy * 90 + 121;
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.drawLine(ohx, ohy, 120, 121, TFT_WHITE);
tft.drawLine(omx, omy, 120, 121, TFT_WHITE);
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.fillCircle(120, 121, 3, TFT_RED);
}
}
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
I uncommented the line in the User_Setup.h file and the garbage disappeared.
#define USE_HSPI_PORT
Спойлер
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library - https://github.com/Bodmer/TFT_eSPI
#include <FS.h>
#include "SD.h"
#include "SPIFFS.h"
#include <LittleFS.h>
#define SD_MISO 19
#define SD_MOSI 23
#define SD_SCK 18
#define SD_CS 5
#define AD9833_CS 15
#define MCP41x1_CS 16 // Define chipselect pin for MCP41010 (CS for Volume)
#define MCP41x1_ALC 17 // Define chipselect pin for MCP41050 (CS for ALC)
#define VSPI_MISO MISO
#define VSPI_MOSI MOSI
#define VSPI_SCLK SCK
#define VSPI_SS SS
#define HSPI_MISO 12
#define HSPI_MOSI 13
#define HSPI_SCLK 14
#define HSPI_SS 0
// G0 - TFT_CS 0 <-> TFT_CS
// G2 - TFT_RST 2 <-> TFT_RST
// G4 - TFT_DC 4 <-> TFT_DC
//
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#define VSPI FSPI
#endif
//uninitalised pointers to SPI objects
SPIClass * vspi1 = NULL;
SPIClass * vspi2 = NULL;
SPIClass * vspi3 = NULL;
SPIClass * vspi4 = NULL;
SPIClass * hspi = NULL;
#define TFT_GREY 0x5AEB
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers
float sdeg = 0, mdeg = 0, hdeg = 0;
uint16_t osx = 120, osy = 120, omx = 120, omy = 120, ohx = 120, ohy = 120; // Saved H, M, S x & y coords
uint16_t x0 = 0, x1 = 0, yy0 = 0, yy1 = 0;
uint32_t targetTime = 0; // for next 1 second timeout
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x
uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
bool initial = 1;
void spiCommand(SPIClass *spi, byte data, int spiclk) {
//use it as you would the regular arduino SPI API
spi->beginTransaction(SPISettings(spiclk, MSBFIRST, SPI_MODE0));
digitalWrite(spi->pinSS(), LOW); //pull SS slow to prep other end for transfer
spi->transfer(data);
digitalWrite(spi->pinSS(), HIGH); //pull ss high to signify end of data transfer
spi->endTransaction();
}
void writeValueMCP41xxx(SPIClass *spi, byte data, int spiclk) {
spi->beginTransaction(SPISettings(spiclk, MSBFIRST, SPI_MODE0));
digitalWrite(spi->pinSS(), LOW);
byte MSb = 0x11; // 0b00010001 ; where x = 0, command bits for write
byte LSb = data & 0xFF; // No value greater than 255 ; send 0x0 otherwise
uint16_t transmission = MSb << 8 | LSb;
spi->transfer16(transmission);
digitalWrite(spi->pinSS(), HIGH); // Disable chip select MCP41xxx
spi->endTransaction();
}
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.path(), levels - 1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void setup(void) {
Serial.begin(115200);
delay(3000);
vspi1 = new SPIClass(VSPI);
vspi2 = new SPIClass(VSPI);
vspi3 = new SPIClass(VSPI);
vspi4 = new SPIClass(VSPI);
hspi = new SPIClass(HSPI);
vspi1->begin();
vspi2->begin(SCK, MISO, MOSI, AD9833_CS);
vspi3->begin(SCK, MISO, MOSI, MCP41x1_CS);
vspi4->begin(SCK, MISO, MOSI, MCP41x1_ALC);
hspi->begin(HSPI_SCLK,HSPI_MISO,HSPI_MOSI,HSPI_SS);
pinMode(vspi1->pinSS(), OUTPUT); // VSPI SS - SD_CS (SD CARD)
digitalWrite(vspi1->pinSS(), HIGH);
pinMode(vspi2->pinSS(), OUTPUT); // VSPI SS - AD9833_CS (AD9833)
digitalWrite(vspi2->pinSS(), HIGH);
pinMode(vspi3->pinSS(), OUTPUT); // VSPI SS - MCP41x1_CS (Potenciometr)
digitalWrite(vspi3->pinSS(), HIGH);
pinMode(vspi4->pinSS(), OUTPUT); // VSPI SS - MCP41x1_ALS (Als)
digitalWrite(vspi4->pinSS(), HIGH);
pinMode(hspi->pinSS(), OUTPUT); // VSPI SS - MCP41x1_ALS (Als)
digitalWrite(hspi->pinSS(), HIGH);
if (!SD.begin(SD_CS, *vspi1, 4000000)) {
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);
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
tft.init();
tft.setRotation(0);
//tft.fillScreen(TFT_BLACK);
//tft.fillScreen(TFT_RED);
//tft.fillScreen(TFT_GREEN);
//tft.fillScreen(TFT_BLUE);
//tft.fillScreen(TFT_BLACK);
tft.fillScreen(TFT_GREY);
tft.setTextColor(TFT_WHITE, TFT_GREY); // Adding a background colour erases previous text automatically
// Draw clock face
tft.fillCircle(120, 120, 118, TFT_GREEN);
tft.fillCircle(120, 120, 110, TFT_BLACK);
// Draw 12 lines
for (int i = 0; i < 360; i += 30) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 114 + 120;
yy0 = sy * 114 + 120;
x1 = sx * 100 + 120;
yy1 = sy * 100 + 120;
tft.drawLine(x0, yy0, x1, yy1, TFT_GREEN);
}
// Draw 60 dots
for (int i = 0; i < 360; i += 6) {
sx = cos((i - 90) * 0.0174532925);
sy = sin((i - 90) * 0.0174532925);
x0 = sx * 102 + 120;
yy0 = sy * 102 + 120;
// Draw minute markers
tft.drawPixel(x0, yy0, TFT_WHITE);
// Draw main quadrant dots
if (i == 0 || i == 180) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
if (i == 90 || i == 270) tft.fillCircle(x0, yy0, 2, TFT_WHITE);
}
tft.fillCircle(120, 121, 3, TFT_WHITE);
// Draw text at position 120,260 using fonts 4
// Only font numbers 2,4,6,7 are valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : . - a p m
// Font 7 is a 7 segment font and only contains characters [space] 0 1 2 3 4 5 6 7 8 9 : .
tft.drawCentreString("Time flies", 120, 260, 4);
targetTime = millis() + 1000;
}
void loop() {
// spiCommand(vspi1, 0b01010101, 1000000); // junk data to illustrate usage
// delay(10);
spiCommand(vspi2, 0b01110111, 1000000); // junk data to illustrate usage
delay(100);
static uint8_t pot = 0;
writeValueMCP41xxx(vspi3, pot, 1000000);
pot++;
delay(100);
static uint8_t alc = 255;
writeValueMCP41xxx(vspi4, alc, 1000000);
alc--;
delay(100);
if (targetTime < millis()) {
targetTime += 1000;
ss++; // Advance second
if (ss == 60) {
ss = 0;
mm++; // Advance minute
if (mm > 59) {
mm = 0;
hh++; // Advance hour
if (hh > 23) {
hh = 0;
}
}
}
// Pre-compute hand degrees, x & y coords for a fast screen update
sdeg = ss * 6; // 0-59 -> 0-354
mdeg = mm * 6 + sdeg * 0.01666667; // 0-59 -> 0-360 - includes seconds
hdeg = hh * 30 + mdeg * 0.0833333; // 0-11 -> 0-360 - includes minutes and seconds
hx = cos((hdeg - 90) * 0.0174532925);
hy = sin((hdeg - 90) * 0.0174532925);
mx = cos((mdeg - 90) * 0.0174532925);
my = sin((mdeg - 90) * 0.0174532925);
sx = cos((sdeg - 90) * 0.0174532925);
sy = sin((sdeg - 90) * 0.0174532925);
if (ss == 0 || initial) {
initial = 0;
// Erase hour and minute hand positions every minute
tft.drawLine(ohx, ohy, 120, 121, TFT_BLACK);
ohx = hx * 62 + 121;
ohy = hy * 62 + 121;
tft.drawLine(omx, omy, 120, 121, TFT_BLACK);
omx = mx * 84 + 120;
omy = my * 84 + 121;
}
// Redraw new hand positions, hour and minute hands not erased here to avoid flicker
tft.drawLine(osx, osy, 120, 121, TFT_BLACK);
osx = sx * 90 + 121;
osy = sy * 90 + 121;
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.drawLine(ohx, ohy, 120, 121, TFT_WHITE);
tft.drawLine(omx, omy, 120, 121, TFT_WHITE);
tft.drawLine(osx, osy, 120, 121, TFT_RED);
tft.fillCircle(120, 121, 3, TFT_RED);
}
}
static uint8_t conv2d(const char* p) {
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
The question remains: how to share the hspi bus between several devices