Another one with trouble doing shifting in 32bit variable.

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

My question is either How to make it work or Why doesn't it work.

My code:

    
uint32_t Lmin, Lmax, Vmin;

while(1){
    Lmax = (2UL<<16UL) | (0xAA<<8) | 0xA8;
    printf("Lmax: %02X",(Lmax>>16UL)&0xFF);
    printf(" %02X ",(Lmax>>8)&0xFF);
    printf("%02X\n", Lmax&0xFF);
}

Everytime, on the console, I get "Lmax : FF AA A8"

If I change the assigment to "Lmax = (2UL<<16UL);"
Then the output is correct: "Lmax : 02 AA A8", but as soon as I add (or OR) the 16bit variables, it stops working.

What is my mistake here?

Im using ATmega 128 RFA1 microcontroller, programming with AtmelStudio v6.2

Last Edited: Thu. Aug 14, 2014 - 07:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, my simple mind makes:

uint32_t Lmax = (2UL<<16UL) | (0xAA<<8) | 0xA8;  //0x0002AAA8
    printf("Lmax: %02X",(Lmax>>16UL)&0xFF);      //0x02
    printf(" %02X ",(Lmax>>8)&0xFF);             //0xAA
    printf("%02X\n", Lmax&0xFF);                 //0xA8

Untested. It should be simple enough to try on the PC. Or even on an AVR.

Note that printf() is 'expecting' an int argument. All of your argument expressions are uint32_t.

Since the AVR is little-endian, a single argument has no problem. printf() simply pulls the 'lowest' part of the uint32_t off the stack.

If you had a M68000 or other big-endian CPU, you would soon learn to get your syntax correct.

David.

p.s. having shouted my mouth off, I better try it!

Edit. I have just tried it and get FF AA A8.

You can get the expected behaviour in several ways. e.g.

    Lmax = (2UL << 16)|(0xAAuL << 8) | 0xA8;
    Lmax = (2UL << 16)|(uint16_t)(0xAA << 8) | 0xA8;

or by building the expression from uintN_t expressions.
I presume that (0xAA<<8 ) is an int expression. e.g. int16_t

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

david.prentice wrote:
... get the expected behaviour ...

Always helps to have the correct expectation in the first place!

:wink:

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

david.prentice wrote:
Edit. I have just tried it and get FF AA A8.

You can get the expected behaviour in several ways. e.g.

    Lmax = (2UL << 16)|(0xAAuL << 8) | 0xA8;
    Lmax = (2UL << 16)|(uint16_t)(0xAA << 8) | 0xA8;

or by building the expression from uintN_t expressions.
I presume that (0xAA<<8 ) is an int expression. e.g. int16_t

I don't see a difference with my code.
I want to have "02 AA A8" as an output, but I'm getting "FF AA A8".
I know there's a mistake somewhere, but ¿where?

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

Pretty obvious from the first post:

0xAA<<8

will be 0xffffaa00 when converted to a long on a machine with a 16-bit int, because 0xaa<<8 is an int expression that has the sign bit set. (assumptions: machine uses two's complement, long is 32 bits, and a left shift merely shifts bits without any overflow check)

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

Side note: You are building for a 24-bit output, fair enough.

But remember (and perhaps for a sanity check in this case--is it the assignment or the output that is fouling up?) that you can use % 08lX [without the space] for a long argument and output all four bytes in one go.

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

Or just run your code through the AS6 Simulator.

In practice, you build up a uint24_t or uint32_t from uint8_t 'expressions'. If you want to use literal constants, bear in mind that they default to 'int' (which is always signed)

David.

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

blargg wrote:
Pretty obvious from the first post:

0xAA<<8

will be 0xffffaa00 when converted to a long on a machine with a 16-bit int, because 0xaa<<8 is an int expression that has the sign bit set. (assumptions: machine uses two's complement, long is 32 bits, and a left shift merely shifts bits without any overflow check)

Aaaaaa!
Now I see it, thanks.

theusch wrote:
Side note: You are building for a 24-bit output, fair enough.

But remember (and perhaps for a sanity check in this case--is it the assignment or the output that is fouling up?) that you can use % 08lX [without the space] for a long argument and output all four bytes in one go.


I thought it was a printing error, that's why I used separate 'printf' calls. I just need a cast, but not on the first variable, but on the other two.

Thanks!