#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    2
    Rep Power
    0

    Please help to explain how this C programming works


    any kind soul can explain detailly how below programing works?

    uint16_t read_blk;
    NANDcmd[3] = 0;
    NANDcmd[4] = 0;
    NANDcmd[5] = 0;

    for (read_blk=0; read_blk<4100; read_blk++)

    { NANDcmd[3] = (uint8_t)((read_blk<<7) & 0x80);
    NANDcmd[4] = (uint8_t)((read_blk>>1) & 0xFF);
    NANDcmd[5] = (uint8_t)((read_blk>>9) & 0x0F);

    }
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    What don't you understand?

    << is the left shift operator. <<7 shifts read_blk left seven times.

    >> is the right shift operator. It shifts the operand to the right the number of times indicated.

    & is the AND operator which ANDs the two operands.

    0xFF is hexadecimal representation of 255.

    uint8_t is a datatype definition for an unsigned 8-bit integer, which is commonly called a "byte".
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    2
    Rep Power
    0
    Originally Posted by dwise1_aol
    What don't you understand?

    << is the left shift operator. <<7 shifts read_blk left seven times.

    >> is the right shift operator. It shifts the operand to the right the number of times indicated.

    & is the AND operator which ANDs the two operands.

    0xFF is hexadecimal representation of 255.

    uint8_t is a datatype definition for an unsigned 8-bit integer, which is commonly called a "byte".
    i would like to know the how is the work flows. for examle if read_blk=2, can any 1 let know know the process line by line?
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    So walk through the code. It's all right there.

    What is it that you do not understand? Please answer that question so that we can help you.

    Is it that you do not understand bit-wise operations? What shifting means? What ANDing means? What hexadecimal is? Do you understand how to convert from hexadecimal to binary in order to get the bit pattern?

    Obviously, if you do not understand all those topics, then you would not be able to understand a normal explanation. Equally obviously is that if you do understand those necessary topic then you wouldn't have to ask what that code does.

    What do you not understand?

    What is the bit pattern of 2?

    What bit pattern do you get from 2<<7, which is shifting 2 to the left seven times?

    What bit pattern do you get when you AND that with 0x80?

    BTW, when you cast a 16-bit integer to being an 8-bit integer, then you simply throw away the higher-order 8 bits and you keep the lower-order 8 bits.

    When you assign a new value to a variable, what happens to the old value? It's gone. So after that for-loop is finished, NANDcmd will contain the results of read_blk having been 4099. So then what is the bit pattern of 4099?

    That's how you work through it. Now what part do you not understand?
    Last edited by dwise1_aol; September 17th, 2013 at 12:45 AM.
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    OK, so you don't know anything, which is what I needed for you to establish for us. That means we have to explain everything to you. Otherwise, you wouldn't understand our explanation anyway.

    We humans use the decimal system for numbers, because we have ten digits (AKA "fingers") to count with and so each decimal digit can have one of ten values ranging from 0 to 9. Digital computers don't use the decimal system, because they don't have any fingers to count with but rather two logic levels represented by two distinct voltages. Therefore, computers' numbers are in binary, AKA "Base 2", because each binary digit (AKA "bit") in a computer's number can have one of only two values, 0 and 1.

    For the following, I will use FORTRAN notation for exponentiation, which is the double asterix, such that 10**3 means "ten raised to the third power". I am using this notation instead of using the caret (^), which may be popular but it's also confusing for C novices because in C the caret is the bit-wise exclusive-OR operator (XOR), such that 10^3 does not raise 10 to the third power, which would yield 1000, but rather XORs 10 and 3 to yield 9 -- obviously, 1000 and 9 are not the same value.

    However, one thing that decimal and binary numbers have in common is that they are place-value numbers, meaning that the position of the digit within its number gives it value. The position values start with 1 and increase by powers of the base as you go to the left. So going from right to left in a decimal (ie, base 10) number the position values are 1's (10**0), 10's (10**1), 100's (10**2), 1000's (10**3), etc. Similarly, going from right to left in a binary (ie, base 2) number the position values are 1's (2**0), 2's (2**1), 4's (2**2), 8's (2**3), 16's (2**4), 32's (2**5), 64's (2**6), 128's (2**7), etc -- programmers quickly become very familiar with the powers of 2.

    One thing this allows us to do is to convert a decimal number to the binary number of the same value and vice versa. So for a decimal 2 you would set the 2's digit to 1 and the rest to zero, so the 8-bit binary bit pattern for 2 would be 00000010B (the trailing "B" is an assembly language convention to indicate a binary value). Similarly, a 5 would have the 4's and the 1's bits set to 1: 00000101B. There is a manual procedure of converting from decimal to any other number base which involves successively dividing the decimal number by the target base and writing the remainders down as the digits, but an easier way is to use Windows' calc program in the scientific view (for WinXP) or the programmer's view (for Win7).

    However, there is no binary notation in C, but rather only decimal, octal (base 8) and hexadecimal (base 16). The reason for octal and hexadecimal is that if you take the binary bit pattern and group the bits three at a time you can represent those three bit with an octal digit, and if you group them four at a time you can represent them with a hex digit. Long binary numbers can get very tedious to write and to read, so converting them to hexadecimal makes it much easier. You can convert between binary and hex on sight:
    Code:
      Dec   Bin   Hex   | Dec   Bin   Hex  |  Dec   Bin   Hex  |  Dec   Bin   Hex
       0    0000   0    |   4   0100   4   |   8    1000   8   |  12    1100   C
       1    0001   1    |   5   0101   5   |   9    1001   9   |  13    1101   D
       2    0010   2    |   6   0110   6   |  10    1010   A   |  14    1110   E
       3    0011   3    |   7   0111   7   |  11    1011   B   |  15    1111   F
    In C, a hexadecimal value is prefaced with "0x", so 0x80 is 80 hex. From the table, you can see that the bit pattern for 0x80 is 10000000B. Similarly, from the code you posted, you can see that 0xFF is 11111111B and 0x0F is 00001111B. Very simple.

    Now, there are three basic logic operations you can perform on bits, plus one more that is a composite of the others:

    1. Inversion (AKA "NOT") with the ~ operator. You change each bit to the opposite value:
    ~0 = 1
    ~1 = 0

    2. AND with the & operator. You AND two bits together and the result will be 1 only if both bits are one:
    0 & 0 = 0
    0 & 1 = 0
    1 & 0 = 0
    1 & 1 = 1

    3. OR with the | operator. You OR two bits together and the result will be 1 if either or both are one:
    0 | 0 = 0
    0 | 1 = 1
    1 | 0 = 1
    1 | 1 = 1

    3. Exclusive-OR (XOR) with the ^ operator. You XOR two bits together and the result will be 1 if the two bits are different and zero if they are the same:
    0 ^ 0 = 0
    0 ^ 1 = 1
    1 ^ 0 = 1
    1 ^ 1 = 0

    When you apply these operations bit-wise in C, you pair up the bits in the same corresponding position (eg, the two bits both in the 128's position). For example:
    01011010B & 00001111B = 00001010B
    01011010B & 10000000B = 00000000B
    10101010B & 10000000B = 10000000B

    You can also shift a bit pattern to the left (<<) or to the right (>>); zeroes are shifted in and the bits that get shifted out are gone ("They drop into the bit bucket."). For example:
    00000101B = 0x05 = 5
    00000101B << 1 = 00001010B = 0x0A = 10
    00000101B << 2 = 00010100B = 0x14 = 20
    00000101B << 3 = 00101000B = 0x28 = 40
    00000101B << 4 = 01010000B = 0x50 = 80

    You will notice that the same thing happens in binary as happens in decimal when you shift digits to the left. In decimal, every time you shift left you multiply by 10: 5, 50, 500, 5000, 50,000. In binary, every time you shift left you multiply by 2: 5 2 = 10 2 = 20 2 = 40 2 = 80. Similarly, each time you shift right, you divide by the base; eg:
    01010000B = 0x50 = 80
    01010000B >> 1 = 00101000B = 0x28 = 40
    01010000B >> 2 = 00010100B = 0x14 = 20
    01010000B >> 3 = 00001010B = 0x0A = 10
    01010000B >> 4 = 00000101B = 0x05 = 5

    Now the only piece left to fill in the gaps in your knowledge is the most obviously one.

    Binary numbers consist of a set number of bits. An 8-bit number has eight bits. A 16-bit number has sixteen bits. No more, no fewer. If you try to store a value in a number and the value needs more bits than the number has, then in C only the lower-order bits will be stored; the higher-order bits will be lost (for some unknown reason, that bit bucket never fills up).

    In the code snippet, unint16_t is a 16-bit unsigned integer datatype and uint8_t is an 8-bit unsigned integer datatype. I will forego explaining signed vs unsigned and Two's Complement format for the time being.

    And now you know enough to be able to see for yourself what that code snippet does. Here it is again:
    Code:
        uint16_t read_blk;
        NANDcmd[3] = 0;
        NANDcmd[4] = 0;
        NANDcmd[5] = 0;
    
        for (read_blk=0; read_blk<4100; read_blk++)
        { 
            NANDcmd[3] = (uint8_t)((read_blk<<7) & 0x80);
            NANDcmd[4] = (uint8_t)((read_blk>>1) & 0xFF);
            NANDcmd[5] = (uint8_t)((read_blk>>9) & 0x0F);
        }
    BTW, there's a slight trick that the author had played on you. That for-loop iterates 4100 times, but each time you go through that loop you overwrite the results of the previous iteration. That means that the only iteration that means anything at all is the very last one, where read_blk equals 4099, which is 0x1003. You may consider that a gift.

    PS
    I would say:
    NANDcmd[3] = 0x80
    NANDcmd[4] = 0x01
    NANDcmd[5] = 0x08

    You can see why.

    Comments on this post

    • dingmutt agrees
    Last edited by dwise1_aol; September 17th, 2013 at 05:10 PM.

IMN logo majestic logo threadwatch logo seochat tools logo