### You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Interesting code structure.

 April 17, 2011 by Hexorg Hey guys, I've been researching some piece of code I need, and I found this German guy who has very interesting ways of doing the bit-wise arithmetic, so I decided to post this tricks here for your help and comments. First of all, many of you already use this one, but not all: `````` PORTB |= _BV(PB1); // instead of PORTB |= (1>>PB1); `````` Reason for this I found in avr-libc: "The bit shift is performed by the compiler which then inserts the result into the code. Thus, there is no run-time overhead when using _BV()." Second, is a way to do "LED = 1" to make just one LED turn on or off: `````` struct bits { char b0:1; char b1:1; char b2:1; char b3:1; char b4:1; char b5:1; char b6:1; char b7:1; } __attribute__((__packed__)); #define PORTA_0 ((*(volatile struct bits*)&PORTA).b0) #define PORTA_1 ((*(volatile struct bits*)&PORTA).b1) #define PORTA_2 ((*(volatile struct bits*)&PORTA).b2) #define PORTA_3 ((*(volatile struct bits*)&PORTA).b3) #define PORTA_4 ((*(volatile struct bits*)&PORTA).b4) #define PORTA_5 ((*(volatile struct bits*)&PORTA).b5) #define PORTA_6 ((*(volatile struct bits*)&PORTA).b6) #define PORTA_7 ((*(volatile struct bits*)&PORTA).b7) `````` After that, if your led is on, say PORTA, 3rd bit, you do #define LED PORTA_3, and now you can assign 1 or 0 to LED to turn it off or on. And third, is a way to convert 32-bit integer into four 8-bit integers, without getting confused with bit-shifts: `````` typedef union conver_ { unsigned long dw; unsigned int w[2]; unsigned char b[4]; } CONVERTDW; typedef union conver2_ { unsigned int w; unsigned char b[2]; } CONVERTW; `````` From what I understand, a "union" means that all the variables in this "structure" have the same beginning address, so if you write 0xAADD into CONVERTW.w, then CONVERTW.b[0] will be 0xDD, and CONVERTW.b[1] will be 0xAA _BV() is a compiler macro defined as #define _BV(bit) (1<<(bit)) in so it results in exactly the same code as (1<>12) { } `````` which is not that complex, once you learn what and how it works. But doesn't this look much easier when you do ``````struct gameFlags { char b0:1; char b1:1; char b2:1; // ... // char isNewEnemy:1; char isGamePaused:1; char isNewGame:1; char isAbleToFly:1; char isDead:1; } __attribute__((__packed__)); struct GameFlags status; if (status.isNewGame) { } `````` And according to bretm, the latter not only looks better but is more efficient: "The most important thing about it, to me, is that the avr-gcc compiler generates smaller and faster machine code for complicated bit-manipulating operations than when I write the equivalent manipulations in C using shifts and ANDs and ORs. The optimizations it comes up with are pretty surprising." it gets you around architecture issues Not really. Since the C language specification doesn't completely specify how bit-field packing is actually implemented, you're still at the mercy of the compiler. The order of bits within a storage unit and the behavior of bit-fields that straddle storage units are implementation-defined. Luckily for us, avr-gcc for 8-bit processors implements this in a desirable way. I would never do ``````if (status & (1<<12))>>12) { } `````` in the first place. I would instead do ``````if ((status >> 12) & 1) { } `````` so that the "12" is only specified in one place. And according to bretm, the latter not only looks better but is more efficient It's not a blanket statement--sometimes the compiler can optimize both ways just as well. If you want to maximize performance you have to look at how the compiler optimizes each case. But in my experience so far I've seen better code come out of the packed bit-field approach than the shift-and-mask approach because some types of shifts produce inefficient shifting loops. Thanks Hexorg, I see now there is a performance advantage to using bitfields if your bitmap is greater than 8 bits in size. The mask/shift method loads all the bytes in the field while the bitfield struct loads only the byte containing the target bit. Hey bretm, Can you give an example of setting more than one pin at once in the same port using a "volatile bit field". I don't think I understand yet how you would do that. Thanks, Paul The mask/shift doesn't necessarily move all the bits, or even any bit. For example in the case where you test the 12th bit using shifts in C and use it in an if statement, the compiler optimizes it into a single bit test against the upper byte, with no shifting at all. Example of setting multiple bits...setting 4 bits to write to the LCD in 4-bit mode, assuming the four bits are PB5 through PB2: ``````struct bits2b4 { char : 2; // padding char data : 4; }; #define LCD_DATA (((volatile struct bits2b4*)&PORTB)->data) `````` For bit manulipation of I/O pins I like the shift/mask method a little better. One thing I try to accomidate in my code is that I may have to move pins around at PCB layout and I prefer to make that as simple as possible. Ideally to swap pins only two simple defines would require change in the code even if ports are different. I like the multiple bit method using bitfields but I may stay clear of it for I/O because it is not flexible concerning pin assignment. For static bitmaps, particularily those with more than 8 bits, there is a clear performance advantage to using bitfields and use seems easier too. I like the ability to set or read the bit value in a simple assign statement like NEW_GAME=1 or x=NEW_GAME vs shift/mask SET(NEW_GAME) or x=READ(NEW_GAME). This is a good thread, thank you all. The shifting/masking is easy for me, which is why I usually use it. For new programmers, not so much. Shifting and masking seems hard for people to understand. But so is casting to a volatile pointer and dereferencing a structure pointer, so it's a lose-lose situation for hobby programmers in this regard. If avr-libc defined the macros with this functionality in mind in the first place, things could have been much nicer. Instead of "ADIE" being equal to a bit position within the ADCSR register, it could have been a direct volatile reference to that bit field within that register, and you could just say "ADIE = 1" to enable the ADC interrupt. But using shifts and masks doesn't really make the code any easier to maintain, compared to bit fields. In the 4-bit data example above, to set bits PB5 through PB2 would require doing ``````PORTB = (PORTB & ((1<

## Post a Reply

Please log in to post a reply.

 Did you know that you can adjust most wire strippers to make it easier to strip insulation faster? Learn more...