简体   繁体   中英

Bitwise shift of an array of chars in AVR C

Initially I need to send and receive serially some data. The packet length is 48 bits. For shorter packets (32 bits) I could do something like that:

unsigned long data=0x12345678;

for(i=0;i<32;i++){
  if(data & 0x80000000)
    setb_MOD;
  else
    clrb_MOD;
  data <<= 1;
}

This code compilation is really pleasing me:

        code<<=1;
  ac:   88 0f           add r24, r24
  ae:   99 1f           adc r25, r25
  b0:   aa 1f           adc r26, r26
  b2:   bb 1f           adc r27, r27
  b4:   80 93 63 00     sts 0x0063, r24
  b8:   90 93 64 00     sts 0x0064, r25
  bc:   a0 93 65 00     sts 0x0065, r26
  c0:   b0 93 66 00     sts 0x0066, r27

After I needed to extend the packet (to 48 bits) I faced with the need to shift an array:

unsigned char data[6]={0x12,0x34,0x56,0x78,0xAB,0xCD};

for(i=0;i<48;i++){
  if(data[5] & 0x80)
    setb_MOD;
  else
    clrb_MOD;
  for(j=5;j>0;j--){
    data[j]<<=1;
    if(data[j-1] & 0x80)
      data[j]+=1;
  }
  data[0] <<= 1;
}

The compilled code is slightly depends on an optimization settings but generally it is doing what I commanded in C:

        for(j=5;j>0;j--){
            code[j]<<=1;
  a8:   82 91           ld  r24, -Z
  aa:   88 0f           add r24, r24
  ac:   80 83           st  Z, r24
            if(code[j-1]&0x80)
  ae:   9e 91           ld  r25, -X
  b0:   97 fd           sbrc    r25, 7
  b2:   13 c0           rjmp    .+38        ; 0xda <__vector_2+0x74>
            clrb_MOD;
        }
        else{
            setb_MOD;
        }
        for(j=5;j>0;j--){
  b4:   80 e0           ldi r24, 0x00   ; 0
  b6:   a3 36           cpi r26, 0x63   ; 99
  b8:   b8 07           cpc r27, r24
  ba:   b1 f7           brne    .-20        ; 0xa8 <__vector_2+0x42>
            code[j]<<=1;
            if(code[j-1]&0x80)
                code[j]+=1;
        }

As you can see there is no obvious (for a human) solution to shift an array byte after byte.

I'd like to skip injection of inline assembler as I don't really manage this technique and I don't really understand how do I address C variables in Asm. Is there any alternatives?

If you know your input is less than 64 bits, you can do something like (assuming stdint.h is available, otherwise convert to unsigned long long , etc):

union BitShifter
{
   uint64_t u64;
   uint32_t u32[2];
   uint16_t u16[4];
   uint8_t  u8[8];
};

union BitShifter MyBitshifter;

MyBitShifter.u64 <<= 1;

The compiler should use the best instruction to accomplish that (probably two 32 bit shifts and some other logic to get the bit from one word to another. Of course, the backend might be lazy and do it as bytes...

Depending on the endianness of the AVR, you'll have to swizzle your bytes in the right order to the outgoing bit order correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM