12 Bit data inside 16 bit words: how to truncate blanking bits

Discussion in 'C Programming' started by johnny, Jan 8, 2009.

  1. johnny

    johnny Guest

    Dear comp.lang.c members,

    I have the following problem:
    I am writing an application which reads data from a device. This data
    is 12 bit wide and comes as a stream of words to be stored to a file.
    At the moment I write it to 16 bit words, which creates an unessecary
    overhead.

    I currently use uint16_t.

    How may I do this?

    Any comments welcome ;-)

    Thank you and
    best regards,
    Johann
    johnny, Jan 8, 2009
    #1
    1. Advertising

  2. johnny

    Guest

    On Jan 8, 9:17 am, johnny <> wrote:
    > Dear comp.lang.c members,
    >
    > I have the following problem:
    > I am writing an application which reads data from a device. This data
    > is 12 bit wide and comes as a stream of words to be stored to a file.
    > At the moment I write it to 16 bit words, which creates an unessecary
    > overhead.
    >
    > I currently use uint16_t.
    >
    > How may I do this?


    It depends on what you need to do with the data. If all you need is to
    read it and then write it to somewhere else, you can just use unsigned
    char[] (i.e., "bytes") and be done with it.

    But if you need to perform arithmetic operations on the 12-bit
    integers, for example, you can still use unsigned char[] to hold the
    data and then copy individual 12-bit units into uint16_t variables to
    perform the desired operations:

    unsigned char* data;
    size_t len;
    ReadDeviceData(&data, &len);

    // Fetch the first 12-bit unit and store it in a uint16_t
    uint16_t num = *(uint16_t*) data >> 4;

    (Your program may need to take byte ordering into account.) You may
    write a macro to fetch a 12-bit value that is at a specific "bit
    offset":

    //
    // Returns a 12-bit unit as a uint16_t
    //
    // @param offset the bit offset of the 12-bit value; must be
    // a multiple of 12
    // @param ptr a pointer to the block of memory
    //
    #define GET_UNIT(offset, ptr) \
    (*(uint16_t*) ((ptr) + (offset) / CHAR_BIT) >> \
    4 - (offset) % CHAR_BIT & \
    ~0U >> (offset) % CHAR_BIT)

    Using such a macro you could step through every 12-bit value in an
    arbitrary block of memory (unsigned char[]). For example, this loop
    would print all 12-bit values as decimal numbers:

    for (size_t offset = 0; offset + 12 < len * CHAR_BIT; offset +=
    12)
    printf("%" PRIu16 "\n", GET_UNIT(offset, data));

    The point is that now you're using an array of unsigned char to hold
    the data (thus saving space), and then copying individual 12-bit
    values into uint16_t variables whenever you need to perform an
    operation on them.

    Sebastian
    , Jan 8, 2009
    #2
    1. Advertising

  3. johnny

    Tim Rentsch Guest

    Eric Sosman <> writes:

    > johnny wrote:
    > > Dear comp.lang.c members,
    > >
    > > I have the following problem:
    > > I am writing an application which reads data from a device. This data
    > > is 12 bit wide and comes as a stream of words to be stored to a file.
    > > At the moment I write it to 16 bit words, which creates an unessecary
    > > overhead.
    > >
    > > I currently use uint16_t.
    > >
    > > How may I do this?

    >
    > With a bit of shifting and OR-ing you can pack two 12-bit
    > samples into three 8-bit bytes (uint8_t) and write those to
    > the file. [snip]


    It seems to me that doing such packing takes at least four bits
    of shifting.

    (Sorry, I couldn't resist...)
    Tim Rentsch, Jan 8, 2009
    #3
  4. On Jan 8, 11:12 pm, Eric Sosman <> wrote:

    >      With a bit of shifting and OR-ing you can pack two 12-bit
    > samples into three 8-bit bytes (uint8_t) and write those to
    > the file.


    The amount of memory need is calculable as follows:

    (amount_twelves * 3 / 2) + (amount_twelves * 3 % 2)

    Throw together in five minutes so likely to contain a bug:

    #include <assert.h>
    #include <stdint.h>

    uint_fast16_t GetChunk(uint8_t *const mem, uint_fast32_t chunk_index)
    {
    if ( !(chunk_index & 1) ) /* If index is not odd */
    {
    /* The first 8 bits are in the leading octet,
    The last 4 bits are the lowest 4 in the trailing octet */

    return (uint_fast16_t)(mem[chunk_index * 3 / 2])
    | (mem[chunk_index * 3 / 2 + 1] & 0xF);
    }
    else
    {
    /* The first 4 bits are the high 4 in the leading octet,
    The last 4 bits are the low 4 in the trailing octet */

    --chunk_index;

    return (uint_fast16_t)(mem[chunk_index * 3 / 2 + 1] >> 4)
    | (mem[chunk_index * 3 / 2 + 2] & 0xF);
    }
    }


    void SetChunk(uint8_t *const mem, uint_fast32_t chunk_index,
    uint_fast16_t const val)
    {
    assert(val <= 0xFFFu);

    if ( !(chunk_index & 1) ) /* If index is not odd */
    {
    /* The first 8 bits are in the leading octet,
    The last 4 bits are the lowest 4 in the trailing octet */

    mem[chunk_index * 3 / 2] = val;

    mem[chunk_index * 3 / 2 + 1] &= 0xF0;

    mem[chunk_index * 3 / 2 + 1] |= val >> 8;
    }
    else
    {
    /* The first 4 bits are the high 4 in the leading octet,
    The last 8 bits are in the trailing octet */

    --chunk_index;

    mem[chunk_index * 3 / 2 + 1] &= 0x0F;

    mem[chunk_index * 3 / 2 + 1] = val & 0xFu << 4;

    mem[chunk_index * 3 / 2 + 2] = val >> 4;
    }
    }

    Again, likely to contain a bug.
    Tomás Ó hÉilidhe, Jan 9, 2009
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?VG9iZQ==?=

    Blanking on Redirect

    =?Utf-8?B?VG9iZQ==?=, Feb 19, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    319
    Brian K. Williams
    Feb 20, 2004
  2. TylerB
    Replies:
    3
    Views:
    1,555
    TylerB
    Aug 26, 2004
  3. Chris Murphy

    blanking a java.util.Date in 1.5

    Chris Murphy, Sep 18, 2004, in forum: Java
    Replies:
    10
    Views:
    799
    Chris Murphy
    Oct 18, 2004
  4. GGG
    Replies:
    10
    Views:
    12,510
    Donar
    Jul 6, 2006
  5. Richard Heathfield
    Replies:
    7
    Views:
    349
    Barry Schwarz
    Oct 5, 2003
Loading...

Share This Page