1

I try to run an Nucleo-STMF411RE as a SPI Slave/device with an ESP32 as a Master.

One way data transmisson runs smoothly but as soon as the device should transmit data back to the master things get corrupted.

My SPI Master side looks like this:

void setup() {
  // put your setup code here, to run once:
    Serial.begin(9600);
  pinMode(SPI_MOSI, OUTPUT);  //MOSI 23
  pinMode(SPI_MISO, INPUT);   //MISO 19
  pinMode(SPI_SCK, OUTPUT);  //CLK 18
  pinMode(SPI_CS, OUTPUT);  //SS/CS 5

  digitalWrite(SPI_CS, HIGH); // disable Slave Select
  SPI.begin ();
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV64);
  SPI.setDataMode(SPI_MODE0);
}
void loop() {
  // put your main code here, to run repeatedly:
  sendData(a, 0x01020304);
  a++;
  delay(3000);
}

void sendData(unsigned long address, unsigned long datagram)
{
uint8_t TxBuff[5] = {0,0,0,0,0};
uint8_t RxBuff[5] ={0,0,0,0,0};

 TxBuff[0] = address;
 TxBuff[1] = (datagram >> 24) & 0xff;
 TxBuff[2] = (datagram >> 16) & 0xff;
 TxBuff[3] = (datagram >> 8) & 0xff;
 TxBuff[4] = (datagram >> 0) & 0xff;

 Serial.print("Tx: 0x");
 Serial.print(TxBuff[0], HEX);
 Serial.print(" 0x");
 Serial.print(TxBuff[1], HEX);
 Serial.print(TxBuff[2], HEX);
 Serial.print(TxBuff[3], HEX);
 Serial.println(TxBuff[4], HEX);

 digitalWrite(SPI_CS,LOW);
 delayMicroseconds(10);
 SPI.transferBytes((uint8_t *)&TxBuff,(uint8_t *)&RxBuff, 5);
 delayMicroseconds(10);
 digitalWrite(SPI_CS,HIGH);


 Serial.print("Rx: 0x");
 Serial.print(RxBuff[0], HEX);
 Serial.print(" 0x");
 Serial.print(RxBuff[1], HEX);
 Serial.print(RxBuff[2], HEX);
 Serial.print(RxBuff[3], HEX);
 Serial.print(RxBuff[4], HEX);
 Serial.println("");
}

On the STM side I am using the HAL and code generated from MXCube. I already tried the interrupt and blocking methods but with both i got the same unsatisfying results.

Here is my Clock and Initialisation code for SPI2:

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** 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 = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

static void MX_SPI2_Init(void)
{

  /* USER CODE BEGIN SPI2_Init 0 */

  /* USER CODE END SPI2_Init 0 */

  /* USER CODE BEGIN SPI2_Init 1 */

  /* 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_SOFT;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI2_Init 2 */

  /* USER CODE END SPI2_Init 2 */

}

In my while(1) I ask for the slave_select pin and as soon as its get low the slave gets ready for receiving/transmitting:

while (1) {
   
   slave_select = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12);
   if (slave_select == 0) {
       status = HAL_SPI_Receive(&hspi2, (uint8_t *) aRxBuffer, 5, 5000);
   }

}

When I substitute the HAL-Receive function with status = HAL_SPI_TransmitReceive(&hspi2, (uint8_t*) aTxBuffer, (uint8_t *) aRxBuffer, 5, 5000); things get out of sync and not even the received data is correct anymore. I really don't know what seems to be the problem as I tried multiple Boards and platforms already.

PhilM
  • 56
  • 5

1 Answers1

1

After a couple of weeks trying and failing I could figure out that it had to be a EMI-Problem. I was aware that the connection running the SPI should not be too long and in my case the ribbon cable had a length of 15 cm. After a while I found out that you should have common GNDs between your signal lines when using a protocol like SPI over ribbon cables that it looks like this:

GND - MOSI - GND - GND - MISO - GND - GND - SCK - GND - GND CS - GND

Alternatively you could seperate the cables and use even shorter ones.

That solved the problem for me =)

PhilM
  • 56
  • 5