Big ESP32 + SX127x topic part 3

There should not be any difference. LMiC uses the same radio functions for both.

What is critical is that the DIO that indicates transmit complete, and especially receive success correctly change and be seen. But that is critical for any downlink in either mode.

If I remember correctly: DIO1 is needed by LMIC for handling of downlink messages. For OTAA, DIO1 is required to be able to join. A succesful join is required to send normal uplink messages.
Using OTAA, when DIO1 is not correctly wired or its LMIC pin-mapping is set incorrectly, the node will be unable to join and will be unable to send uplink messages (other than join requests).
When using ABP and DIO1 is not correctly wired/mapped this will not restrict the node from sending uplink messages (but downlink messages will fail).
So there actually is a practical difference related to DIO1 between OTAA and ABP.

As a result, when DIO1 is incorrectly wired/mapped, when using ABP the node can still successfully send uplink messages, while this is not possible when using OTAA.

I have succeded in flashing my TTGO with micro python firmware for ESP32
Micro Python works but does not include SX127x nor LMIC library.

Does somebody knows a LoRaWAN library for micro python ?

You could check the sources of LoPy. That is a ESP32 based devices supporting LoRaWAN.

At the top of the topic it states:
The LMIC-Arduino library can be found here: This was last updated 2 years ago.
Also on GitHub I find: This has more recent updates.
What is the reason for identifying the matthijskooijman repository; not the mcci-catena?

Good question. The reason is: changes over time while the topic start has not been updated (much) recently. The mcci-catena version was already included in a future ‘part 4’ of this topic (to be released later). Based on your response I have updated the library information in the current topic start.

For information about available LoRaWAN libraries see: Overview of LoRaWAN Libraries [HowTo]

1 Like

At the top of this topic, under LoRa Performance, it is said:

The LoRa performance of the Heltec and TTGO boards has shown to be sub-optimal. Important factors are the quality of the RF circuitry (design) and the antennas.

There is a things network gateway some 300m distant from my node. It reliably receives uplink data. But about half of downlink data packets were lost. My node was often not hearing the gatweay.

For my TTN node I have a TTGO LoRa32 V1 with the small helical antenna pictured here.

To optimize performance I have found:

  • the antenna is best laid horizontal rather than
    stood upright
  • a virtical quarter wave stub should be attached at the antenna mount.

This picture shows the arrangement

With these optimizations, the uplink SNR values are improved on average by about 10dB, and the downlink SNR is improved by about 11dB (LMIC values divided by 4). Both uplink and downlink are now adequately reliable. Typically uplink SNR is about +6dB and downlink SNR is about +3dB (LMIC values divided by 4)


You can try .
Only ABP is supported.

Heltec Wifi LoRa 32 V2 - I2C issues

While checking the board’s pinout diagram and its pin definitions (defined in the ESP32 Arduino Core) I noticed that the default SDA and SCL (I2C) pins are defined incorrectly which can cause problems.
This is explained below.

ESP32 by default uses GPIO21 and GPIO22 pins for I2C but also has the possibility to remap the I2C interface to different pins. Heltec Wifi Lora 32 V2 does not use the standard I2C pins for its OLED display and uses GPIO4 and GPIO15 instead. The values of SDA and SCL should be defined correspondingly but they are not. The values of SDA and SCL are incorrect.

SDA and SCL are defined as pin 21 (GPIO21) and pin 22 (GPIO22), which is common for ESP32.
But for connecting the display they used pins GPIO4 and GPIO15 instead.
Vext (which is actually ‘Vext control’) controls (enables/disables) Vext external power.
Like SDA, Vext is defined as GPIO21 which is weird because it conflicts with SDA.

The following is defined in the board’s pins_arduino.h file (part of ESP32 Arduino Core):

static const uint8_t SDA = 21;          /* CONFLICT! */
static const uint8_t SCL = 22;
static const uint8_t SDA_OLED = 4;
static const uint8_t SCL_OLED = 15;
static const uint8_t Vext = 21;         /* CONFLICT! */

When using the Arduino Wire (I2C) library, the ‘Wire’ object (which controls the I2C hardware interface) is initialized with Wire.begin(). Without parameters, this will initialize the I2C interface using the pins defined by SDA and SCL. To use different pins for I2C, the pins have to be explicitly specified: Wire.begin(sda_pin, scl_pin).

Vext and SDA are mutually exclusive. One GPIO cannot be used to control both Vext external power and SDA at the same time, but unfortunately that is how the pins are defined! The values of SDA and SCL cannot be changed in application code because they are defined in the ESP32 Arduino Core as const int.

During I2C communication the SDA and SCL interface pins will switch between HIGH/LOW with a frequency of 100+ kHz. If GPIO21 is used for SDA then Vext power will also switch with 100+ kHz accordingly. This is not good and the Vext voltage regulator is not designed for that.
Therefore GPIO21 must not be used for SDA but unfortunately that is exactly what happens if Wire.begin() is called without parameters.

To use pins GPIO4 and GPIO15 for I2C instead (which is how the on-board display is wired) use:

Wire.begin(/*sda*/ 4, /*scl*/ 15);


The ESP32 Wire library will remember the sda_pin and scl_pin parameters that were specified in the first Wire.begin(…) call. If any 3rd-party library later calls Wire.begin() (without parameters) that luckily does not cause the pins used for I2C to be reset to the default SDA and SCL pins.
Wire.begin(sda_pin, scl_pin) must be called before calling any third-party library initialization code (e.g. bme280.begin()).

The ESP32 supports two separate I2C hardware interfaces. The second interface is accessible via the Wire1 object which can be initialized as follows:

Wire1.begin(alternate_sda_pin, alternate_scl_pin)

I2C is a shared bus that can be shared by many peripherals/sensors. In most cases a single I2C interface will be sufficient and the second I2C bus will not be needed.

About calling Wire.begin() from within third party library code

The I2C interface is a shared bus that can be used by many peripherals. Different types of peripherals will require different (third party) libraries. Initializing a shared bus is therefore the responsibility of the application and not the responsibility of third party libraries, which should therefore not try to initialize it (i.e. should not call Wire.begin()).

In the early Arduino days only Atmel 8-bit MCU’s were supported. These only had a single I2C interface on fixed pins. But when Arduino matured, the framework was ported to other MCU architectures like ESP32 which supports 2 hardware I2C interfaces that can be mapped to different pins. If third party libraries then call Wire.begin() without parameters this can introduce problems.

Unfortunately, many libraries (including from Adafruit) call Wire.begin() (without parameters) from library code and do not provide a mechanism for specifying which pins to use for I2C so they will always use the pins defined by SDA and SCL - unless the application initializes the Wire object (I2C interface) first. If the real (mapped) I2C pins are different from what is defined by SDA and SCL the application has to call Wire.begin(sda_pin, scl_pin) before any third party library initialization code is called.


@chote yeah know you have an good ground to this antenna.
The most important thing is a ground plane to the antenna and only the SMA connector makes this not.

A node’s antenna performance is determined by several factors:

  • The RF circuitry and impedance matching on the board.
  • The type, RF characteristics, quality and position of the antenna.
  • If monopole antenna the inclusion of a good ground plane in the design is essential.
  • The quality and characteristics of the antenna cabling and connectors.

A monopole antenna is actually the half of a dipole antenna. The other half is formed by the ground plane. Without a good ground plane a monopole antenna will have suboptimal to bad performance.
A good ground plane is determined by several factors and designing good antennas is not simple.

Often the quality of these (Chinese) quarter-wave-length monopole antennas is not very high and not optimal for the frequency used. Together with the ground plane this has significant impact on the antenna’s performance. Another aspect is that the IPEX/U.FL antenna connectors have a specified lifetime of rather limited number of insertions and removals. These connectors must be inserted and removed with care, but in practice are often handled worse which lowers their quality and lifetime.

Your setup initially lacked a (good) ground plane and you have now added some ground plane, which makes your antenna more like a real dipole. The two halves of true dipoles are normally positioned in the same axis opposite of each other (not in 90 degree angle). For best results a node’s antenna should be positioned upright (which is related to its radiation pattern).

1 Like

Let’s start with a huge thank you for this thread. I have been at it for a few days and need some help. My TTGO LoRa 32 v2 won’t properly join TTN in OTAA. My D1 is jumpered over to pin 33. I was getting the unknown response error so I mapped 20 - EV_JOIN_TXCOMPLETE.

My DeviceEUI and AppEUI were taken from TTN with the ‘lsb’ string showing.

My App Key was entered as is.

My serial monitor shows:
21978561: EV_TXSTART
22862112: EV_TXSTART
23300886: EV_TXSTART

The gateway traffic shows Join Request and Join Accept messages.

Device Data - Application
“time”: “2020-03-03T01:22:36.97466618Z”,
“frequency”: 904.6,
“modulation”: “LORA”,
“data_rate”: “SF8BW500”,
“coding_rate”: “4/5”,
“gateways”: [
“gtw_id”: “eui-b827ebfffe8486bd”,
“timestamp”: 3731584794,
“time”: “”,
“channel”: 8,
“rssi”: -58,
“snr”: 10

Gateway Data - Join Request
“gw_id”: “eui-b827ebfffe8486bd”,
“payload”: “ALSdAtB+1bNwOT14/v+oxWA+GpBa4Cw=”,
“dev_eui”: “60C5A8FFFE783D39”,
“lora”: {
“spreading_factor”: 10,
“bandwidth”: 125,
“air_time”: 370688000
“coding_rate”: “4/5”,
“timestamp”: “2020-03-03T00:17:24.979Z”,
“rssi”: -38,
“snr”: 12.5,
“app_eui”: “70B3D57ED0029DB4”,
“frequency”: 905300000

Gateway Data - Join Accept
“gw_id”: “eui-b827ebfffe8486bd”,
“payload”: “IDkOaXuYgIFoMBlZJAjJNdw=”,
“lora”: {
“spreading_factor”: 10,
“bandwidth”: 500,
“air_time”: 82432000
“coding_rate”: “4/5”,
“timestamp”: “2020-03-03T00:17:28.980Z”,
“frequency”: 927500000

Do I need to configure the Device Downlink information? Any help establishing a connection would be much appreciated.

It may be useful to provide some additional information like:

  • What LoRaWAN library are you using and which version?
    (Based on EV_JOIN_TXCOMPLETE apparently you are using some version of MCCI LoRaWAN LMIC library).

  • Which sketch are you using? Is it one of the standard examples or a custom sketch?

  • Have the pin mappings been set correctly in the sketch? And has this been double checked?
    Also verify that DIO1 is truly wired to GPIO33.
    If pin mapping for DIO1 is set incorrectly, downlink messages will not be received (successfully). When downlink messages cannot be received the node will fail to receive/handle the join accept.

  • Have you double checked the correct format of the keys and ID’s required for OTAA, in the sketch? See: Format of Keys and ID's for Arduino LMIC library [HowTo]

  • What is your region and have you correctly configured the LoRaWAN library for your region?
    (Based on the logs this should be one of the 915MHz regions).

  • Did you follow ‘get the basics working first’ in the topic start? If so did you get uplink message to work correctly when using ABP?

Using OTAA you may try to power up the node and leave it trying to join for 20 minutes or so and at the same time watch the Gateway Traffic on the TTN Console and observe when join requests and join accepts are transmitted, what SF/BW they are using and if it will finally join after multiple join attempts.

@bluejedi Thanks for the quick reply! I have to be super close, just missing a pin number or a check mark somewhere in the gateway or ttn config.

Using the MCCI LoRaWAN LMIC library version 3.1.0.

Using the ttn-otaa.ino sketch from the library examples.

I added a case to the event handler switch to catch the EV_JOIN_TXCOMPLETE
Previously that was giving an unknown event error : 20

DIO1 is indeed wired to GPIO33

My pin mapping is:
const lmic_pinmap lmic_pins = {
.nss = 18,
.rst = 14,
.dio = {26, 33, LMIC_UNUSED_PIN},

My keys are entered as (not sure if they are secret):
DEVEUI = { 0xF7, 0x61, 0xXX, 0xXX, 0xXX, 0xXX, 0xED, 0x00 };
APPEUI = { 0x8B, 0xB9, 0xXX, 0xXX, 0xXX, 0xXX, 0xB3, 0x70 };
APPKEY = { 0xDB, 0xFB, 0x38, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0x23, 0xA0, 0x19, 0xDE };

My lmic_project_config:
// project-specific definitions
#define CFG_us915 1
#define CFG_sx1276_radio 1

With a long soak doing OTAA the device still doesn’t connect.

When using ABP I get see the following in the serial monitor:
Packet queued
140332: EV_TXCOMPLETE (includes waiting for RX windows)
3890356: EV_TXSTART

I’m interested in what the gateway traffic log looks like the first 15 to 20 minutes from the moment just before the node is powered on.

I would expect to see multiple join requests (‘retries’) with longer pauses in between.

I’m only familiar with eu868 so I’m not sure how these retries will occur on 915MHz and on what SF (sequence).

(The keys/IDs should be treated as secrets, not as public.)

Prior to powering up my node, there is no gateway traffic. I would hope all the data is the same regardless of frequency.

Are there settings I should be making in my gateway to play nice with TTN or do you think this is a Node problem? I am using the rak7246 and have followed the Setup Guide

Should I make edits to the Edit packet-forwarder config?

This is related to the join process only. If the node is unable to join at a lower spreading factor/higher data rate, then it normally will try at a higher spreading factor with lower data rate which can reach more far. That is at least LMIC’s behavior for eu868.
In your case the gateway is near but it is still interesting to see what exactly happens in the first 15 to 0 minutes after powering on the node.

The minimal distance between node and gateway should be 3m at minimum. If not this can have impact on proper operation. So if the distance between your node and gateways is less than 3m, you could try to increase the distance.

As said, I’m not sure how the join retry sequence for us915 should exactly behave when the first join attempt(s) fail.

“OTAA doesn’t work” won’t give any hints of what could possibly go wrong. Some possible causes are mentioned above already. For further analysis additional information is preferred, like the traffic log of those first 15 to 20 minutes.

That depends on the steps in the setup guide and RAK’s installer software.
For proper configuration of your gateway I suggest to search the forum for relevant topics/threads for the RAK7246 (not this thread).

It will be useful to test if the gateway is working correctly. Maybe you can check it with a different node which is known to be working correctly and/or try your node with a gateway that is known to be working correctly.

Yes, that bug in ttn-otaa.ino has not yet been fixed unfortunately.

According to issue 487 this should have been fixed in v3.1.0 already but it appears that ttn-otaa.ino was forgotten in the fix.

Turns out my issues were in the gateway configuration. I am able to join with my RAK811s and my ESP32s. Now it is time to write some apps.

More info here:

TTGO LoRa V1.3 (is actually TTGO LoRa32 V1.3?)

I noticed a (relatively) new board: TTGO LoRa V1.3
It appears to be an upgraded version of TTGO LoRa32 V1 but the ‘32’ has been removed from its name. I’m not aware if there have been any changes in pin layout.

Comparison between Lora V1.3 and Lora V1.0 (source: LilyGO):

  1. Product low power design
  2. Optimize LORA RF circuit
  3. Add battery voltage detection Pin IO35

The board is labeled LORA_V1.3, 20190614.
Dated June 2019 so V1.x boards apparently are still manufactured.
I wonder why they are still producing the V1.x series boards because its WiFi antenna is located inefficiently and the board was already superseded by the V2.x series.
Why an improved V1.0 and not an improved V2.0 instead? Because V1.x has more available GPIOs and almost nobody is using the compact flash slot of the V2.0?

TTGO LoRa V1.3

Unfortunately LilyGO again adds confusion with the name of this new board:
The original TTGO LoRa is SX1278 based and not available for 868/915MHz. The TTGO LoRa32 V1 and V2.x models are SX1276 based and are available in models for 433MHz and 868/915MHz.
LilyGO has recently introduced the TTGO LoRa V1.3 which is SX1276 based. This appears to be an upgraded TTGO LoRa32 V1 so it actually is ‘TTGO LoRa32 V1.3’ (with ‘32’ in the name). Why this naming inconsistency and confusion?

TTGO LoRaxx models currently available in LilyGO’s shop on AliExpress:

  • TTGO LoRa V1 (SX1278 based)
  • TTGO LoRa32 V1 - they don’t show ‘V1’ in the descriptions
  • TTGO LoRa V1.3 - be aware that this is actually a TTGO LoRa32 V1.3 (SX1276 based)
  • TTGO LoRa32 V2.0 with Compact Flash slot (CF)
  • TTGO LoRa32 V2.1 release 1.6 (aka V2.1.6) with CF and SMA connector for the LoRa antenna

If you are interested in one of these boards, take care that you order the correct model and version and for the correct frequency band (LilyGO has not made it easy with their naming).

1 Like