The purpose of the subsequent use of the assignment operators OR and AND on registers

In C and C ++ code, particularly for embedded systems, I regularly come across assignments that take the following form:

A |= B; A &= B; 

Not sure if this is necessary, but here are registers A and B. See Example: http://processors.wiki.ti.com/index.php/Interrupt_Nesting_on_C28x#Example_Code The following lines will appear:

 IER |= 0x002; IER &= 0x002; 

However, these subsequent assignments seem identical to one assignment.

 A = B; 

Except that theoretically the first can be interrupted between two lines, but this does not play an important role in most codes.

Is there an advantage to using the former over the latter, or is there another difference that I don’t see?

+7
c embedded compound-assignment
source share
4 answers

Of course, a sequence of the following two commands:

 A |= 0x02; A &= 0x02; 

Equally:

 A = 0x02; 

If A not a variable, but a hardware register. In this case, you need to refer to the manual of the MCU / CPU (or reconfigured peripherals) to check why this sequence is required.


UPDATE

Variable vs Hardware register

In the comments above, the OP asked a question about how to distinguish between variables and registers.

This is pretty easy. All you have to do is look at the definition. Although a typical variable will be defined as something like:

 unsigned char A; 

A hardware register definition will look like this:

 #define A (*(volatile uint16_t *)(0x1234)) 

Here A defined as the value of the hardware register displayed at 0x1234 . Each microcontroller or processor has its own set of hardware registers, and it will vary not only between different types of architectures and models, but also between different manufacturers. If the source code is poorly documented, the only way to tell what exactly is a hardware register is to study the technical description of the hardware. In addition, some advanced architectures can map hardware registers from some peripherals to the address space of the processor, so you can access the hardware registers of external components in the same way.

Pay attention to the volatile keyword. From the wiki :

This keyword does not allow the optimizing compiler to optimize subsequent reads or writes, and thus it is incorrect to use an obsolete value or to omit records. Volatile values ​​mainly occur when accessing hardware (I / O with memory), where reading or writing to memory is used to communicate with peripheral devices and in streaming, where another thread can change the value.

+6
source share

In case the variable is a hardware register, which appears to be volatile . Writing bits followed by clearing bits is not the same as just writing a value.

Hardware registers do not always behave like simple RAM variables. This is not to say that a zero record is cleared a bit. In particular, flags and status registers may have certain conditions, such as "this flag is cleared by writing to a bit, and then read into the register." In other cases, the flags could be cleared just by reading the register.

This is very often used for users of flag / state registers for peripheral serial communication devices such as SPI or UART.

Also note that there is no guarantee that A = B; will result in one team. Rather, it leads to: "load B", "store B in A". If you need things to be atomic, you should always parse the code to see what actually happened.

+1
source share

Perhaps there are situations for hardware registers where certain bit sequences are necessary for “special” behavior, although it is difficult to understand what might be in this particular case.

Do not underestimate the likelihood that the code that you find on the Internet is nonsense, even if it is on the site of the chip supplier. Looking at the documentation, it seems that the author has read this:

enter image description here

and was confused by the reference to OR IER / AND IER - they activate and deactivate interrupts, but also makes the MOV IER instruction atomically. this is what the direct purpose will do.

There is a later example on the same page:

 IER |= M_INT2; IER &= MINT2; // Set "global" priority 

If the operands are different from each other; so maybe the author just has a generic template and sticks to it.

+1
source share

A | = 0x02; same as A = 0x02;

A & = 0x2 is still zero (assumption A = 0)

if both A and B are bytes. But there are cases when it is not equal to one byte, in this scenario all these operators have different properties.

I take an example of a 4 byte value.

A = 0x12345600

A | = 0x2 is 0x12345602 while A & = 0x2 is 0x12345600 and A = 0x2 is 0x00000002

-2
source share

All Articles