cancel
Showing results for 
Search instead for 
Did you mean: 

Regarding function calls when performing SPI communication in half-duplex mode

pass3master
Senior

Regarding function calls when performing SPI communication in half-duplex mode.

We would like to develop a product that performs SPI communication in half-duplex mode.

Are there any sample programs in which the slave side transmits and the master side receives in half-duplex mode?

1 ACCEPTED SOLUTION

Accepted Solutions

Start by learning the very basics of SPI communication. Sorry to say, but response from @liaifat85 is highly misleading and incorrect.

In SPI, the data transfer is always bidirectional, on bit basis. On every clock cycle Master sends one bit to Slave and receives one bit from Slave. This is explained everywhere.

So, it is not possible for the slave to get a byte from the master and then respond with a byte. The response is sent while the master is sending the command byte. The problem with slave implementation in a microcontroller is that the slave response to a command sent by master may appear no sooner than during the THIRD frame transmitted by master (not even in the second one).

In theory, there is no half duplex, BUT:

In many cases we only need one way communication. For master-to-slave case, master transmits a frame. For slave-to-master case, master also transmits a frame, but there might be no data connection from master to slave. The master doesn't even know this - it is sending (maybe random) bits to generate the clock signal for slave; the slave cannot send anything without the clock signal generated by master, and the only way for master to generate clock pulses is to send data.

There is another case with single, bidirectional data line, still based on the same rules.

Again, Read The F(ine) Docs.

The simplest, baseline advice:

Start by using TransmitReceive() only until you understand more about SPI. Then, maybe, start playing with others (not really necessary).

And if SPI is too hard, use UART, having no problems with asynchronous unidirectional communication. For connecting two MCUs UART is much easier than SPI and it requires only 2 logic signals instead of 4.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

View solution in original post

4 REPLIES 4
liaifat85
Senior III

For STM32 microcontrollers, half-duplex SPI communication can be achieved using the hardware SPI peripheral configured in half-duplex mode.

The master initiates communication by sending a request to the slave and then switches to receive mode.

#include "main.h"

extern SPI_HandleTypeDef hspi1;  // Ensure SPI handle is set up by CubeMX

void SPI_Master_ReceiveData() {
    uint8_t request = 0xAA;          // Example request byte to ask for data
    uint8_t receivedData = 0;

    // Pull NSS low to select the slave
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);  // Adjust GPIO as needed for NSS

    // Send request byte to slave
    HAL_SPI_Transmit(&hspi1, &request, 1, HAL_MAX_DELAY);

    // Delay briefly to give slave time to respond
    HAL_Delay(1); 

    // Receive data from slave
    HAL_SPI_Receive(&hspi1, &receivedData, 1, HAL_MAX_DELAY);

    // Pull NSS high to end communication
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);

    // Process the received data
    printf("Received Data: 0x%X\n", receivedData);  // Adjust to your preferred output method
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_SPI1_Init();  // SPI1 configured as Half-Duplex Master in CubeMX

    while (1) {
        SPI_Master_ReceiveData();
        HAL_Delay(1000);  // Request data every second
    }
}

On the slave side, the MCU listens for a request from the master and then sends back the requested data.

#include "main.h"

extern SPI_HandleTypeDef hspi1;

uint8_t dataToSend = 0x55;  // Example data to send

void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi->Instance == SPI1) {
        uint8_t receivedRequest;
        HAL_SPI_Receive(&hspi1, &receivedRequest, 1, HAL_MAX_DELAY);  // Receive request from master

        if (receivedRequest == 0xAA) {  // Check if request matches expected
            HAL_SPI_Transmit(&hspi1, &dataToSend, 1, HAL_MAX_DELAY);  // Transmit data to master
        }
    }
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_SPI1_Init();  // SPI1 configured as Half-Duplex Slave in CubeMX

    while (1) {
        HAL_Delay(1);  // Keep looping, data transmission handled in callback
    }
}

 If you need some info regarding SPI communication of STM32, you can see this:

https://www.theengineeringprojects.com/2021/11/stm32-spi-communication.html

Thank you for your response.
They are very helpful. And we are very close to realizing it.
it is really helpful.

Please tell me one more point.
I would like to change the SPI Mode to “Recieve Only Master” and “Transmit Only Slave” from this state.

I thought that SPI Master requires transmit. But “Recieve Only Master”? I don't understand what it means.

Start by learning the very basics of SPI communication. Sorry to say, but response from @liaifat85 is highly misleading and incorrect.

In SPI, the data transfer is always bidirectional, on bit basis. On every clock cycle Master sends one bit to Slave and receives one bit from Slave. This is explained everywhere.

So, it is not possible for the slave to get a byte from the master and then respond with a byte. The response is sent while the master is sending the command byte. The problem with slave implementation in a microcontroller is that the slave response to a command sent by master may appear no sooner than during the THIRD frame transmitted by master (not even in the second one).

In theory, there is no half duplex, BUT:

In many cases we only need one way communication. For master-to-slave case, master transmits a frame. For slave-to-master case, master also transmits a frame, but there might be no data connection from master to slave. The master doesn't even know this - it is sending (maybe random) bits to generate the clock signal for slave; the slave cannot send anything without the clock signal generated by master, and the only way for master to generate clock pulses is to send data.

There is another case with single, bidirectional data line, still based on the same rules.

Again, Read The F(ine) Docs.

The simplest, baseline advice:

Start by using TransmitReceive() only until you understand more about SPI. Then, maybe, start playing with others (not really necessary).

And if SPI is too hard, use UART, having no problems with asynchronous unidirectional communication. For connecting two MCUs UART is much easier than SPI and it requires only 2 logic signals instead of 4.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
PGump.1
Senior III

Hi,

You would be best served by obtaining a solid understanding of Full-duplex, Half-duplex, and Simplex modes of communication. Applying this knowledge to SPI will assist you in making good choices...

I hope this helps.

Kind regards
Pedro

AI = Artificial Intelligence, NI = No Intelligence, RI = Real Intelligence.