FUNCTIONS - returning byte array........ :~{

Hi,
Sorry for the post. I have researched this but… still no joy in getting this to work. There are two parts to the question too. Please ignore the code TWI Reg code as its application specific I need help on nuts and bolts C problem.

So… to reduce memory usage for a project I have started to write my own TWI (wire.h lib) for ATMEL328p. Its not been put into a lib yet as ‘1’ I have no idea how to do that yet… will get to that later and '2’its a work in progress which keeps getting added to.

The problem I’m having is with reading multiple bytes.

Problem 1
I have a function that I need to return an Array

byte *i2cBuff1[16];

void setup () {
i2cBuff1 =  i2cReadBytes(mpuAdd, 0x6F, 16);
}

/////////////////////READ BYTES////////////////////
byte* i2cReadBytes(byte i2cAdd, byte i2cReg, byte i2cNumBytes) {
  static byte result[i2cNumBytes];
  /////START CONDITION////
  TWCR = B10100100; //(TWINT)(TWSTA)(TWEN) - Set START condition
  while (!(TWCR & B10000000)) { //Wait for TWI to set TWINT
  }
  /////SLA + W////
  TWDR = (i2cAdd << 1); //load address to Atmega i2c buffer, set R/W bit
  TWCR = B10000100; //(TWINT)(TWEN) - SLA+R
  while (!(TWCR & B10000000)) {
  }
  /////REG////
  TWDR = i2cReg;
  TWCR = B10000100; //(TWINT)(TWEN) - Send Reg
  while (!(TWCR & B10000000)) {
  }

  ///////REPEATED START/////////
  TWCR = B10100100; //(TWINT)(TWSTA)(TWEN)
  while (!(TWCR & (1 << TWINT))) {
  }
  /////SLA + R////
  TWDR = (i2cAdd << 1) | (B00000001); //load address to Atmega i2c buffer, set R/W bit
  TWCR = B10000100; //(TWINT)(TWEN) - SLA+R
  while (!(TWCR & B10000000)) {
  }
  /////////REQUEST DATA///////////
  for (byte x = 0; x < i2cNumBytes; x++) {
    TWCR = B10000100;//(TWINT)(TWEN)
    while (!(TWCR & (1 << TWINT))) {
    }
    result[x] = TWDR;
  }
  /////STOP and SET//////
  TWCR = B10010100;
  TWCR = B11000101;

  return result;
}

What I understand ( :o ) is I have declared a Static byte array in the function which I point to as the :/return argument of the function.
The function call requests the return of a pointer value for a byte array.

Well … it doesn’t work … I have checked multiple sites and I think this should work. The error message I get is:

MPU6050_I2C_rev1:232: error: incompatible types in assignment of 'byte* {aka unsigned char*}' to 'byte* [16] {aka unsigned char* [16]}'
 i2cBuff1 =  i2cReadBytes(mpuAdd, 0x6F, 16);

Problem 2
Ok say IF the code sample above worked. I am trying to reduce the amount of memory that I use in my sketch. By using any memory in the function even though the memory (need) is released after the function call, the function must need to reserve an amount of ‘space’ in some way, for when the function is called. Ideally I would like to avoid the use of static variables within the function that are duplicated within the main program.

Does anyone know the trade off with repeated function call… i.e looping a function call with a bit shift operator, as apposed to calling a function once to complete a process and return … an Array? Or was this this the whole point that C does not really support Array return in the first place.

Hope this made sense, just want to get the best from the little I got.

BR
Danny

I think it's easier if you declare your result array outside of the i2cReadBytes scope, and then pass the pointer to i2cReadBytes. No need for static variables or other hacks. If I'm not mistaken, that's how similar libraries with buffers do it as well.

Hi Pieter P

Are you saying that I should declare the function as returning void?

Yes.

And why do you use "byte *i2cBuff1[16];" ? When you use "byte i2cBuff1[16];", i2cBuff1 is a pointer to the first byte of a 16-byte block of memory. No need to have a pointer to that pointer, right? If you then try to change the value of i2cBuff1, it'll point to a different byte, but the first 16 bytes still exist in memory. To solve it, you can simply remove the "[16]" on the first line, since allocation of the array is done on the first line of you function.

That'll compile, but I think it's still better to pass a reference to the array into the function as a parameter, and perform all operations on the array itself. Like so:

void setup () {
  uint8_t res[16];
  i2cReadBytes(0, 0x6F, res, 16);
}

/////////////////////READ BYTES////////////////////
void i2cReadBytes(byte i2cAdd, byte i2cReg, uint8_t* result, byte i2cNumBytes) {
  /////START CONDITION////
  TWCR = B10100100; //(TWINT)(TWSTA)(TWEN) - Set START condition
  while (!(TWCR & B10000000)) { //Wait for TWI to set TWINT
  }

[...]

ve03vsx:
Hi Pieter P

Are you saying that I should declare the function as returning void?

I think the problem you are seeing is caused by the prototype generation of the Arduino environment.

You have two methods around this problem.

first create a .h file that contains all of your function prototypes or put your code in a .cpp file.

attached are two files, one an .ino, the other a .cpp; By using the .cpp file you can have complex function return parameters and function parameters.

Maybe this example will help?

Chuck.

P.S. just put both files in your Arduino projects directory. the Subdirectory name must be ‘param’ to work with the Arduino environment.

example.cpp (954 Bytes)

param.ino (185 Bytes)