STM32F722ZE Comunicación SPI con LSM6DS33 usando HAL

Durante mucho tiempo no puedo leer los datos correctos del registro de control LSM6DS33 (acelerómetro + giroscopio).

Como leí en la hoja de datos, la dirección del registro de control WHO_I_AM es 0x0f. Para leer los datos, el MSB debe establecerse en 1, por lo que finalmente envío 0x8f. Sin embargo, los datos recibidos no tienen nada que ver con el valor esperado 0x69, normalmente recibo algo como 0xff, 0x8f.

Compruebo los datos en modo de depuración, también miro directamente en el registro DR. Revisé todas las combinaciones de CLKPolarity, CLKPhase y nada ayudó, estoy convencido de que todo está bien conectado.

Estoy usando TrueSTUDIO y el complemento MXCube, stm32f722ze en la placa nucleo

/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2018 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f7xx_hal.h"

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

SPI_HandleTypeDef hspi1;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  *
  * @retval None
  */
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_SPI1_Init();
  /* USER CODE BEGIN 2 */
  uint8_t sent,received;
  sent = 0x8f;
  received =0x00;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      HAL_GPIO_WritePin(SSPIN_GPIO_Port,SSPIN_Pin,GPIO_PIN_RESET);
      HAL_SPI_Transmit(&hspi1,&sent,1,10);
      HAL_SPI_Receive(&hspi1,&received,1,10);


      HAL_GPIO_WritePin(SSPIN_GPIO_Port,SSPIN_Pin,GPIO_PIN_SET);
      HAL_Delay(500);

  /* 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;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 216;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Activate the Over-Drive mode 
    */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**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_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* SPI1 init function */
static void MX_SPI1_Init(void)
{

  /* 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_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  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_ENABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

/** Configure pins as 
        * Analog 
        * Input 
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct;

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(SSPIN_GPIO_Port, SSPIN_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin : SSPIN_Pin */
  GPIO_InitStruct.Pin = SSPIN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  HAL_GPIO_Init(SSPIN_GPIO_Port, &GPIO_InitStruct);

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* 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****/
Bienvenido. ¿Qué has intentado para aislar el problema? ¿Funciona la comunicación SPI con algún otro chip o en modo loopback? ¿Tiene acceso al osciloscopio/analizador lógico?
Desafortunadamente, actualmente no tengo otro chip para la prueba. Así que hice el modo loopback, conecté las líneas MISO y MOSI, modifiqué el programa y funcionó. Intenté ejecutar LSM6DS33 con raspberrypi y funciona parcialmente, obtengo el tipo de datos 0x69, 0x69,0x69, 0xff, 0xff, 0x69. Actualmente no tengo un analizador lógico u osciloscopio.
Uso la placa Pololu (n.º de artículo de Pololu: 2736) con LSM6DS33.
Extraño. ¿Puede confirmar que el pin SS es correcto y está cableado correctamente (simplemente cree un "parpadeo" en ese pin y mida con un voltímetro en LSM6DS33)? ¿Está LSM6DS33 en modo SPI? También puedes intentar bajar el reloj aunque parece que debería estar bien.
El pin SS está conectado correctamente y lo verifiqué de acuerdo con las instrucciones. En el caso de raspberry pi, probablemente un cable estaba un poco suelto, pero ahora está bien y lee los datos 0x69 correctamente... Sin embargo, en stm también verifiqué el pin SS: funciona correctamente pero los datos son completamente aleatorios . Cuando el pin SS está en estado alto, spi está en modo inactivo, cuando el pin SS está en estado bajo, SPI comienza a enviar datos. La comunicación spi no se puede deshabilitar en el módulo dado. Es posible SPI/I2C activo (predeterminado) o solo SPI activo.
SPI_NSS_PULSE_ENABLE? Si desconecta MISO, ¿todavía obtiene datos aleatorios o 0xff como se esperaba?
"hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;", no lo cambié, era el valor predeterminado. Cuando desconecto el valor de registro de MISO spi1 dr es 0x00.
Bueno, intente cambiar eso a deshabilitado, ya que está controlando SS manualmente. Si eso no cambia nada, ¿intenta bajar el reloj?
@R.Griffin - Hola, gracias por regresar para agregar su solución. :-) Sin embargo , agregar la solución a la pregunta no es cómo se escriben las respuestas en los sitios de Stack Exchange. Si ha resuelto su propio problema, puede escribir su propia respuesta :-) Por lo tanto, ¿puede escribir su solución en su propia respuesta y luego eliminarla de la pregunta? Gracias. :-) Finalmente, acepte una de las respuestas, para que el sitio sepa que la pregunta ha sido resuelta. Es posible aceptar su propia respuesta. Si la otra respuesta también funcionó, lo animo a que al menos la vote a favor .
Gracias por el buen consejo, me pareció extraño escribir una respuesta por separado y luego aceptar :) De todos modos, hice lo que me recomendaste. Desafortunadamente, no puedo votar porque tengo muy pocos puntos de reputación.

Respuestas (2)

Las partes de STM generalmente esperan lecturas en ráfaga con la primera palabra como dirección y el segundo byte ficticio. Intente convertir sus datos TX/RX en matrices y, HAL_SPI_TransmitReceive()en su lugar, haga lo siguiente:

uint8_t txBuf[2] = {0x8f, 0x00};
uint8_t rxBuf[2] = {0x00, 0x00};
HAL_SPI_TransmitReceive(&hspi1, &txbuf, &rxBuf, 2, 10);

Su respuesta debe estar en el segundo byte ([1]) de la matriz de respuesta.

Consulte la sección 6.2.1 de la hoja de datos LSM6DS33

Funciona, pero mi solución también debería funcionar, porque SSPIN todavía está en un estado bajo.
Teóricamente, sí. Prácticamente, el chip podría tener algún tiempo de espera de marco interno. Es decir, si el siguiente reloj no llega dentro de 2 a 4 períodos de reloj completos, considere que la ráfaga anterior ha terminado, o algo así. Para obtener detalles al respecto, debe comunicarse con el fabricante. Busqué en la hoja de datos y no encontré ninguna información sobre la duración de validez de un solo cuadro.

Ayudó a establecer el CPOL en 'bajo'. No sé por qué no funcionó la primera vez, pero esta vez conecté el sensor del otro lado (a los pines macho)