|= or something else

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Freaks,

I have been looking through a few threads for a post regarding the use of

 

|=

to set a bit, or bits.

 

For example:

DDRB |= 0x0F;    //set lower 4 bits

I myself use this method rather frequently having learned it from this thread:

https://www.avrfreaks.net/forum/...

 

The post I am looking for IIRC discouraged using this.  I believe it was favoring some other method that I cannot remember, but the post had a very direct explanation of the method, and the reason it is a better option than the one above.

 

If someone knows of the thread/post I would appreciate it if you could point it out.  If anyone knows a better method of setting bit(s) I too would appreciate it.

 

This is a purely educational inquiry as I am always looking to better my crude progrmming skills.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can think of two situations not to use '|='.

 

1)  You are trying to clear a flag in a status register by writing a 1 to the bit.

     If you use the |=, you could end up writing a 1 to another status flag in a different bit

     (because it reads as a 1), thus clearing it when you didn't intend to.

 

2)  You use it to initialize a register, thinking the register is in the reset default state.

      But because the uC uses a bootloader that starts the ap, the register is not in the

      reset default state and so the device does not behave as you intended.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Chuck99 wrote:
1) You are trying to clear a flag in a status register by writing a 1 to the bit. If you use the |=, you could end up writing a 1 to another status flag in a different bit (because it reads as a 1), thus clearing it when you didn't intend to.

 

I believe that was what the post in the other thread I am looking for referred to.  The OP in that thread was clearing a flag or something and ended up mucking the works up.

 

Thanks Chuck!

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:
The post I am looking for IIRC discouraged using this.

Well, you use it when appropriate.  But thread after thread shows that many use it ... just because.  As I am fond of saying, "there must be a sale on |= in full-reel quantities.

 

I don't know if the links here

https://www.avrfreaks.net/commen...

are what you are thinking of.  the OP in that thread demonstrated [IMO/IME] the overuse of |=.  Take the links there and see if it is what you are recalling.

 

Chuck99 wrote:
I can think of two situations not to use '|='.

I'd add that "gratuitous" use can be problematical.  It takes more code words and cycles.  It introduces possible RMW effects.

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Lee,

The thread I am thinking of is rather recent...last week/10days or so.  But the thread you referenced to is on the same page as to what I was thinking

 

JIm

 

 

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you know what you want all of the bits to be (you often will), just use equals, then there is no foggy question or presumptions about the final result.  Of course, this might interfere with some other code elsewhere, in an arm-wrestling match.

Writing a one to get a zero (certain flag resets) is an odd case that hopefully doesn't cause extra confusion (such as if you were using a shadow variable).

Basically, there is no substitute for knowing what is going on in your program!

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:
The post I am looking for IIRC discouraged using this.  I believe it was favoring some other method that I cannot remember,

I think I know the one you're thinking of.

 

The alternative method advocated was to use a simple assignment - instead of the read-modify-write (RMW) of |= (or &=)

 

You use the RMW when you specifically want to affect only specific bits, and leave the others alone.

 

As noted, when you're setting-up a peripheral, you generally want to set the entire register to a known value - so just use a simple assignment.

 

EDIT

 

I think this is the one you're thinking of: Register Initialisation And The Dreaded "|="

 

(which I found by googlinging "full-reel quantities" theusch site=avrfreaks.net laugh  )

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Aug 15, 2018 - 07:01 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
You use the RMW when you specifically want to affect only specific bits, and leave the others alone.

This assumes that that the Read and/or Write operations do simply that - but, in the case of hardware registers, that ain't necessarily so:

 

  • In some cases, the mere act of reading or writing a bit has a specific effect - it may not result in that value actually being stored;
     
  • In some cases, read and write operations access different things.

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is yet another example of where it all went wrong for someone who used |=

 

https://www.avrfreaks.net/commen...

 

(Not to mention the many example where an xxIF is cleared by writing 1 and the last thing you want is an RMW!)

 

Just say "no".

Last Edited: Wed. Aug 15, 2018 - 08:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Just say "no".

Trouble is, it's not that simple:  in many cases, |= is the correct thing to do - so we can't just have a blanket ban.

 

As theusch said, you use it when appropriate.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff has the recent one and Andy gas another one I forgot about. Yes, that's it.

Thanks gents.

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jgmdesign wrote:
a better option

In summary, one is not universally better than the other - they are different, and one has to evaluate the pros & cons of each in the particular context at hand.

 

In some cases, one or the other is definitely wrong; in some, one may be advantageous; in some, it doesn't matter.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use assignment by default and the |=, &= and ^= stuff only if it's necessary to set/reset/toggle some bits selectively and preserve the others.

 

Besides, these operations are usually more expensive in terms of size and/or cycles than assignment, even when in range of sbi/cbi instructions, so why would you use them unless they are really needed?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

El Tangas wrote:
Besides, these operations are usually more expensive in terms of size and/or cycles than assignment

Does that still hold in CodeVision (is it?) with its REGISTER.bit extension ?

 

Or, more generally, where a struct/bitfield is mapped onto a register ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Wed. Aug 15, 2018 - 10:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, a good compiler will generate the most optimal code whatever the source code is. Most compilers do benefit if the source already has hints like bit fields, because it makes their optimization job easier.

 

In this case, the "best code" means to use the AVR assembly instructions sbi/cbi if you are changing a single bit and the I/O register is in range of these instructions (that is, the first 32 I/O addresses). This usually includes DDRx, PINx, PORTx, and some peripherals depending on AVR model, but for many peripherals it really doesn't make any difference if you use these hints or not.

 

edit: sometimes I have observed that if I use "compiler hints" on avr-gcc, the local code is not changed, but some remote part of the code becomes better optimized by some weird 2nd order effect. These compilers have become so sophisticated that it's not always easy to predict what code they will generate.

Last Edited: Wed. Aug 15, 2018 - 10:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
Does that still hold in CodeVision (is it?) with its REGISTER.bit extension ?

Yes, surely it holds.  As we are generally talking I/O registers here, then the compiler is forced to carry out the RMW operations.

 

But if you bring that up, a semi-related topic where the compilers break the rules; "1<<n Considered Harmful"...

https://www.avrfreaks.net/forum/...

I'm not making a suggestion one way or the other.  As an AVR8 app writer, indeed I want SBI/CBI for my PORTB work.

 

What I'm asking is whether a compiler that is supposedly playing by the rules of C; standard-conforming; similar -- is right to ignore explicit RMW "orders" from the programmer on a "volatile" item?

 

awneil wrote:
Or, more generally, where a struct/bitfield is mapped onto a register ?

Hmmm-- I'd have to see it in context.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

 

Chuck99 wrote:

I can think of two situations not to use '|='.

 

I'd add that "gratuitous" use can be problematical.  It takes more code words and cycles.  It introduces possible RMW effects.

 

Oh, yeah, using a stream of |= to set up peripheral subsystems at startup [as in the earlier link] assumes that you got to that point through a clean reset and all the I/O registers have their initial values.  What about the case(s) where the program counter ends up at/near 0 >>without<< a hard reset?  The code ran amok, for example -- could be a programming error, or a noise spike, or whatever.  Code caused a jump to 0 -- bootloader exit, perhaps, or uncaught interrupt vector.  and similar.  The point here is that it costs you nothing to be defensive, and in fact the code will be smaller and faster.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
awneil wrote:
Or, more generally, where a struct/bitfield is mapped onto a register ?
Hmmm-- I'd have to see it in context.

I do that very thing here:

 

https://www.avrfreaks.net/forum/...

 

The bottom line is that my:

tccr2_wgm20 = 1;

which is in effect:

pSFR->_TCCR2.bits._WGM20 = 1;

where a bitfield is used on the register will turn out as efficient as the

TCCR2.WGM20 = 1;

you might use in Codevision and it will use an SBI as long as the register is in range. If it isn't then as for Codevision (and anything else you might use to generate code) it's going to involve some kind of RMW with IN/op/OUT or LDS/op/STS depending on the location.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

|= is for the ones.

To be sure of the zeros, one needs &=.

One should not process a volatile register more than necessary.

If one has zeros and ones, the result is:

volreg=(volreg|ones) & ~zeros;

When initializing timers and the like,

the relevant module generally "owns" the entire register.

Simple assignment is usually the way to go.

 

Pin registers are more often split among modules.

In that case, a DDRx |= with interrupts disabled might be useful.

For PORTx, I generally avoid atomicity issues by assiging to PINx.

 

 

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be careful with the new bitfield-style structures used on ARM, Xmega, and "Xtiny" style CPUs.

 

https://www.avrfreaks.net/forum/...

 

 You really want

SERCOM5->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_ERROR;

rather than
    SERCOM5->USART.INTENCLR.bit.ERROR = 1;

   

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was going to mention that one, Westy. I was using a saml21 recently and had to stop and think about the implications of using .bit as it hides the implicit RMW.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's nasty. Perhaps the set/clear/toggle registers should just return zero on read instead of a copy of the main register. OTOH, returning a copy may be useful in some situations. Well, I guess we just need to be aware of that issue.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
Be careful with ...

Yet another example of "RMW side effect of |= considered harmful"? ;)  [I'm guessing the first method does an implicit RMW on the volatile]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The first does .reg which will read or write the register. The .bit is a bitfield where the compiler will do a mask on read and a RMW on write.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The .bit is a bitfield where the compiler will do a mask on read and a RMW on write.

Which of course is required if your instruction set doesn't have bitfield instructions that can operate on memory.   The AVR can modify SOME "memory bitfields" as long as they're only 1 bit long and located in the right part of the address space.  The SAMD chips can't do it at all.  The SAM3 chips MIGHT be able to do 1-bit fields anywhere in IO memory (using bit-banding), but the compiler doesn't know how to do it, and the Atmel .h files don't set it up manually.

 

// Write bitfield manually:  Rightmost bit position in b, size in s
temp = memory;
temp &= ~(((1<<s) - 1) << b);   // zero s bits
temp |= (newval & ((1<<s)-1)) << b;            // or in the one bits.
memory = temp;

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
The SAMD chips can't do it at all.
Isn't one of the things that sets Cortex M0+ apart from Cortex M0 "bit banding"? I thought this was supposed to be a way to make atomic it accesses?

 

This seems to confirm that ARM see it as one of the M0+ highlights:

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is an hardware feature that is optional and apparently was opted out on the SAMD chips. I came across it once while looking at some STM32 chips.