1. OCAU Merchandise is available! Check out our 20th Anniversary Mugs, Classic Logo Shirts and much more! Discussion in this thread.
    Dismiss Notice

Packing Bytes (unsigned char) to Integers

Discussion in 'Programming & Software Development' started by LINUX, Oct 10, 2010.

  1. LINUX

    LINUX Member

    Joined:
    Sep 18, 2001
    Messages:
    3,062
    Location:
    Dudley, Newcastle
    Background: I'm currently playing around with AVRs and am working on a simple 1-bit DAC programme.

    Problem: I've got 16-bit signed .wav data written to an SD card (no filesystem, dd'ed from a .wav to /dev/sdb) and need to find a way to read the data off the SD card (a byte-oriented operation done in 512-byte blocks) and convert sections of 2-bytes back into signed ints.

    I'm guessing that it can all be done with bit shifts and logical operations but don't quite know enough about how the bytes are packed together on the SD card to be confident about an implementation.

    A first guess would be something like:

    Code:
    x[2] = {byte1, byte2} //from SD card
    int y = x[0]<<8 | x[1]; //Swapping x[0]/[1] if needed for edianness.
    
    Anyone able to say if the above will possibly work?
     
  2. dakiller

    dakiller Resistance is futile

    Joined:
    Jun 27, 2001
    Messages:
    8,591
    Location:
    3844
    That is a valid method, though I've found that it is faster to cast the array directly into an integer

    Code:
    x[2] = {lsb, msb}; //from SD card
    int y = *(int*)x;
    
     
  3. OP
    OP
    LINUX

    LINUX Member

    Joined:
    Sep 18, 2001
    Messages:
    3,062
    Location:
    Dudley, Newcastle
    Well, it's working, but it sounds like absolute shit :p. here's a screenshot of a captured waveform:


    Click to view full size!


    Quantisation error? What quantisation error? :p. Looks like it could do with a LPF with a much lower cutoff frequency :p. Anyway, it's been a really cool experiment :).
     
  4. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,059
    Location:
    Sleepwithyourdadelaide
    Wrote both versions for a PIC24 in the C30 compiler as it uses a similar instruction set to the AVR both are 16bit as far as I know, anyway here are the results.

    Here is the unoptimised disassembly of both methods, can see that casting to an int is slightly faster.

    Code:
    52:                int function(char a, char b){
     00288  FA0006     lnk #0x6
     0028A  984740     mov.b 0x0000,[0x001c+4]
     0028C  984751     mov.b 0x0002,[0x001c+5]
    53:                
    54:                char x[2] = {a, b}; //from SD card
     0028E  E8800E     inc2.w 0x001c,0x0000
     00290  9040CE     mov.b [0x001c+4],0x0002
     00292  784801     mov.b 0x0002,[0x0000]
     00294  E8800E     inc2.w 0x001c,0x0000
     00296  9040DE     mov.b [0x001c+5],0x0002
     00298  984011     mov.b 0x0002,[0x0000+1]
    55:                int y = x[0]<<8 | x[1]; //Swapping x[0]/[1] if needed for edianness.
     0029A  E8800E     inc2.w 0x001c,0x0000
     0029C  784010     mov.b [0x0000],0x0000
     0029E  FB0000     se 0x0000,0x0000
     002A0  DD00C8     sl 0x0000,#8,0x0002
     002A2  E8800E     inc2.w 0x001c,0x0000
     002A4  904010     mov.b [0x0000+1],0x0000
     002A6  FB0000     se 0x0000,0x0000
     002A8  708F00     ior.w 0x0002,0x0000,[0x001c]
    56:                return y;
     002AA  78001E     mov.w [0x001c],0x0000
    57:                }
     002AC  FA8000     ulnk
     002AE  060000     return
    
    Code:
    52:                int function(char a, char b){
     00288  FA0006     lnk #0x6
     0028A  984740     mov.b 0x0000,[0x001c+4]
     0028C  984751     mov.b 0x0002,[0x001c+5]
    53:                
    54:                char x[2] = {a, b}; //from SD card
     0028E  E8800E     inc2.w 0x001c,0x0000
     00290  9040CE     mov.b [0x001c+4],0x0002
     00292  784801     mov.b 0x0002,[0x0000]
     00294  E8800E     inc2.w 0x001c,0x0000
     00296  9040DE     mov.b [0x001c+5],0x0002
     00298  984011     mov.b 0x0002,[0x0000+1]
    55:                int y = *(int*)x;
     0029A  E8800E     inc2.w 0x001c,0x0000
     0029C  780F10     mov.w [0x0000],[0x001c]
    56:                return y;
     0029E  78001E     mov.w [0x001c],0x0000
    57:                }
     002A0  FA8000     ulnk
     002A2  060000     return
    58:                
    
    But if you turn on optimisations they are both the same, the bitshift just does two shifts and an OR where as the cast takes advantage of the 16bit word size.

    Code:
    52:                int function(char a, char b){
     00288  FA0002     lnk #0x2
    53:                
    54:                char x[2] = {a, b}; //from SD card
     0028A  9FFFE0     mov.b 0x0000,[0x001e-2]
     0028C  9FFFF1     mov.b 0x0002,[0x001e-1]
    55:                int y = *(int*)x;
     0028E  97B87F     mov.w [0x001e-2],0x0000
    56:                return y;
    57:                }
     00290  FA8000     ulnk
     00292  060000     return
    58:                
    
    Code:
     00288  DD0048     sl 0x0000,#8,0x0000
     0028A  FB0081     se 0x0002,0x0002
     0028C  700001     ior.w 0x0000,0x0002,0x0000
    53:                
    54:                char x[2] = {a, b} ;//from SD card
    55:                int y = x[0]<<8 | x[1]; //Swapping x[0]/[1] if needed for edianness.
    56:                return y;
    57:                }
     0028E  060000     return
    
    so the faster method will come down to what optimisations the compiler can take advantage of on the CPU, both will work fine though.

    edit: I think mov.w is a 2 cycle instruction so the bitshift might be ever so slightly faster.
     
    Last edited: Oct 11, 2010
  5. dakiller

    dakiller Resistance is futile

    Joined:
    Jun 27, 2001
    Messages:
    8,591
    Location:
    3844
    When I used it, I was using gcc (-Os optimisation) and putting 4 bytes into a long, the difference was much more
     
  6. Foliage

    Foliage Member

    Joined:
    Jan 22, 2002
    Messages:
    32,059
    Location:
    Sleepwithyourdadelaide
    -O3 (what I used) will sometimes optimise it more but for simple stuff like this I doubt it would be much different, looks like X86 can be optimised further, you'd think the compiler would recognise if one method is substantially faster than the other and use that method though.
     

Share This Page

Advertisement: