Bird
Raised Fist0
Embedded Cprogramming~20 mins

SPI data transfer sequence in Embedded C - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
SPI Mastery Badge
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
SPI Data Transfer: What is the output?
Consider this SPI transfer code snippet. What will be the value of received_data after the transfer completes?
Embedded C
#define SPI_DATA_REGISTER (*(volatile unsigned char*)0x4001300C)
#define SPI_STATUS_REGISTER (*(volatile unsigned char*)0x40013008)
#define SPI_STATUS_TXE (1 << 1)  // Transmit buffer empty
#define SPI_STATUS_RXNE (1 << 0) // Receive buffer not empty

unsigned char spi_transfer(unsigned char data) {
    SPI_DATA_REGISTER = data; // Start transmission
    while (!(SPI_STATUS_REGISTER & SPI_STATUS_TXE)) {}
    while (!(SPI_STATUS_REGISTER & SPI_STATUS_RXNE)) {}
    return SPI_DATA_REGISTER; // Read received data
}

int main() {
    unsigned char sent_data = 0xA5;
    unsigned char received_data = spi_transfer(sent_data);
    return received_data;
}
A0x5A
B0xA5
C0xFF
D0x00
Attempts:
2 left
💡 Hint
Think about what happens in SPI: data sent is simultaneously received.
🧠 Conceptual
intermediate
1:30remaining
SPI Transfer Sequence: Which step comes first?
In an SPI data transfer sequence, which step must happen first to start communication?
ASet the chip select (CS) line low to enable the slave device
BSend the data byte to the SPI data register
CWait for the receive buffer to be not empty
DRead the received data from the SPI data register
Attempts:
2 left
💡 Hint
Think about how the slave device knows communication is starting.
❓ Predict Output
advanced
2:00remaining
SPI Transfer Loop: What is the final value?
Given this code that sends multiple bytes over SPI, what is the final value of last_received?
Embedded C
#define SPI_DATA_REG (*(volatile unsigned char*)0x4001300C)
#define SPI_STATUS_REG (*(volatile unsigned char*)0x40013008)
#define SPI_STATUS_TXE (1 << 1)
#define SPI_STATUS_RXNE (1 << 0)

unsigned char spi_transfer(unsigned char data) {
    SPI_DATA_REG = data;
    while (!(SPI_STATUS_REG & SPI_STATUS_TXE)) {}
    while (!(SPI_STATUS_REG & SPI_STATUS_RXNE)) {}
    return SPI_DATA_REG;
}

int main() {
    unsigned char data_to_send[3] = {0x10, 0x20, 0x30};
    unsigned char last_received = 0;
    for (int i = 0; i < 3; i++) {
        last_received = spi_transfer(data_to_send[i]);
    }
    return last_received;
}
A0x30
B0x10
C0x00
D0x60
Attempts:
2 left
💡 Hint
The last received byte matches the last sent byte in this simple loop.
🔧 Debug
advanced
2:00remaining
Identify the error in SPI transfer code
This SPI transfer function is intended to send and receive a byte. What error will it cause?
Embedded C
unsigned char spi_transfer(unsigned char data) {
    SPI_DATA_REGISTER = data;
    while (!(SPI_STATUS_REGISTER & SPI_STATUS_TXE)) {}
    while (!(SPI_STATUS_REGISTER & SPI_STATUS_RXNE)) {}
    return SPI_DATA_REGISTER;
}
AIt causes a syntax error due to missing semicolon
BIt returns the wrong register value
CIt causes an infinite loop waiting for receive buffer flag
DIt reads the data before transmission starts
Attempts:
2 left
💡 Hint
Check the flags being waited on in the while loops.
🧠 Conceptual
expert
1:30remaining
SPI Full-Duplex Transfer: What happens during data exchange?
In SPI full-duplex communication, what happens when the master sends a byte to the slave?
AThe master only sends data; the slave sends data separately later
BThe master sends a byte first, then waits to receive a byte after transmission
CThe master sends a byte and the slave ignores it until the next clock cycle
DThe master sends a byte and simultaneously receives a byte from the slave
Attempts:
2 left
💡 Hint
SPI is known for simultaneous send and receive.

Practice

(1/5)
1. In SPI communication, what happens during a data transfer sequence?
easy
A. Data is only sent, no data is received.
B. Data is sent and received simultaneously, one byte at a time.
C. Data is received first, then sent after completion.
D. Data is sent in large blocks without waiting for response.

Solution

  1. Step 1: Understand SPI full-duplex nature

    SPI sends and receives data simultaneously, byte by byte.
  2. Step 2: Confirm data transfer behavior

    Each byte sent triggers a byte received at the same time.
  3. Final Answer:

    Data is sent and received simultaneously, one byte at a time. -> Option B
  4. Quick Check:

    SPI full-duplex = simultaneous send/receive [OK]
Hint: Remember SPI sends and receives one byte at a time simultaneously [OK]
Common Mistakes:
  • Thinking SPI only sends data without receiving
  • Assuming data is received after all sending completes
  • Believing SPI transfers data in large blocks
2. Which of the following code snippets correctly waits for SPI transfer completion before reading received data?
easy
A. while(!(SPI_SR & SPI_SR_RXNE)); uint8_t data = SPI_DR;
B. uint8_t data = SPI_DR; while(!(SPI_SR & SPI_SR_RXNE));
C. while(SPI_SR & SPI_SR_BSY); uint8_t data = SPI_DR;
D. while(!(SPI_SR & SPI_SR_TXE)); uint8_t data = SPI_DR;

Solution

  1. Step 1: Identify the correct flag for received data ready

    SPI_SR_RXNE indicates data received and ready to read.
  2. Step 2: Confirm waiting loop and reading order

    Wait until RXNE is set, then read SPI_DR to get received byte.
  3. Final Answer:

    while(!(SPI_SR & SPI_SR_RXNE)); uint8_t data = SPI_DR; -> Option A
  4. Quick Check:

    Wait RXNE flag before reading data [OK]
Hint: Wait for RXNE flag before reading SPI data register [OK]
Common Mistakes:
  • Waiting for TXE instead of RXNE
  • Reading data before checking RXNE flag
  • Waiting for BSY flag incorrectly
3. Given the following code snippet, what will be the content of the array received[3] after execution?
uint8_t data_to_send[3] = {0xA1, 0xB2, 0xC3};
uint8_t received[3];
for(int i = 0; i < 3; i++) {
  SPI_DR = data_to_send[i];
  while(!(SPI_SR & SPI_SR_RXNE));
  received[i] = SPI_DR;
}
medium
A. [0xA1, 0xB2, 0xC3]
B. [unknown garbage values]
C. [data received from SPI slave during transfer]
D. [0x00, 0x00, 0x00]

Solution

  1. Step 1: Understand SPI transfer behavior

    Each byte sent causes a byte to be received simultaneously from the slave device.
  2. Step 2: Analyze received array assignment

    received[i] stores the byte read from SPI_DR after waiting for RXNE flag.
  3. Final Answer:

    Data received from SPI slave during transfer -> Option C
  4. Quick Check:

    Received array = slave response bytes [OK]
Hint: Received data is from slave, not the sent bytes [OK]
Common Mistakes:
  • Assuming received data equals sent data
  • Ignoring that SPI_DR reads slave response
  • Expecting zeros or uninitialized values
4. Identify the error in this SPI data transfer loop:
for(int i = 0; i < 4; i++) {
  SPI_DR = data[i];
  received[i] = SPI_DR;
  while(!(SPI_SR & SPI_SR_RXNE));
}
medium
A. Loop counter exceeds array size.
B. Not sending data before reading.
C. Missing SPI enable command.
D. Reading SPI_DR before waiting for RXNE flag.

Solution

  1. Step 1: Check order of reading SPI_DR and waiting for RXNE

    The code reads SPI_DR before waiting for RXNE flag, which is incorrect.
  2. Step 2: Correct sequence for SPI read

    Must wait for RXNE flag before reading SPI_DR to get valid received data.
  3. Final Answer:

    Reading SPI_DR before waiting for RXNE flag. -> Option D
  4. Quick Check:

    Wait RXNE before reading SPI_DR [OK]
Hint: Always wait RXNE flag before reading SPI_DR [OK]
Common Mistakes:
  • Reading SPI_DR too early
  • Ignoring RXNE flag status
  • Assuming data is ready immediately after writing
5. You want to send an array of 5 bytes over SPI and store the received bytes simultaneously. Which code snippet correctly implements this transfer sequence?
hard
A. for(int i=0; i<5; i++) { SPI_DR = tx[i]; while(!(SPI_SR & SPI_SR_RXNE)); rx[i] = SPI_DR; }
B. for(int i=0; i<5; i++) { while(!(SPI_SR & SPI_SR_TXE)); SPI_DR = tx[i]; rx[i] = SPI_DR; }
C. for(int i=0; i<5; i++) { SPI_DR = tx[i]; rx[i] = SPI_DR; while(!(SPI_SR & SPI_SR_RXNE)); }
D. for(int i=0; i<5; i++) { while(SPI_SR & SPI_SR_BSY); SPI_DR = tx[i]; rx[i] = SPI_DR; }

Solution

  1. Step 1: Confirm correct order of operations

    Send byte by writing SPI_DR, wait for RXNE flag, then read received byte.
  2. Step 2: Validate correct snippet

    The correct snippet writes SPI_DR, waits for RXNE, then reads SPI_DR into rx array correctly.
  3. Step 3: Check distractors for errors

    Others read SPI_DR before RXNE is set, read before waiting, or wait for incorrect flags like BSY.
  4. Final Answer:

    for(int i=0; i<5; i++) { SPI_DR = tx[i]; while(!(SPI_SR & SPI_SR_RXNE)); rx[i] = SPI_DR; } -> Option A
  5. Quick Check:

    Send, wait RXNE, then read = correct SPI transfer [OK]
Hint: Send byte, wait RXNE flag, then read received byte [OK]
Common Mistakes:
  • Reading SPI_DR before RXNE flag is set
  • Not waiting for transfer completion
  • Confusing TXE and RXNE flags
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard