XBee Pro 900HP Using SPI in Gen3 Devices

I’m feeling pretty frustrated about now and could use some help. I’m trying to send and receive frame data between an XBee Pro 900HP and an Argon using SPI, and I’m missing something.

I’ve connected the Argon’s pins to the the pins of a Sparkfun XBee Explorer - Regulated as mapped for SPI in this doc from Digi (page 41). To do this, I soldered two 11-pin headers to the Sparkfun board and plugged it into 2 breadboards (it’s too wide for 1). This worked when testing a serial connection between the Argon, the XBee, and other XBees on the same mesh.

The test setup includes 3 XBee 900HPs. One is in the Sparkfun board connected to an Argon, the other 2 are in WaveShare XBee USB carriers connected to my windows dev machine. Using XCTU, the boards communicate as expected. In other words, I created a type 0x10 frame in XCTU and broadcast it across the mesh network. I know the XBee connected to the Argon receives the frame packet because the RSSI and DIN LEDs light on the Sparkfun board when I click “Send Selected Frame” in XCTU, and the data shows up in the XCTU Frames Log for the sending node and the node in the other USB carrier.

All 3 XBees are configured for API Mode 1. Encryption is off. The DL for all 3 XBees is FFFF, which broadcasts to all nodes on the mesh.

However, I can’t receive the data using the code I have written for the Argon. I’ve tried several variations, but this is the most recent…

SYSTEM_THREAD(ENABLED);

static uint8_t rx_buffer[64];
static uint8_t tx_buffer[64];
static uint32_t transfer_state = 0;

void setup() {
    Serial.begin();

    for (uint16_t i = 0; i < sizeof(tx_buffer); i++){
        tx_buffer[i] = (uint8_t)i;
    }

    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    SPI.setClockSpeed(1, MHZ);    
    SPI.begin(SPI_MODE_MASTER, A5);
}

void loop() {
    uint16_t availableBytes = SPI.available();
    
    if (availableBytes>0){
        Serial.println("Data available...");
        SPI.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), onTransferFinished);

        while(transfer_state==0);

        for(uint16_t i=0; i<sizeof rx_buffer; i++){
            Serial.print(rx_buffer[i], HEX);
        }
        transfer_state=0;
    }
}

void onTransferFinished() {
    Serial.println("In onTransferFinished");
    transfer_state = 1;
}

I feel like I’ve overlooked something really dumb. I would suspect the Argon signals are being level-shifted by the Sparkfun “regulated” board if the Serial testing using the same board and headers hadn’t worked.

Any help much appreciated!! Meanwhile, I think I’ll enjoy a little primal scream therapy. And some Scotch. Maybe just Scotch.

Steve

You cannot have A5 as the SS pin. A5 is already the MOSI pin.
The default SS pin for SPI is A2 but you can use any but A3, A4 & A5.

(only true for Gen1 & 2 - Gen3 A5 is fine :blush:)

And a rule of thumb: When you have issues with external components it’s always best to also explicitly communicate how you actually wired your devices.

If you don’t want that call to run asynchronous you can just pass NULL in place of the callback. This way you won’t need onTransferFinished() nor your while() loop.

See here

BTW, the default mode is MASTER so you don’t need to specify that.

1 Like

Hi, @ScruffR, thanks for the feedback. I think I’m missing something here. According to the Particle docs for the SPI.begin() function, A5 is the default pin…

Where, the parameter ss is the SPI device slave-select pin to initialize. If no pin is specified, the default pin is:

  • Argon, Boron, Xenon: A5 (D14)

Same in the pinout diagram here.

Maybe you’re thinking Photon?

Steve

Yup, I was :blush:

BTW, I just stumbled over this

Is this a typo that there are no parentheses around rx_buffer?
Should this not be sizeof(rx_buffer)?

I believe the reason sizeof works either way is because it’s a C operator.

Steve

1 Like

One never stops learning :blush:

SYSTEM_THREAD(ENABLED);

static uint8_t rx_buffer[64];
static uint8_t tx_buffer[64];

void setup() {
  Serial.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);
  SPI.setClockSpeed(1, MHZ);    
  SPI.begin(A5);
}

void loop() {
  static uint32_t ms = 0;
  if (millis() - ms < 1000) return;  // trasfer only once per second
  ms = millis();

  SPI.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), NULL);
  for(uint16_t i=0; SPI.available(); i++)
    Serial.printf("%02x ", rx_buffer[i]);
}

Just for lack of a better suggestion, can you try this?
Also, do you ever get your “Data available…” message at all?
I guess SPI.available() is never actually populated as it would only be during or after an SPI.transfer() call.
https://docs.particle.io/reference/device-os/firmware/argon/#available--1

Yes, I will definitely try that in the next few minutes.

No, I never got the “Data available…” message, but I missed the fact that SPI.available() is only populated after a call to SPI.transfer(). I hate when I miss something like that :slightly_frowning_face:

Steve

1 Like

As I close in on a nervous breakdown, I thought I’d add more detail. @ScruffR helped by pointing out my logic was faulty in the relationship between SPI.transfer() and SPI.available(). However, I still can’t get the Argon to send or receive an XBee API 1 type 0x10 message via SPI.

Here are the pin connections I’m using from Argon to XBee.

Argon XBee
MISO 4
MOSI 11
SS 17
SCK 18
3.3v 1
Gnd 10

Here are the bytes for the Type 0x10 “Transmit Request” message.

7e 00 0f 10 01 00 00 00 00 00 00 ff ff ff ff 00 00 41 b1

The bytes were generated by XCTU’s Frame Generator tool. The payload is just the letter ‘A’. This frame works correctly when published from XCTU to a 3rd XBee in a USB carrier and to the one connected to the Argon if I disconnect from the Argon and place in a USB carrier.

This is the code I most recently tried. I gave up on receiving and thought I’d try sending:

SYSTEM_THREAD(ENABLED);

static uint8_t rx_buffer[19];
static uint8_t tx_buffer[19] = {0x7E, 0x00, 0x0F, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x41, 0xB1};;

void setup() {
    Serial.begin();

    SPI.setBitOrder(MSBFIRST);
    SPI.setDataMode(SPI_MODE0);
    SPI.setClockSpeed(1, MHZ);    
    SPI.begin(SS);
}

void loop() {
    static uint32_t ms = 0;
    if (millis() - ms < 500) return;  // trasfer only once per second
    ms = millis();
    
    SPI.transfer(tx_buffer, rx_buffer, sizeof(tx_buffer), NULL);

    Serial.println("\nrx_buffer:");
    for(uint16_t i=0; i<SPI.available(); i++)
        Serial.printf("%02x ", rx_buffer[i]);

    Serial.println("\ntx_buffer:");
    for(uint16_t i=0; i<SPI.available(); i++)
        Serial.printf("%02x ", tx_buffer[i]);    
}

I’ve tried other things like explicitly setting SS high on startup, low right before transfer, and high again right after, but the XBee is not having it. I haven’t tried SPI.beginTransaction(...) and SPI.endTransaction().

The XBee really acts like it needs to be explicitly put into SPI mode. For example, XBee pin 19 is supposed to be an ATTN going low to indicate SPI data is available, but it starts low and stays that way. I have looked in numerous Digi docs and can’t find anything that seems to apply, though.

At this point, I actually look forward to feeling really dumb when someone points out what I’ve overlooked!

As always, any insight much appreciated.

Steve

You may want to put that in your code and leave it there as it would be the normal thing to to when having multiple devices on the SPI bus.
Some SPI slaves even expect a rising edge on the SS pin before they move on in their routine.

Unfortunately I have no experience with the Pro 900HP so I cannot advise specifically, but have you got a logic analyzer (or at least an oscilloscope) to see how the signals behave when connected to your computer vs. when connected to the Argon.

BTW, do you get anything back from your Serial.print() statements?

I can now send and receive data, and yep, it was a dumb oversight on my part. The acronym “RTFM” comes to mind!

Bottom line, use XCTU’s I/O Settings section to turn off the UART DIN & DOUT pins in the firmware and turn on the SPI pins as shown below (see the lines with the blue triangles at the end.) This might vary if you’re using a device other than the 900Pro.


@ScruffR - thanks again for your feedback. This application will be using multiple SPI devices, so I added that code back in, as you suggested. Plus it’s very helpful to have someone with your level of experience to help with a sanity check!

Steve

2 Likes

This is great. I see we are both working with Xbee 900HP.

This thread couldn’t have come at a better time, as I am about to change my Xbee from UART to SPI.

I do have a quick question for you though. Are you using a library for any of this? You mentioned you were working in API 1 mode, and my understanding was that the library’s that have been ported only work in API 2 mode.

I opted to use Transparent mode to build out the logic for now. But will need to change to API mode later.

Thanks again. This community is great.

Hey @the_mick ,

Glad this was helpful!!

I’m not using a library at this point, it’s just a PoC. I found an Arduino lib that uses SPI, but it would need some work to port. We’re looking at XBees to replace Particle’s thread mesh, but we’re trying BLE at the same time. If BLE works for the current application, it might be a while before I can get back to the XBee solution, but I really like the range of those 900MHz radios!

Steve

@retupmoc1,

I have been going back and forth about pivoting to use LoRa rfm95w for my application. Range should be about the same from what I read, and definitely good enough for my application.

My biggest problem is the price for what you get. It was the “stable ecosystem” pitch that had me sold at first. But it just isn’t stable at all. I have actually been trying to get my 6 Xbee’s to connect to XCTU for the last 3 hours, but XCTU just won’t detect them.

Also I assumed because these have been around for so long, the documentation would be rich and up to date. But it’s not, not even close.

Their customer support is terrible also, I opened a couple support tickets two weeks ago and still haven’t heard back. But, I called the next day to inquire about the the cost of the smt for production, and even at a volume of 10,000 units they couldn’t get the price below USD18.00. lol. Funny thing is they have called back every day since trying to sell.

I think they need to hire more engineers, and less sales people.

I had the XBee 900 HP’s up and running in SPI mode on Photons in a Digimesh configuration just fine.

Took awhile to get everything figured out though as far as the firmware and library goes.

I’ve use the 900HP in a few projects now. Its much more pain free to just use them in point to point serial mode. I could never get digimesh to work with the sleep modes that i wanted so point to point is much easier to get up and running.