Stack overflow on serial monitor

unsigned long int  odometer_read;

//Start current_odometer_count Function//
void current_odometer_count() {
  unsigned long int counts; //I dont know why this is needed here;
    
  counts =  EEPROM.get(eeprom_odometer_overflow_counter,eeprom_get_2byte)*255*((eeprom_odometer_end_counter+1)-eeprom_odometer_start_counter);
            //+ (setup_odometer_write_address - eeprom_odometer_start_counter)*255 
            //+ EEPROM.read(setup_odometer_write_address); 

  odometer_read = counts;
}
//End current_odometer_count Function//type or paste code here

EEPROM.get correctly returns a 1.
The number after 255* is 464.
The correct value would therefore be 118,320.
counts is an unsigned long int local variable.
odometer_read is an unsigned long int global variable.

In void setup:

  current_odometer_count();
  Serial.print("Your odometer reading is : ");
  Serial.println(odometer_read);
  delay(100);

  Serial.print("Your overflow counter : ");
  Serial.println(EEPROM.get(eeprom_odometer_overflow_counter,eeprom_get_2byte));
  delay(100);

  Serial.print("Long Test : ");
  testvallong = 77777;
  testvalshort = 55555;
  testvalsum = testvallong+testvalshort;
  Serial.println(testvalsum); 

and the serial monitor outputs:

"Your odometer reading is : 52784
Your overflow counter : 1
Long Test : 133332"

The difference from the correct value and serial print value is 2^16. I think serial print is printing a short when the variables have been defined as long. When I run sizeof() counts, it returns 4 bytes. Anybody see the error or have any recommendations?

Try defining your value as uint32_t and see if that helps. If that does not solve post the values in HEX.

I am in doubts that the construction below is correct:

Please show the types of every variable in the expression.

In general, it would be better if you could show the code in full.

So its:
counts (unsinged long int) = unsigned short int * 255 * ((unsigned short int +1)-unsigned short int);

I was able to force the code to work when converting 255 to 255L, but I dont fully understand why. I guess it has everything to do with nothing on the right hand side is 4 bytes long. I think the L makes 255 the number a "long".

1 Like

The whole expression on the right is calculated as unsigned short int type and only then it casts to unsigned long. So, if the result of calculation exceeds the maximum of unsigned short int, it experiences an overflow before assigning the result to insigned long.

Converting 255 to 255L you make one term long, so the whole expression will be caculated as long and there will be no overflow.

By the way, one bit in the upper byte represents 256, not 255. So there's that.

1 Like

Yes. Use a 'UL' to keep the calculation all unsigned.

https://en.cppreference.com/w/cpp/language/integer_literal

So I made a counter on EEPROM that uses wear leveling. Byte N starts at zero and counts upward from zero to 255, so 2^8-1 count states. Then Byte N++ counts, etc. at the end of EEPROM, the code sums up the the number of Bytes counted to 255 multiplied by 255 multiplied by the flag count. My count limit using approximately 90% of the EEPROM for counting is 46,144,800 individual counts. Well beyond the requirements of the machine it runs.

//Start current_odometer_count Function//

/* This function reads the current odometer */
void current_odometer_count() {
  unsigned long int counts; //I dont know why this is needed here;
    
  counts =  EEPROM.get(eeprom_odometer_overflow_counter,eeprom_get_2byte)*255UL*((eeprom_odometer_end_counter+1)-eeprom_odometer_start_counter) \
            + (setup_odometer_write_address - eeprom_odometer_start_counter)*255UL \
            + EEPROM.read(setup_odometer_write_address); 

  odometer_read = counts;
}
//End current_odometer_count Function//


//Start eeprom_odometer_write_address_finder Function//

/*This function searches through the level wearing EEPROM byte
counters looking for the current block to write to. This replaces 
the eeprom_odometer_write_address limiting byte that wears out
after 25.6M cycles. Limiting bytes now become the individual block
counters 46,144,800 if counting by 1. */

void eeprom_odometer_write_address_finder(){
  
  unsigned short int i = eeprom_odometer_start_counter;
  
  while (EEPROM.read(i) == 255) {
    i++;
  }

 setup_odometer_write_address = i; 
}
//End eeprom_odometer_write_address_finder Function//

//Start odometer_count Function//

/*This function should work with values greater than 1.
The count would likely increase either each target or when a person
logs out of the station and then uploads the number.
It counts a block of EEPROM from the start_counter block to the
end_counter block from 1-255. When a block reaches 255 it moves to the 
next block. When all blocks equal 255, the overflow counter is increased
by 1, the write address is set back to the first write block, and the 
write blocks are reset to 0. 
This is an implementation of wear leveling.*/
void odometer_count(unsigned int increase) { 
  unsigned short int block_count_val_add =  EEPROM.read(setup_odometer_write_address) + increase;

  while (block_count_val_add >= 255) {
    EEPROM.update(setup_odometer_write_address,255);
    setup_odometer_write_address++;
    block_count_val_add = block_count_val_add - 255;
      
    if (setup_odometer_write_address > eeprom_odometer_end_counter){   
      unsigned short int overflow_counter_get = EEPROM.get(eeprom_odometer_overflow_counter,eeprom_get_2byte);
      overflow_counter_get++;
      EEPROM.put(eeprom_odometer_overflow_counter,overflow_counter_get);
      setup_odometer_write_address = eeprom_odometer_start_counter;
      
      for (unsigned int i = eeprom_odometer_start_counter; i <= eeprom_odometer_end_counter; i++) {//It should not be possible for 255 to exist in last EEPROM BLOCK and 0 in the first EEPROM BLOCK.
        EEPROM.update(i,0); //This sets all odometer write blocks to zero. Normal EEPROM is 255 initially.
      }
    }
  }
  EEPROM.update(setup_odometer_write_address,block_count_val_add); //adds any remainder below 255 to the active write block
}
//End odometer_count Function//

Is uP math (or in the alternative - CPP math) performed right to left?

0...255 is 2^8=256 states. 0...254 is 2^8-1 states.

Zero isn't a count state. 1 is the first count state. Therefore, the block only increments 2^8-1 times. The counter works just fine and without error. Understand there are 256 possibilities, but a zero is meaningless to the counter.