Concurrent VSPI and HSPI not working
Posted: Sun Oct 06, 2019 8:44 pm
Hi,
I am using Arduino ESP32 on a Lilygo T-Beam v1.0 ESP32 (same problem on an older v0.7 T-Beam).
Seems like using VSPI and HSPI concurrently on two different cores fails.
I am using HSPI to communicate with the T-Beam's on-board SX1278 (a task on core 0) and VSPI to communicate with an external 2" ILI9225 TFT display. SX1278 communication is working perfectly while the Arduino main loop (on core 1) is idle in an delay(), but when the Arduinio main loop is communicating with the display using VSPI, all SPI read operation in the SX1278 task return 0 (my measurent means are somewhat limited, but on my analog oscilloscope it seems like the chip select is not pulled to low on the SX1278 while the display is active!?????).
The problem originally arouse in a larger project, but I was able it to reduce it to the following lines of code (arduinio sketch):
The output on the console is the following:
I.e., while loop() is accessing the display, the read operation the the core0 task most of the time returns 0. During the delay() operation in the main loop(), everything is fine. The problem disappears if I pin the sx1278 task to core 1, but in the larger real project, core 0 should be busy with other things, and core 0 should perform some time-critical background tasks, so moving the task to a different core is not a easy option (and, what I understand from the SPI documentation (https://docs.espressif.com/projects/esp ... aster.html), the SPI API should be thread safe. Well.. it says "thread safe for different devices on the same bus", but it is my interpretation that it then should also be thread safe for different devices on different busses). But maybe the problem is a different one???
I am using Arduino ESP32 on a Lilygo T-Beam v1.0 ESP32 (same problem on an older v0.7 T-Beam).
Seems like using VSPI and HSPI concurrently on two different cores fails.
I am using HSPI to communicate with the T-Beam's on-board SX1278 (a task on core 0) and VSPI to communicate with an external 2" ILI9225 TFT display. SX1278 communication is working perfectly while the Arduino main loop (on core 1) is idle in an delay(), but when the Arduinio main loop is communicating with the display using VSPI, all SPI read operation in the SX1278 task return 0 (my measurent means are somewhat limited, but on my analog oscilloscope it seems like the chip select is not pulled to low on the SX1278 while the display is active!?????).
The problem originally arouse in a larger project, but I was able it to reduce it to the following lines of code (arduinio sketch):
Code: Select all
#include <axp20x.h>
#include <SPI.h>
#include <TFT_22_ILI9225.h>
#include <../fonts/FreeSans9pt7b.h>
SPIClass sxspi(HSPI);
SPIClass spiDisp(VSPI);
AXP20X_Class axp;
TFT_22_ILI9225 *tft;
#define REG_OP_MODE 0x01
const uint8_t FSK_SLEEP_MODE = 0x00;
const uint8_t FSK_STANDBY_MODE = 0x01;
#define REG_RSSI_VALUE_FSK 0x11
#define REG_FRF_MSB 0x06
#define REG_FRF_MID 0x07
#define REG_FRF_LSB 0x08
#define REG_OCP 0x0B
#define SX127X_CRYSTAL_FREQ 32000000
#define SX127X_FSTEP (SX127X_CRYSTAL_FREQ*1.0/(1<<19))
#define SX1278_SS SS
class SX1278FSK {
private:
SPIClass _spi;
SPISettings spiset;
public:
void begin(SPIClass &spi) {
spiset = SPISettings(10000000L, MSBFIRST, SPI_MODE0);
pinMode(SX1278_SS, OUTPUT);
digitalWrite(SX1278_SS, HIGH);
_spi = spi;
_spi.begin(SCK, MISO, MOSI, SS);
_spi.setBitOrder(MSBFIRST);
_spi.setClockDivider(SPI_CLOCK_DIV4);
_spi.setDataMode(SPI_MODE0);
delay(100);
int rate = 0x1B;
rate |= B00100000;
writeRegister(REG_OP_MODE, FSK_SLEEP_MODE); // Sleep mode (mandatory to change mode)
writeRegister(REG_OP_MODE, FSK_SLEEP_MODE);
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE); // Set FSK Standby mode to write in registers
writeRegister(REG_OCP, rate); // Modifying maximum current supply
int x = readRegister(REG_OP_MODE);
delay(100);
}
byte readRegister(byte address) {
byte value = 0x00;
_spi.beginTransaction(spiset);
digitalWrite(SX1278_SS, LOW);
bitClear(address, 7); // Bit 7 cleared to write in registers
_spi.transfer(address);
value = _spi.transfer(0x00);
digitalWrite(SX1278_SS, HIGH);
_spi.endTransaction();
//Serial.printf("Register %02x reads value %02x\n", address, value);
return value;
}
void writeRegister(byte address, byte data) {
_spi.beginTransaction(spiset);
digitalWrite(SX1278_SS, LOW);
bitSet(address, 7); // Bit 7 set to read from registers
_spi.transfer(address);
_spi.transfer(data);
digitalWrite(SX1278_SS, HIGH);
_spi.endTransaction();
//Serial.printf("Register %02x: writing value %02x\n", address&0x7f, data);
}
uint8_t setFrequency(float freq) {
// set mode to FSK STANDBY
writeRegister(REG_OP_MODE, FSK_STANDBY_MODE);
uint32_t frf = freq * 1.0 * (1 << 19) / SX127X_CRYSTAL_FREQ;
writeRegister(REG_FRF_MSB, (frf & 0xff0000) >> 16);
writeRegister(REG_FRF_MID, (frf & 0x00ff00) >> 8);
writeRegister(REG_FRF_LSB, (frf & 0x0000ff));
return 0;
}
float getFrequency() {
uint8_t fmsb = readRegister(REG_FRF_MSB);
uint8_t fmid = readRegister(REG_FRF_MID);
uint8_t flsb = readRegister(REG_FRF_LSB);
return ((fmsb << 16) | (fmid << 8) | flsb) * 1.0 / (1 << 19) * SX127X_CRYSTAL_FREQ;
}
};
SX1278FSK sx1278;
void sx1278Task(void *parameter) {
while (1)
{
sx1278.setFrequency(403300000);
float f = sx1278.getFrequency();
Serial.printf(" freq:%f\n", f);
delay(100);
}
}
void setup()
{
Serial.begin(115200);
// For T-Beam 1.0 => Enable 3.3V on DCDC1 for display
Wire.begin(21, 22);
if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) {
Serial.println("AXP192 Begin PASS");
} else {
Serial.println("AXP192 Begin FAIL");
}
axp.setPowerOutPut(AXP192_LDO2, AXP202_ON);
axp.setPowerOutPut(AXP192_LDO3, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC2, AXP202_ON);
axp.setPowerOutPut(AXP192_EXTEN, AXP202_ON);
axp.setPowerOutPut(AXP192_DCDC1, AXP202_ON);
axp.setDCDC1Voltage(3300);
// setup display
tft = new TFT_22_ILI9225(14, 2, 0, 4, 13, 0, 100);
tft->begin(spiDisp);
tft->setOrientation(1);
tft->clear();
tft->setGFXFont(&FreeSans9pt7b);
// setup sx1278
sx1278.begin(sxspi);
delay(100);
sx1278.setFrequency(403700000);
xTaskCreatePinnedToCore( sx1278Task, "sx1278Task",
10000, /* stack size */
NULL, /* paramter */
1, /* priority */
NULL, 0); /* task handle*/
}
#define XSKIP 14
#define YSKIP 22
void drawString(uint8_t x, uint8_t y, const char *s) {
int16_t w, h;
tft->getGFXTextExtent(s, x * XSKIP, y * YSKIP, &w, &h);
int len = strlen(s);
tft->fillRectangle(x * XSKIP, y * YSKIP + 3, x * XSKIP + len * 14, y * YSKIP + 22, COLOR_BLACK);
tft->drawGFXText(x * XSKIP, (1 + y)*YSKIP, s, COLOR_WHITE);
}
void loop() {
Serial.printf("Mainloop...\n");
for (int i = 0; i < 50; i++) {
char buf[50];
sprintf(buf, "cnt: %d ", i);
drawString(0, 1, buf);
}
Serial.printf("Mainloop delay\n");
delay(1000);
}
The output on the console is the following:
Code: Select all
22:27:52.459 -> Mainloop...
22:27:52.459 -> freq:0.000000
22:27:52.562 -> freq:0.000000
22:27:52.634 -> freq:0.000000
22:27:52.737 -> freq:0.000000
22:27:52.846 -> freq:0.000000
22:27:52.953 -> freq:0.000000
22:27:53.060 -> freq:0.000000
22:27:53.129 -> freq:0.000000
22:27:53.237 -> freq:0.000000
22:27:53.343 -> freq:0.000000
22:27:53.444 -> freq:0.000000
22:27:53.554 -> freq:0.000000
22:27:53.628 -> Mainloop delay
22:27:53.661 -> freq:403300000.000000
22:27:53.734 -> freq:403300000.000000
22:27:53.838 -> freq:403300000.000000
22:27:53.945 -> freq:403300000.000000
22:27:54.052 -> freq:403300000.000000
22:27:54.157 -> freq:403300000.000000
22:27:54.232 -> freq:403300000.000000
22:27:54.339 -> freq:403300000.000000
22:27:54.450 -> freq:403300000.000000
22:27:54.552 -> freq:403300000.000000
22:27:54.628 -> Mainloop...
22:27:54.665 -> freq:0.000000
22:27:54.733 -> freq:0.000000
22:27:54.839 -> freq:403300000.000000
22:27:54.941 -> freq:403300000.000000
22:27:55.045 -> freq:403300000.000000
22:27:55.154 -> freq:0.000000
22:27:55.256 -> freq:0.000000
22:27:55.360 -> freq:0.000000
22:27:55.461 -> freq:0.000000
22:27:55.560 -> freq:0.000000
22:27:55.662 -> freq:0.000000
22:27:55.730 -> freq:0.000000
22:27:55.833 -> Mainloop delay
22:27:55.833 -> freq:403300000.000000
22:27:55.937 -> freq:403300000.000000
22:27:56.040 -> freq:403300000.000000
22:27:56.142 -> freq:403300000.000000
22:27:56.245 -> freq:403300000.000000
22:27:56.346 -> freq:403300000.000000
22:27:56.447 -> freq:403300000.000000
22:27:56.549 -> freq:403300000.000000
22:27:56.651 -> freq:403300000.000000
22:27:56.754 -> freq:403300000.000000