Skip to main content
Visitor II
July 28, 2020
Solved

SPI half-duplex example

  • July 28, 2020
  • 7 replies
  • 11433 views

Hello, I would like to know if there are any special tricks to SPI half-duplex mode. As far as I know the configuration is done normally with only the direction as 1 line. Can anyone point me to some form of an example for setting up the SPI in half-duplex and then receiving through said port SPI mode. I have searched for days and could not find anything concrete.

Please I am really desperate. Any help will be appreciated

Thank you

    This topic has been closed for replies.
    Best answer by FBoth.1

    Thanks for all the replies. I found the answer. You configure in master half duplex mode then add lines 24 to 27

    HAL_StatusTypeDef MX_SPI2_Init(SPI_HandleTypeDef* hspi)
    {
     HAL_StatusTypeDef ret = HAL_OK;
     hspi->Instance = SPI2;
     hspi->Init.Mode = SPI_MODE_MASTER;
     hspi->Init.Direction = SPI_DIRECTION_1LINE;
     hspi->Init.DataSize = SPI_DATASIZE_8BIT;
     hspi->Init.CLKPolarity = SPI_POLARITY_HIGH;
     hspi->Init.CLKPhase = SPI_PHASE_2EDGE;
     hspi->Init.NSS = SPI_NSS_SOFT;
     hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
     hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
     hspi->Init.TIMode = SPI_TIMODE_DISABLE;
     hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
     hspi->Init.CRCPolynomial = 7;
     hspi->Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
     hspi->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
     
     if (HAL_SPI_Init(hspi) != HAL_OK)
     {
     ret = HAL_ERROR;
     }
     
     HAL_Delay(5);
     SPI_1LINE_TX(hspi);
     HAL_Delay(5);
     __HAL_SPI_ENABLE(hspi);
     
    }

    In order to receive from SPI in half duplex use the following:

    void LSM6DS3_WriteReg(uint8_t reg, uint8_t setting)
    {
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
    	HAL_SPI_Transmit(&hspi1,&reg,1,15);
    	HAL_SPI_Transmit(&hspi1,&setting,1,15);
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
    }

    Note this is to read the contents of a register on an accelerometer+gyro chip

    To write to said chip use code below:

    uint8_t LSM6DS3_ReadReg(uint8_t reg)
    {
    	uint8_t readMask;
    	uint8_t dataInReg;
    	
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
    	readMask = reg|0x80;
    	HAL_SPI_Transmit(&hspi1,&readMask,1,15);
    	__HAL_SPI_DISABLE(&hspi1);
    	SPI_1LINE_RX(&hspi1);
    	__HAL_SPI_ENABLE(&hspi1);
    	HAL_SPI_Receive(&hspi1,&dataInReg,1,15);
    	__DSB();
    	__DSB();
    	__HAL_SPI_DISABLE(&hspi1);
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
    	SPI_1LINE_TX(&hspi1);
    	__HAL_SPI_ENABLE(&hspi1);
    	
    	return dataInReg;
    }

    Pin 12B is my current chip select pin. I hope this helps someone in the future

    7 replies

    Visitor II
    July 28, 2020

    I would simply use full duplex and only configure the SPI pins I need. This is mostly because even as master, half duplex seems to have some SPI SCK uncontrollable clock generation mode (probably the SW needs to keep up the pace). In full duplex mode, even without using MOSI, writing the DR will generate the right amount of SCK clock pulses so you are in full SW control of what is happening. Then move to the half duplex...

    Visitor II
    July 28, 2020

    which MCU used?

    Typically this functionality is explained in reference manual. also there is step by step instructions to config in that mode

    FBoth.1Author
    Visitor II
    July 28, 2020

    STM32L47. I will look at the refrence manual thank you. The problem is I need to transmit and receive using the same pin

    FBoth.1Author
    Visitor II
    July 28, 2020

    Can I set and clear BDIOE bit or is that handled by the HAL libraries? In order to ensure the correct clock?

    Visitor II
    July 28, 2020

    I don't know about HAL libraries.

    ​you can set and clear BIDIOE before send/receive manually.

    Visitor II
    July 28, 2020

    I recommend to short externally MISO and MOSI and avoid using the MISO/MOSI swap which seems not functional in full duplex mode.

    FBoth.1AuthorAnswer
    Visitor II
    July 29, 2020

    Thanks for all the replies. I found the answer. You configure in master half duplex mode then add lines 24 to 27

    HAL_StatusTypeDef MX_SPI2_Init(SPI_HandleTypeDef* hspi)
    {
     HAL_StatusTypeDef ret = HAL_OK;
     hspi->Instance = SPI2;
     hspi->Init.Mode = SPI_MODE_MASTER;
     hspi->Init.Direction = SPI_DIRECTION_1LINE;
     hspi->Init.DataSize = SPI_DATASIZE_8BIT;
     hspi->Init.CLKPolarity = SPI_POLARITY_HIGH;
     hspi->Init.CLKPhase = SPI_PHASE_2EDGE;
     hspi->Init.NSS = SPI_NSS_SOFT;
     hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
     hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
     hspi->Init.TIMode = SPI_TIMODE_DISABLE;
     hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
     hspi->Init.CRCPolynomial = 7;
     hspi->Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
     hspi->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
     
     if (HAL_SPI_Init(hspi) != HAL_OK)
     {
     ret = HAL_ERROR;
     }
     
     HAL_Delay(5);
     SPI_1LINE_TX(hspi);
     HAL_Delay(5);
     __HAL_SPI_ENABLE(hspi);
     
    }

    In order to receive from SPI in half duplex use the following:

    void LSM6DS3_WriteReg(uint8_t reg, uint8_t setting)
    {
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
    	HAL_SPI_Transmit(&hspi1,&reg,1,15);
    	HAL_SPI_Transmit(&hspi1,&setting,1,15);
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
    }

    Note this is to read the contents of a register on an accelerometer+gyro chip

    To write to said chip use code below:

    uint8_t LSM6DS3_ReadReg(uint8_t reg)
    {
    	uint8_t readMask;
    	uint8_t dataInReg;
    	
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
    	readMask = reg|0x80;
    	HAL_SPI_Transmit(&hspi1,&readMask,1,15);
    	__HAL_SPI_DISABLE(&hspi1);
    	SPI_1LINE_RX(&hspi1);
    	__HAL_SPI_ENABLE(&hspi1);
    	HAL_SPI_Receive(&hspi1,&dataInReg,1,15);
    	__DSB();
    	__DSB();
    	__HAL_SPI_DISABLE(&hspi1);
    	HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
    	SPI_1LINE_TX(&hspi1);
    	__HAL_SPI_ENABLE(&hspi1);
    	
    	return dataInReg;
    }

    Pin 12B is my current chip select pin. I hope this helps someone in the future

    Explorer
    January 14, 2025

    I think I am facing a similar issue. 

    Just reading your solution, you say "In order to receive from SPI in half duplex use the following:" then have code which is only transmitting. Is this typo or am I not understanding correctly? The opposite for writing to the chip. 

    Super User
    January 14, 2025

    @RahulGuiris wrote:

    you say "In order to receive from SPI in half duplex use the following:" then have code which is only transmitting.


    Indeed. And the function name is LSM6DS3_WriteReg - so does look very much like a typo.

    Visitor II
    August 6, 2020

    The thing is SPI master half duplex has some time period where the SCK clock free runs, so if your sensor can accept it, it's fine.

    The swap MISO/MOSI seems not work in full duplex mode though...