memcpy float to char array.. freezing

Ok so I started with this:

float info[3]; // floats with info
byte data[12];

void getPower() {
  info[0] = ina219.getBusVoltage_V() + (ina219.getShuntVoltage_mV() / 1000);
  info[1] = ina219.getCurrent_mA();

  memcpy(data,info,sizeof(info)); //copy floats from info to data[]
}

but the M0 I am using completely locked up after a random amount of time(between 5secs to 30min) so after a ton of searching I changed it to this(added ampersand to info) which seems to have stopped the M0 from freezing:

float info[3]; // floats with info
byte data[12];

void getPower() {
  info[0] = ina219.getBusVoltage_V() + (ina219.getShuntVoltage_mV() / 1000);
  info[1] = ina219.getCurrent_mA();

  memcpy(data,&info,sizeof(info)); //copy floats from info to data[]
}

but shouldn't both those effectively do the same thing?

They should be the same for memcpy() since it uses void pointers - the only difference is the type of the pointer. &info[0] should work too, and make your intentions a bit clearer.

Did you try memmove()?

KeithRB:
They should be the same for memcpy() since it uses void pointers - the only difference is the type of the pointer. &info[0] should work too, and make your intentions a bit clearer.

Did you try memmove()?

i did not try memmove, theoretically it shouldn’t make a difference here as there should be no way I am overwriting my variables however I always forget of its existence(I barely know c) and I should be using it anyhow as to my mind it supersedes memcpy

right now I am going to leave my simple code running overnight with memcpy(with the ampersand) and if it runs all night then the ampersand must have fixed it… which is very odd.

the test im doing as a whole is sending a radio signal between two 900mhz radios… Here is my entire code if anyone wants to try and figure out why this makes a difference, as of right now I have had it go through 1000 iterations 5x without issue(doing a reset after 1000) before the ampersand I dont even think it got to 1000 once out of 10+ trys.

RX Code a.k.a the problem code:

#include <SPI.h>
#include <RH_RF69.h>
#include <RHReliableDatagram.h>
#include <Adafruit_INA219.h>
unsigned long previousMillis = 0;        // will store last time LED was updated

/********** PIN DEFINITIONS *******************/
const int camTriggerPin = A0;
const int relaySet = A1;
const int relayUnSet = A2;

#if defined(ARDUINO_SAMD_FEATHER_M0) // Feather M0 w/Radio
  #define RFM69_CS      5   // "E"
  #define RFM69_RST     6   // "D"
  #define RFM69_INT     10    // "B"
  #define LED           13
#endif

/************ INA219 Setup **************/
Adafruit_INA219 ina219;

/************ Radio Setup ***************/

float info[3]; // floats with info

// Change to 434.0 or other frequency, must match RX's freq!
#define RF69_FREQ 915.0

// who am i? (server address)
#define MY_ADDRESS     1

// Singleton instance of the radio driver
RH_RF69 rf69(RFM69_CS, RFM69_INT);

// Class to manage message delivery and receipt, using the driver declared above
RHReliableDatagram rf69_manager(rf69, MY_ADDRESS);


int16_t packetnum = 0;  // packet counter, we increment per xmission

void setup() {
  unsigned long currentMillis = millis();
  ina219.begin();
  Serial.begin(115200);

  pinMode(LED, OUTPUT);
  pinMode(relaySet, OUTPUT);
  pinMode(relayUnSet, OUTPUT);
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, LOW);
  digitalWrite(relaySet,LOW);
  digitalWrite(relayUnSet,LOW);
  digitalWrite(camTriggerPin,LOW);


  // manual reset
  digitalWrite(RFM69_RST, HIGH);
  delay(10);
  digitalWrite(RFM69_RST, LOW);
  delay(10);
  
  if (!rf69_manager.init()) {
    Serial.println("RFM69 radio init failed");
    while (1);
  }
  Serial.println("RFM69 radio init OK!");
  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
  // No encryption
  if (!rf69.setFrequency(RF69_FREQ)) {
    Serial.println("setFrequency failed");
  }

  rf69.setTxPower(20, true);  // range from 14-20 for power, 2nd arg must be true for 69HCW

  // The encryption key has to be the same as the one in the server
  uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  rf69.setEncryptionKey(key);
  
  pinMode(LED, OUTPUT);

  Serial.print("RFM69 radio @");  Serial.print((int)RF69_FREQ);  Serial.println(" MHz");
}


// Dont put this on the stack:
byte data[12];
// Dont put this on the stack:
byte buf[RH_RF69_MAX_MESSAGE_LEN];

void loop() {
  keepAlive();
  if (rf69_manager.available())
  {
    getPower();
    Serial.println("Returned from getPower()");
    // Wait for a message addressed to us from the client
    uint8_t len = sizeof(buf);
    uint8_t from;
    if (rf69_manager.recvfromAck(buf, &len, &from)) {
      buf[len] = 0; // zero out remaining string
      
      Serial.print("Got packet from #"); Serial.print(from);
      Serial.print(" [RSSI :");
      Serial.print(rf69.lastRssi());
      Serial.print("] : ");
      Serial.println((char*)buf);
      Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks

      // Send a reply back to the originator client
      if (!rf69_manager.sendtoWait(data, sizeof(data), from))
        Serial.println("Sending failed (no ack)");
    }
  }
}


void getPower() {
  Serial.println("Entered getPower()");
  info[0] = ina219.getBusVoltage_V() + (ina219.getShuntVoltage_mV() / 1000);
  info[1] = ina219.getCurrent_mA();
  Serial.println("Doing MemCPY");
  memcpy(data,info,sizeof(info)); //copy floats from info to data[]
  Serial.println("Done MemCPY");
}

void keepAlive() {
  if (millis() - previousMillis >= 2000) {
    // save the last time you blinked the LED
    previousMillis = millis();

    // set the LED with the ledState of the variable:
      digitalWrite(relaySet,1);
  }
  if (millis() - previousMillis >= 100) {

    // set the LED with the ledState of the variable:
      digitalWrite(relaySet,0);
  }
}
void Blink(byte PIN, byte DELAY_MS, byte loops) {
  for (byte i=0; i<loops; i++)  {
    digitalWrite(PIN,HIGH);
    delay(DELAY_MS);
    digitalWrite(PIN,LOW);
    delay(DELAY_MS);
  }
}

TX Code(added same memcpy method as above initial tests where done just printing it out as a string):

float info[3];
#include <SPI.h>
#include <RH_RF69.h>
#include <RHReliableDatagram.h>
/************ Radio Setup ***************/

// Change to 434.0 or other frequency, must match RX's freq!
#define RF69_FREQ 915.0

// Where to send packets to!
#define DEST_ADDRESS   1
// change addresses for each client board, any number :)
#define MY_ADDRESS     2


#if defined (__AVR_ATmega32U4__) // Feather 32u4 w/Radio
  #define RFM69_CS      8
  #define RFM69_INT     7
  #define RFM69_RST     4
  #define LED           13
#endif

RH_RF69 rf69(RFM69_CS, RFM69_INT);

RHReliableDatagram rf69_manager(rf69, MY_ADDRESS);

unsigned long fail1;
unsigned long fail2;
int16_t packetnum = 0;  // packet counter, we increment per xmission

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

  pinMode(LED, OUTPUT);     
  pinMode(RFM69_RST, OUTPUT);
  digitalWrite(RFM69_RST, LOW);

  Serial.println("Feather Addressed RFM69 TX Test!");
  Serial.println();

  // manual reset
  digitalWrite(RFM69_RST, HIGH);
  delay(10);
  digitalWrite(RFM69_RST, LOW);
  delay(10);
  
  if (!rf69_manager.init()) {
    Serial.println("RFM69 radio init failed");
    while (1);
  }
  Serial.println("RFM69 radio init OK!");

  if (!rf69.setFrequency(RF69_FREQ)) {
    Serial.println("setFrequency failed");
  }

  rf69.setTxPower(20, true);  // range from 14-20 for power, 2nd arg must be true for 69HCW

  // The encryption key has to be the same as the one in the server
  uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
  rf69.setEncryptionKey(key);
  
  pinMode(LED, OUTPUT);

  Serial.print("RFM69 radio @");  Serial.print((int)RF69_FREQ);  Serial.println(" MHz");
}


// Dont put this on the stack:
uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
uint8_t data[] = "  OK";

void loop() {
  delay(1000);  // Wait 1 second between transmits, could also 'sleep' here!

  char radiopacket[20] = "Hello World #";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Sending "); Serial.println(radiopacket);
  
  // Send a message to the DESTINATION!
  if (rf69_manager.sendtoWait((uint8_t *)radiopacket, strlen(radiopacket), DEST_ADDRESS)) {
    // Now wait for a reply from the server
    uint8_t len = sizeof(buf);
    uint8_t from;   
    if (rf69_manager.recvfromAckTimeout(buf, &len, 2000, &from)) {
      buf[len] = 0; // zero out remaining string
      
      Serial.print("Got reply from #"); Serial.print(from);
      Serial.print(" [RSSI :");
      Serial.print(rf69.lastRssi());
      Serial.print("] : ");
      memcpy(info,&buf,12);
      for(int x = 0;x<3;x++){
        Serial.print(info[x]);
        Serial.print(", ");
      }
      Serial.println("");
      Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
    } else {
      Serial.println("No reply, is anyone listening?");
      fail1++;
    }
  } else {
    Serial.println("Sending failed (no ack)");
    fail2++;
  }
  Serial.print("Failed Send(No ACK): ");
  Serial.print(fail2);
  Serial.print(" Failed Reply: ");
  Serial.println(fail1);
}

void Blink(byte PIN, byte DELAY_MS, byte loops) {
  for (byte i=0; i<loops; i++)  {
    digitalWrite(PIN,HIGH);
    delay(DELAY_MS);
    digitalWrite(PIN,LOW);
    delay(DELAY_MS);
  }
}

memcpy() should work, and I don't see a problem with what you are doing. Make sure, though that you don't have a local variable with the same name as a global variable.

Using a union is easier IMO, and eliminates the need for the copy. You simply reference the same memory locations, using different variable names and types.

Example:

union convert { long x; byte b[4]} val;
//example of use
val.x = 12345678L;
byte b0 = val.b[0];

jremington:
memcpy() should work, and I don't see a problem with what you are doing. Make sure, though that you don't have a local variable with the same name as a global variable.

Using a union is easier IMO, and eliminates the need for the copy. You simply reference the same memory locations, using different variable names and types.

Example:

union convert { long x; byte b[4]} val;

//example of use
val.x = 12345678L;
byte b0 = val.b[0];

well I appreciate the union code... is the "convert" necessary? i ended up doing this, couldn't figure out what "convert" was for.
#define SensorArraySize 8 // size of the Sensor array
union { float f[SensorArraySize]; byte b[sizeof(float)*SensorArraySize];} SensorData;

that will allow me to send my sensor data all at once before I had to send one value at a time and make 8 requests and I was converting the floats to char arrays which takes up more memory... so much better :stuck_out_tongue:

The word "convert" defines a new data type, and is not necessary.

When in doubt, it is quickest, safest and most informative to consult on line language tutorials.

jremington:
The word "convert" defines a new data type, and is not necessary.

It depends on how the union variable is defined. If you use:

union convert {
   long x; 
   byte b[4];      // You need a semicolon here
} val;

It creates a union variable named val. You could also define it as:

union {
   long x; 
   byte b[4];      // You need a semicolon here
} val;

which is what jremington is saying when he says it doesn't matter. However, if you do name the union, then you can create an instance of the union without tying it to its declaration, as in.

union convert {
   long x; 
   byte b[4];      // You need a semicolon here
};
// more code...
void setup()
{
    convert val;
    // more code...
}

This form declares the union with global scope, but the union variable val now has function block scope, which encapsulates val within setup(). Tying an ID to the union also lets you use it as a function argument if needed:

void InitializeUnion(convert myUnion) {   // Note how we need to identify the union in the parameter list
   myUnion.x = 0L;
   memset(0, myUnion.b, sizeof(long));
}

Therefore, the way you declare the union in part depends on how you want to define and use the variables identified with it.