Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SX1280 ranging not working #293

Closed
miked531 opened this issue Apr 26, 2021 · 7 comments
Closed

SX1280 ranging not working #293

miked531 opened this issue Apr 26, 2021 · 7 comments
Labels
bug Something isn't working resolved Issue was resolved (e.g. bug fixed, or feature implemented)

Comments

@miked531
Copy link

miked531 commented Apr 26, 2021

I am attempting to use the SX128x_Ranging example and it always reports 0 meters. Transmit/receive examples work successfully.

Comparing the SX1280 DS (section 14.5) to the code and I see the calibration (step 9) missing. There may be a few steps missing with trying to read the result in step 12. I have no idea if any of the steps are important. (I am new to Arduino and SX1280). Using DS_SX1280-1_V3.2 as my reference PDF.

Sketch that is causing the module fail

/*
   RadioLib SX128x Ranging Example

   This example performs ranging exchange between two
   SX1280 LoRa radio modules. Ranging allows to measure
   distance between the modules using time-of-flight
   measurement.

   Only SX1280 and SX1282 support ranging!

   For default module settings, see the wiki page
   https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx128x---lora-modem

   For full API reference, see the GitHub Pages
   https://jgromes.github.io/RadioLib/
*/

// include the library
#include <RadioLib.h>

// SX1280 has the following connections:
// NSS pin:   10
// DIO1 pin:  2
// NRST pin:  3
// BUSY pin:  9
// my wiring matches these pins vvv
SX1280 radio = new Module(10, 7, 9, 8);

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

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

  // initialize SX1280 with default settings
  Serial.print(F("[SX1280] Initializing ... "));
  int state = radio.begin();
  if (state == ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }
}

#define IS_MASTER true
void loop() {
  Serial.print(IS_MASTER ? "[master]" : "[slave]");
  Serial.print(F(" [SX1280] Ranging ... "));

  // start ranging exchange
  // range as master:             true
  // slave address:               0x12345678
  int state = radio.range(IS_MASTER, 0x12345678);

  if (state == ERR_NONE) {
    // ranging finished successfully
    Serial.println(F("success!"));
    Serial.print(F("[SX1280] Distance:\t\t\t"));
    Serial.print(radio.getRangingResult());
    Serial.println(F(" meters"));

  } else if (state == ERR_RANGING_TIMEOUT) {
    // timed out waiting for ranging packet
    Serial.println(F("timed out!"));

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

  }

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

Hardware setup
Two Arduino Nano 33 IOT boards with NiceRF SX1280-TCXO modules.

Debug mode output
this repeats...

23:06:45.948 -> [master] [SX1280] Ranging ... CMD	3	
23:06:45.948 -> DATR	0	47	0	2	
23:06:45.948 -> 
23:06:45.948 -> CMD	8B	
23:06:45.948 -> DATW	90	43	18	43	3	43	
23:06:45.948 -> 
23:06:45.948 -> CMD	8C	
23:06:45.948 -> DATW	16	43	0	43	FF	43	20	43	40	43	0	43	0	43	
23:06:45.948 -> 
23:06:45.948 -> CMD	19	9	31	
23:06:45.948 -> DATR	0	47	0	C0	
23:06:45.948 -> 
23:06:45.948 -> CMD	18	9	31	
23:06:45.948 -> DATW	C0	47	
23:06:45.948 -> 
23:06:45.948 -> CMD	18	9	12	
23:06:45.948 -> DATW	12	47	34	47	56	47	78	47	
23:06:45.948 -> 
23:06:45.948 -> CMD	8D	
23:06:45.948 -> DATW	6	43	0	43	2	43	0	43	0	43	0	43	0	43	0	43	
23:06:45.948 -> 
23:06:45.948 -> CMD	A3	
23:06:45.948 -> DATW	1	43	
23:06:45.948 -> 
23:06:45.948 -> CMD	83	
23:06:45.948 -> DATW	0	43	0	43	0	43	
23:06:45.948 -> 
23:06:46.014 -> CMD	97	
23:06:46.014 -> DATW	FF	43	FF	43	
23:06:46.014 -> 
23:06:46.014 -> CMD	80	
23:06:46.014 -> DATW	0	43	
23:06:46.014 -> 
23:06:46.014 -> success!
23:06:46.014 -> [SX1280] Distance:			CMD	19	9	61	
23:06:46.014 -> DATR	0	47	0	0	0	0	0	0	
23:06:46.014 -> 
23:06:46.014 -> 0.00 meters

Additional info (please complete):

  • MCU: Arduino Nano 33 IOT
  • Wireless module type SX1280-TCXO
  • Arduino IDE version 1.8.13
  • Library version 4.4.0
@jgromes jgromes added the bug Something isn't working label Apr 26, 2021
@jgromes
Copy link
Owner

jgromes commented Apr 26, 2021

I haven't used SX1280 ranging since it was originally implemented, so it's very possible it's been broken at some point, or even that it never worked correctly.

The missing calibration as well as the missing readout steps were added in the last commit, could you check if that fixed the issue?

@miked531
Copy link
Author

miked531 commented Apr 27, 2021 via email

@jgromes
Copy link
Owner

jgromes commented Apr 27, 2021

The values are from SX1280 ranging guide - to get more accurate results you might have to do your own calibration, using the process described in that document.

@miked531
Copy link
Author

miked531 commented May 5, 2021

I tried doing a PR with the changes, but screwed up something on my system so I'm falling back to the rather crude "sending you the diffs" method.

These changes are still returning incorrect ranging, and I need to investigate further but wanted to get this off my mind. I don't think the 3 separate readRegister calls make any difference over a single read of 3 bytes, but that's what I found in Semtech code someplace. The more significant changes are the (1<<1) for enabling the clock and make sure to respect endianness when building the raw value.

diff --git a/src/modules/SX128x/SX1280.cpp b/src/modules/SX128x/SX1280.cpp
index 66b728c..4e6429c 100644
--- a/src/modules/SX128x/SX1280.cpp
+++ b/src/modules/SX128x/SX1280.cpp
@@ -105,7 +105,7 @@ int16_t SX1280::startRanging(bool master, uint32_t addr) {
       return(ERR_INVALID_BANDWIDTH);
   }
   uint8_t calBuff[] = { (uint8_t)((val >> 8) & 0xFF), (uint8_t)(val & 0xFF) };
-  state = writeRegister(SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 4);
+  state = writeRegister(SX128X_REG_RANGING_CALIBRATION_MSB, calBuff, 2);
   RADIOLIB_ASSERT(state);
 
   // set role and start ranging
@@ -138,7 +138,7 @@ float SX1280::getRangingResult() {
   state = readRegister(SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1);
   RADIOLIB_ASSERT(state);
 
-  data[0] |= 1;
+  data[0] |= (1 << 1);
   state = writeRegister(SX128X_REG_RANGING_LORA_CLOCK_ENABLE, data, 1);
   RADIOLIB_ASSERT(state);
 
@@ -147,12 +147,16 @@ float SX1280::getRangingResult() {
   RADIOLIB_ASSERT(state);
 
   data[0] &= 0xCF;
-  data[0] |= 1 << 4;
+  data[0] |= (1 << 4);
   state = writeRegister(SX128X_REG_RANGING_TYPE, data, 1);
   RADIOLIB_ASSERT(state);
 
   // read the register values
-  state = readRegister(SX128X_REG_RANGING_RESULT_MSB, data + 1, 3);
+  state = readRegister(SX128X_REG_RANGING_RESULT_MSB, data + 0, 1);
+  RADIOLIB_ASSERT(state);
+  state = readRegister(SX128X_REG_RANGING_RESULT_MID, data + 1, 1);
+  RADIOLIB_ASSERT(state);
+  state = readRegister(SX128X_REG_RANGING_RESULT_LSB, data + 2, 1);
   RADIOLIB_ASSERT(state);
 
   // set mode to standby RC
@@ -160,9 +164,8 @@ float SX1280::getRangingResult() {
   RADIOLIB_ASSERT(state);
 
   // calculate the real result
-  uint32_t raw = 0;
-  memcpy(&raw, data, sizeof(uint32_t));
-  return((float)raw * (150.0/(4.096 * _bwKhz)));
+  uint32_t raw = ((uint32_t)data[0] << 16) | ((uint32_t)data[1] << 8) | data[2];
+  return((float)raw * 150.0 / (4.096 * _bwKhz));
 }
 
 #endif

@jgromes
Copy link
Owner

jgromes commented May 5, 2021

Thanks, I'll put that into commits and push it. What sort of values do you get out of ranging now?

@miked531
Copy link
Author

miked531 commented May 7, 2021

I have been happy that I can just get the values to change as I move the devices around. I still need to look into the calibration some more. I did find an additional issue: _sf should not be used as an index into calTable (line 96+). Try:

uint16_t sfindex = (_sf >> 4) - 5;
...
val = calTable[0][sfindex]
...

...I really need to get my dev environment sane again so I can just submit the PR...

@jgromes
Copy link
Owner

jgromes commented Jan 1, 2023

@miked531 not sure if this is still relevant, but I went through the documentation available for SX128x ranging (mainly the datasheet, AN1200.29 and https://os.mbed.com/teams/Semtech/code/SX1280Lib/). It seems everything in RadioLib should be correct, the only issue is the calibration.

Since it seems the process is quite involved, I added the option for users to set their own calibration table.

@jgromes jgromes closed this as completed Jan 1, 2023
@jgromes jgromes added the resolved Issue was resolved (e.g. bug fixed, or feature implemented) label Jan 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working resolved Issue was resolved (e.g. bug fixed, or feature implemented)
Projects
None yet
Development

No branches or pull requests

2 participants