counter won't work with int but with unsiged char??

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I'm scratching my head why this doesn't work. I'm using AS7 programing an ATmega328p.

 

The counter variable CONTROL.cms_counter will count up nicely from 0 to SPS if it's a unsigned char.

If a change it to an int, it's a bit random if it starts at 0 or 1 or -2 or -600..... for exampel (verified using debugwire). 

It can run nicely for a few minutes and the suddenly go to -22000.

 

The code is located in a sub function under main(), thus not in an ISR.

 

If I remove the else statment and put CONTROL.cms_counter++; just after the If, it seams more prone to jump to larger values like -22000, -600...for exampel.

	
	if (CONTROL.cms_counter >= SPS)
	{
		CONTROL.cms_counter = 0;
	}
	else
	{
		CONTROL.cms_counter++;
	}

 

Last Edited: Tue. Jun 25, 2019 - 12:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Need more context like what SPS is and what the CONTROL{} structure looks like.

 

Also if you are "watching" it with a debug watch window then is it "volatile" ?

 

Finally it could be that the CONTROL{} structure itself is being over-written by something else (write through a rogue pointer etc) and maybe as a byte it just misses being damaged but as a word it's then in the right place to be corrupted.

 

(obviously a sudden jump to a hugely negative number means the upper byte just went to a value with bit 7 set)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your fast reply.

 

SPS:

#define SPS 33

 

CONTROL:

struct OUTPUT
{
    int pointer;
    int cms;
    int cms_avg[33];
    unsigned char cms_counter;
}CONTROL;

 

I've tried making it volatile but no change.

 

The counter itself is used to fill an array with measurment like this: CONTROL.cms_avg[CONTROL.cms_counter] = CONTROL.cms;

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it never exceeds 33 then why would you need more than 8 bits anyway?

 

Anyway put a memory window on the whole CONTROL structure instance and watch the bytes for changes. As I say, when 16 bit, it looks like there may be something doing rogue writes to the upper byte where that member is stored. 

Actually this couldn't be a "Buffer over-run" from writes beyond the 33'd element of cms_avg[] could it? (don't forget they are numbers 0..32 not 1..33 ;-)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your right on both, increasing cms_avg to 34 did the trick.

And also, I don't need more than 8bit but I used an int before I knew how high SPS needed to be.

 

Thank you very much for your help, you write alot of good posts on this forum :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Given that cms_counter is located right after an array, it sure makes me think that the code is writing past the end of the array and into cms_counter.  And sure enough, you're testing for >= 33 at one point, which makes me wonder if the code is not writing into cms_avg[33], which will of course trash some data outside of the array.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Glad you found it but the odd thing here is that if you were using:

    int cms_avg[33];
    unsigned char cms_counter;
}CONTROL;

then writing to [33] I'd expect the uchar to be corrupted too. Also if you use:

    int cms_avg[33];
    int cms_counter;
}CONTROL;

then write to [33] you are actually corrupting the LOW byte of cms_counter (as AVR C compilers store stuff "little endian") so the -22,000 thing is odd as that suggests damage not to the immediately adjacent byte but the one after.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since cms_avg is an array of ints, writing to cms_avg[33] will write 2 bytes past the array.  My guess is that the incorrect low byte (or only byte of a char counter) looked 'reasonable', but once the high byte of the int counter was trashed, the problem became obvious.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ah missed it was int's that explains the 2 byte thing - thanks.