Reputation: 4585
I am trying to read the 'size' of an SD card. The sample example which I am having has following lines of code:
unsigned char xdata *pchar; // Pointer to external mem space for FLASH Read function;
pchar += 9; // Size indicator is in the 9th byte of CSD (Card specific data) register;
// Extract size indicator bits;
size = (unsigned int)((((*pchar) & 0x03) << 1) | (((*(pchar+1)) & 0x80) >> 7));
I am not able to understand what is actually being done in the above line where indicator bit is being extracted. Can somebody help me in understanding this?
Upvotes: 1
Views: 188
Reputation: 22986
The size
is made up of bits from two bytes. One byte is at pchar
, the other at pchar + 1
.
(*pchar) & 0x03)
takes the 2 least significant bits (chopping of the 6 most significant ones).
This result is shifted one bit to the left using << 1
. For example:
11011010 (& 0x03/00000011)==> 00000010 (<< 1)==> 00000100 (-----10-)
Something similar is done with pchar + 1
. For example:
11110110 (& 0x80/10000000)==> 10000000 (>> 7)==> 00000001 (-------1)
Then these two values are OR-ed together with |
. So in this example you'd get:
00000100 | 00000001 = 00000101 (-----101)
But note that the 5 most significant bits will always be 0
(above indicated with -
) because they were &
-ed away:
To summarize, the first byte holds two bits of size
, while the second byte only one bit.
Upvotes: 4
Reputation: 1430
size = (unsigned int)((((*pchar) & 0x03) << 1) | (((*(pchar+1)) & 0x80) >> 7));
We have byte *pchar
and byte *(pchar+1)
. Each byte consists of 8 bits.
Let's index each bit of *pchar
in bold: 76543210 and each bit of *(pchar+1)
in italic: 76543210.
1.. ((*pchar) & 0x03) << 1
means "zero all bits of *pchar
except bits 0 and 1, then shift result to the left by 1 bit":
76543210 --> xxxxxx10 --> xxxxx10x
2.. (((*(pchar+1)) & 0x80) >> 7)
means "zero all bits of *(pchar+1)
except bit 7, then shift result to the right by 7 bits":
76543210 --> 7xxxxxxx --> xxxxxxx7
3.. ((((*pchar) & 0x03) << 1) | (((*(pchar+1)) & 0x80) >> 7))
means "combine all non-zero bits of left and right operands into one byte":
xxxxx10x | xxxxxxx7 --> xxxxx107
So, in the result we have two low bits from *pchar
and one high bit from *(pchar+1)
.
Upvotes: 1
Reputation: 5221
The first and second line figure out how to point to the data that you want.
Let's now go through the steps involved, from left to right.
The first portion of the operations takes the byte pointed to by pchar
, performs a logical AND on the byte and 0x03
and shifts over that result by one bit.
That result is then logically ORed with the next byte (*pchar+1)
, which in turn is ANDed with 0x80
, which is then right shifted by seven bits. Essentially, this portion just strips off the first bit in the byte and shifts it over by seven bits.
What the result is essentially this:
Imagine pchar
points to the byte where bits are represented by letters: ABCDEFGH
.
The first part ANDs with 0x03
, so we are left with 000000GH
. This is then left shifted by one bit, so we are left with 00000GH0
.
Same thing for the right portion. pchar+1
is represented by IJKLMNOP
. With the first logical AND, we are left with I0000000
. This is then right shifted seven times. So we have 0000000I
. This is combined with the left hand portion using the OR, so we have 00000GHI
, which is then casted into an int, which holds your size.
Basically, there are three bits that hold the size, but they are not byte aligned. As a result, some manipulation is necessary.
Upvotes: 1
Reputation: 5307
It seems the size indicator, say SI, consists of 3 bits, where *pchar
contains the two most significant bits of SI in its lowest two bits (0x03
) and *(pchar+1)
contains the least significant bit of SI in its highest bit (0x80
).
Upvotes: 3