jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.46k stars 367 forks source link

E22-900M30S not working, E22-900M22S on same board does #608

Closed code8buster closed 4 months ago

code8buster commented 1 year ago

Sketch that is causing the module fail

#include <RadioLib.h>

// SX1262 has the following connections:
// NSS pin:   33
// DIO1 pin:  27
// NRST pin:  NC
// BUSY pin:  35
SX1262 lora = new Module(33, 27, RADIOLIB_NC, 35);

// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1262 radio = RadioShield.ModuleA;

// or using CubeCell
//SX1262 radio = new Module(RADIOLIB_BUILTIN_MODULE);

void setup() {
  Serial.begin(115200);

  // initialize SX1262 with default settings
  SPI.begin(18, 19, 23, 33);
  pinMode(21, OUTPUT);

  int state = lora.begin(904.0, 125.0, 7, 5, 0x1424, 14, 8);
  lora.setDio2AsRfSwitch(true);
  lora.setRfSwitchPins(21, RADIOLIB_NC);
  lora.setTCXO(1.8);
  Serial.print(F("[SX1262] Initializing ... "));
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);

  // some modules have an external RF switch
  // controlled via two pins (RX enable, TX enable)
  // to enable automatic control of the switch,
  // call the following method
  // RX enable:   4
  // TX enable:   5
  /*
    lora.setRfSwitchPins(4, 5);
  */
  }
}
void loop() {
  Serial.print(F("[SX1262] Transmitting packet ... "));

  // you can transmit C-string or Arduino string up to
  // 256 characters long
  // NOTE: transmit() is a blocking method!
  //       See example SX126x_Transmit_Interrupt for details
  //       on non-blocking transmission method.
  int state = lora.transmit("Hello World!");

  // you can also transmit byte array up to 256 bytes long
  /*
    byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF};
    int state = lora.transmit(byteArr, 8);
  */

  if (state == RADIOLIB_ERR_NONE) {
    // the packet was successfully transmitted
    Serial.println(F("success!"));

    // print measured data rate
    Serial.print(F("[SX1262] Datarate:\t"));
    Serial.print(lora.getDataRate());
    Serial.println(F(" bps"));

  } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
    // the supplied packet was longer than 256 bytes
    Serial.println(F("too long!"));

  } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
    // timeout occured while transmitting packet
    Serial.println(F("timeout!"));

  } else {
    // some other error occurred
    Serial.print(F("failed, code "));
    Serial.println(state);

  }

  // wait for a second before transmitting again
  delay(1000);
}

Hardware setup https://github.com/sudomesh/disaster-radio/tree/master/hardware/board_esp32_v3

Debug mode output https://gist.github.com/code8buster/5eb6c5c973f2a27737e2a6f3cc47cd0e Edit: Things got a little jumbled radiolib900m30s.log shows the -20 wrong modem error only occurs under these conditions:

  1. start with board powered, flashed with sketch configured for 900m22s and working
  2. flash board, sketch configured to use 900m30s
  3. no power cycle between flashes.

the other, radiolib900m30s-powercycle.log occurs after the first power cycle or starting from an erased flash.

note the similarity to #586

Additional info (please complete):

What is odd is that this module works just fine when I compile meshtastic firmware/1.2-legacy branch. I also include a verbose debug log from that in the gists. New versions of meshtastic give the same problem as above since they now track upstream RadioLib (though not when trying to use the 900m22s)

details relating to meshtastic 1.2-legacy:

jgromes commented 1 year ago

I have an E22-900M30S, so I can try to replicate this. However, a few observations about the code first.

  1. You're initializing SPI with SPI.begin(18, 19, 23, 33);, howeer, you are still using default Module constructor. This will cause internal initialization using SPI.begin();. I don't know what happens on ESP32 when you try to initialize SPI twice.

  2. You are setting a TCXO reference level of 1.8V - why this and not the default 1.6V? If the module needs 1.8V to work properly, then it should be passed to the begin() method directly.

EDIT: Also, maybe a more general point - as far as I can tell, the only difference between E22-900M30S and E22-900M22S should be in the PA. However, maybe Ebyte could tell us a bit more about any additional differences?

code8buster commented 1 year ago

I changed the setup() to try to eliminate any issues with point 1, and moved TCXO into the begin method call. I'm doing something wrong here because I now get lora is undeclared in the scope of loop().

TCXO according to their manual is expecting 1.8V https://www.ebyte.com/en/pdf-down.aspx?id=781

void setup() {
  Serial.begin(115200);
SPIClass *vspi = new SPIClass(VSPI);
SPISettings spiSettings (2000000, MSBFIRST, SPI_MODE0);
vspi->begin(18,19,23,33);
SX1262 lora = new Module(33, 27, RADIOLIB_NC, 35, *vspi, spiSettings);

  int state = lora.begin(904.0, 125.0, 7, 5, 0x1424, 14, 8, 1.8);

  pinMode(21, OUTPUT);
  lora.setRfSwitchPins(21, RADIOLIB_NC);
jgromes commented 1 year ago

something wrong here because I now get lora is undeclared in the scope of loop().

Well - yes, because you declared it in the scope of the setup() function. You can declare it in the global scope, that's fine, just provide the new VSPI instance as you did and RadioLib will not attempt to perform initialization on its own - see https://github.com/jgromes/RadioLib/wiki/Basics#non-standard-spi-setup

code8buster commented 1 year ago

My bad, attached the heading of a sketch that will compile and upload. The behavior stays the same in the first case, save for the fact that in the last six commands A2 became C0. Returns the same -2 error + spi log on subsequent reboots. https://gist.github.com/code8buster/5f44062e43711342ea1e731639595ccb

SPIClass *vspi = new SPIClass(VSPI);
SPISettings spiSettings (2000000, MSBFIRST, SPI_MODE0);
SX1262 lora = new Module(33, 27, RADIOLIB_NC, 35, *vspi, spiSettings);

void setup() {
  Serial.begin(115200);
  vspi->begin(18,19,23,33);  
  int state = lora.begin(904.0, 125.0, 7, 5, 0x1424, 14, 8, 1.8);

  pinMode(21, OUTPUT);
  lora.setRfSwitchPins(21, RADIOLIB_NC);
  Serial.print(F("[SX1262] Initializing ... "));
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
jgromes commented 1 year ago

I hooked up an E22-900M30S to an ESP32, and everything seems to be working. What exactly are the difference between configuration of E22-900M22S and 30S?

code8buster commented 1 year ago

Not sure that the modules themselves are functionally different, but if I just switch these pins to the following (which are the pins specific to the 900m22s I/O on that board), the sketch inits the m22s and transmits the packet. LORA_DIO1 = 26 LORA_TXEN still RADIOLIB_NC LORA_RXEN = 17 NSS = 16 BUSY = 22

I'll try to compile a similar sketch with RadioLib 4.5.0, which is the last version I know of that could init the module; that might shed some light on whether or not it is the underlying esp32 framework as the source of the problem.

EDIT: Using the same arduino-esp32 core (1.0.6) w/ Radiolib tag 4.5.0, on initial flash I get the same stream of empty responses to CMD 80, but if I reset the ESP32 either by the on board button or by toggling RTS, I get a successful transmission. Log of post-reset cmd stream attached. empty cmd stream can be induced by further power cycling/resetting. What do you think? Some kind of race condition? radiolib450.log

jgromes commented 1 year ago

Let's slow down a bit. Your report said that the problem appears under the following conditions:

  1. start with board powered, flashed with sketch configured for 900m22s and working
  2. flash board, sketch configured to use 900m30s
  3. no power cycle between flashes.

So, what is the change you do from 900m22s to 900m30s? If it's just the pins, then that would seem to suggest a hardware issue.

code8buster commented 1 year ago

dr-board

This is the device. Its schematic is linked in the original issue. Under those conditions numerically listed, I get an initial -20 wrong modem, followed by -2 chip not found on subsequent resets. That's with RadioLib 5.4.1.

With RadioLib 4.5.0, both the M22S and M30S transmit, the M30S not entirely reliably. Sometimes requires a quick toggling of the esp32 ENable pin to make the m30s begin txing

In either case, all I'm doing is switching pin numbers in the Sketch/ meshtastic configuration file.

jgromes commented 1 year ago

Ah, I see - an interesting design.

I was able to replicate the issue by uploading a known working pin configuration, then changing to a wrong NSS pin. Even after uploading back the original correct configuration, the behavior would remain the same. Only a power cycle would resolve this.

However, this only happened when the NRST pin was not connected. If it is, then everything works as expected, after flashing configuration with corrected NSS pin, the radio starts working again. I think that not resetting the radio is probably the root cause, unfrotunately the only way to that is to toggle the NRST pin. I see that in your design, NRST is not connected to the ESP32. If there are some free pins left, maybe you could conenct the NRST pin and see if the issue persists?

code8buster commented 1 year ago

Interesting, indeed leaving essentially no GPIO free. I jumped the NRST pin on the 900m30s to SD_DAT2 on the back of the board, GPIO12

Unfortunately, that made no difference with either version of RadioLib. Over the weekend, I'll get the oscilloscope set up to verify that gpio12 is toggling.

jgromes commented 1 year ago

I still suspect a fault in the hardware, especially since you reported that in previous versions, the M30S did not transmit reliably. Maybe it would also be worth it to check the power line?

I also have some doubts about the usage of DIO2 - you have it tied directly to TX Enable, as well as to an LED. Are you sure the SX1262 chip can provide sufficient current for both? Table 3-10 in SX1262 datasheet seems to suggest that the maximum source/sink current for digital pins is 2.5 mA, which is not a lot. I tried to breadboard this (including the diode), and it didn't seem to affect the function, but maybe your setup is slightly different.

EDIT: OK I just reviewed one of my own designs and it also uses a direct DIO2-TXEN connection (though without an LED, which is driven separately). So I guess we can scratch that one.

code8buster commented 1 year ago

I have verified the NRST drops to low-voltage, and that there is activity on the vspi bus. According to the manual, this is the valid condition for chip-reset trigger. Vcc stays steady at 3.25v

There is a 10kOhm resistor on the LED, so it's probably sinking less than 0.33mA

In terms of reliably, it either starts or it doesn't. If it does get into the transmission sequence, it's rock steady; I have to reset or pull power to get it into its fault state again. I'm not quite yet ready to concede this to the hardware goblins since you can sort of reproduce it. Maybe I can just send the board to you as some head scratcher material, just like it was sent to me!

jgromes commented 1 year ago

The thing that confuses me the most is the fact that it is working in prior version - since then there were quite a few changes, including at the level of SPI communications, which complicates the comparison.

The main issue (and what drives to the hardware conclusion) is the fact that I can't seem to replicate this with NRST connected. I even tried with older version of ESP32 Arduino core. I'd love to take a look at the hardware (this sort of thing is really bugging me!), but unfortunately the time I get to spend on these projects has been pretty limited.

I will keep this open in case there are any more insights.

jgromes commented 1 year ago

@code8buster FYI there were some changes the the SX126x calibration sequence, maybe it's worth retesting this?

code8buster commented 1 year ago

Yes, I'll give this board another try and report back.

ghost commented 1 year ago

Yes, I'll give this board another try and report back.

Any update?

ghost commented 12 months ago

Why is NRST NC?

S5NC commented 8 months ago

E22-900M30S works for me and many others, it's likely a problem with your specific wiring.

code8buster commented 8 months ago

GPIO pre-transfer timeout, is it connected? GPIO pre-transfer timeout, is it connected? SX126x not found! (5 of 10 tries) RADIOLIB_SX126X_REG_VERSION_STRING: 0000320 20 00 00 00 65 26 0d 80 90 55 fc 3f f4 1b fc 3f | ...e&...U.?...?

This is the output without NRST connected. Using my bodge wire results in the same empty messages as before. At least it's getting something, even if it's garbled. M22S module is very solid, without NRST connection.

I'll attempt to use a significantly shorter bodge when my microsoldering kit comes in.

Here's the example sketch that can cause this behavior with my set up:

#include <RadioLib.h>
SPIClass *vspi = new SPIClass(VSPI);
SPISettings spiSettings (2000000, MSBFIRST, SPI_MODE0);
//900m22s
//SX1262 lora = new Module(16, 26, RADIOLIB_NC, 22, *vspi, spiSettings);
//900m30s
SX1262 lora = new Module(33, 27, 12, 35, *vspi, spiSettings);

void setup() {
  Serial.begin(115200);
  vspi->begin(18,19,23,33);  
  lora.setDio2AsRfSwitch(true);
  int state = lora.begin(904.0, 125.0, 7, 5, 0x1424, 14, 8, 1.8);

  Serial.print(F("[SX1262] Initializing ... "));
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

  // some modules have an external RF switch
  // controlled via two pins (RX enable, TX enable)
  // to enable automatic control of the switch,
  // call the following method
  // RX enable:   4
  // TX enable:   5
  /*
    radio.setRfSwitchPins(4, 5);
  */
}

// counter to keep track of transmitted packets
int count = 0;

void loop() {
  Serial.print(F("[SX1262] Transmitting packet ... "));

  // you can transmit C-string or Arduino string up to
  // 256 characters long
  String str = "Hello World! #" + String(count++);
  int state = lora.transmit(str);

  // you can also transmit byte array up to 256 bytes long
  /*
    byte byteArr[] = {0x01, 0x23, 0x45, 0x56, 0x78, 0xAB, 0xCD, 0xEF};
    int state = radio.transmit(byteArr, 8);
  */

  if (state == RADIOLIB_ERR_NONE) {
    // the packet was successfully transmitted
    Serial.println(F("success!"));

    // print measured data rate
    Serial.print(F("[SX1262] Datarate:\t"));
    Serial.print(lora.getDataRate());
    Serial.println(F(" bps"));

  } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
    // the supplied packet was longer than 256 bytes
    Serial.println(F("too long!"));

  } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
    // timeout occured while transmitting packet
    Serial.println(F("timeout!"));

  } else {
    // some other error occurred
    Serial.print(F("failed, code "));
    Serial.println(state);

  }

  // wait for a second before transmitting again
  delay(1000);
}
jgromes commented 4 months ago

As this issue is quite old at this point without significant updates, I'm going to take the easy way out, blame some weird hardware issue and close this. It's pretty much impossible to trace this bug now after 1+ years of continuous udpates to the library.