Quote:
Originally Posted by Adam Y.
Well. Reading the manual it makes it pretty clear that if Im going to do any operations to certain registers that I either have to do it to all 32-bits or risk corrupting the register which would actually mean your example code wouldn't work unless you added a few extra zeros. Don't ask me why because its not applicable for any of their other peripherals that I have used. Only the CAN bus is like this.
Im not too worried about this happening because there is probably only going to be one compiler for this device for as long as I live.
|
... I just wanted you to be aware that portability issues exist.
The example code would work fine for the bit positions denoted, as there is no need to prepend zero's to a number. Certainly if you wanted to denote a bit position greater than 16, then it would be proper to add something like a 'UL' suffix to the constant.
Since you haven't mentioned which CPU this is for, and curiosity got the better of me, I used Google and turned up some example code for the TMS320 series.
TI's example code is inconsistent, some of it shows direct manipulation, others show using this shadow register workaround.
Finally, one example came clean with the following embedded comment:
Code:
/* Create a shadow register structure for the CAN control registers. This is
needed, since, only 32–bit access is allowed to these registers. 16–bit access
to these registers could potentially corrupt the register contents. This is
especially true while writing to a bit (or group of bits) among bits 16 – 31 */
struct ECAN_REGS ECanaShadow;
There's a better treatment in TI document SPRAA85A, if you aren't already aware of it.
... ok, so this is a workaround for the C compiler which may generate a 16 bit read/modify/write operation. It is an understandable optimization for the compiler, but a bit surprising that TI doesn't offer some native functionality to denote memory locations that are 32bit wide access
only.
Since optimization appears to be the problem, then my examples of |= and &= would similarly be optimized and create the same problem.
In any event, this seems to work ok:
Code:
struct foo {
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned many:3;
};
struct bar {
struct foo cat;
struct foo dog;
};
struct bar x;
struct bar y;
#define eCANWrite(a,b,c) y=x; y.a.b=c; x=y;
void test(void) {
eCANWrite(cat,many,1);
// produces the same code as
y=x;
y.cat.many = 1;
x=y;
}