combine 2 byte in 1 int

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

Hello all ,we have 2 char data (byte), and want to combine them to build a int (16 bit)

we write follow code but not works

can any body help me?

 

for example if we have 0x12  and 0x34   we want to build 0x1234 in flash_word_buffer

 

for(m=0;m<PAGE_SIZE;m++){

                flash_memory_word_buffer[m]=(flash_memory_buffer[2*m+1])|(flash_memory_buffer[2*m]<<4);

                }

 

Last Edited: Mon. Jun 24, 2019 - 08:26 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint8_t low, high;
uint16_t word;

low = 0x34;
high = 0x12;

word = (high << 8) | low;

Not sure why you have just "<<4" above? One lot of 8 bits needs to move 8 full bits to the left (to the high byte) to make room for the other 8 in the low byte.

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

clawson wrote:

word = (high << 8) | low;

This works, and it works because of integer promotion (without integer promotion you might reasonably wonder what happens if you shift an 8 bit value 8 times).

So the uint8_t high is promoted to int for the shift operation (with int being 16 bits on AVR), but note that the promotion is to 'int' ie. signed.

There is another issue here, although more of a theoretical issue than a practical issue.

It means the shift is conceptually being carried out on a signed type (essentially intt16_t) and there are some aspects of left shifting a signed type that are undefined within the C standard.

It's undefined if the value is negative, which can't be the case here so that's OK.

It's also undefined if the resulting value doesn't fit in the range of the signed type.

So if high = 0x80 (128) for example, after left shifting 8 times the resulting value is 128 * 256 = 32768, which doesn't fit in the range of int16_t (max positive value is 32767), and is therefore undefined beahviour.

The gcc compiler, however, I'm pretty sure says that it won't take advantage of the fact that these aspects of left shifting a signed type are undefined, so in practice it's not a problem.

But long story short, for this kind of thing, it's not a bad idea to add a cast

word = ((uint16_t)high << 8) | low;

By casting to uint16_t, on AVR with 16 bit ints, the value (before integer promotion) is now already of type unisgned int, which means the integer promotion does nothing and the shift is conceptually carried out on type unsigned int, which does not suffer from the undefined aspects of the signed type. 

 

 

 

 

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

Note that AVR-Libc has <avr/boot.h> with the documentation here:

 

https://www.nongnu.org/avr-libc/user-manual/group__avr__boot.html

 

That shows an example use of the API and for the 2 byte buffer stuffing that example code uses:

    for (i=0; i<SPM_PAGESIZE; i+=2)
    {
        // Set up little-endian word.
        uint16_t w = *buf++;
        w += (*buf++) << 8;
    
        boot_page_fill (page + i, w);
    }

which works very nicely.

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

Do you really need to copy the data, or do you just want to to access it both as a word and byte array?

If you just need dual access you can use union.

 

Either a union of a word array with a byte array, or an array of word/byte union.

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

I am 99.9% certain (from his other threads) that he is trying to do EXACTLY this:

    for (i=0; i<SPM_PAGESIZE; i+=2)
    {
        // Set up little-endian word.
        uint16_t w = *buf++;
        w += (*buf++) << 8;
    
        boot_page_fill (page + i, w);
    }

except that this is Codevision not GCC he's using so he doesn't have <avr/boot.h> but I suspect there is probably something similar? Either way the SPM buffer preparation basically involves stuffing 2 bytes at a time into Z and SPMing them into the temporary buffer before you then issue the "re-program page from buffer" command to finally commit it to flash. So the whole exercise is about doubling up pairs of bytes into 16 bit Z values.

 

If this is Codevision and you are going to use #asm for the actual SPM sequence anyway (in AVR-Libc it's also asm() sections) then perhaps the byte combining is easier done in the preparatory Asm anyway In fact maybe you can just coerce two vars onto R30 and R31 anyway something? (after all R30/R31 that make up Z are two separate 8 bit locations anyway)

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


clawson wrote:
except that this is Codevision not GCC he's using so he doesn't have <avr/boot.h> but I suspect there is probably something similar?

unsigned char __AddrToZByteToSPMCR_LPM(void flash *addr, unsigned char ctrl)
{
#asm
     ldd  r30,y+1
     ldd  r31,y+2
     ld   r22,y
     WR_SPMCR_REG_R22
     lpm
     mov  r30,r0
#endasm
}

...

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.