Byte pinching, swapping int' for uint8_t

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

I have some code im playing with that is a tick and execute state machine' os (i guess what you call it)

and all my integers were int types, the code compiled to 552 bytes of flash.

 

I changed all the integers to unsigned 8 bit integers (uint8_t) and the program size dropped to 416 bytes!

And this was with only ten integers, saved 136 bytes. Optimization set to [-Os]  

I knew there were other number types, floats and what not. It did not occur to me to define something lower than an int' integer.

Probably also got 8bit, 255 max stuck in my head because of learning the timers recently, none of my numbers go above 255! ;p. green...

 

This topic has a solution.

~GuitarDude

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

The AVR is an eight bit processor, so a 16 bit operation takes at least twice the instructions. Note that for a 32 bit processor, a 8 bit operation may be more costly than a 32 bit operation due to byte alignment.

As you've found, paying attention to the variable size makes a big difference - especially with little micros like the AVR

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

OP, you didn't do too bad.  We've seen newcomers using floats where a unint8_t would do!

 

Since you're doing OS stuff, another strong benefit of 8-bit values is that access is atomic.  You don't have to worry about code that loads one byte of a multi-byte variable, then an interrupt comes along and changes all the bytes, then the code loads some of the changed bytes, resulting in an invalid value.

 

I have an 8-bit mantra:

Never use an int when a char will do

Never use a long when an int will do

Never use a float when a long will do

Never use a signed when an unsigned will do

 

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

To the tune of "Macarena" no doubt ;)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

joeymorin wrote:

To the tune of "Macarena" no doubt ;)

Mostly on Fridays after lunch...

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

My ISR(TIMER1_OVF_vect) is ticking 80,000 times per second and setting a 'flag variable to one.

 

ISR(TIMER1_OVF_vect){
    TCNT1 = 231;// needed, ISR is nulling TCNTs value in main!
    flag=1; 
}

My statement that starts off the work to be done;   

if(flag == 1){  /// ticks 80,000 times per second
                cli(); //disable interrupts, renable at the end of if 'flag==1
                /// disableing interrupts needed so data doesnt corrupt?.
                flag = 0;
                x++;
                z++;
                if(x > 200){ /// ticks 400 times per second/every 20k cycles
                ...

I thought i was having an interrupt error/data corruption during a button press down the line but it turns out i did not clear a certain variable in my de-bounce code, which it needed.

I decided to disable Interrupts while my code was doing work that i wanted it to do regardless if it had more than enough cpu cycles to do the work

and because i thought it was causing an error. 

If my variables do all fit within 8bits (0-255), that means i dont have to worry about corruption and generally don't have to disable interrupts?

If so, cool. I understand something important like serial data transfer or something i might want to disable interrupts, have not got that far to know how it works.

Thanks for the info. 

~GuitarDude

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
ISR(TIMER1_OVF_vect){
    TCNT1 = 231;// needed, ISR is nulling TCNTs value in main!
    flag=1; 
}

This always says "OP does not know about CTC"!! If you only want a counter to count 1..25 then actually have it run in CTC with the compare register set to 24 (as it counts from 0 not 1). BTW what's the prescaling on this timer? Obviously if it's just CS00 then your interrupts may be occuring too fast for the ISR - or certainly the ISR will eat a large proportion of the available time. I assume you actually have quite a large prescale for OS "ticks"?

 

As for a flag that only takes 0 and 1 values - however wide it is surely you don't need atomic access as it cannot be caught in a state where some of the 2/4/8 bytes are out of sync because only one of the 2/4/8/ is actually being used? But ideallly make it 8bit both to ensure atomicity and simply to use as little RAM as possible. In fact a bitfield cast over GPIOR0 may be even better. You can get eight bool flags that have very fast (and usually atomic) SBI/CBI access.

 

Anyway familiarize yourself with <stdint.h> then use it. (and that's not just for AVRs but for all CPUs) then you always pick an appropriate width variable and what's more, if you port the code to another CPU where sizeof(int) is different it still works. If you have a for() loop counting 0..49 then a uint8_t is appropriate. If you are working with circles in either direction so need -359..+359 then a int16_t is the one to use and so on. Of course you do probably want to think about "what's efficient for this CPU". A uint64_t on an AVR is a dog. On an AMD64 it's trivial, in fact it might be "natural".

Last Edited: Fri. Nov 7, 2014 - 10:17 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am using an Attiny45, 8Mhz internal(probably not accurate) prescaled or ck/4 times then prescaled 25 times more with TCNT1 overflowing.

In my notes i wrote TOV1 doesnt work in CTC1 mode with OCR1C.

So i tried it again and its a no go, the TOV1 flag will not set when OCR1C overflows Counter/Timer1 (TCNT1) if the CTC1 bit is set.

TOIE is enabled so the TOV1 flag can be set.

In the datasheet 2586Q–AVR–08/2013,chapter 12.3.8 pg.'93: 

 

This states TOV1 will set when TCNT1 matches OCR1C when in PWM mode. In normal mode it doesn't specifically say TOV1's flag will set when TCNT1 matches OCR1C. Although it would be cool if it did. 

I should probably use a different interrupt flag/mask to accomplish my tick.

Have OCR1A = OCR1C's value while in CTC1 mode? OCR1C does the overflow value/work, OCR1A piggy backs the count of Counter/Timer1 to OCR1C.

 

 

• Bit 2 – TOV1: Timer/Counter1 Overflow Flag
In normal mode (PWM1A=0 and PWM1B=0) the bit TOV1 is set (one) when an overflow occurs in Timer/Counter1.
The bit TOV1 is cleared by hardware when executing the corresponding interrupt handling vector. Alternatively,
TOV1 is cleared, after synchronization clock cycle, by writing a logical one to the flag.

 

In PWM mode (either PWM1A=1 or PWM1B=1) the bit TOV1 is set (one) when compare match occurs between
Timer/Counter1 and data value in OCR1C - Output Compare Register 1C.

 

When the SREG I-bit, and TOIE1 (Timer/Counter1 Overflow Interrupt Enable), and TOV1 are set (one), the
Timer/Counter1 Overflow interrupt is executed.

...

 

 

~GuitarDude

Last Edited: Fri. Nov 7, 2014 - 01:02 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

In my notes i wrote TOV1 doesnt work in CTC1 mode with OCR1C.

Sorry but why would expect an overflow interrupt in a compare mode of operation? Surely you switch the ISR() from OVF to a COMP one?

Last Edited: Fri. Nov 7, 2014 - 01:18 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Makes sense, i wouldn't have made that connection until after reading your comment.

My thought process was that the clear timer on compare match was causing an early overflow of the Counter/Timer1, when infact an overflow only occurs

when TCNT1 literally overflows from 255 to zero and the CTC only resets the clock so it never gets to overflow. Thank you again for your time and knowledge, another step forward. 

 

 

~GuitarDude

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

Most AVR8 datasheets have a "Table 15-8. Waveform Generation Mode Bit Description" for each timer.  Indeed, the Tiny25 family doesn't.  I always have to look at the table when doing timer work, for things just like being discussed.  From the table I was looking at for Mega48 family Timer0 (and generally applicable to AVR8 models with "normal" timers), "TOV Flag Set on" column shows "MAX" in CTC mode.  So indeed, generally on AVR8 timers in CTC mode the overflow interrupt won't fire.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.