Big ESP32 + SX127x topic part 3

The topic-start has been updated with the LMIC-node example and a link to the pinout-diagrams repository which contains pinout diagrams for most of the boards described in this topic. In addition some notes were added for The Things Stack V3.

2 Likes

Hey guys, great thread here!

sadly im trying to connect my TTGO Lora32 v1.0 to TTN, without success so far. I hoped i would get the new example from the LMIC-node to work but this is without success so far. A single channel gateway i am running here is receiving something that doesnt look completely wrong. I know the TTGO Lora32 isnt listed in the supported devices. Since the lmic pins are the same as on the Heltec Lora32 V1 i gave it a try. I suppose some configuration is still wrong since packets are received by the gateway but not correctly forwarded to the network?!

I use ABP from LMIC-node example since i am using a single channel gateway in my flat. With OTAA i got no succcess either. There should be some Gateways not too far away, but for testing purposes i decided to go with ABP and an own 1-Ch-Gateway.

This is the received packet as shown in the gateway console:

Maybe someone of you can see waht im doing wrong. thanks a lot in advance

{
  "name": "gs.up.receive",
  "time": "2021-10-16T09:34:08.455140041Z",
  "identifiers": [
    {
      "gateway_ids": {
        "gateway_id": "b8f009ffffcca210"
      }
    },
    {
      "gateway_ids": {
        "gateway_id": "b8f009ffffcca210",
        "eui": "B8F009FFFFCCA210"
      }
    }
  ],
  "data": {
    "@type": "type.googleapis.com/ttn.lorawan.v3.UplinkMessage",
    "raw_payload": "QOFECyaAAwAKVIab8UMu",
    "payload": {
      "m_hdr": {
        "m_type": "UNCONFIRMED_UP"
      },
      "mic": "m/FDLg==",
      "mac_payload": {
        "f_hdr": {
          "dev_addr": "260B44E1",
          "f_ctrl": {
            "adr": true
          },
          "f_cnt": 3
        },
        "f_port": 10,
        "frm_payload": "VIY="
      }
    },
    "settings": {
      "data_rate": {
        "lora": {
          "bandwidth": 125000,
          "spreading_factor": 7
        }
      },
      "coding_rate": "4/5",
      "frequency": "868099975",
      "timestamp": 161729712
    },
    "rx_metadata": [
      {
        "gateway_ids": {
          "gateway_id": "b8f009ffffcca210",
          "eui": "B8F009FFFFCCA210"
        },
        "timestamp": 161729712,
        "rssi": -113,
        "channel_rssi": -113,
        "snr": 2,
        "uplink_token": "Ch4KHAoQYjhmMDA5ZmZmZmNjYTIxMBIIuPAJ///MohAQsJmPTRoMCJC5qosGEMKK/dgBIICf3r7aBA=="
      }
    ],
    "received_at": "2021-10-16T09:34:08.455034178Z",
    "correlation_ids": [
      "gs:conn:01FJ472WX5SW5A0DHHMFAXWKYC",
      "gs:uplink:01FJ477527VN20ZQ7PJ0C9AWQC"
    ]
  },
  "correlation_ids": [
    "gs:conn:01FJ472WX5SW5A0DHHMFAXWKYC",
    "gs:uplink:01FJ477527VN20ZQ7PJ0C9AWQC"
  ],
  "origin": "ip-10-100-12-248.eu-west-1.compute.internal",
  "context": {
    "tenant-id": "CgN0dG4="
  },
  "visibility": {
    "rights": [
      "RIGHT_GATEWAY_TRAFFIC_READ",
      "RIGHT_GATEWAY_TRAFFIC_READ"
    ]
  },
  "unique_id": "01FJ4775275M22MKG96D7MXAYY"
}

We do not support Single or Dual Packet Forwarders. Please disconnect it from TTN and get a LoRaWAN gateway NOT a LoRa ‘Gateway’ - one that fully supports 8 channels, across the full spread of SF’s or more. These are disruptive to other users on the network (use Forum search) and cause issues of the type you may be experiencing yourself. Come back when in range of a LoRaWAN gateway or get one for your own use and add to the communities coverage then many here will be able to assist you.

It may be that if the other gateways are really in coverage range then simply scrapping your SCPF will allow them to correctly start servicing your node…

Thanks a lot for the fast reply. SCPF is shut off now.

There should be a few gateways not too far away, but im not sure if the TTGO Lora32 V1.0 has enough range. Ill try to let it run for a while. Should i then try to go with OTAA since this is the preferred way then? Just went with ABP since i’ve read OTAA isnt possible with the SCPF i was using

Thank for this very useful comparison.
Has anybody worked out which peripheral is connected to which bus for the TTGO LoRa V2.1.6? In these pin-out diagrams it would appear that the SD card is connected using its native iterface (CMD, SD0, etc.) but in another pinout for the same board, pinout-diagrams/TTGO LoRa32 V2.1.6 Pinout.pdf at main · lnlp/pinout-diagrams · GitHub, the SD card appears to be connected to a SPI bus. From the choice of pins, it looks like it maybe H-SPI. Which is the definitive diagram?
The SX12xx appears to be connected to V-SPI. Is this the case does anybody know?
I am working on a project that will connect to the board via SPI with fairly tight latency requirements; so I do not want to share the SPI bus with the LoRa activity. Sharing the bus with the SD card (if it actually uses a SPI would be OK as I have control when this would be active.
Any advice would be greatly appreciated.

It looks like the SD card may be wired so that it can be used in 1 bit MMC mode or SPI mode, in my experience, MMC mode is more reliable.

With TTN use, there will not be a great deal of LoRa based SPI activity, so there may not be an issue. However nodes that have ‘tight’ connection latencies might not be a good fit for TTN.

Where is the first pinout diagram?

Which one of both diagrams is correct?
Try to find a corresponding schematic diagram of the board to verify it.
The problem with TTGO boards documentation is that it is often not (fully) reliable, can contain errors and omissions, different versions may exist and not clear which one is (more) correct because document versioning is lacking.

That can be checked by looking up the GPIO numbers for V-SPI in the ESP32 datasheet.

Thank you LoRa Tracker for your prompt and astute reply. I am sure you are correct; the SD card slot is wired for both approaches. This belief is reinforced by the fact that the GPIO pins used are the default used by Espressif’s SD Card driver (SDMMC Host Driver - ESP32 - — ESP-IDF Programming Guide v4.4 documentation). However, I suspect that some other examples for the Arduino IDF use one of the SPI drivers. These are all brought out on the pins of the TTGO LoRa board. A warning to anyone trying to run more than one device off the same bus. If the devices are controlled from difference tasks, you have to be very sure they will not clash. The Espressif SPI driver is not thread safe and I would be surprised if the Arduino driver was.

The GPIO pin numbers connected to the SX12xx hint at the VSPI (aka SPI3) but this example (esp-idf-sx127x/lora.c at main · nopnop2002/esp-idf-sx127x · GitHub) actually maps these to HSPI (aka SPI2). Which goes to show that pin numbers are only a hint at best!

I plan to identify 4 GPIO pins that are not being used for anything else and map these to which ever SPI interface not being used by the LoRa driver.

Many thanks again.

Well you can re-map the pins and it does work.

However, which LoRa driver are you using ?

The first diagram with the SD card mapped to its native interface was posted by yourself, bluejedi, “TTGO LoRa32 V2.1 rev1.6 versus TTGO LoRa32 V2.0 pin layouts”, back in October 2019. And very useful it is too. It corrects TTGO’s mistake in mapping IO0 and IO4 to power and ground for starters! Thanks.

Good catch.

The TTGO LoRa32 V2.1.6 pinout has now been corrected, enhanced and the file has been renamed.

Maybe this helps:

Below microSD connection details come from the TTGO LoRa32 V2.1.6 schematic diagram:

TTGO V2.1.6 microSD schematic diagram

A post was split to a new topic: Programming ESP32 + SX1276 in Rust

Hello,

I have an issue with my TTGO SD LoRa 32 V2.0
I would like to use SD card and LMIC in the same sketch, but theese 2 libraries do not work together in my sketch.
Are there some samples using SD card and LoRaWAN together ?

NB :

  • Sketch using SD card alone works
  • Shetch using LMIC alone works well with TTN

I have not used LMIC on the ESP32, but in what way does the SD card and LoRa device ‘not work together’ ?

IIRC some modules in the market can ‘share’ pinouts & functions e.g. GPIO, SPI bus(es) etc. Is this one where say a SD Card connection conflicts with the LoRa radio function? :thinking: perhaps SPI i/f?

Update, just scrolled up and saw discussion earlier this year on just such connections - perhaps @bluejedi can advise…

Step away from the soldering iron …

SPI can share the In, Out & Clock but each item connected needs it’s own Select. Arduino broke it all by assuming only one SPI device when they made pin 10 as Select. So almost all libraries use that assumption. Sometimes you can override the SS / NSS / CS pin in the library - you can in LMIC but the Select will be hardwired on the PCB. Whereas the Select for the SD Card can be moved to a different pin which would then need specifying in the code - either when initialised or by hacking the library, depending on what library you are using.

The general advice (I don’t have a source) is to not share the SPI bus where the LoRa radio is connected to with other peripherals, when using (Arduino) LMIC. This is because LMIC uses its own proprietary scheduler and timing and was not designed with sharing the SPI bus in mind.

Fortunately the ESP32 supports two different SPI busses. To use the second SPI bus you will have to create a second SPI object instance and map specific ESP32 pins for the second SPI.
In addition you will need to use libraries that can handle more than only the standard default SPI instance (allow you to specify a specific SPI object instance for your SDCard).

Above is a description for the approach, but you will have to search for the nitty gritty details for how to exactly do this in code yourself (I don’t have examples at hand).

For SD cards there afe different interfaces / modes you can use: One-bit SD mode, four-bit SD mode or SPI. Check the ESP32 documentation/datasheet for which interface requires/allows which IO ports.

Be aware that it depends on the type of ESP32 board which GPIO ports are (not) available as physical pins on the board. It is also possible that some board type already uses some of the required GPIO’s for other purposes.
Some boards are better (or worse) designed in this aspect than others so your mileage may vary.

I found when doing the file\image transfer stuff for point to point LoRa that you could share an SPI bus with LoRa and SDs on say an ATmega328P, ATmega1284P or an Arduino DUE, that was OK.

However, I would certainly concur that its not a good idea to have the SD card and LoRa device sharing the same SPI bus on an ESP32, its just not reliable, the SD card just fails to respond after a while. And for some reason an SX128X LoRa device was worse in this respect compared to an SX127X.

So for an ESP32 keep the SD card on a seperate SPI bus or use it in 1 bit MMC mode, which has the advantge of using one less IO pin than an SPI setup.

I have modified my sketch, and created another instance of SPIClass with SPI pins that are connected to SD reader.

I works well !

Thank you very much ! :slight_smile:

/*******************************************************************************
 * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman
 *
 * Permission is hereby granted, free of charge, to anyone
 * obtaining a copy of this document and accompanying files,
 * to do whatever they want with them without any restriction,
 * including, but not limited to, copying, modification and redistribution.
 * NO WARRANTY OF ANY KIND IS PROVIDED.
 *
 * This example sends a valid LoRaWAN packet with payload "Hello,
 * world!", using frequency and encryption settings matching those of
 * the The Things Network.
 *
 * This uses OTAA (Over-the-air activation), where where a DevEUI and
 * application key is configured, which are used in an over-the-air
 * activation procedure where a DevAddr and session keys are
 * assigned/generated for use with all further communication.
 *
 * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in
 * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably
 * violated by this sketch when left running for longer)!

 * To use this sketch, first register your application and device with
 * the things network, to set or generate an AppEUI, DevEUI and AppKey.
 * Multiple devices can use the same AppEUI, but each device has its own
 * DevEUI and AppKey.
 *
 * Do not forget to define the radio type correctly in config.h.
 *
 *******************************************************************************/
//bq
#include "SPI.h"
#include "SD.h"
//qb
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>

// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

void os_getArtEui(u1_t* buf) {
  memcpy_P(buf, APPEUI, 8);
}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8]={ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

void os_getDevEui(u1_t* buf) {
  memcpy_P(buf, DEVEUI, 8);
}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
// The key shown here is the semtech default key.
static const u1_t PROGMEM APPKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C };

void os_getDevKey(u1_t* buf) {
  memcpy_P(buf, APPKEY, 16);
}

static uint8_t mydata[] = "Hello, world!";

static osjob_t sendjob;

// Schedule TX every this many seconds (might become longer due to duty
// cycle limitations).
const unsigned TX_INTERVAL = 60;

/*bq
// Pin mapping
const lmic_pinmap lmic_pins = {
    .nss = 6,
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 5,
    .dio = {2, 3, 4},
};
*/
// constantes definies dans C:\Users\adm\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.4\variants\ttgo-lora32-v1\pins_arduino.h
// si pas bonne valeur => 1 seul envoi
const lmic_pinmap lmic_pins = {
  .nss = LORA_CS,
  .rxtx = LMIC_UNUSED_PIN,
  .rst = LORA_RST,
  //    .dio = {26, 26, LMIC_UNUSED_PIN}, // 1 seul envoi
  .dio = { /*dio0*/ 26, /*dio1*/ 33, /*dio2*/ 32 }
};

SPIClass spiSD(HSPI);  // à faire en global pour que ce ne soit pas détruit en sortant du setuo

//qb
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"));
      LMIC_setLinkCheckMode(0);
      break;
    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;
      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"));
        //bq
        File file = SD.open("/fic.txt", FILE_APPEND);
        if (!file)
          Serial.println("Failed to open file for appending");  // failed systématique
        else {
          for (int i = 0; i < LMIC.dataLen; i++) {
            file.print(LMIC.frame[LMIC.dataBeg + i], HEX);
          }
          file.println();
          file.close();
        }
        //qb
      }
      // Schedule next transmission
      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;
    default:
      Serial.println(F("Unknown event"));
      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 {
    // Prepare upstream data transmission at the next possible time.
    LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
    Serial.println(F("Packet queued"));
  }
  // Next TX is scheduled after TX_COMPLETE event.
}

void setup() {
  Serial.begin(115200);
  Serial.println(F("Starting"));
  //bq
  spiSD.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
  if (!SD.begin(SD_CS, spiSD)) {
    Serial.println("Card Mount Failed");
    return;
  }
  //qb

#ifdef VCC_ENABLE
  // For Pinoccio Scout boards
  pinMode(VCC_ENABLE, OUTPUT);
  digitalWrite(VCC_ENABLE, HIGH);
  delay(1000);
#endif

  // LMIC init
  os_init();
  // Reset the MAC state. Session and pending data transfers will be discarded.
  LMIC_reset();

  // Start job (sending automatically starts OTAA too)
  do_send(&sendjob);
}

void loop() {
  os_runloop_once();
}
2 Likes