This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I've just concluded the development of an application using the IAR IDE.
I included the io430g2553.h header file to write the code using a bitfield approach.
Hereafer a couple of examples of definition I used to access individual bits in the MSP registers:
#define SWITCH_IN P2IN_bit.P6 // P2.6
#define AUDIO_AMPLIFIER_ENABLE_OUT P2OUT_bit.P7 // P2.7
I'm now starting the migration to the Code Composer Studio IDE (I'm new with this IDE).
I only found the msp4302553.h header file: it seems it isn't possible to access the registers using a bit field approach.
Hereafter my questions:
Thanks in advance
Hi Flavio,
i have been working with MSP430 since almost two years, and most of the time, i rarely see codes using bitfields, and also it is not really recommended in C:
http://c-faq.com/struct/bitfields.html
So unfortunatelly, i am afraid if you want to migrate to CCS, you have to modify your code by using the bitmasks definitions in the header file. The good thing is that it is also readable as with the bitfield.
Thank you for the fast reply, so I will start using bitmasks.
:-)
I heard that it's not recommended using macros to perform this task, e.g.:
#define setbit(A,B) ((A)|=(B))
#define clearbit(A,B) ((A)&=~(B))
#define testbit(A,B) ((A)&(B))
#define togglebit(A,B) ((A)^=(B))
Is it true?
So, what is the best approach between the code A and the code B?
Code A
setbit(P1OUT, BIT0)
setbit(P2OUT, (BIT0|BIT1))
Code B
P1OUT |= BIT0;
P2OUT |= (BIT0|BIT1);
Thanks
Flavio
Hi Flavio,
i think it should be ok to use the macros above, because you are using it correctly with the brackets. i can't think of any cases that using the macros would lead to an unexpected result (again because you are doing it with the brackets). However the example codes given for MSP430 usually use the second approach of "Code B". But in the end, i think this just a matter of programming taste :)
Use of bitfields is rather ineffective. They are usually use don hardware registers which are declared volatile. So the compiler has to generate one access per bit assignment.
Normal & and | accesss to a register can be grouped and are way more effective.
Also, in many cases it is unimportant whether e.g. P2.6 returns 1 or 0x40. It's either zero or not.
So in most cases, P2IN_Bit.P6 can be translated into (P2IN&BIT6). In some (few) cases, it shoul dbe better translated into ((P2IN&BIT6) >>6). Which is what the compiler generates for the bitfield anyway.
It has the additional advantage that this is an rvalue. You cannot do SWITCH_IN = 1 anymore, which would have been allowed with the bitfield.
For outputs, things are a bit more complex:
#define AUDIO_AMPLIFIER_ENABLE_OUT(x) P2OUT= (P2OUT&~BIT7)|(x?BIT7:0)
This too isn't an lvalue but more or less what the compiler generates for the bitfields. Well, if you do the change, you'll get an error for each usage in teh code, whcih makes it easy to fix :)
For a new project, I'd suggest using
#define AUDIO_AMPLIFIER_ENABLE (P2OUT|=BIT7)
#define AUDIO_AMPLIFIER_DISABLE (P2OUT &= ~BIT7)
Yes, you can more or less auto-generate bitfield definitions for all used registers. For one single project/MSP type, this is likely more effort than it's worth.Flavio Renga said:Is there any procedure to use the already developed code "as it is"?
That's the better approach.Flavio Renga said:Should I modify ALL the code using the "standard" syntax?
See above. Mainly because of its inefficiency. But in some cases, ther emight be side-effects on registers which cannot be avoided using the bitfields. Or are obfuscated by using bitfields ("I didn't touch this bit, why is it gone?" - because access to an other member of the bitfield caused a read/write operation that in turn cleared other bits)Flavio Renga said:There is any reason to avoid this the bitfield syntax?
In most cases, especially for user-defined bitfields, this may be true. However, as explaind above, when bitfields are more than plain memory access, things can become even less readable. And cause bugs that are difficult to track down then.Flavio Renga said:(I started years ago using bitfield approach because in my opinion the code is more readable)
I put down this macro to assign a predefined value to a subset of bits in a register:
#define ASSIGN_BIT_MASK(REG,VAL,MASK) ((REG)=(VAL)|(REG)&(~(MASK)))
For instance:
ASSIGN_BIT_MASK(TA0CTL, MC_0, MC1|MC0);
Is there any smarter expression?
Hi Flavio,
Flavio Renga said:I put down this macro to assign a predefined value to a subset of bits in a register:
#define ASSIGN_BIT_MASK(REG,VAL,MASK) ((REG)=(VAL)|(REG)&(~(MASK)))
i would do it in this way:
#define ASSIGN_BIT_MASK(REG,VAL,MASK) do {REG &= ~(MASK); REG |= VAL;} while(0);
it is more readable, and i think your implementation is not 100% correct (CMIIW), it should be maybe like this:
#define ASSIGN_BIT_MASK(REG,VAL,MASK) ((REG)=(VAL)| ((REG)&(~(MASK)))
the reason is that i think the compiler will read it left to right, so without the brackets, your macro above will works:
- VAL | REG
- result above & (~(MASK))
and i don't think this is what you want. so i would do it my way above, since after compilation it will produce the same code, but much more readable (not too many brackets).
Please without the ';' at the end.lhend said:i would do it in this way:
#define ASSIGN_BIT_MASK(REG,VAL,MASK) do {REG &= ~(MASK); REG |= VAL;} while(0);
Yes, it would always clear out the masked values at the end rather than clearing the original content and or'ing the new value in.lhend said:without the brackets, your macro above will works
However, I'd prefer this version (with the proper brackets) of your proposal because your marco does two read-modify-wite acceses to the register. It does not require any intermediate storage in a processor register for doing the math, but two read/write operations may cause unwanted side-effects and leave the hardware register in a potentially dangerous intermediate state for five clock cycles.
I much prefer using enums and inlined functions than macros for register access, like so:
#include "msp430g2452.h"
#include <stdint.h>
typedef enum {
SWITCH_IN = BIT6,
AUDIO_AMPLIFIER_ENABLE_OUT = BIT7
} PIN_Def;
static inline void set_pin(uint8_t volatile * const port, PIN_Def pin) {
*port |= pin;
}
static inline void clear_pin(uint8_t volatile * const port, PIN_Def pin) {
*port &= ~pin;
}
static inline uint8_t test_pin(uint8_t volatile * const port, PIN_Def pin) {
return *port & pin;
}
static inline void toggle_pin(uint8_t volatile * const port, PIN_Def pin) {
*port ^= pin;
}
int main( void )
{
set_pin(&P2OUT, SWITCH_IN);
clear_pin(&P2OUT, AUDIO_AMPLIFIER_ENABLE_OUT);
if(test_pin(&P2OUT, SWITCH_IN))
toggle_pin(&P2OUT, AUDIO_AMPLIFIER_ENABLE_OUT);
}
And this is the generated assembly (from IAR):
main:
BIS.B #0x40, &0x29
BIC.B #0x80, &0x29
BIT.B #0x40, &0x29
JNC ??main_0
XOR.B #0x80, &0x29
Not only does it do away with all the macro precedence counting, it enforces static type checking on the pins, all with zero code overhead.
Anyway just my two-cents ;)
Tony
Yes, enums are a nice thing if you use them right (as types). I use them all the time for status return values and similar things.TonyKao said:I much prefer using enums and inlined functions than macros for register access, like so:
At least MSPGCC 3.2.3 allows it without even a warning. I just tried with two different enum types and also int or constant parameters. All are accepted. So forget about the typechecking.
And if it comes to multiple-bit values, the set and clear functions won't work too and a more complex 'change' function is needed.
However, an inlined function, if supported by the compiler as expected (which isn't guaranteed), will ensure that even more complex, multi-instruction operations won't break an if/else, just like the do/while in the macro.
So while it is not necessarily better, it is at least equally good. :)
Folks,
looks like everyone's all clear on the usage of bitfield vs. bitmask, as well as macros/inline definitions. I just want to point out that the ULP Advisor tool also offers to check and flag any bitfield usage and recommends switching to bitmask. Here's the wiki page for this rule, ULP15.1
http://processors.wiki.ti.com/index.php/Compiler/diagnostic_messages/MSP430/1546
This thread has quite a bit of valuable discussion on the topic, so please feel free to contribute to the wiki page if you can see any improvements we can make there.
And for those of you who are GCC users, ULP Advisor is currently provided with CCS & IAR, but soon it will come out with a stand-alone version that supports GCC projects.
Regards,
Dung
Teh 'Why is this happening' info is incomplete.
The compiler could combine several bitfield accesss into one instruction - if it weren't on a hardware register that is declared volatile.
It's not the bitfield per se, it's the volatile target that makes bitfield operations ineffective, because the compiler is forced to access the target as many times and in exactly the order the source code does it. Imagine a multi-bit field in a hardware register would first be cleared and then be set. This would result in an intermediate state that is possibly hazardous. OTOH, on some registers it is absolutely necessary to set or clear certain bits simultaneously. In a volatile target, the compiler can do so only if both operations are in the same assignment. Impossible on bitfields.
On self-defined bitfields on memory structures, these problems do not apply - unless the structure is used in main as well as in an ISR and therefore must be declared volatile.
Well, I also find it more readable to have all settings on a hardware register in one line, but that's personal preference. :)
**Attention** This is a public forum