I don't understand function written in the code https://en.wikipedia.org/wiki/Serial_Peripheral_Interface
uint8_t SPI_transfer_byte(uint8_t byte_out)
{
uint8_t byte_in = 0;
uint8_t bit;
for (bit = 0x80; bit; bit >>= 1) {
/* Shift-out a bit to the MOSI line */
write_MOSI((byte_out & bit) ? HIGH : LOW);
/* Delay for at least the peer's setup time */
delay(SPI_SCLK_LOW_TIME);
/* Pull the clock line high */
write_SCLK(HIGH);
/* Shift-in a bit from the MISO line */
if (read_MISO() == HIGH)
byte_in |= bit;
/* Delay for at least the peer's hold time */
delay(SPI_SCLK_HIGH_TIME);
/* Pull the clock line low */
write_SCLK(LOW);
}
return byte_in;
}
How does function work to transfer one byte ?
The "clever" part of the function is how the
for loop is used. You're probably familiar with the standard idiom:
for (bit = 0; bit < 8; bit++) { }but remember what the three statements in the parentheses mean.
The first just initializes the index variable at the start of the loop.
The second is the test to see if the statements in the loop body are executed or if the loop ends. If the condition is false, the loop exits. The body is not executed, and execution continues at the first line after the loop. If true, then the loop body execute, and when it's finished, the third statement is executed. In the standard idiom, then, we first clear bit to zero. Then we test: is bit < 8? Yes, of course, so we execute the loop. Then we increment bit, and test again. At some point, bit is incremented to 8, so the condition fails and the loop exits.
In the SPI example, what happens? First, we initialize bit to 0x80. Then we test. What do we test? In C, a boolean test of an integer returns true if the integer is non-zero. It returns false if it's zero. Therefore, at the first test, bit is 0x80 which evaluates as true. The loop executes. At the end of the loop, bit is shifted right one position, so its new value is 0x40. Test 0x40. Is that non-zero? Yes, so do the loop again. After the 8th iteration, we right-shift 0x01, which gives us 0x00. Is 0x00 true? No, it's not, so the loop exits.
----
Inside the loop, the first thing we do is shift out a bit. SPI shifts out most-significant bit first (usually). That's why bit is initialized to 0x80. In the call to write_MOSI(), the byte we want to send (byte_out) is bit-wise ANDed with bit -- that's a standard bit-masking operation. The mask is bit. Since bit is 0x80, all but the MSb of byte_out are cleared. What about the MSb? If the MSb of byte_out is set, the bit-wise AND result will be 0x80. If not, then the result is 0x00. That result is applied to the ternary operation ?: in the same way that bit is used in the for statement. If the result of the bit-mask is true -- non-zero -- then we "write" a HIGH to the SPI MOSI port. If it's false -- zero -- then we write a LOW to that port. HIGH and LOW must be defined somewhere, and they're used like this to allow for possible inversion of the output bit, or whatever.
The rest just follows.