cancel
Showing results for 
Search instead for 
Did you mean: 

LSM6DSM on SensorTile using SPI?

SWenn.1
Senior III

I would like to know what I am doing wrong or what register setting on the LSM6DSM that I missed setting?

Using a sensorTile (STM32L476JG) that is connected to LSM6DSM. APB1 Clk = 16MHz.

My settings are :

0693W00000KbYP9QAN.png 

My code is trying to read WHO_AM_I register on the part, I get 0xC5 , should get 0x6A.

	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x12;
	  txBuf[1] = 0x08;
	  HAL_SPI_Transmit(&hspi2, txBuf, 2, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
 
	  /*
	   * disable i2c
	   */
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x13;
	  txBuf[1] = 0x04;
	  HAL_SPI_Transmit(&hspi2, txBuf, 2, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
 
	  /*
	   * who_am_I :  should return 0x6a
	   */
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x0F | 0x80;
	  HAL_SPI_Transmit(&hspi2, txBuf, 1, 50);
	  HAL_SPI_Receive(&hspi2, rxBuf, 1, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);

7 REPLIES 7
Eleon BORLINI
ST Employee

Hi @SWenn.1​ ,

I would suggest you to start by comparing your code with the SPI line configuration in the Sensortile firmware, i.e. the FP-SNS-ALLMEMS1 firmware function pack. You can refer to the two functions of the SensorTile_motion_sensors.c for:

  • Initializing of the SPI line:
/**
 * @brief  Initialize SPI bus for LSM6DSM
 * @retval BSP status
 */
static int32_t BSP_LSM6DSM_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  int32_t ret = BSP_ERROR_UNKNOWN_FAILURE;
  
  HAL_GPIO_WritePin(BSP_LSM6DSM_CS_PORT, BSP_LSM6DSM_CS_PIN, GPIO_PIN_SET);
  
  GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  
  BSP_LSM6DSM_CS_GPIO_CLK_ENABLE();
  GPIO_InitStruct.Pin = BSP_LSM6DSM_CS_PIN;
  HAL_GPIO_Init(BSP_LSM6DSM_CS_PORT, &GPIO_InitStruct);
  HAL_GPIO_WritePin(BSP_LSM6DSM_CS_PORT, BSP_LSM6DSM_CS_PIN, GPIO_PIN_SET);
 
  if(BSP_SPI2_Init() == BSP_ERROR_NONE)
  {
    ret = BSP_ERROR_NONE;
  }
 
  return ret;
}

  • SPI read function:
/**
 * @brief  Write register by SPI bus for LSM6DSM
 * @param  Addr not used, it is only for BSP compatibility
 * @param  Reg the starting register address to be written
 * @param  pdata the pointer to the data to be written
 * @param  len the length of the data to be written
 * @retval BSP status
 */
static int32_t BSP_LSM6DSM_WriteReg(uint16_t Addr, uint16_t Reg, uint8_t *pdata, uint16_t len)
{
  int32_t ret = BSP_ERROR_NONE;
  uint8_t dataReg = (uint8_t)Reg;
 
  /* CS Enable */
  HAL_GPIO_WritePin(BSP_LSM6DSM_CS_PORT, BSP_LSM6DSM_CS_PIN, GPIO_PIN_RESET);
 
  if (BSP_SPI2_Send(&dataReg, 1) != 1)
  {
    ret = BSP_ERROR_UNKNOWN_FAILURE;
  }
 
  if (BSP_SPI2_Send(pdata, len) != len)
  {
    ret = BSP_ERROR_UNKNOWN_FAILURE;
  }
 
  /* CS Disable */
  HAL_GPIO_WritePin(BSP_LSM6DSM_CS_PORT, BSP_LSM6DSM_CS_PIN, GPIO_PIN_SET);
 
  return ret;
}

By the way, are you always getting I get 0xC5 instead of 0x6A? Did you try to read other registers (such as the output regs after having configured at least the ODR in the control registers?)

-Eleon

Hello Eleon....

Thank you. I am not reading C5 consistently.....Sometimes 0xC5 sometimes 0x09....Never 0x6A. I did try to write a value to 0x25 to 0x71 address as well and there I receive back 0x09....I feel like I am missing some initializations on the LSM6DSM register settings?? As you can see I am setting register 0x12 (although I have no way to confirm that these writes are working......) which should set me for 3 wire SPI and register 0x13 which should disable I2C.....

	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x12;
	  txBuf[1] = 0x08;
	  HAL_SPI_Transmit(&hspi2, txBuf, 2, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
 
	  /*
	   * disable i2c
	   */
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x13;
	  txBuf[1] = 0x04;
	  HAL_SPI_Transmit(&hspi2, txBuf, 2, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
 
	  /*
	   * who_am_I :  should return 0x6a
	   */
/*
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x0F | 0x80;
	  HAL_SPI_Transmit(&hspi2, txBuf, 1, 50);
	  HAL_SPI_Receive(&hspi2, rxBuf, 1, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
*/
 
 
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x71;
	  txBuf[1] = 0x25;
	  HAL_SPI_Transmit(&hspi2, txBuf, 2, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);
 
 
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_RESET);
	  txBuf[0] = 0x71 | 0x80;
	  HAL_SPI_Transmit(&hspi2, txBuf, 1, 50);
	  HAL_SPI_Receive(&hspi2, rxBuf, 1, 50);
	  HAL_GPIO_WritePin(SPI_CS_GPIO_Port, SPI_CS_Pin, GPIO_PIN_SET);

Hi @SWenn.1​ ,

but are you using the 3-wire SPI instead of the 4-wire standard? IN the first case you have to properly manage the SDI/O line, and also to write the SIM bit of the CTRL3_C (12h) register (but, if the SPI is not working, this action would not be possible).

In this case, you might refer to the following piece of code:

/**
* @brief  This function reads multiple bytes on SPI 3-wire.
* @param  xSpiHandle: SPI Handler.
* @param  val: value.
* @param  nBytesToRead: number of bytes to read.
* @retval None
*/
void LSM6DSM_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);
}

Note that if you want to read the WHO_AM_I register, you don't need a specific register setting, but only to initialize correctly the pins (Vdd, VddIO, SPI, GND).

Could you try to setup the SPI-4 communication?

-Eleon

Yes I am using 3 wire SPI...I am using STEVAL-STLKT01V1....User manual clearly shows only 3 wire connection.....In CubeMX I am set up as Master Half Duplex...I believe this is all l have to do for 3 wire, correct? The board is a dev board and should be configured already.

Here is the sensorTile connection.....The pic suggests by the net name that it can be SPI but the data sheet calls the pin SDA, which is traditionally used for I2C??

Unfortunately I NEED PB14 and PB15 to work on the STM32L476JGYX part of the sensorTile. I have used up all the I/O which includes the coveted PC0 and PC1 for other external things. Please tell me it is possible to use PB14 and PB15 as SPI along with the below pic of the Accel wiring to it. PB15 cannot be configured as I2C.

0693W00000Kbi9pQAB.png

Hi @SWenn.1​ ,

it's correctly a 3-wire SPI.

But is the example code FP-SNS-ALLMEMS1 not working?

-Eleon

Hello Eleon....

Please forgive me as I am a hardware guy at this end that is working my way through firmware....I was able to download the above as you suggested and include the folder /Components/lsm6dsm into my project. I can now see the function calls....Unfortunately I am struggling quite a bit trying to define the structure handle LSM6DSM_Object_t. All the pointers to functions, etc has me quite confused. I am using a sensorTile and am confident that the HW works.....I believe it is a matter of just setting up all the registers correctly on the SPI within the STM32L476 as well as the registers on the LSM6D. If you could supply me the LSMD6 registers and their settings (keep it simple just Hex values) that I need to set prior to reading the WHO_AM_I for 3-Wire SPI that would be helpful. I ordered a demo board with another variant of the LSM6D that is broke out with 0.100" spaced header on the board so that I can hook a logic analyzer up to it to see what is going on. I am pretty sure I have the Firmware on the STM32 correct as it is pretty simple. I am using 8MHz clock for the LSM6D, CPOL = 1 and CPHA = 2 Edge and have the STM3 as Master Half Duplex.

If you supply the HEX values I will just use the reads and writes of the code earlier that I showed you in the email chain. Once working then I can tackle all the pointers and how to use your function calls in the lsm6dsm.h and .c files.

Thanks

Steve