Swapping nybbles

I don't know much about bit math, or else I wouldn't be asking this.

What is the simplest way to swap the first and last nybbles in a byte?
For example, turn
01101010 into 10100110

Thanks for the help!
:slight_smile:

By the way, if you want to know why, I have a custom pcb for 2 led matrices, but I swapped the top and bottom rows of each matrices' connections! I can't rotate it, since it is not rotationally symmetrical.

byte = (byte << 4) | (byte >> 4);

No guarantee that would compile to the most efficient nibble swap implementation. But we are using C here...where the rule is to do it the easiest way until you run into performance problems.

sciguy,

The most obvious way is:

    unsigned char oldbyte;
    unsigned char newbyte;

    oldbyte = 0xab;
    newbyte = ((oldbyte & 0xf) << 4) | ((oldbyte & 0xf0) >> 4);
// newbyte is now 0xba

Regards,

-Mike

but where does (the equivalent of) oldbyte come from?
There is little point combining two nybbles wrong and then fix it with shifts and and:s.

if you previously had e.g.

oldbyte = (A << 4) | B;

then just replace it with

oldbyte = (B << 4) | A;

ATMega has an assembler instruction for swapping nibbles. Not sure if the C ever gets translated into it.

Here is a discussion on the topic:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=192345
Basically this macro does that

#define swap(value) asm("swap %0" : "=r" (value) : "0" (value))

in your code you do

byte i;
swap( i );

Thanks for all the replies!

Whatever solution I use, I am just going to make a function (or a #define) called swap(value), so it doesn't really matter which is simplest or shortest.

but how were the bytes-with-incorrect-nybble-order originally assembled? Is it not possible to modify that code so that no extra swap need to be performed?

but how were the bytes-with-incorrect-nybble-order originally assembled?

It is a mapping between the software and the hardware.

Yes, I messed it up so whennit should be going through the rows and columns linearly,
12345678
It goes through them as follows,
56781234
Sort of annoying, but easily solved thru software.

To revise my earlier code snippet for maximum portability:

    unsigned char oldbyte;
    unsigned char newbyte;

    oldbyte = 0xab;
    newbyte = ((oldbyte << 4) & 0xf0) | ((oldbyte >> 4) & 0x0f);
// newbyte is now 0xba

-Mike

Did you say you wanted the simplest way? Here is a method that doesn't use the shift operator:

struct nybbles {
        unsigned char n1:4;
        unsigned char n2:4;
        };

union {
        unsigned char b;
        struct nybbles n;
        } u;

setup()
{
        u.b = 0xab;
        u.n.n1 = u.n.n1 ^ u.n.n2;
        u.n.n2 = u.n.n1 ^ u.n.n2;
        u.n.n1 = u.n.n1 ^ u.n.n2;
        // u.b now contains 0xba
}

:slight_smile:
-Mike

Did you say you wanted the simplest way? Here is a method that doesn't use the shift operator: Code:

You trying to make us all seem stupid, is that really C. ;D

lefty,

That was crystal clear compared to the code here: http://www0.us.ioccc.org/years.html

-Mike

I'm pretty sure the assembler generated by the bitfield-manipulations will generate shifts though.

swap is a single cycle instruction on the atmega. there will be some additional code for moving a memory location into a register and then writing back, but that is also the case with the shifts.
so the swap version is the fastest/smallest. not c portable though, but we are in the context of arduino here, aren't we? :slight_smile: