cancel
Showing results for 
Search instead for 
Did you mean: 

SPI half-duplex example

FBoth.1
Associate III

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

1 ACCEPTED SOLUTION

Accepted Solutions
FBoth.1
Associate III

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

View solution in original post

8 REPLIES 8
S.Ma
Principal

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...

prain
Senior III

which MCU used?

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

FBoth.1
Associate III

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

FBoth.1
Associate III

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

I don't know about HAL libraries.

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

S.Ma
Principal

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

FBoth.1
Associate III

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

S.Ma
Principal

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...