Writing a 2D array over I2C

I have an array which looks like this:

const cfg_reg registers[] PROGMEM = {
   { 0x00, 0x00 },
   { 0x02, 0x10 },
   { 0x00, 0x01 },
    ........
    ........
    }

Above the array is an explanation about how to use it:

   // Externally implemented function that can write n-bytes to the device
   extern int i2c_write(unsigned char *data, int n);
   // Externally implemented function that delays execution by n milliseconds
   extern int delay(int n);
   // Example implementation.  Call like:
   //     transmit_registers(registers, sizeof(registers)/sizeof(registers[0]));
   void transmit_registers(cfg_reg *r, int n)
   {
       int i = 0;
       while (i < n) {
               i2c_write((unsigned char *)&r[i], 2);
               break;
           }
           i++;
       }
   }

It say to externally implement the 'i2c_write' function, which I did with Wire.write (with begin tranmission before, and stop tranmission after)

However on my logic analyzer the data transmits and ack's, but it's not the data it should send and the chip also does not do what I want.

Did I use the Wire.write function right?
Is there another way to easily write a 2D array of a certain length? I don't necesarily have to use the example.

Please edit your post to include code tags. Very hard to read now.

Even better, make it MCVE.

However on my logic analyzer the data transmits and ack's, but it's not the data it should send and the chip also does not do what I want.

I wonder if that's because you put the data in PROGMEM but access it as though it was in SRAM.

How would I fix this? There is no sufficient SRAM available.

Did not know that data gets treated different if it's in flash.

Here you go, some bed time reading.

Thanks, this is new stuff, so please bear with me;

I've read up on PROGMEM, what it does and how to retrieve data from flash to SRAM.
So if I want to write values from this array I first have to retrieve them using pgm_read_byte()?

So some kind of loop that copies an array value (flash) to a variable (sram), writes it via I2C and then repeats this for the next variable in the array?

I will try to come up with some code and post it here, but in the meanwhile all help is appreciated.

So if I want to write values from this array I first have to retrieve them using pgm_read_byte()?

If cfg_reg is a fancy name for a byte, yes.

So some kind of loop that copies an array value (flash) to a variable (sram), writes it via I2C and then repeats this for the next variable in the array?

The array being a 2D array, you'll need two (nested) loops. But, yes, that is the idea. You only need one byte of SRAM to hold the one byte at a time fetched from PROGMEM.

How would the nested loops work? One incrementing the rows, one incrementing on the columns?

I can imagine something like this working, but I can't get the syntax right because it won't compile:

void transmit_registers(int regsize)
{
  int i = 0;
  while (i < regsize) {
    Wire.beginTransmission(address);
    Wire.write(pgm_read_byte(registers[i][0]);
    Wire.write(pgm_read_byte(registers[i][1]);
    Wire.endTransmission();
    i++;
  }
}

From what I need you need to pass the address to the pgm_read_byte function, but I don't yet get how you would do that.

How would the nested loops work? One incrementing the rows, one incrementing on the columns?

Yes.

From what I need you need to pass the address to the pgm_read_byte function, but I don't yet get how you would do that.

Typically, people do that using the address-of operator (&).

Okay I confirmed that it was indeed a problem that the array was in flash.
I copied part of the array to the SRAM, called the transmit function, and now the I2C transfers correctly.

However, it can't stay in the SRAM because there is no space.

For the record, this works:

void transmit_registers(cfg_reg *r, int n)
{
  int i = 0;
  while (i < n) {
    Wire.beginTransmission(TASadr);
    Wire.write((unsigned char *)&r[i], 2);
    Wire.endTransmission();
    i++;
  }
}

So now I need to rewrite this part so that it first copies a value from the flash array to the SRAM, then writes it via I2C and then repeats

For that I first need to understand what this does:

(unsigned char *)&r[i]

It looks like something with a typecast, pointer and the address of an array value.
However I don't really understand what this does in practice.

To answer your question @PaulS, I don't know for sure if 'cfg_reg' is a byte. I think this piece of the code has something to do with that:

typedef unsigned char cfg_u8;
typedef union {
    struct {
        cfg_u8 offset;
        cfg_u8 value;
    };
    struct {
        cfg_u8 command;
        cfg_u8 param;
    };
} cfg_reg;

It looks like something with a typecast, pointer and the address of an array value.
However I don't really understand what this does in practice.

Work from the right to the left. r[ i ] is an element of an array. &r[ i ] is the address where that element is in memory. The cast tells the compiler to treat that memory location, and subsequent locations, as a though it was an unsigned char array.

You do NOT need to copy the entire array into SRAM. You are currently sending one byte at a time. Just fetch that byte, using pgm_read_byte(), before you send it.