Author Topic: Microcontroller coding style for bit assignments  (Read 7632 times)

0 Members and 1 Guest are viewing this topic.

Offline tsmzTopic starter

  • Contributor
  • Posts: 30
Microcontroller coding style for bit assignments
« on: June 18, 2011, 08:24:37 pm »
There are quite a few coding styles for microcontrollers, especially when it comes to setting bits in registers. While they are all functionally and computationally equivalent (the compiler will most likely take care of replacing everything with constants), they do differ in style quite a lot.
I was wondering on the advantages and disadvantages of the various styles and what people use and why.

Style 1:
BITx definitions
Code: [Select]
#define BIT1 0x01
#define BIT2 0x02
#define BIT3 0x04
#define BIT4 0x08
#define BIT5 0x10
#define BIT6 0x20
#define BIT7 0x40
#define BIT8 0x80

// LED on Port1.5
#define MY_LED BIT6

// program code

P1OUT |= BIT3;
P1OUT ^= MY_LED;


Style 2:
Bitshifts
Code: [Select]
// LED on Port1.5
#define MY_LED 5

// program code
P1OUT |= (1<<3);
P1OUT ^= (1<<MY_LED);

Style 3:
Direct usage of constants
Code: [Select]
// LED on Port1.5
#define MY_LED 0x20;

// program code
P1OUT |= 0x04;
P1OUT ^= MY_LED;

Are there any other styles? What do you use and why? What should one use? I've seen several styles in code so far. I'll keep back my own preference until later to not give a preference from the start.
 

Offline Bored@Work

  • Super Contributor
  • ***
  • Posts: 3932
  • Country: 00
Re: Microcontroller coding style for bit assignments
« Reply #1 on: June 18, 2011, 09:00:11 pm »
I was wondering on the advantages and disadvantages of the various styles and what people use and why.

There aren't any technical advantage or disadvantages of the various styles.

The only reason to use a particular style is because it is the common style on the particular platform you are working on. The value in using the platform's typical style is in consistency on that platform. Which in turn contributes to maintainability.

If you see someone imposing his one personal style on every platform, instead of using the platform's normal style, you know you are dealing with one of those annoying jokers who have no clue and make a marginal issue (the style) a matter of life and death.
I delete PMs unread. If you have something to say, say it in public.
For all else: Profile->[Modify Profile]Buddies/Ignore List->Edit Ignore List
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 10181
  • Country: nz
Re: Microcontroller coding style for bit assignments
« Reply #2 on: June 19, 2011, 02:09:02 am »
i use style 2.

Only because when i learned avr's that's what all the examples used.
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4277
  • Country: us
Re: Microcontroller coding style for bit assignments
« Reply #3 on: June 19, 2011, 04:22:04 am »
fourth style: C bitfields:
Code: [Select]
struct ioport {
  bit0:1;
  bit1:1;
  bit2:1;
  bit3:1;
  bit4:1;
  bit5:1;
  bit6:1;
  bit7:1;
} *porta = (0x123);

porta->bit0 = 1;
porta->bit7 = 0;

Fifth style: non standard compiler extensions:
Code: [Select]
  PORTA.5 = 1;

// or

  bit statbit @ PORTA.4;
  statbit = 1;
 

In general, you're at the mercy of the manufacturer or compiler vendor for the constants in include files for the CPUs in use, and should stick with similar structures for bits within user defined structures/etc.  (although they may come with their own standards.)  This may be influenced by whether the particular CPU architecture has instructions that have arguments that are bit numbers or not.  PIC and AVR (and many microcontrollers) feature such instructions, but other CPUs (say, the x86 and MSP430) do not.

 

Offline tsmzTopic starter

  • Contributor
  • Posts: 30
Re: Microcontroller coding style for bit assignments
« Reply #4 on: June 19, 2011, 01:20:10 pm »
Compilers will calculate the value of the bitshift and write a constant in the code. So (1<<3) is really equivalent to 0x04. Styles 1 to 3 are equivalent, you won't find a compiler that messes up these things.
Style 4 is quite elegant, but I wouldn't be so sure if all compilers will do the right thing.

By the way, i = i + 1 and i += 1 are identical and will thus most likely be optimized in the same way by a decent compiler. Compilers are quite good today and will, if you don't mess up their configuration, compute constant expressions at compile time.

Personally, I use style 2 because I think it's the clearest way to express things. Also, numbering is absolutely obvious with this. Since the BITx definitions usually start with BIT1, but ports are numbered from 0 to y, PORT1.0 will actually be set by P1OUT |= BIT1, which I think is slightly ugly and confusing. It's much nicer and clearer to use P1OUT |= (1<<0), even if it doesn't look as obvious at first.
 

alm

  • Guest
Re: Microcontroller coding style for bit assignments
« Reply #5 on: June 19, 2011, 04:50:42 pm »
Agreed, any decent compiler will optimize arithmetic with only constants, like 1+1 or 1<<3. The issue with bitfields is that there is no efficient way to do something like PORTA |= (1<<3) & (1<<1), which is just a single OR.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4277
  • Country: us
Re: Microcontroller coding style for bit assignments
« Reply #6 on: June 20, 2011, 06:59:26 am »
In the bad old days, compilers might have generated better code for  "i += 1" than for "i = i+1"
In modern times, if your compiler does crap like this, it is time to look for another compiler.
(ditto if various forms of infinite loop take different times, or it doesn't compiler "v |= bit" to the appropriate single instruction when it ought to be able to do so.)
 

Offline codepinger

  • Newbie
  • Posts: 2
Re: Microcontroller coding style for bit assignments
« Reply #7 on: June 26, 2011, 11:13:58 pm »
Agreed, any decent compiler will optimize arithmetic with only constants, like 1+1 or 1<<3. The issue with bitfields is that there is no efficient way to do something like PORTA |= (1<<3) & (1<<1), which is just a single OR.

Correct me if I'm wrong, but (1<<3) & (1<<1) would equal zero, and thus no change to PORTA.
Perhaps the "&" should be a "|" ?
 

alm

  • Guest
Re: Microcontroller coding style for bit assignments
« Reply #8 on: June 27, 2011, 12:22:03 am »
You're of course correct. So a smart compiler may actually optimize it zero instructions ;).
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3867
  • Country: us
Re: Microcontroller coding style for bit assignments
« Reply #9 on: June 27, 2011, 08:13:53 pm »
Except that memory mapped IO should be declared volatile and the compiler will not modify any access to it.  The compiler will still do constant folding in the first three examples and generate the same code.  However, with bitfield access each statement always causes a write.  Even a 'no-op' statement that adds zero to a register shouldn't be optimized away.
 

alm

  • Guest
Re: Microcontroller coding style for bit assignments
« Reply #10 on: June 27, 2011, 09:03:41 pm »
The or statement will probably be optimized away, the load/store not.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4277
  • Country: us
Re: Microcontroller coding style for bit assignments
« Reply #11 on: June 28, 2011, 08:17:59 pm »
There are some anti-optimizations to watch out for.  For example, I often see code like:
Code: [Select]
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
Where sbi is defined as something so that these become ADCSRA |= 1<<ADPS2 and similar.  The compiler would hapily optimize these to single sbi instructions (Atmel AVR "set bit in IO register")  IF it were possible to do so.  But the compiler, and use of high-level expressions, end up hiding the fact that the registers being set aren't in the IO address space (I don't know if that's true of these particular registers, BTW.  It's just an example I pulled of a github page.)  So the "sbi" instruction becomes a load/or immediate/store sequence.  And since the register is volatile, it will do that separately for each statement.  What you expected to be three instructions (6 bytes) is now 9 instructions and 30 bytes.  Ouch!  Suddenly "ADCSRA |= (1<<ADPS2)+(1<<ADPS1)+(1<<ADPS0)" would have been better, and you probably should have used "ADCSRA = (1<<ADPS2)+(1<<ADPS1)+(1<<ADPS0)"

But it's hard to notice unless you're really paying attention!
 

alm

  • Guest
Re: Microcontroller coding style for bit assignments
« Reply #12 on: June 28, 2011, 09:41:29 pm »
I believe GCC will automatically convert FOO |= (1<<BAR) to sbi if it's a single bit and it's in the IO address space, so there's no point in using the sbi/cbi macros anymore (which is why they're deprecated).
 

Offline Mechatrommer

  • Super Contributor
  • ***
  • Posts: 11701
  • Country: my
  • reassessing directives...
Re: Microcontroller coding style for bit assignments
« Reply #13 on: June 29, 2011, 05:48:21 am »
beside compiler optimization in mind, how about maintainability? how about let say you finished up with your code for a particular uC, and then later decided to rewire the pin and change which pin to light up led etc, or the uC become obsolete and you are forced to use new pin/bit assignment on newer chip. with style 2, if you have hundreds of fix constant bit operations, changing all those is a certain pain in the arse (and in style 3 line P1OUT |= 0x04;). with #define (style 1), all you need is to change those definitions. but surely will not 100% applicable, you may as well forced to re-code all over again, depending on your particular case. but prevention in the first place could save you something later. my 2cnts.
Nature: Evolution and the Illusion of Randomness (Stephen L. Talbott): Its now indisputable that... organisms “expertise” contextualizes its genome, and its nonsense to say that these powers are under the control of the genome being contextualized - Barbara McClintock
 

Offline TheDirty

  • Frequent Contributor
  • **
  • Posts: 440
  • Country: ca
Re: Microcontroller coding style for bit assignments
« Reply #14 on: June 29, 2011, 12:46:42 pm »
beside compiler optimization in mind, how about maintainability? how about let say you finished up with your code for a particular uC, and then later decided to rewire the pin and change which pin to light up led etc, or the uC become obsolete and you are forced to use new pin/bit assignment on newer chip. with style 2, if you have hundreds of fix constant bit operations, changing all those is a certain pain in the arse (and in style 3 line P1OUT |= 0x04;). with #define (style 1), all you need is to change those definitions. but surely will not 100% applicable, you may as well forced to re-code all over again, depending on your particular case. but prevention in the first place could save you something later. my 2cnts.

Am I missing something?  All of these methods, except 4 use defines for the constants, so any of them would just require a change to the #define statements.

I generally like #2 since the numbers are more easily translated to the bits 0 thru 7 rather than 1 thru 8.  I work with 3 uC cores and flip code back and forth with method 1, 2, and 3 without issue.  I've avoided bitfields as I've worked with iffy compilers that just do not handle them properly.
Mark Higgins
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf