RadioLib
RadioLib copied to clipboard
SX1280 ranging not working
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
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?
Thanks for the quick update. The commit is almost working after a few small tweaks. I can see the values in the ranging result register and they change as I move the devices around, but the conversion to meters is not accurate, though the formula appears correct.
My copy of the code is a mess with debug garbage in it now. When I get it more presentable I can submit a PR or just share the changes.
How did you come up with the values for calibration?
Sent from my iPhone
On Apr 26, 2021, at 12:29 PM, Jan Gromeš @.***> wrote:
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?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
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.
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
Thanks, I'll put that into commits and push it. What sort of values do you get out of ranging now?
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...
@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.