2

I'm using Raspberry Pi and Arduinos for my home automation project where Raspberry Pi is the controler of Arduino nodes. I use nRF24 wireless transceivers to communicate.

My problem is that when I was sending a structure like following

struct TempSensorData

{ uint32_t result; uint32_t temperature; uint32_t humidity; };

From Raspberry to Raspberry everything went fine but now when I use Arduino as sender I get very strange results:

received: status: 335544320, temperature: 754974720 degrees, humidity: 0%

While on Raspberry it was

received: status: 0, temperature: 22 degrees, humidity: 44%

Can this be a problem with types? Or with different type of architecture (like different sizes on 3-2bit and 64-bit arch)?

EDIT:

Code on Raspberry:

if (radio.available())

{ // dump the payloads until we've got everything Message receivedData = {0}; radio.read(&receivedData, sizeof(Message)); TempSensorData data = receivedData.msgData.tempSensorData; std::cout << "received: status: " << data.result << ", temperature: " << data.temperature << " degrees, humidity: " << data.humidity << "%" << std::endl; //TODO here we have some strange numbers - check if we have proper types }

Before that I have:

radio.begin();
radio.setPALevel(RF24_PA_LOW);
radio.setChannel(0x4c);
radio.openReadingPipe(1, RASPI_READ_ADDR);
radio.openWritingPipe(RASPI_WRITE_ADDR);

radio.enableDynamicPayloads();
radio.setAutoAck(true);
radio.powerUp();
radio.startListening();

And on Arduino:

Header header = {thisNodeId, thisNodeType, 0, static_cast<uint8_t>(MsgType::TEMP_SENSOR_DATA), 12345, Status::ok};
TempSensorData dhtData;
dhtData.result = DHT.read11(DHT11_PIN);
dhtData.humidity = (int)DHT.humidity;
dhtData.temperature = (int)DHT.temperature;
Message message = {0};
message.header = header;
message.msgData.tempSensorData = (dhtData);
radio.stopListening();
radio.write(&message, sizeof(message));
radio.startListening();

I also use a common header with defined structures for both Arduino and Raspberry, which contains:

#define RASPI_WRITE_ADDR 0xF0F0F0F0F0LL
#define RASPI_READ_ADDR 0xF0F0F0F0E1LL

struct TempSensorData {   
  uint32_t result;
  uint32_t temperature;
  uint32_t humidity;
};  

enum class Status : uint8_t

{
ok, error, fail };

enum class MsgType : uint8_t {
    INITIALIZATION,
    RESET_REQUEST,
    ACK_NACK,
    TEMP_SENSOR_DATA,
};

struct Header {
  uint8_t nodeId;
  uint8_t nodeType;
  uint8_t location;
  uint8_t msgType;
  uint16_t checksum;
  Status status;
};

union MsgData {
  InitMsgData initMsgData;
  AckNack ackNack;
  TempSensorData tempSensorData;
};

struct Message {
    Header header;
    MsgData msgData;
};

radio is an item of RF24 class from https://github.com/TMRh20/RF24/

Unfortunately the RF24 repo is 64 commits ahead of what I use.

EDIT2:

Maybe the problem lays in that

enum class Status {};

which I use in both files.

I must add that I use g++-4.7 when compiling on Raspberry and when compiling on Arduino I use avr-g++-4.8.2

4
  • 2
    Can you post the arduino send code and and the raspi receive code? Commented May 28, 2015 at 23:47
  • I second that - posting the code will help the most.
    – rslite
    Commented May 29, 2015 at 2:38
  • I added code...
    – lewiatan
    Commented May 29, 2015 at 17:17
  • @yeti - "Tags should help to describe what the question is about, not just what it contains." The nrf chip is merely background context of the question, the actual issue is a difference of structure padding between the two C environments which has no dependence on the communication channel, so adding that tag (at least as a 3rd party edit proposal) is not appropriate. Commented Oct 4, 2015 at 19:27

3 Answers 3

0

It is not a size problem: uint32_t is always 32 bits. Converting the numbers to hex gives:

  • Raspberry to Raspberry: 0x00000000, 0x00000016, 0x0000002c
  • Arduino to Raspberry: 0x14000000, 0x2d000000, 0x00000000

There seems to be an offset between the two. You may just have lost one byte when the Arduino is the sender. There may be also a byte order issue, but your test is not sufficient to say. You can, e.g., send a series of 0x12345678 to know for sure.

You need to devise a way of synchronizing the communication, i.e. to identify, in the byte stream, which is the first byte of the packet.

Edit: Let me illustrate how this can happen both with and without and endianness issue. I'll assume you are transmitting {status: 0, temperature: 20, humidity: 45} and the first byte(s) of the first packet are lost. On the receiving side, you combine the remaining bytes of the first packet with the first byte(s) of the second packet, and interpret the whole as a single packet. You get: {status: 335544320, temperature: 754974720, humidity: 0}.

In a little endian to little endian scenario, you only need to loose one byte:

original data:     0x00000000, 0x00000014, 0x0000002d
transmitted bytes: 00 00 00 00 14 00 00 00 2d 00 00 00
received bytes:    00 00 00 14 00 00 00 2d 00 00 00 00
received data:     0x14000000, 0x2d000000, 0x00000000

In a big endian to little endian scenario, you get the exact same result if you loose 4 bytes:

original data:     0x00000000, 0x00000014, 0x0000002d
transmitted bytes: 00 00 00 00 00 00 00 14 00 00 00 2d
received bytes:    00 00 00 14 00 00 00 2d 00 00 00 00
interpreted data:  0x14000000, 0x2d000000, 0x00000000
3
  • 1
    Off-by-a-byte synchronization issues can be a big challenge when working with streaming channels like UARTs, but the nRF24L01 is at least natively packetized, so I wouldn't expect that to be an issue here, unless the code driving it wraps the native behavior in a streaming abstraction that can split data across packets. Another potential concern might be misaligned access on the pi side; would have to check if that throws a fault, aliases oddly to an aligned address, or gets fixed in software emulation. Commented May 29, 2015 at 18:09
  • 3
    I found out that adding "__attribute__((packed))" to all structs I'm sending helped! Thanks @EdgarBonet - your answer made me think and helped resolving this issue..
    – lewiatan
    Commented May 30, 2015 at 21:25
  • This answer is fundamentally wrong - in fact it is a size issue, specifically an alignment one where a multi-byte type follows a smaller type. The pi wants the larger type aligned, the Arduino doesn't care. Commented Apr 16, 2018 at 13:57
-1

I believe this could be because the Raspberry pi is big endian and the arduino is little endian.

Learn about Endianness here!

5
  • It's definitely not just an endianness problem since 0 appeared as a different number.
    – rslite
    Commented May 29, 2015 at 2:40
  • Without code detailing how the logistics is implemented, it could realistically be anything. It is important to factor in endianness however.
    – Élie
    Commented May 29, 2015 at 3:34
  • 2
    Are you sure about the Pi? I've read in several places it's little endian by default. AVR based Arduinos are little endian too. I do not know about the Due. Commented May 29, 2015 at 8:07
  • 1
    This is incorrect. While the pi's hardware may be capable of running in a big endian mode, and there are people who have tried to do that raspberrypi.stackexchange.com/questions/7279/… Most normal Raspberry Pi Linux distributions are little-endian Commented May 29, 2015 at 18:06
  • @ChrisStratton, thanks for the insight. I generally use Big Endian with the Pi out of habit - it sort of stemmed from ignorance in an operating systems Uni project years ago, and I have just sticked with it. I guess I jumped the gun and didn't even consider that the OP was probably using a *nix distribution. You're absolutely right!
    – Élie
    Commented May 30, 2015 at 5:01
-1

You may have multiple problem. First of all the structure get align to be efficient on the specific architecture, to avoid those filling you have to tell the compiler to pack the structure. There are different way to pack depending on compiler used.

Then endianess is different, so the byte composing the value has to be swapped.

Finally there may be a desincronization or a bus error. In those case a sync message (normally 2 byte before each transmission) and a CRC are used to fix the issue.

4
  • No, endianness is not different here. Commented Apr 16, 2018 at 13:58
  • I said "may". i listed the common mistakes, and the first one was actually the one that fixed the problem:<<I found out that adding "__attribute__((packed))" to all structs I'm sending helped!>>
    – Lesto
    Commented Apr 22, 2018 at 11:01
  • The problem is that you made a false declarative statement in its own paragraph - if you did not mean to falsely argue that the endianness was different, you need to edit your post. And even then, suggesting as a possibility something that is not true in the given case would be unhelpful and misleading. Commented Apr 22, 2018 at 13:57
  • yes, you are righr about phrasing, but english is not my maon language. If you propose an edit i can accept it. About the answer, given the problem that is wat could be realistically the problems; this will be helpful to people having similar issue, but an other of the possible other cause
    – Lesto
    Commented May 3, 2018 at 20:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.