Register Initialisation And The Dreaded "|="

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

Where does the horrible practice of using "|=" to set initial values come from?

 

Somewhere out there must be a highly ranked webpage which tells people that it's the right way (hint: it isn't) and other sites are slavishly pointing to it.

 

I would love to track down the source of this advice.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

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

Brian Fairchild wrote:

Where does the horrible practice of using "|=" to set initial values come from?

 

…  the right way … it isn't ...

 

 

Whilst I understand the point you are making - that you shouldn't rely on things being zero at startup - I'm not completely convinced. The system is either working as it is supposed to be and registers are initialised to known values or you've got bigger things to worry about than register bits being set when they shouldn't be.

 

I've seen it in lots of places and it'll be the result of the heavy use of libraries and copy-and-pasted code. People aren't sure what's being set up elsewhere in 'opaque' code whilst they're learning and it follows from project to project as boilerplate. Things get complicated fast with microcontroller development and the last thing you think of doing is going back to code that's always done what you expect it to!

 

 

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

There is a style that places each bitfield on a separate line.   And sometimes as separate statements.

Personally,  I prefer to put the whole lot in a single assignment statement.

 

I think that newcomers see the separate line style and are impressed with the individual explanatory comment field.

They also note that the Reset value of most SFRs is 0.    So the separate line / statement style is harmless (albeit long-winded)

 

They do not realise that the Arduino initialises several SFRs before it gets to setup().

So Timer SFRs have already been initialised for PWM and hold non-zero values.

 

Any subsequent assumption that you can use |= fails miserably.

 

As a general rule,  you initialise a peripheral from an unknown state to a known state.   You make no assumptions about it being called from reset or from any other point in a program.

 

There is nothing wrong with the long-winded style.  Just make sure that you assign 0 to the SFR before you start.

I find long sequences difficult to read.   I like to see concise functions that will fit in a screen window.   But hey-ho,  it is individual choice.

 

David.

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

I learned about |= from Deans Tutorial:

 

So let's say I have a byte foo that is initialized to 0:

unsigned char foo = 0;

To set bit 0 in foo and then store the result back into foo:

foo = foo | 0x01;

The OR operation is used between the variable that we want to change and a constant which is called a BIT MASK or simply the MASK. The mask is used to identify the bit that we want changed.

Remember that we write the constants in hexadecimal because it's shorter than writing it in binary. It is assumed that the reader knows how to convert back and forth between hex and binary. ;-)

Usually, though the statement is made shorter in real programming practice to take advantage of C's compound assignment:

foo |= 0x01;

This is equivalent to the statement above.

Now in Deans example he is using a variable, but in my early days of C I used it for setting up registers until it bit me(no pun) in the bum.  I do not use this practice anymore.

 

@Brian

For those new to C, what would you consider the 'proper' way to initialize a register?

 

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

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"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, RSLogix user

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

jgmdesign wrote:

@Brian

For those new to C, what would you consider the 'proper' way to initialize a register?

 

Brute force, using Atmels assigned bit names...

 

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART0 Mode: Asynchronous
// USART Baud Rate: 9600
	UCSR0A=(0<<RXC0) | (0<<TXC0) | (0<<UDRE0) | (0<<FE0) | (0<<DOR0) | (0<<UPE0) | (0<<U2X0) | (0<<MPCM0);
	UCSR0B=(1<<RXCIE0) | (1<<TXCIE0) | (0<<UDRIE0) | (1<<RXEN0) | (1<<TXEN0) | (0<<UCSZ02) | (0<<RXB80) | (0<<TXB80);
	UCSR0C=(0<<UMSEL01) | (0<<UMSEL00) | (0<<UPM01) | (0<<UPM00) | (0<<USBS0) | (1<<UCSZ01) | (1<<UCSZ00) | (0<<UCPOL0);
	UBRR0H=(((XTAL/16/BAUD)-1) >> 8);
	UBRR0L=(((XTAL/16/BAUD)-1) & 0xFF);

 

Now, of course, I'm lucky in that Codevision generates that all for me but the principle remains.

 

In the example above UCSR0A gets set to 0x00 but I'd still rather do that, in code that gets executed just once so no speed penalty, than rely on anything that happens automagically.

 

And the joy of having in the above format is that should I need to change anything I can find it and do it easily knowing that nothing bad will happen.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

Last Edited: Mon. Jul 2, 2018 - 01:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And thinking about it, it would be trivial to make 'init.c' and 'init.h' for the popular chips that set every register to a known state in the above style.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

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

Brian Fairchild wrote:

in code that gets executed just once so no speed penalty, than rely on anything that happens automagically.

 

How many instructions does that generate and how much flash program storage does that require?

 

Brian Fairchild wrote:

And thinking about it, it would be trivial to make 'init.c' and 'init.h' for the popular chips that set every register to a known state in the above style.

 

That's the beauty of computer programming, you're free to create those features yourself - if you advocate everyone-does-it-this-way-because, then for the vast majority of people, that's just going to be more automagic.

 

The processor is hard-wired to initialise things to zero as appropriate on power up (although some of the weird registers get a one here or there I believe). It isn't magic, it's defined, documented behaviour, in exactly the same way you can rely on the ADD instruction to add 2 numbers together. I think it's fine to have "best practice", but we don't need to look down upon those who don't always follow it. They're doing fine too.

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

MalphasWats wrote:

How many instructions does that generate and how much flash program storage does that require?

 

Well, from working production code for a '328 it generates either...

 

*) an LDI/STS sequence of 6 bytes per register or

*) an LDI/OUT sequence of 4 bytes per register

 

...and in the code looked at a total of 184 bytes

 

MalphasWats wrote:

They're doing fine too.

 

Given the several posts a week from people with problems which turn out to be the inappropraite use of '|=' I might dispute that statement wink

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

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

Brian Fairchild wrote:

MalphasWats wrote:

How many instructions does that generate and how much flash program storage does that require?

 

...and in the code looked at a total of 184 bytes

 

 

That's more than a whole level map in one of my attiny games! ;)

 

Brian Fairchild wrote:

MalphasWats wrote:

They're doing fine too.

 

Given the several posts a week from people with problems which turn out to be the inappropraite use of '|=' I might dispute that statement wink

 

Forum burnout is definitely a major issue with these sorts of communities. I've asked some pretty 'dumb' questions here and got patient, thoughtful responses for which I am eternally grateful. I asked a question on StackExchange about a circuit a week or so ago and although I ultimately got some helpful responses, I also got shouted at because the circuit diagram I'd drawn out using their own built-in tools wasn't good enough. I ended up re-drawing it 3 times and still got moaned at!.

 

If you have a few minutes to link some of the posts people have made on this subject, I could write up your responses here and make a little tutorial post for us to link to in the future?

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

MalphasWats wrote:
Whilst I understand the point you are making - that you shouldn't rely on things being zero at startup - I'm not completely convinced. The system is either working as it is supposed to be and registers are initialised to known values or you've got bigger things to worry about than register bits being set when they shouldn't be.

IMO you have it backwards.  In consideration here are the mainstream C toolchains that support AVR8 targets.  Yes, after a clean reset the I/O registers will have the default values as shown  in the datasheet.  Yes, most of these are zero.  I've commented extensively on this before -- "must be a sale on |= in full-reel quantities".

 

Side excursion before considering the startup situation:  a very commonly-seen "problem" has to do with ADMUX.  People just keep |= and wonder why the same channel value is reported.

 

My "reasons":

1)  The toolchain may put you back to program counter of zero for reasons other than a clean chip reset.  For GCC and others, an uncaught interrupt vector has this default action.

2)  Your code may run amok and end up at program counter of zero without the benefit of any reset action.  "Should" it happen?  Well, no.  Only for angels will it >>never<< happen.  Consider the idiots you work with on your team...

3) ([or maybe 1a) ]  A bootloader might jump to zero instead of doing a clean reset.

4)  It isn't efficient on an AVR8.  Often the sequence will be five to seven words.  Save working register-LDS-logic-STS-restore.  Some, on legacy devices or low registers, might be IN/ORI/OUT along with any needed save/restore.  The assignment will be an LDI and OUT/STS.  Repeat those extra words n times, and when your Mega48 app gets full you'd be looking for those dozens of words.

5)  [or maybe 4a) ] The above introduces possible RMW side effects.  While usually not a problem at init time, it mst always be considered in any app that does ISR work.

6)  The operations in 4) take extra cycles.  Again, not usually a problem.

 

I can't really give the finale a number, but certainly as a thought exercise:  Given the reasons above, what is >>gained<< with |= even when carefully examined and determined to be "clean"?  I guess an analogy would be driving to the store and taking a longer route.

 

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

MalphasWats wrote:
If you have a few minutes to link some of the posts people have made on this subject,

Sheesh, I've done that over and over again over the years.  I'll find a few.  Most recent will probably be nothing more than echoes of my post above, and quotes and links to past.

 

Hey, you are free to code however you like.  You can advocate |= all you want; it is your right.  But many of us here with hard knocks experience will point out that even if you have the right it isn't right.

 

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

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

https://www.avrfreaks.net/commen... (where cmartin >>advocated<< |= )

https://www.avrfreaks.net/commen... (where the code shown from OP did multiple |= an the ADC setup register, compounding the bad effects I listed earlier)

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

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

https://www.avrfreaks.net/commen... (where SuperMechaCow voted for your "always zero anyway" reasoning)

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

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

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

https://www.avrfreaks.net/commen... (where Mardec opined "May I ask why you do not use a |= in this case? I thought this was necessary for almost all register adjustments?")

 

theusch wrote:
Besides, we got full-reel quantities of both left and right parenthesis from the distributor when they were on sale. Buying them in quantity like that makes their use virtually free.
Just because I liked that one.  ;)  https://www.avrfreaks.net/forum/...

 

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

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

https://www.avrfreaks.net/commen... (where Cliff also echoed my sentiments, admittedly in an Arduino-related thread)

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

https://www.avrfreaks.net/commen... (where we find out that Dean Camera is Typhoid Mary/Patient Zero)  [I noticed that in one or two of the other threads linked above]

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

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

 

 

The above:

-- just from a single 'Freak -- me.

-- from the past five years or so.

-- all pretty much echo the same opinions.

-- ...and most present the common problems of timer and ADC setup where they get burnt.

-- all from a single forum search result.

 

I'm sure I could find more discussions, reaching back further in Forum history.  But why?  That would be like using |= .

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.

Last Edited: Mon. Jul 2, 2018 - 02:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
even if you have the right it isn't [necessarily] right.

 

"All things are permissible - but not all things are beneficial"

 

 

 

 

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: 1

If you structure your program.

And some blocks use some IO's, you might not init all your IO's one place, but each block init it's own IO use and therefore can't touch other, then |= is the correct way to go.

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

theusch wrote:
from a single 'Freak ... all pretty much echo the same opinions

Well, they would - wouldn't they?

 

Wouldn't want to be called, "inconsistent" - would we?

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

sparrow2 wrote:
And some blocks use some IO's, you might not init all your IO's one place, but each block init it's own IO use and therefore can't touch other, then |= is the correct way to go.

Now, I'm not saying that |= is never appropriate.  "Seldom" IME--once peripheral subsystems are set up, the usually stay in the same configuration forever.

 

But given my list earlier, why would |= be the "correct way to go"?  Straight assignment avoids the listed pitfalls, and "costs" nothing, and "saves" as well.  Why takt the longer route to the store, just because it was recommended by someone?

 

LOL -- maybe sparrow2 is Patient Zero.

 

 

 

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

|= says to read and write.

If more than one one bit is on the right, that is what is going to happen.

Why bother with the read?

 

BTW I no longer use long strings of << expressions.

I use a variadic macro that is basically multi-argument _BV.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

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

awneil wrote:
Wouldn't want to be called, "inconsistent" - would we?

"Insanity is defined as doing the same thing over and over again, and expecting a different result."

 

Remember that I'm responding to the apparent defense of |= as a panacea.  But sparrow2 is a real guru so I must be missing something.

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

YAATAICM£5

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

During initialization, I like to have separate init functions for various IO needs. For example init_leds() and init_swiltches() and init_powercontrol(). Since none knows anything about the other, I try to keep each one self contained. Hence, more read-writes and code than the most compact implementation. Thus, I use the dreaded "|=" and "&= ~" during initialization.

 

That is simply my preference for a relatively complex program. In my mind, its a step toward a class-like structure without actually writing C++. That said, it is a conscious decision in which I (think that I) know the pros and cons, and can make a reasonably informed choice.

 

Until the program writer has enough knowledge to make the informed choice for himself or herself, or for quick knock-together test programs or short class assignments, doing the bulk "=" is certainly the recommended strategy. And, WRITTEN WITHOUT MAGIC NUMBERS! If you have to:

 

#define PORTBINIT ((1<<PB0)|(1<<PB3)|(1<<PB4))
...
PORTB = PORTBINIT;

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

I'm of the opinion you should use |= only if you need to, because an assignment elsewhere has prevented using =.

I've seen too many of these types fail because someone forgot that other bits were not zeroed.

var = value;  leaves no ambiguity as to what the resultant value is (for inspection purposes). 

In fewer cases, this direct assignment leads to wiping out previously configured bits, but at least it is readily apparent that it will be happening. 

You have to pick the default style you want and be aware of all the implications.

 

It's explained at 1:00

https://www.youtube.com/watch?v=Bo759np9-nM

 

 

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

MalphasWats wrote:
YAATAICM£5

???  Something to do with Yateem films?  You asked for links.  I gave them to you.  So this is the tutorial?

MalphasWats wrote:
If you have a few minutes to link some of the posts people have made on this subject, I could write up your responses here and make a little tutorial post for us to link to in the future?

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

avrcandies wrote:
In fewer cases, this direct assignment leads to wiping out previously configured bits

In all cases, it results in wiping out over-writing previously configured bits!

 

The questions is: whether that matters or not?

  • If it does matter, use |= (or &=);
  • If it does not matter, just do the assignment;
  • If you're not sure, then you need to find out!

 

 

EDIT

 

"over-writing"

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: Mon. Jul 2, 2018 - 05:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ka7ehk wrote:
During initialization, I like to have separate init functions for various IO needs. For example init_leds() and init_swiltches() and init_powercontrol(). Since none knows anything about the other, I try to keep each one self contained. Hence, more read-writes and code than the most compact implementation. Thus, I use the dreaded "|=" and "&= ~" during initialization.
Makes sense to me.

It does mean that one has to keep track of what owns what bits of what registers.

It also raises the issue of what one wants to happen before the first init function.

What to do with unowned bits?

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

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

MalphasWats wrote:
YAATAICM£5

theusch wrote:
???

"You Are [AT] And I Claim My £5" ?

 

EDIT

 

https://www.urbandictionary.com/define.php?term=AICM

 

https://en.wikipedia.org/wiki/Lobby_Lud

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: Mon. Jul 2, 2018 - 05:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In fewer cases, this direct assignment leads to wiping out previously configured bits

In all cases, it results in wiping out over-writing previously configured bits!

What I mean is that it is rarer (fewer cases) for someone to use a direct assignment ( myvar = myvalue;) and mistakenly wipe out previously configured bits--we don't see that crop up as much.  Most likely because the direct assignment is very intentional; you have to think exactly what you want for each bit.

 

 

I've seen it in lots of places and it'll be the result of the heavy use of libraries and copy-and-pasted code. People aren't sure what's being set up elsewhere in 'opaque' code whilst they're learning

Sad, but probably true 

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

Last Edited: Mon. Jul 2, 2018 - 05:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You Are All Trolls And I Claim My Five Pounds.

No-one is arguing that |= is the only way it should be done, just that people mostly do it as a result of lack of experience or for a particular reason and yet people are getting shirty about it.

It's so easy to forget that people do this stuff for different reasons - if you're making a flashing LED buttonhole, it doesn't matter how you initialise your registers. If you're designing a controller for a nuclear reactor waste release valve, you probably shouldn't be asking for help on the internet.

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

skeeve wrote:
It also raises the issue of what one wants to happen before the first init function.

It is fine to have separate init functions.  But then IMO >>there should be an explicit "clear" before entering these functions<<.

 

Now, let's explore Jim's approach a bit more.

 

-- I might well have separate init functions for e.g. USART(s) and ADC and timers and such.  IN NEARLY ALL CASES THAT WILL BE THE ONLY TIME IN THE APP THAT THOSE SETUP REGISTERS WILL BE CHANGED.  So if you "know" htat, why not use the better straight-assignment approach.

 

-- One common re-setup peripheral for me on AVR8 is SPI.  Different peripherals on the SPI bus may operate in different SPI modes and/or speeds.  The setup changes often during operation.  I use straight assignment for each.  Why wouldn't that be the best way?  The SPI can only be configured one way at a time.

 

-- For nearly all my timer work, while I might re-configure it, it only again has one possible configuration at a time.  I probably have a few cases over the years with e.g. changing COM on a second channel or similar.  But rare IME.

 

-- I guess for much PORT work the Bit Manipulation 101 applies.  Remember that RMW considerations still apply.  For initial setup and DDR in general, nearly always straight assignment is more appropriate.  The caveat is the manipulation most often used to turn a single bit on/off, where |= and &=~ are used. 
IME single-bit is most common, and the compilers generate the CBI/SBI.  Now that has its own evangelical discussion on whether the toolchains are violating the letter of the law re that volatile operation. "(1<<n) considered harmful" https://www.avrfreaks.net/forum/...

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

MalphasWats wrote:
It's so easy to forget that people do this stuff for different reasons 

The trouble starts when people are doing stuff without any reason - ie, without thinking about it.

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

MalphasWats wrote:
If you're designing a controller for a nuclear reactor waste release valve, you probably shouldn't be asking for help on the internet.
Why not?

UI questions might be useful.

The latest and greatest algorithm for something might only be available on the internet.

Some answers are easier to check than they are to get.

Algorithms, numerical and otherwise come to mind.

What is the Intel assembly instruction that ….?

 

"What is a release valve?" would indicate trouble.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

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

I worked in safety critical software development. You don't ask questions on the internet and you don't use the latest & greatest anything ;) You use only the approved assembly instructions, as detailed in the design documents, chosen by serious faced engineers years before you even started working there and you account for bits changed in registers by stray cosmic radiation.

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

Of course there are the too many who don't use either " |= "  or " = "...they completely forget to make various settings at all (why is ,my uart not sending, why doesn't the LED light up when I set PORTB=0xFF?).

 

Safety critical systems at least try to prevent a single "programming oops" from crashing the whole system.  Lots of cross checks, recovery modes, votings, and other fun times, as well as enforced system/program design & coding practices. 

 

 

 

 

 

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

So are people who are in favor of initializing ALL the bits in a register (even if they have 'correct' power-on values) also in favor of setting ALL the (many) registers on the more modern chips (Xmega, ARM)?

ASF sorta does that:

    get_default_config(&config_struct);
    config_struct->foo  bit;
    set_config(config_struct);

And I don't like it; tends to expand to a lot more code than is actually needed.

 

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

Are there none of the AVR compilers that have the 3 byte pointer structure Keil had for the 8051 ?

where the 3th byte indicate what kind of data the pointer point at (so everything can be pointed at with the same kind of pointer)

 

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

Why bother when the all-knowing compiler knows what a pointer points to?

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

westfw wrote:

So are people who are in favor of initializing ALL the bits in a register (even if they have 'correct' power-on values) also in favor of setting ALL the (many) registers on the more modern chips (Xmega, ARM)?

ASF sorta does that:

    get_default_config(&config_struct);
    config_struct->foo  bit;
    set_config(config_struct);

And I don't like it; tends to expand to a lot more code than is actually needed.

 

Whether you "like" one style or another is irrelevant.   What matters is that "it works".

 

Most people would expect a "peripheral_init()" function to work at all times.  i.e. ensure every SFR is correct.

If you are going to rely on default SFR values,  you would need a separate "peripheral_init_from_vigin()" for every peripheral.

Yes,  those would be smaller.

 

This subject generally comes up because Arduino users do not realise that certain peripherals are configured before setup().    So you can NOT rely on the default reset (virginal state) values.

 

David.

Last Edited: Mon. Jul 2, 2018 - 10:21 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess in "true" C you have to be able to calculate the distance of any two pointers, but that don't naturally is the case for a AVR. 

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

 

 

To ( |= )  |  (~( |= ))......that is the question.....

 

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

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"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, RSLogix user

Last Edited: Tue. Jul 3, 2018 - 01:29 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

+1 smiley

Letting the smoke out since 1978

 

 

 

 

Last Edited: Tue. Jul 3, 2018 - 10:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In some cases using the |= makes sense for the init. For example the Xmega and the new series 0 and 1 chips must have the TX pin configured as an output.

 

Because I always forget and spend some time trying to figure out why the USART is not working I now add a line to configure the pin as part of the USART init.

 

// Make  sure that the TX pin is an output in the init sequence
void USARTC0_init(void)
{
	PORTC_DIR |= (1<<PIN3_bp);		//Set TX pin for output

	USARTC0.BAUDCTRLB = (uint8_t) ((F_CPU / (16UL * baud_USARTC0)) - 1) >>8;	// baud register high
	USARTC0.BAUDCTRLA = (uint8_t) (F_CPU / (16UL * baud_USARTC0)) - 1;			// baud register low
  	USARTC0.CTRLB = (1<<USART_RXEN_bp | 1<<USART_TXEN_bp ); 					// enable receive and transmit
}

in fact in some of the drivers I now have in ASM for the series 0 and 1 chips I set both RX and TX pins to the correct direction in the USART init, just in case I have them wrong during the start up init.

;USART0_INIT - Initialize USART0
USART0_INIT:
	lds		temp, PORTA_DIR
	ori		temp, PIN0_bm		; Set TXD pin for output
	andi	temp, ~ PIN1_bm		; Set RXD pin for input
	sts		PORTA_DIR, temp

	ldi		temp,low ((64*fosc)/(16*baud_0)-1)
	ldi		temp1,high ((64*fosc)/(16*baud_0)-1)

SETBAUD_0:
	sts		USART0_BAUD,temp		;baud register low
	sts		USART0_BAUD + 1, temp1	;baud register high
	ldi		temp, USART_RXEN_bm | USART_TXEN_bm
	sts		USART0_CTRLB, temp		;enable bits
	ret  

 

I should do the same for the C drivers I guess.

 

aaarrrghh the infamous tab strikes again.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

Last Edited: Tue. Jul 3, 2018 - 01:46 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 

aaarrrghh the infamous tab strikes again.

Time for a refreshing debate break.

 

 

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

and just to complicate the issue there are processors that have separate instructions for setting, clearing and toggling multiple bits,
eg. the AVR32 range where you can do ;
.... ovrc = x; (where 'x' is a 32-bit pattern, and it will clear all the bits in the target GPIO register where the bit in 'x' is 1)
.... ovrt = x; (willl toggle all the bits in the target GPIO register where the bit in 'x' is 1) and
.... ovrs = x; (will set all the bits in the target GPIO register where the bit in 'x' is 1)
The compiler will usually convert |= and &= ~ statements into the appropriate multiple-bit set/clear instructions.

personally., i like to use the = technique because i know exactly what the peripheral registers are set to when i do my initialisation, or if i later encounter an error that is best handled by a brute-force reset of a peripheral, (eg TWI)

Last Edited: Tue. Jul 3, 2018 - 12:13 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MalphasWats wrote:

... and you account for bits changed in registers by stray cosmic radiation.

 

I'm interested to know how you do that.

 

David

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

DAFlippers wrote:
MalphasWats wrote:

... and you account for bits changed in registers by stray cosmic radiation.

 

I'm interested to know how you do that.

I expect he means that a simple assignment (=) will fix previous cosmic ray issues.

"Demons after money.
Whatever happened to the still beating heart of a virgin?
No one has any standards anymore." -- Giles

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

Only if the cosmic rays haven't flipped the associated bits in flash.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

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

Only if the cosmic rays haven't flipped the associated bits in flash.

You can use multiple processor & have some type of voting, but of course that is fairly complex.  seems this is an entire subject

https://en.wikipedia.org/wiki/Soft_error

 

https://spectrum.ieee.org/computing/hardware/how-to-kill-a-supercomputer-dirty-power-cosmic-rays-and-bad-solder

 

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: 1

Brian Fairchild wrote:
Where does the horrible practice of using "|=" to set initial values come from?

Isn't it a bit silly to call perfectly normal C syntax for OR-ing a var "horrible".

 

If you don't like standard syntax you can always write your own custom macro's and hide them in some header file 5 layers deep so nowbody can find them.

 

If you do not like C at all  you can write your programs in asm or ADA instead of C.

Apparently there are also Forth implementations for some uC's, but I do not know if the AVR's are supported.

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

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

I fear you missed his point. He was calling the use of |= rather than plain = horrible. On the whole (for first time initialisation) it is.

 

I've lost count of the threads we've had here where a bootloader or more often the Arduino library code has already done some peripheral initialisation so the user is then caught out by only ORing additional bits into a register they don't realise is not at default. Far "safer" to start with a direct assignment then OR into that later if there's something that could not be set during the initial assignment.

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

Another common complaint is, "my code works once the first time after reset, but then won't run again unless I reset it"

 

This also often comes down to things not being properly initialised when it comes to the start of the second iteration ...

 

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's some "typical" initialization code from the Arduino core...

 

  sbi(*_ucsrb, RXEN0);
  sbi(*_ucsrb, TXEN0);
  sbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);

 

:-(

 

 

Last Edited: Wed. Jul 4, 2018 - 11:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I designed hardware for an application that had to detect and failsafe when exposed to all sorts of interference not encountered in normal day to day activities.  I looked at Radhard components but the price was horrendous so I went for dual processor solution with custom comms channel and external hardware.  All sorts of BITE to detect any anomalies.  No interrupts (aside from NMI to halt CPU by other CPU) because that made the code impossible to evaluate.  RAM soft faults you can detect and fix but detecting and fixing soft faults in an internal register would be impossible because that register could contain the status of an IO line or a timer value and you can't know what it should be.  

 

That's why I asked the question as things move on and I am curious.

 

David

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

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...