-3

I am writing a c program which has bit masking in it. What does the macros below define?? What all these operations <<, >>, | and & do??

1. #define SINE_PHASEREG_BASE (0x3 << 14) 
2. #define IOPORT_MODE_MUX_MASK (0x7 << 0) /*!< MUX bits mask */
3. #define IOPORT_MODE_MUX_D    (  3 << 0) /*!< MUX function D */
PRB
  • 25
  • 3
  • There is no language "embedded C". You can use your "normal" C textbook. And the code might invoke undefined behaviour for shifting signed integers. In general: never shift signed integers, use unsigned types. Best use fixed-width types. – too honest for this site Aug 17 '18 at 13:40

1 Answers1

1

These are C macros that perform bit shift operations. Numbers and hardware registers are represented by bits at the lowest level.

Some C basics:

  1. Macros are like functions, but instead of calling the function, the C preprocessor replacing the text which calls the macro, with the macro itself.

For example, I can create a simple C macro to add 1 to a number as follows:

#define ADD_ONE(x) ((x)+1)

And then I can compute the value of a number plus one as follows:

int I = ADD_ONE(5);

This will get replaced by the CPP preprocessor as:

int I = ((5)+1);

Then the compiler compiles this into the equivalent of:

int I = 6;

Notice that this "call" to ADD_ONE is done at compile time, not run time since ADD_ONE is a macro, and not a function.

Lines 1 to 3 are C macros, and they replace the text where they are called, prior to the code being compiled. Sometimes this is awesome, and sometimes it does things you don't expect. If you stick to the basics, they can be very useful, but experts can make code dance with these things.

  1. Numbers are represented by binary numbers, with the rightmost bit (the least significant bit aka b0) representing the value 0 if the bit is zero, or 1 if it is a one, or b0*(2^0).

Why the complicated way of expressing zero or one? Because, the other bits use the similar formula. Bit 1 represents either zero or two: b1*(2^1).

In general, bit n represents bn*(2^n).

So if you have an int x set to 5, then: X = 5=4+1 = 1*2^2+0*2^1+1*2^0 = 101 in binary.

  1. What's a bit shift operation?

It's an how computers shift bits left or right. Numerically, shifting the bits left is the same as multiplying by two, while shifting right is integer division by 2.

The operator << shifts bits left, and >> shifts bits right. The | operator is a bitwise OR operator, and & is a bitwise AND operator. For a great introduction to bitwise operators, refer to this excellent answer.

So if x is 5, then x<<1 is 1010b which equals = 8+0+2+0 = 10. The same as x*2.

Why should you care?

Because these macros are performing bit shift operations! So you need to understand how numbers are represented in binary to understand it.

Let's look at what those macros do!

SINE_CONTREG_BASE (0x1 << 13)

This takes the number one and shifts it left 13 times, so when this macro is used, it is replaced with the text (0x1 << 13) by CPP, and compiled as the constant value of 8196 (which is 2^0 * 2^13). So this macro is a way of documenting that the 14th bit of the SINE_CON register is important enough to have a macro which defines the value of this bit.

SINE_PHASEREG_BASE (0x3 << 14)

Similarly, this is used to represent a two-bit binary bit field in the SINE_PHASE register that can be found in bits 15 and 14 (notice that 3 is 11b).

IOPORT_MODE_MUX_MASK

This is saying that the IOPORT_MODE_MUX register is the first three bits in that register, and a MASK refers to a value, that can be used to extra those three bits using a bitwise AND operation on the value of the register. To set the values, one uses a bitwise OR operation to set the hardware bits in that register.

IOPORT_MODE_MUX_D

The IOPORT_MODE_MUX function D bits re the first two bits in that same register. You can use this macro to extract or set those two bits accordingly.

ScottK
  • 1,526
  • 1
  • 16
  • 23