cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G4 SPI Transmitted Data is also Transmitted while receiving during next cycle

Sidius
Associate III

Hello,

I'm currently working on a project where my STM32G747RE is acting as an SPI Slave.
The SPI transmission is as follow:

  1. Master sends 8 bits "command"
  2. Slave send back 16 bits "data"

My issue is the following; On the MISO line, the STM32 always send back the first 8 bits of data on the first 8 clock cycle of the next SPI transmission. The picture will clarify my words:
20240311_135956.jpgHere the following SPI transmission happends:

  1. Master sends on MOSI the command 8 (then the other 16 bits are 0xFFFF which is good)
  2. Slave sends on MISO the data 253 15 (and then on the first byte of the transmission it also sends 15)

The issue here is that on the MOSI we have 15 that is the data of the previous transmission.
From where can this come from and is there a way to put the SPI buffer (FIFO) high: 0xFF by default ?

Thanks for your support,

Here's the code of my SPI section (there is also a Master SPI but that is for another application which works fine):

/* Includes ------------------------------------------------------------------*/
#include "spi.h"
 
/* USER CODE BEGIN 0 */
uint16_t sbuffer_tx[1];
uint8_t sbuffer_rx[SPI2_PAYLOAD_BYTES];
 
uint8_t adc1Value[3] = {0, 0, 0};
uint8_t adc2Value[3] = {0, 0, 0};
 
/* USER CODE END 0 */
 
SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_rx;
DMA_HandleTypeDef hdma_spi2_tx;
 
 
/* SPI2 init function */
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 */
  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();
  }
  /* USER CODE BEGIN SPI2_Init 2 */
 
  /* USER CODE END SPI2_Init 2 */
 
}
 
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* USER CODE BEGIN SPI2_MspInit 0 */
 
  /* USER CODE END SPI2_MspInit 0 */
    /* SPI2 clock enable */
    __HAL_RCC_SPI2_CLK_ENABLE();
 
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI2 GPIO Configuration
    PB12     ------> SPI2_NSS
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    GPIO_InitStruct.Pin = SPI_Slave_CS_Pin|SPI_Slave_SCLK_Pin|SPI_Slave_MISO_Pin|SPI_Slave_MOSI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SPI2 DMA Init */
    /* SPI2_RX Init */
    hdma_spi2_rx.Instance = DMA1_Channel3;
    hdma_spi2_rx.Init.Request = DMA_REQUEST_SPI2_RX;
    hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_rx.Init.Mode = DMA_NORMAL;
    hdma_spi2_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi2_rx);
 
    /* SPI2_TX Init */
    hdma_spi2_tx.Instance = DMA1_Channel4;
    hdma_spi2_tx.Init.Request = DMA_REQUEST_SPI2_TX;
    hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi2_tx.Init.Mode = DMA_NORMAL;
    hdma_spi2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
    {
      Error_Handler();
    }
 
    __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);
 
    /* SPI2 interrupt Init */
    HAL_NVIC_SetPriority(SPI2_IRQn, 4, 0);
    HAL_NVIC_EnableIRQ(SPI2_IRQn);
  /* USER CODE BEGIN SPI2_MspInit 1 */
 
  /* USER CODE END SPI2_MspInit 1 */
  }
}
 
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{
  /* USER CODE BEGIN SPI2_MspDeInit 0 */
 
  /* USER CODE END SPI2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI2_CLK_DISABLE();
 
    /**SPI2 GPIO Configuration
    PB12     ------> SPI2_NSS
    PB13     ------> SPI2_SCK
    PB14     ------> SPI2_MISO
    PB15     ------> SPI2_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, SPI_Slave_CS_Pin|SPI_Slave_SCLK_Pin|SPI_Slave_MISO_Pin|SPI_Slave_MOSI_Pin);
 
    /* SPI2 DMA DeInit */
    HAL_DMA_DeInit(spiHandle->hdmarx);
    HAL_DMA_DeInit(spiHandle->hdmatx);
 
    /* SPI2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(SPI2_IRQn);
  /* USER CODE BEGIN SPI2_MspDeInit 1 */
 
  /* USER CODE END SPI2_MspDeInit 1 */
  }
}
 
/* USER CODE BEGIN 1 */
 
/* ----------------------------------------------------------------------
 * ----------------------------------------------------------------------
 * ----------------------------SPI2 - SLAVE------------------------------
 * ----------------------------------------------------------------------
 * ----------------------------------------------------------------------
 * ----------------------------------------------------------------------
 */
 
/**
   * @brief  Initialize the SPI2 Communication
   */
void Init_SPI_Slave(void) {
// __HAL_RCC_SPI2_FORCE_RESET();
// __HAL_RCC_SPI2_RELEASE_RESET();
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
if (HAL_SPI_Init(&hspi2) != HAL_OK)
{
My_Error_Handler ("The SPI2 (Slave) Receive Communication did not Start.");
}
 
    if (HAL_SPI_Receive_IT(&hspi2, sbuffer_rx, SPI2_HEADER_BYTES) != HAL_OK) {
        // Handle error if SPI2 (Slave) receive communication fails.
        My_Error_Handler("The SPI2 (Slave) Receive Communication did not Start.");
    }
}
 
/**
   * @brief  CallBack function of HAL_SPI_TransmitReceive_DMA.
   * Gets called at the end of the communication.
   * @PAram  *hspi: Pointer to the SPI object.
   */
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) {
    if (hspi->Instance == SPI2) {
    // Start the 10 microsecond timer for interrupt
    if (HAL_TIM_Base_Start_IT(&htim6) != HAL_OK)
    {
    My_Error_Handler("The 10 microsecond Timer did not Start.");
    }
/* ----------------------------------------------------------------------
* ---------------------------- SPI - READ -------------------------------
* -----------------------------------------------------------------------
*/
    hspi2.Init.DataSize = SPI_DATASIZE_16BIT;
    if (HAL_SPI_Init(&hspi2) != HAL_OK)
    {
    My_Error_Handler ("The SPI2 (Slave) Receive Communication did not Start.");
    }
 
        // If the master wants to read the ADC channel 1
    if (sbuffer_rx[0] == ADC1_MAX << 2){
// Need to Lock & Disable the DMA
__HAL_LOCK(hspi->hdmatx);
__HAL_DMA_DISABLE(hspi->hdmatx);
 
sbuffer_tx[0]= ((adc1Value[2] << 8) | adc1Value[1]);
 
// Unlock & Enable the DMA
__HAL_DMA_ENABLE(hspi->hdmatx);
__HAL_UNLOCK(hspi->hdmatx);
 
if (HAL_SPI_Transmit_IT(hspi, (uint8_t*)(sbuffer_tx), 1) != HAL_OK) {
// Handle error if SPI2 (Slave) transmit communication fails.
My_Error_Handler("The SPI2 (Slave) Transmit Communication did not Start.");
}
 
// If the master wants to read the ADC channel 2
} else if (sbuffer_rx[0] == ADC2_MAX << 2){
// Need to Lock & Disable the DMA
__HAL_LOCK(hspi->hdmatx);
__HAL_DMA_DISABLE(hspi->hdmatx);
 
// Upload the TX buffer values
sbuffer_tx[0]= ((adc2Value[2] << 8) | adc2Value[1]);
 
// Unlock & Enable the DMA
__HAL_DMA_ENABLE(hspi->hdmatx);
__HAL_UNLOCK(hspi->hdmatx);
 
if (HAL_SPI_Transmit_IT(hspi, (uint8_t*)(sbuffer_tx), 1) != HAL_OK) {
// Handle error if SPI2 (Slave) transmit communication fails.
My_Error_Handler("The SPI2 (Slave) Transmit Communication did not Start.");
}
 
        } else if (sbuffer_rx[0] == RISING_LS << 2){
        // Need to Lock & Disable the DMA
__HAL_LOCK(hspi->hdmatx);
__HAL_DMA_DISABLE(hspi->hdmatx);
 
// Do stuff
sbuffer_tx[0] = ((0x00 << 8) | (absDeadtimeValue_LS & 0xFF));
if (deadtimeValue_LS < 0){
sbuffer_tx[0]= ((0x01 << 8) | (absDeadtimeValue_LS & 0xFF));
}
 
// Unlock & Enable the DMA
__HAL_DMA_ENABLE(hspi->hdmatx);
__HAL_UNLOCK(hspi->hdmatx);
 
if (HAL_SPI_Transmit_IT(hspi, (uint8_t*)(sbuffer_tx), 1) != HAL_OK){
My_Error_Handler("The SPI2 (Slave) Transmit Communication did not Start.");
}
 
        } else if (sbuffer_rx[0] == RISING_HS << 2){
// Need to Lock & Disable the DMA
__HAL_LOCK(hspi->hdmatx);
__HAL_DMA_DISABLE(hspi->hdmatx);
 
// Do stuff
sbuffer_tx[0] = ((0x00 << 8) | (absDeadtimeValue_HS & 0xFF));
if (deadtimeValue_HS < 0){
sbuffer_tx[0]= ((0x01 << 8) | (absDeadtimeValue_HS & 0xFF));
}
 
// Unlock & Enable the DMA
__HAL_DMA_ENABLE(hspi->hdmatx);
__HAL_UNLOCK(hspi->hdmatx);
 
if (HAL_SPI_Transmit_IT(hspi, (uint8_t*)(sbuffer_tx), 1) != HAL_OK){
My_Error_Handler("The SPI2 (Slave) Transmit Communication did not Start.");
}
 
        } else if (sbuffer_rx[0] == FALLING_LS << 2){
// Need to Lock & Disable the DMA
__HAL_LOCK(hspi->hdmatx);
__HAL_DMA_DISABLE(hspi->hdmatx);
 
// Do stuff
sbuffer_tx[0] = ((0x00 << 8) | (absDeadtimeFallingAdjust_LS & 0xFF));
if (deadtimeFallingAdjust_LS < 0){
sbuffer_tx[0]= ((0x01 << 8) | (absDeadtimeFallingAdjust_LS & 0xFF));
}
 
// Unlock & Enable the DMA
__HAL_DMA_ENABLE(hspi->hdmatx);
__HAL_UNLOCK(hspi->hdmatx);
 
if (HAL_SPI_Transmit_IT(hspi, (uint8_t*)(sbuffer_tx), 1) != HAL_OK){
My_Error_Handler("The SPI2 (Slave) Transmit Communication did not Start.");
}
 
        } else if (sbuffer_rx[0] == FALLING_HS << 2){
// Need to Lock & Disable the DMA
__HAL_LOCK(hspi->hdmatx);
__HAL_DMA_DISABLE(hspi->hdmatx);
 
// Do stuff
sbuffer_tx[0] = ((0x00 << 8) | (absDeadtimeFallingAdjust_HS & 0xFF));
if (deadtimeFallingAdjust_HS < 0){
sbuffer_tx[0]= ((0x01 << 8) | (absDeadtimeFallingAdjust_HS & 0xFF));
}
 
// Unlock & Enable the DMA
__HAL_DMA_ENABLE(hspi->hdmatx);
__HAL_UNLOCK(hspi->hdmatx);
 
if (HAL_SPI_Transmit_IT(hspi, (uint8_t*)(sbuffer_tx), 1) != HAL_OK){
My_Error_Handler("The SPI2 (Slave) Transmit Communication did not Start.");
}
 
    }
}
 
/**
   * @brief  CallBack function of HAL_SPI_TransmitReceive_DMA.
   * Gets called at the end of each communication.
   * @PAram  *hspi: Pointer to the SPI object.
   */
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
    // If it is SPI2, re-launch the communication
    if (hspi->Instance == SPI2) {
    Init_SPI_Slave();
    }
}
 
/**
   * @brief  CallBack function of SPI Error.
   * Gets called at the end of each communication.
   * @PAram  *hspi: Pointer to the SPI object.
   */
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi) {
// If it is SPI2, re-launch the communication
if (hspi->Instance == SPI2) {
Init_SPI_Slave();
}
}
/* USER CODE END 1 */
8 REPLIES 8
TDK
Guru

There is no setting for default value in the absence of new data. If you want MISO to be high or low, treat it as a normal data byte and write 0xFF or 0x00 to it on the slave side.

Usually these sorts of dummy bytes are specified as "don't care" in the datasheet and you shouldn't worry about how they appear.

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

I can accept the idea behind "dummy bytes" but here we really want to control what is getting on the MISO line.
But on my setup the MISO line signal get through several drivers before ending to the master, that means that the signal can only go from the slave to the master. So that means that the slave is putting something on this line right ?

Because I don't really see why the master would drive the miso line...

> So that means that the slave is putting something on this line right ?

Yes, the slave drives MISO.

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

Alright, and about
"If you want MISO to be high or low, treat it as a normal data byte and write 0xFF or 0x00 to it on the slave side."
What should I do, modify the registers or config values of the SPI2 or just expanding my sbuffer_tx ???

Pavel A.
Evangelist III

There are two parameters that depend on the "flavor" of SPI spec used by specific devices: 

hspi2.Init.CLKPolarity and hspi2.Init.CLKPhase.
Try to change them. There's only 4 or so combinations so it won't take long time.
(hspi2.Init.TIMode is yet another parameter but it is DISABLE for most devices).
Sidius
Associate III

You are right those are the 2 main parameters, but it is not going to change that in a certain way my FIFO is filled with previous data values and then send during the receiving operation.

Expand your buffer and change your program logic to deliberately send 0x00 or 0xFF on the first byte, if that is what you want.

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

Actually, I discover that my SPI TX FIFO was outputting his value when I'm reading the first byte. That means I need to empty it or put 0xFF inside of it. One way to do it is:

HAL_SPI_Abort(&hspi2);

__HAL_RCC_SPI2_FORCE_RESET();

__HAL_RCC_SPI2_RELEASE_RESET();

But that is quite rough for the microcontroller I think, no ?

Is there a way to just change the value inside the SPI TX FIFO in a more gentle way ?

Thanks for your reply,

Sidius