cancel
Showing results for 
Search instead for 
Did you mean: 

Cannot get SPI woriking on STM32L0

JZida.1
Associate II

Greetings good people of ST community

I have a problem which I didn't manage to solve by myself, so I am hoping to get some help if possible

I have an LPS22HB sensor (https://eu.mouser.com/datasheet/2/389/lps22hb-1849683.pdf), and I want to connect it to STM32L010K8T6 MCU using SPI. The problem is, I get some temperature register readings with STM studio but they are invalid (0, 128, 255).

0693W00000aH8s4QAC.bmp 

In settings, the MCU CS pin is a pull-up, while pins SCK, MISO, MOSI are no pull-up and no pull-down. All of them are in push-pull mode.

These are my SPI setting in the code:

hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;

My hardware pinout is as following:

INT_DRDY (LPS) - not connected/used

CS (LPS) - SPI_CS (MCU)

SDO/SA0 (LPS) - SPI_MISO (MCU)

SDA/SDI/SDO (LPS) - SPI_MOSI (MCU)

SCL/SPC (LPC) - SPI_SCK (MCU)

I have used this sensor with I2C where it worked (I have used an already written library and ported it to work on STM). These are parts of the main code:

 
        // CS pin should default high
        HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
 
	LPS22HBTRinit();
	LPS22HBTRsetLowPower(1);
	LPS22HBTRsetOutputRate(OutputRate_OneShot);  // get results on demand
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
	  LPS22HBTRrequestOneShot();
	  lpstlak = LPS22HBTRreadPressure();
	  lpstemp = LPS22HBTRreadTemp();
 
	  LPS22HBTRrequestOneShot();
	  reg1 = LPS22HBTRreadRegister(LPS35HW_TEMP_OUT_L);
	  reg2 = LPS22HBTRreadRegister(LPS35HW_TEMP_OUT_H);
	  HAL_Delay(3000);
  }

Here is the read and write register parts of the library (the only thing I changed in comparison to working I2C library).

uint8_t LPS22HBTRreadRegister(uint8_t regAddress)
{
	uint8_t data = 0;
 
  	HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
 
  	HAL_SPI_Transmit(&hspi1, (uint8_t *)&regAddress, 1, 100);
  	HAL_SPI_Receive(&hspi1, (uint8_t *)&data, 1, 100);
 
	HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
	return data;
}
 
uint8_t LPS22HBTRwriteRegister(uint8_t regAddress,uint8_t *dataToWrite)
{
	uint8_t adresa = regAddress;
 
  	HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
 
	HAL_SPI_Transmit(&hspi1, (uint8_t *)&adresa, 1, 100);
	HAL_SPI_Transmit(&hspi1, (uint8_t *)dataToWrite, 1, 100);
 
	HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
	return 1;
}

Thank you for reading

1 ACCEPTED SOLUTION

Accepted Solutions
JZida.1
Associate II

I found the solutions to my problems. I had two problems:

1) As KnarfB pointed out, it should be like this => hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;

2) When reading the register, I didn't send the R/W bit correctly (1 == read), so I failed to get good data

The code below is what works great for me. I appreciate your help KnarfB and S.Ma.

uint8_t LPS22HBTRwriteRegister(uint8_t regAddr, uint8_t *pData)
{
 
  uint8_t sendData[2] = {regAddr, *pData};
 
  HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
 
  HAL_SPI_Transmit(&hspi1, sendData, 2, 100);
 
  HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
 
  return HAL_OK;
}
 
 
 
uint8_t LPS22HBTRreadRegister(uint8_t regAddr)
{
	uint8_t address = regAddr | 0x80;
 
	uint8_t senddata[2] = {address, 0};
	uint8_t receivedata[2] = {0};
 
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
 
	HAL_SPI_TransmitReceive(&hspi1, senddata, receivedata, 2, 50);
 
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
 
	return receivedata[1];
}

View solution in original post

3 REPLIES 3
KnarfB
Principal III

If I look at the data sheet, shoudn't it be hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;

hth

KnarfB

S.Ma
Principal

Because pressure ODR is low sample rate per seconds compared to motion sensors, I used LPS22HH using I2C with bit bang here

Short of finding a solution, maybe this code will help you move forward then get back to SPI later on.

JZida.1
Associate II

I found the solutions to my problems. I had two problems:

1) As KnarfB pointed out, it should be like this => hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;

2) When reading the register, I didn't send the R/W bit correctly (1 == read), so I failed to get good data

The code below is what works great for me. I appreciate your help KnarfB and S.Ma.

uint8_t LPS22HBTRwriteRegister(uint8_t regAddr, uint8_t *pData)
{
 
  uint8_t sendData[2] = {regAddr, *pData};
 
  HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
 
  HAL_SPI_Transmit(&hspi1, sendData, 2, 100);
 
  HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
 
  return HAL_OK;
}
 
 
 
uint8_t LPS22HBTRreadRegister(uint8_t regAddr)
{
	uint8_t address = regAddr | 0x80;
 
	uint8_t senddata[2] = {address, 0};
	uint8_t receivedata[2] = {0};
 
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_RESET);
 
	HAL_SPI_TransmitReceive(&hspi1, senddata, receivedata, 2, 50);
 
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, GPIO_PIN_SET);
 
	return receivedata[1];
}