cancel
Showing results for 
Search instead for 
Did you mean: 

using SPI to read register value

moha
Associate II

Hello Guys

I am asking you kindly your help.

I am trying to read register data from the LSM6DS3 IMU sensor from STM using SPI. I succeeded reading the value 0x69 from register WHO_AM_I using Arduino.

Now I am stuck when trying to do it with STM32 micro-controller.

Reading data sheet I concluded the following specs: Max SCLK 10MHz, 8 bits word, MSB first, CPOL high, CPAHSE 2 Edge (sampling on trailing edge).

I think I am setting the stm32 micro-controller like so but I am not able to read any data from register WHO_AM_I .

The following code is the reading process, followed by the SPI init routine.

the problem is when I track the evolution of MOSI line and SCLK  by doing a transmit then receive, I am getting the reading in picture 1 using oscilloscope,

it look different than when I use the "HAL_SPI_TransmitReceive" as shown in picture 2.    in the case of  transmit then receive I can read 0x8F on oscilloscope but also an other byte 0x00 which I dont know where it is coming from. in case of "HAL_SPI_TransmitReceive" I can read 0x8F only.

In both ways I can read nothing on the MISO line

uint8_t spitx[2],spirx[2];
uint8_t WHO_AM_I = 0x0F;
 
while (1)
{
spitx[0] = WHO_AM_I | 0x80;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0,GPIO_PIN_RESET);
// HAL_SPI_TransmitReceive (&hspi1, spitx, spirx, 1, 50);
HAL_SPI_Transmit (&hspi1, spitx, 1, 50);
HAL_SPI_Receive (&hspi1, spirx, 1, 50);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0,GPIO_PIN_SET);
memset(spitx,0,2);
memset(spirx,0,2);
HAL_Delay(50);
}
 
static void MX_SPI1_Init(void)
{
 
  /* USER CODE BEGIN SPI1_Init 0 */
 
  /* USER CODE END SPI1_Init 0 */
 
  /* USER CODE BEGIN SPI1_Init 1 */
 
  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  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_2EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */
 
  /* USER CODE END SPI1_Init 2 */
 
}

0690X0000089wYGQAY.jpg

0690X0000089wYQQAY.jpg

1 ACCEPTED SOLUTION

Accepted Solutions
Min-Kyoung Kim
Associate III

Did you add this in your code (before while)?

__HAL_SPI_ENABLE(&SENSORS_SPI);

Even though I'm using 3 wire spi, I solved my problem by adding that code.

Also, I add my code. (I succeed!)

void Sensor_IO_SPI_Read(Sensor_StateTypeDef *handle, uint8_t ReadAddr, uint8_t *pBuffer, uint16_t nBytesToRead)
{
  /* Write Reg Address */
  Sensor_StateTypeDef *ctx = (Sensor_StateTypeDef *)handle;
 
  SPI_Write(&SENSORS_SPI, ReadAddr | 0x80);
 
  /* Disable the SPI and change the data line to input */
  __HAL_SPI_DISABLE(&SENSORS_SPI);
  SPI_1LINE_RX(&SENSORS_SPI);
 
  /* Check if we need to read one byte or more */
  if(nBytesToRead > 1U)
  {
    SPI_Read_nBytes(&SENSORS_SPI, pBuffer, nBytesToRead);
  }
  else
  {
    SPI_Read(&SENSORS_SPI, pBuffer);
  }
  /* Change the data line to output and enable the SPI */
  SPI_1LINE_TX(&SENSORS_SPI);
  __HAL_SPI_ENABLE(&SENSORS_SPI);
}
 
void SPI_Read(SPI_HandleTypeDef *xSpiHandle, uint8_t *val)
{
  /* In master RX mode the clock is automaticaly generated on the SPI enable.
  So to guarantee the clock generation for only one data, the clock must be
  disabled after the first bit and before the latest bit */
  /* Interrupts should be disabled during this operation */
 
  __disable_irq();
 
  __HAL_SPI_ENABLE(xSpiHandle);
  __asm("dsb\n");
  __asm("dsb\n");
  __HAL_SPI_DISABLE(xSpiHandle);
 
  __enable_irq();
 
  while ((xSpiHandle->Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE);
  /* read the received data */
  *val = *(__IO uint8_t *) &xSpiHandle->Instance->DR;
  while ((xSpiHandle->Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY);
}
 
void SPI_Read_nBytes(SPI_HandleTypeDef *xSpiHandle, uint8_t *val, uint16_t nBytesToRead)
{
  /* Interrupts should be disabled during this operation */
  __disable_irq();
  __HAL_SPI_ENABLE(xSpiHandle);
 
  /* Transfer loop */
  while (nBytesToRead > 1U)
  {
    /* Check the RXNE flag */
    if (xSpiHandle->Instance->SR & SPI_FLAG_RXNE)
    {
      /* read the received data */
      *val = *(__IO uint8_t *) &xSpiHandle->Instance->DR;
      val += sizeof(uint8_t);
      nBytesToRead--;
    }
  }
  /* In master RX mode the clock is automaticaly generated on the SPI enable.
  So to guarantee the clock generation for only one data, the clock must be
  disabled after the first bit and before the latest bit of the last Byte received */
  /* __DSB instruction are inserted to garantee that clock is Disabled in the right timeframe */
 
  __DSB();
  __DSB();
  __HAL_SPI_DISABLE(xSpiHandle);
 
  __enable_irq();
 
  while ((xSpiHandle->Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE);
  /* read the received data */
  *val = *(__IO uint8_t *) &xSpiHandle->Instance->DR;
  while ((xSpiHandle->Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY);
}

You should reset and set CS pin.

View solution in original post

4 REPLIES 4
Min-Kyoung Kim
Associate III

Did you add this in your code (before while)?

__HAL_SPI_ENABLE(&SENSORS_SPI);

Even though I'm using 3 wire spi, I solved my problem by adding that code.

Also, I add my code. (I succeed!)

void Sensor_IO_SPI_Read(Sensor_StateTypeDef *handle, uint8_t ReadAddr, uint8_t *pBuffer, uint16_t nBytesToRead)
{
  /* Write Reg Address */
  Sensor_StateTypeDef *ctx = (Sensor_StateTypeDef *)handle;
 
  SPI_Write(&SENSORS_SPI, ReadAddr | 0x80);
 
  /* Disable the SPI and change the data line to input */
  __HAL_SPI_DISABLE(&SENSORS_SPI);
  SPI_1LINE_RX(&SENSORS_SPI);
 
  /* Check if we need to read one byte or more */
  if(nBytesToRead > 1U)
  {
    SPI_Read_nBytes(&SENSORS_SPI, pBuffer, nBytesToRead);
  }
  else
  {
    SPI_Read(&SENSORS_SPI, pBuffer);
  }
  /* Change the data line to output and enable the SPI */
  SPI_1LINE_TX(&SENSORS_SPI);
  __HAL_SPI_ENABLE(&SENSORS_SPI);
}
 
void SPI_Read(SPI_HandleTypeDef *xSpiHandle, uint8_t *val)
{
  /* In master RX mode the clock is automaticaly generated on the SPI enable.
  So to guarantee the clock generation for only one data, the clock must be
  disabled after the first bit and before the latest bit */
  /* Interrupts should be disabled during this operation */
 
  __disable_irq();
 
  __HAL_SPI_ENABLE(xSpiHandle);
  __asm("dsb\n");
  __asm("dsb\n");
  __HAL_SPI_DISABLE(xSpiHandle);
 
  __enable_irq();
 
  while ((xSpiHandle->Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE);
  /* read the received data */
  *val = *(__IO uint8_t *) &xSpiHandle->Instance->DR;
  while ((xSpiHandle->Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY);
}
 
void SPI_Read_nBytes(SPI_HandleTypeDef *xSpiHandle, uint8_t *val, uint16_t nBytesToRead)
{
  /* Interrupts should be disabled during this operation */
  __disable_irq();
  __HAL_SPI_ENABLE(xSpiHandle);
 
  /* Transfer loop */
  while (nBytesToRead > 1U)
  {
    /* Check the RXNE flag */
    if (xSpiHandle->Instance->SR & SPI_FLAG_RXNE)
    {
      /* read the received data */
      *val = *(__IO uint8_t *) &xSpiHandle->Instance->DR;
      val += sizeof(uint8_t);
      nBytesToRead--;
    }
  }
  /* In master RX mode the clock is automaticaly generated on the SPI enable.
  So to guarantee the clock generation for only one data, the clock must be
  disabled after the first bit and before the latest bit of the last Byte received */
  /* __DSB instruction are inserted to garantee that clock is Disabled in the right timeframe */
 
  __DSB();
  __DSB();
  __HAL_SPI_DISABLE(xSpiHandle);
 
  __enable_irq();
 
  while ((xSpiHandle->Instance->SR & SPI_FLAG_RXNE) != SPI_FLAG_RXNE);
  /* read the received data */
  *val = *(__IO uint8_t *) &xSpiHandle->Instance->DR;
  while ((xSpiHandle->Instance->SR & SPI_FLAG_BSY) == SPI_FLAG_BSY);
}

You should reset and set CS pin.

moha
Associate II

@Min-Kyoung Kim​ 

Dear Kim

Thanks a lot I added this piece of code to my SPI_INIT function and now I am able to read the register correctly.

I did not do it at first because Transmit function checks whether the peripheral is enabled if not it will do it for you, this is handled by the HAL driver.

any idea on what caused for SPI not to be enabled ?

>> any idea on what caused for SPI not to be enabled ?

I don't know actually.

But, looking at the transmit function, ENABLE ​is executed last, before data is sent.

So I added ENABLE.

I fount this when I sent the data 2 times. First time, I failed. but second time i succeed. :)

Dear @Min-Kyoung Kim​ 

I apologize for the late reply.

Thank you very much for your insight.

I am doing a lot better than before.

I personally enjoy SPI now more that I2C surprisingly.