Good morning all,
I am coming to you because for more than a week I have been trying to understand how I could use 2 SPI on my ESP32.
The VSPI is used by my RFM95
VSPI_MISO pin19 ESP32
VSPI_MOSI pin23 esp32
VSPI_SCLK pin18 esp32
VSPI_SS pin5 esp32
All is working perfectly on the lora part but When a want to use the HSPI for shift register nothing work.
HSPI MISO pin12 esp32
HSPI SCLK pin14 esp32.
When I just activate the HSPI part for the Shift register all is whorking perfect so the HPSI is working but when I enable the LMIC lora part I have an Failure:
15:18:13.001 → FAILURE
15:18:13.001 → C:\Users\cd06631\OneDrive-Deere&Co\OneDrive - Deere & Co\Documents\Arduino\libraries\arduino-lmic-master\src\lmic\oslmic.c:53
#include <lmic.h>
#include <hal/hal.h>
#include <Wire.h>
#include <SPI.h>
SPIClass SPI1(HSPI);
//SPIClass SPI(VSPI);
const int testLed = 13; //onboard LED
const int LATCH = 16;
//Pins ESP32 wroom
const byte powerGates1 = 2;
const byte powerGates2 = 17;
// supply control
//const int transistorPin = 16;
const int numberOfGates = 24; // 24 gates, 48 sensors
const int startGate = 0; //useful for testing
const int endGate = 24; //useful for testing
const int debeebounce = 30;
const int outputDelay = 20000; //prints bee counts every 15 seconds
unsigned long lastOutput = 0;
unsigned long currentTime = 0;
//boolean 0 or 1 sensor readings, 1 bee is present
boolean inSensorReading[numberOfGates];
boolean outSensorReading[numberOfGates];
boolean lastInSensorReading[numberOfGates];
boolean lastOutSensorReading[numberOfGates];
boolean checkStateIn[numberOfGates];
boolean checkStateOut[numberOfGates];
int inCount[numberOfGates];
int outCount[numberOfGates];
unsigned long startInReadingTime[numberOfGates];
unsigned long startOutReadingTime[numberOfGates];
unsigned long inSensorTime[numberOfGates];
unsigned long outSensorTime[numberOfGates];
unsigned long lastInFinishedTime[numberOfGates];
unsigned long lastOutFinishedTime[numberOfGates];
unsigned long inReadingTimeHigh[numberOfGates];
unsigned long outReadingTimeHigh[numberOfGates];
unsigned long lastInTime[numberOfGates];
unsigned long lastOutTime[numberOfGates];
unsigned long lastInReadingTimeHigh[numberOfGates];
unsigned long lastOutReadingTimeHigh[numberOfGates];
int totalTimeTravelGoingOut[numberOfGates];
int totalTimeTravelGoingIn[numberOfGates];
int firstTestInVariable[numberOfGates];
int firstTestOutVariable[numberOfGates];
int totalsorti;
int totalentree;
int inTotal;
int outTotal;
int n = 0;
// For normal use, we require that you edit the sketch to replace FILLMEIN
// with values assigned by the TTN console. However, for regression tests,
// we want to be able to compile these scripts. The regression tests define
// COMPILE_REGRESSION_TEST, and in that case we define FILLMEIN to a non-
// working but innocuous value.
#ifdef COMPILE_REGRESSION_TEST
# define FILLMEIN 0
#else
# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!"
# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)
#endif
// LoRaWAN NwkSKey, network session key
static const PROGMEM u1_t NWKSKEY[16] = {****************************************** };
// LoRaWAN AppSKey, application session key
static const u1_t PROGMEM APPSKEY[16] = { **************************************** };
// LoRaWAN end-device address (DevAddr)
// See http://thethingsnetwork.org/wiki/AddressSpace
// The library converts the address to network byte order as needed.
#ifndef COMPILE_REGRESSION_TEST
static const u4_t DEVADDR = 0x*********;
#else
static const u4_t DEVADDR = 0;
#endif
// These callbacks are only used in over-the-air activation, so they are
// left empty here (we cannot leave them out completely unless
// DISABLE_JOIN is set in arduino-lmic/project_config/lmic_project_config.h,
// otherwise the linker will complain).
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
// payload to send to TTN gateway
static uint8_t payload[3];
static osjob_t sendjob;
// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 30;
// Pin mapping for Adafruit Feather M0 LoRa
const lmic_pinmap lmic_pins = {
.nss = 5,
.rxtx = LMIC_UNUSED_PIN,
.rst = 13,
// LBT cal for the Adafruit Feather M0 LoRa, in dB
.dio = {27, 26, LMIC_UNUSED_PIN},
// .dio = {27, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN},
};
void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
break;
/*
|| This event is defined but not used in the code. No
|| point in wasting codespace on it.
||
|| case EV_RFU1:
|| Serial.println(F("EV_RFU1"));
|| break;
*/
case EV_JOIN_FAILED:
Serial.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
Serial.println(F("EV_REJOIN_FAILED"));
break;
case EV_TXCOMPLETE:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
// Schedule next transmission
// digitalWrite (transistorPin, LOW);
// Deep_Sleep_Now();
// os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
/*
|| This event is defined but not used in the code. No
|| point in wasting codespace on it.
||
|| case EV_SCAN_FOUND:
|| Serial.println(F("EV_SCAN_FOUND"));
|| break;
*/
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned) ev);
break;
}
}
void do_send(osjob_t* j){
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
Serial.print("T, ");
Serial.print(outTotal);
Serial.print(", ");
Serial.println(inTotal);
int16_t outtotalInt = outTotal * 100; // convert to signed 16 bits integer: 0x0929
int16_t intotalInt = inTotal * 100;
uint8_t buffer[4]; // reserve 2 bytes in memory
// Handle high byte (MSB) first; 0x09 for 23.45
// 0x0929 >> 8 shifts the 0x29 out of memory, leaving 0x0009
// 0x0009 does not fit in a single byte, so only 0x09 is stored in buffer[0]:
buffer[0] = outtotalInt >> 8;
buffer[1] = outtotalInt;
buffer[2] = intotalInt >> 8;
buffer[3] = intotalInt;
// Send on port 1, without asking for confirmation:
LMIC_setTxData2(1, buffer, sizeof(buffer), 0); // 0x0929 for 23.45
Serial.println(F("Packet queued"));
}
// Next TX is scheduled after TX_COMPLETE event.
}
void setup ()
{
SPI1.begin();
SPI1.beginTransaction(SPISettings(3000000, MSBFIRST, SPI_MODE2));
//pinMode (transistorPin, OUTPUT);
// digitalWrite (transistorPin, HIGH);
delay(1000);
Serial.println(F("Starting"));
delay(4000);
while (!Serial);
Serial.begin (115200);
Serial.println ("Begin switch test.");
pinMode (LATCH, OUTPUT);
digitalWrite (LATCH, HIGH);
pinMode (powerGates1, OUTPUT);
digitalWrite(powerGates1, LOW);
pinMode (powerGates2, OUTPUT);
digitalWrite(powerGates2, LOW);
//pinMode(testLed, OUTPUT);
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
// Set static session parameters. Instead of dynamically establishing a session
// by joining the network, precomputed session parameters are be provided.
// On AVR, these values are stored in flash and only copied to RAM
// once. Copy them to a temporary buffer here, LMIC_setSession will
// copy them into a buffer of its own again.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession (0x13, DEVADDR, nwkskey, appskey);
#if defined(CFG_eu868) // EU channel setup
int channel = 0;
int dr = DR_SF7;
for(int i=0; i<9; i++) {
if(i != channel) {
LMIC_disableChannel(i);
}
}
// Set data rate (SF) and transmit power for uplink
LMIC_setDrTxpow(dr, 14); // g-band
#elif defined(CFG_us915) // US channel setup
// Instead of using selectSubBand, which will cycle through a sub-band of 8
// channels. We'll configure the device to only use one frequency.
// First disable all sub-bands
for (int b = 0; b < 8; ++b) {
LMIC_disableSubBand(b);
}
// Then enable the channel(s) you want to use
//LMIC_enableChannel(8); // 903.9 MHz
LMIC_enableChannel(17);
#endif
// Disable link check validation
LMIC_setLinkCheckMode(0);
// TTN uses SF9 for its RX2 window.
LMIC.dn2Dr = DR_SF9;
// Set data rate and transmit power for uplink
LMIC_setDrTxpow(DR_SF7,14);
// Start job
do_send(&sendjob);
}
byte switchBank1;
byte oldSwitchBank1;
byte switchBank2;
byte oldSwitchBank2;
byte switchBank3;
byte oldSwitchBank3;
byte switchBank4;
byte oldSwitchBank4;
byte switchBank5;
byte oldSwitchBank5;
byte switchBank6;
byte oldSwitchBank6;
byte switchBank7;
byte oldSwitchBank7;
byte switchBank8;
byte oldSwitchBank8;
void loop ()
{
os_runloop_once();
//beeProgram();
}
void beeProgram() {
currentTime = millis();
digitalWrite(powerGates1, HIGH);
digitalWrite(powerGates2, HIGH);
delayMicroseconds(75); //first 24 gates only need 15us while gates closer to the end need ~40us-75us
digitalWrite (LATCH, LOW); // pulse the parallel load latch
delayMicroseconds(3);
digitalWrite (LATCH, HIGH);
delayMicroseconds(3);
digitalWrite(powerGates1, LOW);
digitalWrite(powerGates2, LOW);
//Reading 24 bits at 1Mhz should take about 24 microseconds,
//reading 24 bits at 3Mhz should take about 8us
//reading 48 bits at 3Mhz should take abotu 16us
switchBank1 = SPI1.transfer (0); //8
switchBank2 = SPI1.transfer (0); //16
switchBank3 = SPI1.transfer (0); //24
switchBank4 = SPI1.transfer (0); //32
switchBank5 = SPI1.transfer (0); //40
switchBank6 = SPI1.transfer (0); //48
if(switchBank1 != oldSwitchBank1 || switchBank2 != oldSwitchBank2 || switchBank3 != oldSwitchBank3 || switchBank4 != oldSwitchBank4 || switchBank5 != oldSwitchBank5 || switchBank6 != oldSwitchBank6)
{
//convert bytes to gate values
int gate = 0;
for(int i = 0; i < 8; i++)
{
if((switchBank1 >> i) & 1)
outSensorReading[gate] = HIGH;
else outSensorReading[gate] = LOW;
i++;
if((switchBank1 >> i) & 1)
inSensorReading[gate] = HIGH;
else inSensorReading[gate] = LOW;
gate++;
}
for(int i = 0; i < 8; i++)
{
if((switchBank2 >> i) & 1)
outSensorReading[gate] = HIGH;
else outSensorReading[gate] = LOW;
i++;
if((switchBank2 >> i) & 1)
inSensorReading[gate] = HIGH;
else inSensorReading[gate] = LOW;
gate++;
}
for(int i = 0; i < 8; i++)
{
if((switchBank3 >> i) & 1)
outSensorReading[gate] = HIGH;
else outSensorReading[gate] = LOW;
i++;
if((switchBank3 >> i) & 1)
inSensorReading[gate] = HIGH;
else inSensorReading[gate] = LOW;
gate++;
}
for(int i = 0; i < 8; i++)
{
if((switchBank4 >> i) & 1)
outSensorReading[gate] = HIGH;
else outSensorReading[gate] = LOW;
i++;
if((switchBank4 >> i) & 1)
inSensorReading[gate] = HIGH;
else inSensorReading[gate] = LOW;
gate++;
}
for(int i = 0; i < 8; i++)
{
if((switchBank5 >> i) & 1)
outSensorReading[gate] = HIGH;
else outSensorReading[gate] = LOW;
i++;
if((switchBank5 >> i) & 1)
inSensorReading[gate] = HIGH;
else inSensorReading[gate] = LOW;
gate++;
}
for(int i = 0; i < 8; i++)
{
if((switchBank6 >> i) & 1)
outSensorReading[gate] = HIGH;
else outSensorReading[gate] = LOW;
i++;
if((switchBank6 >> i) & 1)
inSensorReading[gate] = HIGH;
else inSensorReading[gate] = LOW;
gate++;
}
oldSwitchBank1 = switchBank1;
oldSwitchBank2 = switchBank2;
oldSwitchBank3 = switchBank3;
oldSwitchBank4 = switchBank4;
oldSwitchBank5 = switchBank5;
oldSwitchBank6 = switchBank6;
}
for (int i = startGate; i < endGate; i++)
{
if(inSensorReading[i] == HIGH || outSensorReading[i] == HIGH)
{
digitalWrite(testLed, HIGH);
break;
}
digitalWrite(testLed, LOW);
}
for (int i = startGate; i < endGate; i++)
//for (int i = 8; i < 12; i++)
{
if(inSensorReading[i] != lastInSensorReading[i]) //change of state on IN sensor
{
checkStateIn[i] = 0;
lastInSensorReading[i] = inSensorReading[i];
inSensorTime[i] = currentTime;
//Serial.print(i);
//Serial.print(", ");
//Serial.println(inSensorReading[i]);
}
if(outSensorReading[i] != lastOutSensorReading[i]) //change of state on OUT sensor
{
checkStateOut[i] = 0;
lastOutSensorReading[i] = outSensorReading[i];
outSensorTime[i] = currentTime;
//Serial.print(i);
//Serial.print(", ");
//Serial.println(outSensorReading[i]);
}
if(currentTime - inSensorTime[i] > debeebounce && checkStateIn[i] == 0) //debounce IN sensor
{
checkStateIn[i] = 1; //passed debounce
//Serial.print(i);
//Serial.print(", IN sensor - high_or_low: ");
//Serial.println(inSensorReading[i]);
if(inSensorReading[i] == HIGH) //a bee just entered the sensor
{
startInReadingTime[i] = currentTime;
//Serial.print(i);
//Serial.print(", I ,");
//Serial.println(currentTime);
}
if(inSensorReading[i] == LOW) //a bee just exits the sensor; that is, it was HIGH, now it is LOW (empty)
{
lastInFinishedTime[i] = currentTime;
inReadingTimeHigh[i] = currentTime - startInReadingTime[i]; //this variable is how long the bee was present for
Serial.print(i);
Serial.print(", IT ,");
Serial.print(inReadingTimeHigh[i]);
Serial.print(", ");
if(outReadingTimeHigh[i] < 650 && inReadingTimeHigh[i] < 650){ //should be less than 650ms
if(currentTime - lastOutFinishedTime[i] < 200){ //the sensors are pretty cose together so the time it takes to trigger on and then the other should be small.. ~200ms
inTotal++;
Serial.print(currentTime);
Serial.print(",");
Serial.println(1);
}else{
Serial.println(currentTime);
}
}else{
Serial.println(currentTime);
}
}
}
if(currentTime - outSensorTime[i] > debeebounce && checkStateOut[i] == 0) //debounce OUT sensor
{
checkStateOut[i] = 1; //passed debounce
//Serial.print(i);
//Serial.print(", IN sensor - high_or_low: ");
//Serial.println(outSensorReading[i]);
if(outSensorReading[i] == HIGH) //a bee just entered the sensor
{
startOutReadingTime[i] = currentTime;
//Serial.print(i);
//Serial.print(", O ,");
//Serial.println(currentTime);
}
if(outSensorReading[i] == LOW) //a bee just exits the sensor; that is, it was HIGH, now it is LOW (empty)
{
lastOutFinishedTime[i] = currentTime;
outReadingTimeHigh[i] = currentTime - startOutReadingTime[i]; //this variable is how long the bee was present for
Serial.print(i);
Serial.print(", OT ,");
Serial.print(outReadingTimeHigh[i]);
Serial.print(", ");
if(outReadingTimeHigh[i] < 600 && inReadingTimeHigh[i] < 600){ //should be less than 600ms
if(currentTime - lastInFinishedTime[i] < 200){ //the sensors are pretty cose together so this time should be small
outTotal++;
Serial.print(currentTime);
Serial.print(",");
Serial.println(1);
}else{
Serial.println(currentTime);
}
}else{
Serial.println(currentTime);
}
}
}
}
delay (15); // debounce
if (currentTime - lastOutput > outputDelay)
{
//Serial.println("sending data");
sendData();
lastOutput = currentTime;
inTotal = 0;
outTotal = 0;
}
}
void sendData() {
Serial.print("T, ");
Serial.print(outTotal);
Serial.print(", ");
Serial.println(inTotal);
// over wifi or ethernet or serial
}
I don’t Know how to declare the 2 SPI with the LMIC
Many thanks for your help
christophe