A bit lost on bit operations.

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

I understand and, or etc and bit shift right/left, but I don't understand the following line.

This is for a ATMEGA328

// wait for empty transmit buffer.

while( !(UCSR0A & (1<<UDRE0)))

UCSR0A is the status register.
UDRE0 is the data register empty.

Can someone please explain in long hand please.

Thanks Wallace

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

The same statement, but a little more obvious.

     while( (UCSR0A & (1<<UDRE0)) == 0) { 
         ;
     }

Read your data sheet. You cannot write to UDR until the UDRE bit is set (Usart Data Register Empty).

You are simply reading the UCSR0A register, masking out all the bits other than bit #5:

     while( (UCSR0A & 0b00100000) == 0) { 
         ;
     }

It is always wiser to test against 0. You could of course do:

     while( (UCSR0A & 0b00100000) != 0b00100000) { 
         ;
     }

But it is prone to typos, and probably slightly less efficient. It is certainly less readable to me.

David.

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

So you understand that UCSR0A & (1<<UDRE0) masks out the URDE0 bit?

So you understand that anything non-zero is true, so if the UDRE0 bit is set the above expression can be interpreted as "true", and if it is not set it can be interpreted as "false")?

So you understand that ! is the logical negation operator?

So you understand that a while-loop repeats as long as the expression is "true" (the purists will say "as long as the expression is non.zero")?

What is there left to understand?!

I.e. loop as long as the data register is not empty. As the comment says, BTW.

I don't have longer hands than these, unless you pose a more specific question.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

I gathered all the & info, thanks.

This make sense 0b00100000
or 0x20 which is the UDRE0 bit

I'm still stuck with 1<<UDRE0

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

But you said that

Quote:

I understand and, or etc and bit shift right/left

but now
Quote:

I'm still stuck with 1<<UDRE0

That IS a bit shit left!

Are you drunk? I'll waste no more time here until you can pose a proper question (or sober up).

EDIT: Or maybe you where lame enough not to look up how UDRE0 is defined in the header file? I won't do it for you but I bet it is

#define UDRE0 5

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Hi Johan. A bit of soap in the mouth helps with those naughty words.
Back to the beginning.

while( !(UCSR0A & (1<<UDRE0))) 

I'm looking to see if the UDRE0 is empty. Why does the original author left shift UDRE0 one bit? What am I missing?

What is wrong with

while(UDRE0 |= 0){}

(PS It's late here and I check back tomorrow.)

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

Quote:

Why does the original author left shift UDRE0 one bit? What am I missing?

He's not. He is left-shifting a 1. The UDRE0 part is how many steps he is left shifting. (UDRE0 is defined as the bit number of the UDRE0 bit in the UCSR0A register, i.e. bit number 5, counting from the least significant bit which has bit number 0.)

Quote:

What is wrong with

while(UDRE0 |= 0){}


As I said. UDRE0 is defined to "5", so your version would actually be

while(5 |= 0){} 

which of-course makes no sense at all.

1. Go over to the Tutorials forum and read the tutorial on "Bit manipulation".
2. Get your textbook on C out and read through the part on shift operations again.
3. Locate the part-specific header file(s) for your AVR model, and find the #define for UDRE0.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

So you have:

while( !(UCSR0A & (1<<UDRE0)))

Lets break it into pieces.

1) 1<<UDRE0
As you said you understand bit shifting. This left shifts the 1 (as Johan said), not the UDRE0 (as you said), by some unknown number of steps(UDRE0 steps). If check the header file for your m328(as Johan said) you'll find

#define UDRE0 5

So your unknown number becomes 5 and left shifting the 1 by 5 (1<<5) becomes 0b00100000 (as David said)

2) UCSR0A & (1<<UDRE0)
As you said you understand and, or etc. Lets assume UCSR0A = 0b10101010 (UDRE0 is 1 so the Data Register is empty). You only care for the 5th bit (counting from LSB to MSB) 0b10101010. So if you AND it with whatever you found at (1) which is 0b00100000 you get:

0b10101010
0b00100000
----------
0b00100000 <-this.

Now lets assume UCSR0A = 0b01010101 (UDRE0 is 0 so the Data Register is not empty). Following the same procedure you get:

0b01010101
0b00100000
----------
0b00000000 <-this.

As David said:

Quote:
You are simply reading the UCSR0A register, masking out all the bits other than bit #5:

3) while( !(UCSR0A & (1<<UDRE0)))
while !(whatever you found at (2)). If (2) results 0b00000000 which means Data Register not empty the !((2)) will result !(0) or "true". As Johan said:
Quote:
So you understand that a while-loop repeats as long as the expression is "true" (the purists will say "as long as the expression is non.zero")

Or as David said:
Quote:

while( (UCSR0A & 0b00100000) == 0) {
    ;
}

It is always wiser to test against 0. You could of course do:

while( (UCSR0A & 0b00100000) != 0b00100000) {
    ;
}

But it is prone to typos, and probably slightly less efficient. It is certainly less readable to me.


My point is:
-Before you say that you understand something be sure that you do.
-Pay attention to whatever someone replys to your questions (especially those guys with a lot of stars :D ). Usually it takes no more than 2-3 replies to get the job done (assuming you asked the right question)
-AVRfreaks tutorials and Google are really good friends of yours. Use them.

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

That shift notation for bit set and clear is SUPPOSED to be readable and maintainable. It also appears to cause lots of grief to new programmers. The idea is to see if the Data Ready Empty bit is zero. Atmel says it is 'bit 6'. This is the bit number, not the bit mask. The mask is 0100 0000. So the boolean expression testing this bit is UCSR0A & 0b01000000. This evaluates to zero or non zero. Problem is that the non zero value isnt in the bottom bit. So we put that boolean expression in a statement with an assignment to a boolean variable, like ok=((UCSR0A & 0b01000000)==0); So ok is either zero or non zero, and since nonzero in the 1 bit is where we look for boolean true, we can put this test for Data Transmit Ready bit in a while loop and it loops while it is not ready, and kicks out when it is ready. The (1 << UDRE0) converts the bit number to a bit mask that can be ANDED or ORED into the status register. Phew. Still not very simple.

Imagecraft compiler user

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

Thanks for the input. I have finally got it. I'm from a Clipper, Basic and Delphi background and c is quite different.

I'm not familiar with looking in header or include files as they are not required in the above languages.

So to summarize. There are 4 aspects to the statement

while( !(UCSR0A & (1<<UDRE0)))

1 what you are trying to achieve ?
2 Understanding the ATMEGA architecture
3 Understanding the language c
4 the compilers interpretation if the c statement. (the part I missed)

Normally, when you load a program like MS Word, it is installed and your files are stored in documents. You never have to go into the \ProgramFiles\Word\BIN\Etc file to see how it works !!

It just works.

I have several books on c programming but now it looks like I need a bit more info.

I guess the question is ? who and when was the h file created for the USART and did they ever create a manual for it ? It looks to me like c has just evolved over the years and you just pick it up as you blunder along.

I finally found the info after a call to a friend.

It's in c:\Arduino\hardware\tools\avr\lib\avr5\iom328p.h

There at the bottom is

#define UDRIE0 5

Thanks all, I've learned a bit today.

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

Quote:

3 Understanding the language c
4 the compilers interpretation if the c statement. (the part I missed)

This is one point, not two. The C language standard determines how a compiler should interpret the code.

Quote:

It looks to me like c has just evolved over the years

While the language has evolved some since its inception in the 1970s, it has actually been quite stable. Without having any hard evidence I'd sat that it has been more stable than most contemporary languages. E.g. C#/.NET has definitively changed more in its 10 year history than C in its close to 40 years.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:
who and when was the h file created for the USART and did they ever create a manual for it ?
If you mean the .h for the chip (there is no .h specifically for the USART), the manual is (mostly) the AVR datasheet. There are a few things that are compiler dependent, these would be in the compiler's manual.
Quote:
It looks to me like c has just evolved over the years
But the things in the .h file are not part of C, they are C definitions and declarations that are written in C, not the definition of the C language.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
I finally found the info after a call to a friend.

It's in c:\Arduino\hardware\tools\avr\lib\avr5\iom328p.h

There at the bottom is

#define UDRIE0 5


My apologies. I went straight from (1<<UDRE0) to (1<<5). i.e. bit#5 in UCSRA (the Status Register)
UDRIE0 is the 'InterruptEnable' bit for 'UsartDataRegisterEmpty' which happens to be bit #5 in a different special fnction register (UCSRB)

The clumsiness of the C syntax for handling individual bits is mirrored in all other languages. In fact a language like Basic probably does not have hex constants or shift operators.

Some other microcontroller vendors use a differnt style e.g.

UCSR0Bbits.UDRIE0 = 1;     // PIC uses this style

Atmel does not use this style. It has many advantages, but has drawbacks too.

If you feel like generating a completely new set of header files for every AVR, you could use it too.

David.

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

Maybe it would help to mention that the expression:

(1 << UDRE0)

is being handled by the compiler (or more accurately, the pre-processor), and not by the MCU at run time.

As two constant values are involved, the compiler resolves it at compile time.

An alternative would be:

_BV(UDRE0)
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's a pity the .h files was not written this way.

UCSR0Bbits.UDRIE0 = 1;     // PIC uses this style 

This format fits in with other programming languages, easy to use and very readable.

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

Nothing stops you doing it. I wrote a thread about this in GCC forum and someone picked up on it and did the full set for the 48/88/168/328 family. If you have the patience you could do the same.

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

As I said earlier, there are many advantages.
It goes seriously wrong with multiple bit assignments.
You run out of structure and field names quite quickly.
Most but not all compilers will generate efficient code.
You cause great confusion with all the existing source code that follows the conventional style.

But you can always generate your own header files that follow this style.
There is at least one other AVR user that will join you.

It is a historical artifact. A bit like driving on the left hand side of the road. Yes, you can drive on the right, but there may be conflict with other road users, road signs etc.

David.

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

marsheng wrote:
I'm from a Clipper, ... background
At long last! I am no longer alone :lol: Started with Autumn 86 myself. Still support a couple of legacy 5.2e apps, although have migrated most to Harbour/MiniGUI.

Cheers,

Ross

Ross McKenzie, Melbourne Australia

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

valusoft wrote:
marsheng wrote:
I'm from a Clipper, ... background
At long last! I am no longer alone :lol:

DBase III/IV and then the new world of Clipper - I remember it well :D