Close

Bitwise Operations

A project log for Open Source Cell Phone

A completely open hardware and open source software cell phone

hugh-darrowHugh Darrow 11/18/2014 at 00:350 Comments

So interestingly when I went to go write the code for the sending screen for SMS, the screen scanning functions didn't work. After doing a formal research I found that in the code when it reads the registers from the the ra8875 driver, it stores it as uint8_t or a 8-bit character or char. When I wrote the code

writeReg(0x20, ((1 << 4)));

I thought I was saying at bit 4 flip to one, in fact this isn't the case. The << operator actually means shift, so I was shifting a 1 into bit 4 from bit (3 or 4), still haven't fully learned the logic and syntax yet, when what I wanted was just to flip the 4th bit, then for the other functions the 3rd bit and/or the 2nd bit, depending on the functions. This is where the bitwise operators come into play. The basic operators are ^= meaning XOR, &= meaning AND and |= meaning OR. Now here's how they work. For all scenarios we'll be using 8 bits. For XOR lets say you read the number 106 and store it in the variable uint8_t. If you were to read that back it would show 106. But what we need to be looking at is the binary, for this you can do it by hand, or with a calculator, I used which one in the OS I was at the time, and I can confirm both Windows and Linux calculators have programmer mode, albeit I prefer the Linux version, straighter to the point. So the number 106 in binary is 0110 1010. If we were to use the the binary sequence 1001 0101 with the operator XOR the result is as follows

0110 1010
1001 0101 XOR
-------------
1111 1111 result

So if you follow the logic, everything is flipped so long as there isn't the same bit in the same sequence here's another couple examples.

0110 1010
1111 0101 XOR
-------------
1001 1111 result

1001 1111
1001 0101 XOR
-------------
0000 1010 result

So its pretty simple logic, the and and or operators are identical to there normal counter parts, if using AND and both bits in each sequence is a 1, then its a 1, if both are 0, then its a 0. If using OR then only one of the bits in the same sequence needs to be a one for it to be a one. Examples

1001 1111
1001 0101 AND
-------------
1001 0101 result

1001 0101
1111 1010 OR
-------------
1111 1111 result

The next step is to actually use them, and do real operations. In the cpp file of the ra8875 library, the function scanV is as follows

void Adafruit_RA8875::scanV_flip(boolean V_scan)
{
if (V_scan) {
writeCommand(0x20);
uint8_t temp = readData();
temp ^= 2;
writeData(temp);
}
else {
writeCommand(0x20);
uint8_t temp = readData();
temp ^= 2;
writeData(temp);
}
}

Now as you can see I've already made the neccesary changes to reflect the operations I wanted, but lets start from scratch. The first part says define a new function called scanV_flip, accept a boolean input, and create a temporary (boolean) variable named V_scan. Next is to check that new temp variable V_scan, and if true, then perform writeCommand(0x20). This is what allows us to tell the driver, hey we are referring to your register address in hex 0x20. Then we create a new variable 8 bits long with uint8_t temp, and initialize it to readData() or the 8-bit sequence located at Register address 0x20. We now have some unknown sequence, that right now we really don't care. What we do want is is to flip the #1 bit in the sequence, like this XXXX X_XX. So if its a zero, make it a 1, if its a 1, make it a 0. For this operation I decided to use the XOR operator for the logic stated above. Now the number 2 is used because when we represent the number 2 in binary (using 8-bits) 0000 0010. So now matter whats int the rest of the sequence we'll only flip the 2nd bit. Lets say we wanted to flip the 3rd bit, XXXX _XXX. We would use the number 4. This is because each bit in the sequence is really just 2 ^ of that bit. So bit 0 is XXXX XXX_ and is equal to 1 (2^0), and bit 7 is _XXX XXXX and is equal to 128 (2^7). So we can write any sequence of binary in any number want by just knowing the bit we want to operate. Another example its lets say we wanted to flip the 3rd, 4th, and 7th bit, again I would use the XOR operator and write

temp ^= 152;

Because 1001 1000, with the bits 3, 4 and 7 flipped to one. So if we had the sequence read from the Register address 0x20 read out 44, or 0010 1100. Then after the XOR operator using temp ^= 152; the same address would read, 180 or 1011 0100 in binary.

I've corrected my mistake in the libraries and uploaded the new versions to Github. This was a good learning experience and a real wtf is going on. Especially when I would use just one function and it would work, but not two, and not if the same one was used again? Took awhile but that's the result. Good old fashioned learning by failure, after failure, and the desire to get it right.

Discussions