cancel
Showing results for 
Search instead for 
Did you mean: 

Simple SPI Echo Application drops receiving Bytes and sends undefined data (STM32G474RE)

ATrug.1
Associate II

Hello,

I tried to impelement a simple SPI Echo Slave.

The Master transmits Data (Example for Nucleo 474RE - Master Full Duplex Interrupt) and the Slave waits for reception using HAL with a datasize of 1 Byte.

After the Transfer is completed I am copying the received Byte into the Buffer for the next TX Byte and waiting for the next Transfer again.

When receiving Data, every second Byte received gets dropped, and when trying to echo it, undefined data is sent.

0693W00000FCMYEQA5.jpgAs seen in the Image, the first Channel is MOSI, the second Channel is CLK, the third Channel is MISO. The Slave should transmit the identical message sent by the Master, starting with the second Byte.

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; Copyright (c) 2021 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 ---------------------------------------------------------*/
UART_HandleTypeDef hlpuart1;
 
SPI_HandleTypeDef hspi2;
 
/* USER CODE BEGIN PV */
uint32_t callbackCalledTimes = 0;
uint8_t echoTxByte = 0;
uint8_t echoRxByte = 0;
char debugBuffer[255];
uint8_t debugBufferCounter = 0;
 
/* USER CODE END PV */
 
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_LPUART1_UART_Init(void);
static void MX_SPI2_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)
{
 
  HAL_Init();
 
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_LPUART1_UART_Init();
  MX_SPI2_Init();
 
	if (HAL_SPI_TransmitReceive_IT(&hspi2, &echoTxByte, &echoRxByte, 1) != HAL_OK) {
		/* Transfer error in transmission process */
		Error_Handler();
	}
 
	while (1) {
	}
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
 
  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV4;
  RCC_OscInitStruct.PLL.PLLN = 85;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses 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_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the peripherals clocks
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LPUART1;
  PeriphClkInit.Lpuart1ClockSelection = RCC_LPUART1CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}
 
 
/**
  * @brief SPI2 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI2_Init(void)
{
 
  /* USER CODE END SPI2_Init 1 */
  /* SPI2 parameter configuration*/
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_SLAVE;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_HARD_INPUT;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 7;
  hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
 
 
/**
 * @brief  TxRx Transfer completed callback.
 * @param  hspi: SPI handle
 * @note   This example shows a simple way to report end of Interrupt TxRx transfer, and
 *         you can add your own implementation.
 * @retval None
 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
	debugBuffer[debugBufferCounter] = echoRxByte;
	debugBufferCounter++;
	callbackCalledTimes = callbackCalledTimes + 1;
	echoTxByte = echoRxByte;
	if (HAL_SPI_TransmitReceive_IT(&hspi2, &echoTxByte, &echoRxByte, 1) != HAL_OK) {
		/* Transfer error in transmission process */
		Error_Handler();
	}
 
}
 
/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1) {
		HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
		HAL_Delay(500);
	}
}

How is this behaviour explained? And how to achieve the task?

Thank you very much.

Edit:

SPI is configured with Hardware CS, 8-bit Datasize. 170MHz on the Slave Peripheral Clock. Master uses 664kbit/s transmission Speed.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

The slave needs more time to process the incoming data. Put a 1ms delay between bytes and it will likely work.

It's difficult to achieve this with SPI without restricting how the master sends data. One option is to set up the SPI in circular DMA mode and place outgoing bytes in the correct location as they come in. You will need to poll for new data quite frequently.

For this particular case, you could set up a 1-byte buffer in circular mode and use the same buffer for TX and RX, but that wouldn't be very useful in the long run.

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

View solution in original post

2 REPLIES 2
TDK
Guru

The slave needs more time to process the incoming data. Put a 1ms delay between bytes and it will likely work.

It's difficult to achieve this with SPI without restricting how the master sends data. One option is to set up the SPI in circular DMA mode and place outgoing bytes in the correct location as they come in. You will need to poll for new data quite frequently.

For this particular case, you could set up a 1-byte buffer in circular mode and use the same buffer for TX and RX, but that wouldn't be very useful in the long run.

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

Thanks for the fast answer.

For the sake of science, I tested it with a Circular 1 Byte DMA Buffer. Didn't work out either and caused the same behaviour :)