Arduino Stack Exchange is a question and answer site for developers of open-source hardware and software that is compatible with Arduino. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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

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 32bit and 64bit 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 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 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

share|improve this question
2  
Can you post the arduino send code and and the raspi receive code? – BrettAM May 28 '15 at 23:47
    
I second that - posting the code will help the most. – rslite May 29 '15 at 2:38
    
I added code... – lewiatan May 29 '15 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. – Chris Stratton Oct 4 '15 at 19:27
up vote 1 down vote accepted

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
share|improve this answer
    
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. – Chris Stratton May 29 '15 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 May 30 '15 at 21:25

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

Learn about Endianness here!

share|improve this answer
    
It's definitely not just an endianness problem since 0 appeared as a different number. – rslite May 29 '15 at 2:40
    
Without code detailing how the logistics is implemented, it could realistically be anything. It is important to factor in endianness however. – Gui May 29 '15 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. – Edgar Bonet May 29 '15 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 – Chris Stratton May 29 '15 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! – Gui May 30 '15 at 5:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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