mcci-catena / arduino-lmic

LoraWAN-MAC-in-C library, adapted to run under the Arduino environment
https://forum.mcci.io/c/device-software/arduino-lmic/
MIT License
645 stars 211 forks source link

PICO rp2040 not able to read serial1 while LMIC is active #922

Closed SnkMtn000 closed 1 year ago

SnkMtn000 commented 1 year ago

Describe your question or issue GPS is not being read on Serial1 when using the lmic and hal libraries. Is something blocking serial1?

Please give a clear and concise description of the problem you're facing and what you'd like help with.

Hooked up a Oled, Adafruit HopeRF 95 915 MHz on SPI0, and TinyGPSPlus neo6 on Serial1 on a bread board using code from the example ttn-otta.ino.

Code works great with my breadboard wiring if only reading GPS module. Adding the Lorawan code it fails to read serial1 with the addition of the LMIC code. Despite the GPS not being read it it shows up on the things network and delivers a dummy payload correctly.

Environment

/* 
  PICO, Oled, add LORA
*/

#include <Wire.h>
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#include <Adafruit_SSD1306.h>
#include <TinyGPSPlus.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3C 

int readSensorDelay = 5000;
const unsigned TX_INTERVAL = 10;  // was 60 Schedule TX every this many seconds (might become longer due to duty
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };  //  LSB
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
static const u1_t PROGMEM DEVEUI[8]={ Nope! };  // LSB
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
static const u1_t PROGMEM APPKEY[16] = { Nope! };  //  MSB
void os_getDevKey (u1_t* buf) {  memcpy_P(buf, APPKEY, 16);}
static osjob_t sendjob;
const lmic_pinmap lmic_pins = {  // Pin mapping  Feather MO
    .nss = 17,  // was 6  was 8
    .rxtx = LMIC_UNUSED_PIN,  //  was LMIC_UNUSED_PIN
    .rst = 22,  //  was 5
    .dio = {20, 21, LMIC_UNUSED_PIN},  //   was 2 3
};
int count = 0;
int mycount = 0;
int myhr, mymin, mysec;
int mysat = 0;
float mylat = 0.0;
float mylon = 0.0;
float mytemp = 0.00;
String myString = "";

//uint8_t mydata[] = "012345678901234567890123456789012345678901234567890123456789";  // = 60 characters
uint8_t mydata[] = "0123456789012345678901234567890123456789012345678901234567890123";  // = 64 characters

//uint8_t mydata[] = "**************************************************";  // = 50 characters
int myintdata[80];

TinyGPSPlus gps;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup()
{
  Serial.begin(115200);
  Serial1.begin(9600);
  initOled();
  SPI.setRX(16);
  SPI.setCS(17);
  SPI.setSCK(18);
  SPI.setTX(19);
  //SPI.begin();
  pinMode(LED_BUILTIN, OUTPUT);
  os_init();  // LMIC init
  LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);  // Let LMIC compensate for +/- 1% clock error ************** ny addition
  LMIC_reset();  // Reset the MAC state. Session and pending data transfers will be discarded.
  do_send(&sendjob);  // Start job (sending automatically starts OTAA too)
  delay(5000);
}

void loop()
{
  os_runloop_once();
}

void do_send(osjob_t* j){
  //readGps();
  Serial.println("do_send osjob .....     ");
  readGps();
  if (LMIC.opmode & OP_TXRXPEND) {
    Serial.println(F("OP_TXRXPEND, not sending"));
    } else {
      //readGps();
      for(int i = 0;i < myString.length(); i++) {
          //mydata[i] = (byte)myString[i];
          mydata[i] = myString[i];
        }
      LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
      Serial.println(F("Packet queued"));

    }

}// Next TX is scheduled after TX_COMPLETE event.

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"));
            {
              u4_t netid = 0;
              devaddr_t devaddr = 0;
              u1_t nwkKey[16];
              u1_t artKey[16];
              LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
              Serial.print("netid: ");
              Serial.println(netid, DEC);
              Serial.print("devaddr: ");
              Serial.println(devaddr, HEX);
              Serial.print("AppSKey: ");
              for (size_t i=0; i<sizeof(artKey); ++i) {
                if (i != 0)
                  Serial.print("-");
                printHex2(artKey[i]);
              }
              Serial.println("");
              Serial.print("NwkSKey: ");
              for (size_t i=0; i<sizeof(nwkKey); ++i) {
                      if (i != 0)
                              Serial.print("-");
                      printHex2(nwkKey[i]);
              }
              Serial.println();
            }
            // Disable link check validation (automatically enabled
            // during join, but because slow data rates change max TX
      // size, we don't use it in this example.
            LMIC_setLinkCheckMode(0);
            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.print(F("Received "));
              Serial.print(LMIC.dataLen);
              Serial.println(F(" bytes of payload"));
            }
            // Schedule next transmission
            os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            //displayOled();
            readGps();
            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"));
            readGps();
            break;
        case EV_TXCANCELED:
            Serial.println(F("EV_TXCANCELED"));
            break;
        case EV_RXSTART:
            /* do not print anything -- it wrecks timing */
            break;
        case EV_JOIN_TXCOMPLETE:
            Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
            //displayOled();
            readGps();
            break;

        default:
            Serial.print(F("Unknown event: "));
            Serial.println((unsigned) ev);
            break;
    }
}

void readGps() {
  Serial.println("Reading GPS");
  blinka();  //
  displayOled();  //
  Serial.end();
  Serial1.begin(9600);
  while (Serial1.available() > 0) {
    gps.encode(Serial1.read());
  }
  if (gps.location.isUpdated()) {
    fetchGps();
    printAll();
    displayOled();
    blinka();
  }
  Serial.begin(115200);
}

void fetchGps() {
  count++;
  myhr = gps.time.hour();
  mymin = gps.time.minute();
  mysec = gps.time.second();
  mysat = gps.satellites.value();
  mylat = gps.location.lat();
  mylon = gps.location.lng();      
}

void blinka() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(10);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(10);                       // wait for a second
}

void initOled() {
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,30);             
  display.println("LoraWAN");
  display.println("Site Survey");
  display.display();
  delay(5000);
}

void displayOled(void) {

  displayGraphic();  // graphic cutie but the current culprit !!!!!!!!!!
  display.clearDisplay();
  display.setCursor(0,0);
  display.print("Cnt= ");
  display.print(String(count++));
  display.setCursor(60,0);
  display.print("Temp= ");
  display.print(String((1.8 * analogReadTemp()) + 32));

  display.setCursor(0,10);
  display.print("Time= ");
  display.print(myhr);display.print(":");
  display.print(mymin);display.print(":");
  display.print(mysec);

  display.setCursor(0,20);
  display.print("RSSI=");
  display.print(LMIC.rssi);
  display.print(":SNR=");
  display.print(LMIC.snr);

  display.setCursor(0,30);
  display.print("Satellites = ");
  display.print(mysat);

  display.setCursor(0,40);
  display.print("Latitude = ");
  display.println(String(mylat,4));

  display.setCursor(0,50);
  display.print("Longitude = ");
  display.print(String(mylon,4));
  display.display();
  delay(5);  // lets drop from 5000 to 50 or five.
}

void displayGraphic() {
  display.clearDisplay();
  for (int16_t i=0; i<SCREEN_WIDTH; i+=4) {
    display.drawLine(0, 0, i, SCREEN_HEIGHT-1, 1);
    display.display();
    delay(10);
  }
  for (int16_t i=0; i<SCREEN_HEIGHT; i+=4) {
    display.drawLine(0, 0, SCREEN_WIDTH-1, i, 1);
    display.display();
    delay(10);
  }
  printAll();
}

void printAll() {
  Serial.println(count++);
  Serial.print("Temp = ");Serial.println((1.8 * analogReadTemp()) + 32);
  Serial.print("RSSI = ");Serial.println(LMIC.rssi);
  Serial.print("SNR = ");Serial.println(LMIC.snr);
  Serial.print("MOSI = ");Serial.println(MOSI);
  Serial.print("MISO = ");Serial.println(MISO);
  Serial.print("SCK = ");Serial.println(SCK);
  Serial.print("CS = ");Serial.println(SS);
  Serial.print("lmic NSS = "); Serial.println(lmic_pins.nss);
  Serial.print("lmic rst = "); Serial.println(lmic_pins.rst);
  Serial.print("lmic SPI FREQ = "); Serial.println(lmic_pins.spi_freq);
  Serial.print("lmic DIO 0 = "); Serial.println(lmic_pins.dio[0]);
  Serial.print("lmic DIO 1 = "); Serial.println(lmic_pins.dio[1]);
  //Serial.print("lmic pConfig = "); Serial.println(lmic_pins.pConfig);
  Serial.print("lmic rssi cal = "); Serial.println(lmic_pins.rssi_cal);
  Serial.print("lmic rxtx = "); Serial.println(lmic_pins.rxtx);
  Serial.print("lmic rxtx rx active = "); Serial.println(lmic_pins.rxtx_rx_active);
  Serial.print("Satellites = "); Serial.println(mysat);
  Serial.print("Latitude = ");Serial.println(mylat);
  Serial.print("Longitude = "); Serial.println(mylon);
  Serial.println();
  delay(1000);

}

void printHex2(unsigned v) {
    v &= 0xff;
    if (v < 16)
        Serial.print('0');
    Serial.print(v, HEX);
}
terrillmoore commented 1 year ago

Added markdown code fence for readability.

terrillmoore commented 1 year ago

HI @SnkMtn000, sorry you're having problems.

I don't have a pico, and am on the road at the moment, so this is a theoretical response.

Your description sounds like a problem with SPI pins and GPIOs conflicting with the pins used for Serial1. It could be due to the board support package -- there's a lot of "automatic" stuff that can cause confusion.

I would try calling the LMIC initialization code and not transmit data, see if that blocks Serial1 operation.

If it does, I'd go through the LMIC init code and copy pieces to the test sketch, until I find the thing that breaks Serial1.

If it doesn't, I'd document exactly what has to be done to break Serial1 (what LMIC routines need to be called), again using a simplified, small test sketch.

Best regards, --Terry

SnkMtn000 commented 1 year ago

Was able to figure it out. Thanks for your suggestions. Turns out code is working as designed. My GPS battery backup was very discharged causing a very long wait for an initial satellite lock.