what is the most space compacted method to copy arrays?

I am looking for the most compact way of copying a byte array into another byte array.
These byte arrays contain data that I am expanding into a 35 byte array so I probably can't
use string functions. I am using a tiny84 and am running out of space...

I have 35 arrays that have 5 bytes per array and I am trying to save programming space but
need to select one of these arrays which I am doing with a switch.

Which method would save the most programming space:

memcpy(FonType, fontA, sizeof FonType);

or

int 1 = 5;
while(i--) *FonType++ *FonType++;

or something else?

here is a snippet of my code:

byte fontA[5]= {116,127,24,198,32};
byte fontB[5]= {244,99,232,199,192};
byte fontC[5]= {116,97,8,69,192};
byte fontD[5]= {244,99,24,199,192};
// there are 31 more of these

byte SELFONT[35];
byte FonType[5]= {0,0,0,0,0};
byte hexval[8] = {128,64,32,16,8,4,2,1};

byte dsread =0;		// read dipswitch input variable
byte pattrn = 0;	// font pattern choice

void setup() {
  pinMode(Bit0, INPUT_PULLUP);	// dipswitch 1
  pinMode(Bit1, INPUT_PULLUP);	// dipswitch 2
  pinMode(Bit2, INPUT_PULLUP);	// dipswitch 3
  pinMode(Bit3, INPUT_PULLUP);	// dipswitch 4
  pinMode(Bit4, INPUT_PULLUP);	// dipswitch 5
  pinMode(Bit5, INPUT_PULLUP);	// dipswitch 6

// read dipswitch and assign pattern

  dsread = digitalRead(Bit0);	// get dipswitch 1 setting
  if(dsread == HIGH){ pattrn++; }
   dsread = digitalRead(Bit1);
   if(dsread == HIGH){ pattrn += 2; }

  dsread = digitalRead(Bit2);
   if(dsread == HIGH){ pattrn +=  4; }

  dsread = digitalRead(Bit3);
   if(dsread == HIGH){ pattrn +=  8; }

  dsread = digitalRead(Bit4);
   if(dsread == HIGH){ pattrn +=  16; }

  dsread = digitalRead(Bit5);
   if(dsread == HIGH){ pattrn +=  32; }

  switch (pattrn) {
  
   case 0:  
    memcpy(FonType, fontA, sizeof FonType);
    break;
  
   case 1:  
    memcpy(FonType, fontB, sizeof FonType);
    break;

   case 2:  
    memcpy(FonType, fontC, sizeof FonType);
    break;
  
   case 3:  
    memcpy(FonType, fontD, sizeof FonType);
   break;

  } // --- end of switch
 

// ---- This next section expands the 5 byte array (FonType[5]) into a 35 byte array (SELFONT[35]) ----

ndx = 0;   				// ndx selects the hex value for conversion to binary
byte indx = 0;				// indx selects which byte of FonType is being decoded (expanded) 
for(byte i=0; i < 35; i++)  {		// i selects the byte of SELFONT that is getting set up
  if (FonType[indx] >=hexval[ndx]) {	// here we check if the selected byte of FonType should be set
      SELFONT[i] = 1;			// if yes, set SELFONT[i] = 1
      FonType[indx] = FonType[indx]- hexval[ndx];	// then remove that value from FonType[indx]
  }
  else {
      SELFONT[i] = 0;	// otherwise set SELFONT[i] = 0
  }
  ndx++;		// increment the hex value 
  if (ndx >= 8) {	// if all hex values hav ebeen applied, reset for the next FonType byte to be converted
   ndx = 0;
   indx++;		// increment to select the next byte of FonType
  }
}
   
} // end of setup

Your arrays should be declared const if they are not being changed.
You could also use a pointer instead of copying arrays.

const byte fontA[5]= {116,127,24,198,32};
...
...
byte* FonType;
...

...
case 1:  
    FonType = fontB;
    break;
...

...

...

You can compile both approaches; the IDE will tell you :slight_smile:

Depending of which memory you're running out of (RAM or FLASH) and if the arrays are fixed or not, you can consider to move them to PROGMEM or store them in EEPROM.

You can also consider to just use a pointer to an array instead of copying; but looking at your code, your operations on FonType are destructive so I don't think that that is an option.

It looks like each entry in the SELFONT byte array is either 1 or 0. Not sure how the rest of the code uses that array, but it seems to me that you only need 35 bits to store that information.

Since 5 bytes stores 40 bits, could you just store the expanded values in the first place and perform bitwise operations to pull out the proper values?

Why are you copying the arrays at all?

Mark

holmes4:
Why are you copying the arrays at all?

Mark

I am using a dipswitch to select which array will be used.

Is there a better way to select the array instead of copying it
or is it better to just set a pointer to the array that is selected
by the dipswitch?

What is the most compact way to do this?

thanks

BulldogLowell:
Your arrays should be declared const if they are not being changed.
You could also use a pointer instead of copying arrays.

const byte fontA[5]= {116,127,24,198,32};

...
...
byte* FonType;
...

...
case 1: 
    FonType = fontB;
    break;
...

...

...

Thanks for the tips

I tried this:

const byte fontA[5]= {116,127,24,198,32};

case 0:
FonType= fontA;
break;

and I got the following error messages when attempting to use the pointers:

148:12: error: invalid conversion from 'const byte* {aka const unsigned char*}' to 'byte* {aka unsigned char*}' [-fpermissive]

Thanks for the reply.

I like the idea of this but not quite sure how to set it up...

sterretje:
You can compile both approaches; the IDE will tell you :slight_smile:

Depending of which memory you're running out of (RAM or FLASH) and if the arrays are fixed or not, you can consider to move them to PROGMEM or store them in EEPROM.

You can also consider to just use a pointer to an array instead of copying; but looking at your code, your operations on FonType are destructive so I don't think that that is an option.

thanks for the reply...

Currently, the sketch uses 4,554 bytes of program storage space. maximum is 8,192 bytes.
Global variables use 349 bytes (68%) of dynamic memory leaving 163 bytes for local variables. maximum is 512 bytes

but there is more to add...

So try your other approach and check the difference :slight_smile:

You did not indicate if your arrays are fixed or not. If they need to be modified on the fly (e.g. based on some input), store them in EEPROM, else store them in FLASH. Copy them from there into the fontype array or process each byte.

Can you describe what your code needs to do in the for loop. I can see it modifies fontype array but that is about it :wink:

irethedo:
and I got the following error messages when attempting to use the pointers:

148:12: error: invalid conversion from 'const byte* {aka const unsigned char*}' to 'byte* {aka unsigned char*}' [-fpermissive]

sorry

const byte* FonType;

sterretje:
So try your other approach and check the difference :slight_smile:

You did not indicate if your arrays are fixed or not. If they need to be modified on the fly (e.g. based on some input), store them in EEPROM, else store them in FLASH. Copy them from there into the fontype array or process each byte.

Can you describe what your code needs to do in the for loop. I can see it modifies fontype array but that is about it :wink:

Thanks for the reply...
I am attempting to set these arrays up as const bytes (not sure if this will conserve space) but am having some difficulty as a couple arrays need to be variables which causes some type mismatches when attempting to use pointers...

Not sure how to store these arrays in EEPROM or FLASH or if this is an option as I am only using a tiny84 chip.

In the following code I am trying to decode the 5 decimal bytes in the selected array (FonType[5]) into 35 binary bits which are then loaded into the SELFONT[35] array. I am checking the value of each byte of FonType with hexval[] in order to convert the decimal bytes to binary but I am sure there must be a better way to do this with bitwise operators...

Because I am doing it this way, I end up having to change the value of FonType[5] which does not allow me to set it to a const byte type as suggested by BulldogLowell:

ndx = 0;   
byte indx = 0;
for(byte i=0; i < 35; i++)  {
  if (FonType[indx] >=hexval[ndx]) {
      SELFONT[i] = 1;
      FonType[indx] = FonType[indx]- hexval[ndx];
  }
  else {
      SELFONT[i] = 0;
  }
  ndx++;
  if (ndx >= 8) {
   ndx = 0;
   indx++;
  }
}

I need to find a clean way of using bitwise operators to convert the 5 decimal bytes in the array FonType[5] into Binary to be loaded into SELFONT[35]...

Would this work? ( I need to try this out when I get home from work later today...)

byte ndx = 0;   
byte indx = 0;
while(indx <= 4) {
for (int b=0 ; b < 8 ; b++ ) {
   SELFONT[ndx] =  ( 0x0001 & (FonType[indx] << b ) );
   ndx++;
}
indx++;
}

Why are you doing this?

Have you thought of just using a struct?

FonType has all values set to 0 while hexval has all values > 0:

byte FonType[5] = {0, 0, 0, 0, 0};
byte hexval[8]  = {128, 64, 32, 16, 8, 4, 2, 1};

Therefore, 0 >= <some_positive_value> will always be false:

if( FonType[indx] >= hexval[ndx] ) {    // check if the selected byte of FonType should be set

BulldogLowell:
Why are you doing this?

Have you thought of just using a struct?

I am just trying to select one array based upon a dipswitch setting and then converting it over
from a 5 byte array to a 35 byte array. I converted these 35 arrays into 5 byte arrays to conserve memory space...

I haven't thought of using a struct for this.
Is this code space efficient and what is the best way to set this up?

I am thinking of modifying the decimal conversion over to this:

byte ndx = 0;   
byte indx = 0;
while(indx <= 4) {
for (int b=0 ; b < 8 ; b++ ) {
   SELFONT[ndx] =  ( 0x0001 & (FonType[indx] << b ) );
   ndx++;
}
indx++;
}

thanks

BulldogLowell:
Why are you doing this?

Have you thought of just using a struct?

Is this what you meant?

typedef struct fonType
{
    byte font[5];
};

fonType Font[5]= {
{49, 254, 24, 227, 3},  
{47, 198, 23, 227, 3},  
{46, 134, 16, 162, 3}, 
{47, 198, 24, 227, 3}, 
{63, 132, 19, 194, 7}
};

That will not safe you anything; still 5x5 bytes in RAM.

I don't use PROGMEM that often so it might be a little buggy and can't test.

#include <avr/pgmspace.h>

const byte PROGMEM fonts[][5] =
{
  {116, 127, 24, 198, 32},
  {244, 99, 232, 199, 192},
  {116, 97, 8, 69, 192},
  {244, 99, 24, 199, 192},
};

byte FonType[5];

void setup() {
  // put your setup code here, to run once:

}

void loop()
{
  memcpy_P(FonType, &fonts[pattrn], sizeof(Fontype);
}

The code uses a 2 dimensional array instead of your fontA, fontB etc and it's stored in PROGMEM. memcpy_P is used to copy from fonts to FonType. Also no need to use a switch because the 'pattrn' variable is used as index into the array.

sterretje:
That will not safe you anything; still 5x5 bytes in RAM.

I don't use PROGMEM that often so it might be a little buggy and can't test.

#include <avr/pgmspace.h>

const byte PROGMEM fonts[][5] =
{
 {116, 127, 24, 198, 32},
 {244, 99, 232, 199, 192},
 {116, 97, 8, 69, 192},
 {244, 99, 24, 199, 192},
};

byte FonType[5];

void setup() {
 // put your setup code here, to run once:

}

void loop()
{
 memcpy_P(FonType, &fonts[pattrn], sizeof(Fontype);
}



The code uses a 2 dimensional array instead of your fontA, fontB etc and it's stored in PROGMEM. memcpy_P is used to copy from fonts to FonType. Also no need to use a switch because the 'pattrn' variable is used as index into the array.

thanks, I will try it tonight when I get home from work...

Following up on #7.

You can define your fonts like this:

byte fontA[5] = {B00101110, B11111110, B00011000, B01100011, B00000111};

and they will still take up 5 bytes. When one is selected you can point to it like this:

byte *FonType;
FonType = fontA;

To index into a value you would first select the correct byte from the array by dividing the index by 8. The position of the specific bit is the remainder when the index is divided by 8.

// getVal(ndx) is analogous to SELFONT[ndx]



// return value of a single bit in FonType
//
byte getVal(int idx)
{

  // claculate byte based on index
  int byteNum = idx / 8;

  // calculate bit in byte
  int bitNum = idx % 8;

  // isolate specific bit in byte
  Serial.print("byte = ");  Serial.print(byteNum); Serial.print("   bit = "); Serial.print(bitNum); Serial.print("   val = ");
  Serial.println((FonType[byteNum] >> bitNum) & 1 );

  return ((FonType[byteNum] >> bitNum) & 1 );

}

Thank you for all of the tips and ideas. They were very good
and very creative.

I have chosen to place the arrays in program memory as a two dimensional array.

This has resulted in now using 4,684 bytes of program storage as compared 4,554 bytes of program storage space from the original code.

This is a little bit more but what it improved was that now Global variables use 157 bytes (30%) of dynamic memory as compared to 349 bytes (68%) of dynamic memory leaving 355 bytes for local variables instead of 163 bytes for local variables from the original code.

thanks again for the helpful ideas...