cancel
Showing results for 
Search instead for 
Did you mean: 

Not reading SPI WHO_AM_I register correctly

JMart.5
Associate II

Hi everybody,

I hope someone there could help me. I am trying to read the WHO_I_AM register of the LIS3MDL magnetic sensor (reg 0x0F). I have a custom pcb with a STM32L151VET6 . I got largley inspired by the STEVAL-WESU-1. I am using STMCubeMx for the set up and STMCubeIDE. I debug with serial wire (STLink v2).

I have spent hours but I cannot find my error. I just get random values, the most common being 0xff out of RxData[0]. I don't think I have a Hardware error since I'm also unable to get a correct reading with the STEVAL-Wesu-1 that works completely fine. Its my first time with SPI and HAL.

These are my SPI parameters set in STMCubeMX :

  • Motorola
  • 8 Bits
  • MSB First
  • Prescaler 16 (since Im runing from a 24 Mhz crystal)
  • CPOL high and CPHA 2 Edge since the LIS3MDL datasheet says : "Those lines are driven at the falling edge of SPC and should be captured at the rising edge of SPC. "

Unfurtunately I don't have an osciloscope or a logic analyser available at the moment.. working from home..

Thank you for your help and please tell me if you require more info.

Have a nice day =)

Jean

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
 
/* Includes ------------------------------------------------------------------*/
#include "main.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
 
/* USER CODE END Includes */
 
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
 
/* USER CODE END PTD */
 
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
 
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
 
/* USER CODE END PM */
 
/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi3;
 
/* USER CODE BEGIN PV */
static uint8_t TxData[2] = {0};
static uint8_t RxData[2] = {0};
//uint8_t rxData;
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI3_Init(void);
/* USER CODE BEGIN PFP */
 
/* USER CODE END PFP */
 
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
 
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI3_Init();
  /* USER CODE BEGIN 2 */
 
  TxData[0] = 0x0F|0x80;
 
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
 
  if(HAL_SPI_TransmitReceive(&hspi3, TxData, RxData, 2, 100) != HAL_OK)
  {
	  //Error handler
  }
 
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
 
  /** Configure the main internal regulator output voltage 
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief SPI3 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI3_Init(void)
{
 
  /* USER CODE BEGIN SPI3_Init 0 */
 
  /* USER CODE END SPI3_Init 0 */
 
  /* USER CODE BEGIN SPI3_Init 1 */
 
  /* USER CODE END SPI3_Init 1 */
  /* SPI3 parameter configuration*/
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_MASTER;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi3.Init.NSS = SPI_NSS_SOFT;
  hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi3.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI3_Init 2 */
 
  /* USER CODE END SPI3_Init 2 */
 
}
 
/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_SET);
 
  /*Configure GPIO pins : PB6 PB7 */
  GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
}
 
/* USER CODE BEGIN 4 */
 
/* USER CODE END 4 */
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
 
  /* USER CODE END Error_Handler_Debug */
}
 
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

12 REPLIES 12

Presumably it is going to take more than a single byte transfer, the data transfer is symmetrical. ie byte going in, byte coming out at same time, how would it know it is register 0x0F until after you've sent it?

Look at Figure 7

https://www.st.com/resource/en/datasheet/lis3mdl.pdf

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
JMart.5
Associate II

thanks for you answer. It was a mistake from my part. I normally set to two. But still not working.. I hope it is what you mean. Cheers!

  TxData[0] = 0x0F|0x80;
 
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
 
  if(HAL_SPI_TransmitReceive(&hspi3, TxData, RxData, 2, 100) != HAL_OK)
  {
	  //Error handler
  }
 
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);

TDK
Guru

> I just get random values, the most common being 0xff out of RxData[0]

Your data is going to be in RxData[1]. RxData[0] isn't useful.

> I don't think I have a Hardware error since I'm also unable to get a correct reading with the STEVAL-Wesu-1 that works completely fine.

That's an interesting take that since 2 different boards both don't work, you don't have a hardware error. Maybe there is a typo here?

If you feel a post has answered your question, please click "Accept as Solution".

Lacking a scope/analyzer just bit-bang the protocol and output the state for inspection.

Might have expectations for CS to settle, give it a couple of micro-seconds.

Make sure it is not in I2C mode, and doesn't enter such at reset. Not a part I'm actively using, perhaps needs a pull up/down.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
KnarfB
Principal III

I wont go though your code, but X-CUBE-MEMS1 has a BSP (board support package) for many sensors including LIS3MDL.

The BSP code has some abstraction layers, but you could use it just to understand the low level register read and write functions.

How do I make sure is not in i2c mode? And you are completely right.. I need an scope/analyser

Sorry my phrase was not clear. I know that the WESU1 onboard LIS3MDL works because the demos (factory settings). When I try manually to read the WHO AM I reg i get the same errors I get with my custom pcb. So I think is my code/method that something is wrong

SPI can be bit-banged, and most devices are static so you can go down with the frequency to around one hertz, where things can be observed using LEDs and a multimeter.

OTOH, things like high speed bouncing due to inadequately high output drive

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

inadequate ground/return, and crosstalk due to long parallel traces, are things which are relatively hard to debug even with oscilloscope/LA.

JW

JMart.5
Associate II

Thanks all for your help.. but nothing has changed. I suspected that STM3CubeMX was not setting the SPI3 rermap correctly but that is not the case. Any other ideas?

Thanks!