1
votes

I am communicating 2 uC (an arduino display as MASTER and STM32F429 as slave).Its communication consists of 10 bytes in full duplex through SPI using DMA, every 150ms.

During some minutes the communication goes very good, both uC are sending their 10 bytes properly. During this time, I have noted that "HAL_SPI_ErrorCallback" function is called becasue I have added a counter within and it is increased little by little, but the comminication still goes well.

My first question is: Is it normal that sometimes ErrorCallback function is called randomly? due to noise or whatever the communication has an instantaneous error... I guess..

Here are a capture of the MISO signal in green, CLK in whie and CS in yellow

On the other hand, after a while (randomly 10 min, 1h ...) the communication is corrupted just in the MISO signal , the STM32 sends the 10 bytes frame but instead of sending Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10, (LSB first)

it sends:

Byte10 Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9, IT IS MOVED TO RIGTH 1 byte!?!?

Attached you can see the capture "Working.jpg" with byte0 = 0x02 and the rest of the bytes = 0. In the other capture "NOT_working.jpg" is a capture with the problem. Both uC were working properly for a while and suddenly the STM32 uC started to send this frame all the time (the communication frame is byte = 0x02 and the rest of the bytes = 0 in order to see easily this error).

Working.jpg - which is MISO signal sending the frame properly

NOT_working.jpg - which is MISO signal sending the frame incorrectly

I have tried the communication in: "Init.Mode = DMA_NORMAL" and "DMA_CIRCULAR", and both configuration have the same behaviour. I have creaged the 2 variables in order to find out the problem:

    DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
    DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx); 

And the the comunications goes well, DMA_counter_RX = 10 BUT DMA_counter_TX = 9. This values are normal. But as soon as the shift error occurs, both DMA counters are = 10.

Also this problem always happens in debug mode when I click on "suspend" (pause) and "resume"(play) as soon as I click on "resume" and the processor continues with the program, the MISO signal is shifted forever.

Additionally I am using TIM1, TIM5, TIM2, TIM3 and TIM4 for other things like PWM and interruptions but not related to SPI...

I have tried to solve this problem modifying all the NVIC priorities for all interruptions and so on but the problem get worst.

I am using System Workbench for STM32 latest version.

Any help is appreciate! Thanks in advance and best regards.

Alejandro

Sorry for long question... :(

Bellow you can see my configuration for SPI and DMA if it can help you:

void MX_DMA_Init(void)
{
  __HAL_RCC_DMA2_CLK_ENABLE();



  HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
  HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 2, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);

}

void MX_SPI6_Init(void)
{

  hspi6.Instance = SPI6;
  hspi6.Init.Mode = SPI_MODE_SLAVE;
  hspi6.Init.Direction = SPI_DIRECTION_2LINES;
  hspi6.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi6.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi6.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi6.Init.NSS = SPI_NSS_HARD_INPUT;
  hspi6.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi6.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi6.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi6.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi6) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{

      GPIO_InitTypeDef GPIO_InitStruct;
      if(hspi->Instance==SPI6)
      {
        __HAL_RCC_SPI6_CLK_ENABLE();



        /**SPI6 GPIO Configuration
        PG8     ------> SPI6_NSS
        PG12     ------> SPI6_MISO
        PG13     ------> SPI6_SCK
        PG14     ------> SPI6_MOSI
        */
        GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
        GPIO_InitStruct.Alternate = GPIO_AF5_SPI6;
        HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);



        hdma_spi6_rx.Instance = DMA2_Stream6;
        hdma_spi6_rx.Init.Channel = DMA_CHANNEL_1;
        hdma_spi6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_spi6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_spi6_rx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_spi6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_spi6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_spi6_rx.Init.Mode = DMA_NORMAL;
        hdma_spi6_rx.Init.Priority = DMA_PRIORITY_MEDIUM;
        hdma_spi6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_spi6_rx) != HAL_OK)
        {
          Error_Handler();
        }



        __HAL_LINKDMA(hspi,hdmarx,hdma_spi6_rx);



        hdma_spi6_tx.Instance = DMA2_Stream5;
        hdma_spi6_tx.Init.Channel = DMA_CHANNEL_1;
        hdma_spi6_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
        hdma_spi6_tx.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_spi6_tx.Init.MemInc = DMA_MINC_ENABLE;
        hdma_spi6_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
        hdma_spi6_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
        hdma_spi6_tx.Init.Mode = DMA_NORMAL;
        hdma_spi6_tx.Init.Priority = DMA_PRIORITY_MEDIUM;
        hdma_spi6_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        if (HAL_DMA_Init(&hdma_spi6_tx) != HAL_OK)
        {
          Error_Handler();
        }



        __HAL_LINKDMA(hspi,hdmatx,hdma_spi6_tx);



        /* Peripheral interrupt init */
        HAL_NVIC_SetPriority(SPI6_IRQn, 2, 0);
        HAL_NVIC_EnableIRQ(SPI6_IRQn);
      }
}

During initialization code, I configure SPI6 and DMA as it is described before, just after that I enable communication using:

HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);

Also it were added the following 2 functions related to SPI communication:

void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi -> Instance == SPI6)
    {
        HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
    }
}





void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi -> Instance == SPI6)
    {

        HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
    }
}

STM cube mx automatically created:

void DMA2_Stream5_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream5_IRQn 0 */



  /* USER CODE END DMA2_Stream5_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_spi6_tx);
  /* USER CODE BEGIN DMA2_Stream5_IRQn 1 */



  /* USER CODE END DMA2_Stream5_IRQn 1 */
}



/**
* @brief This function handles DMA2 stream6 global interrupt.
*/
void DMA2_Stream6_IRQHandler(void)
{
  /* USER CODE BEGIN DMA2_Stream6_IRQn 0 */



  /* USER CODE END DMA2_Stream6_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_spi6_rx);
  /* USER CODE BEGIN DMA2_Stream6_IRQn 1 */



  /* USER CODE END DMA2_Stream6_IRQn 1 */
}



void SPI6_IRQHandler(void)
{
  /* USER CODE BEGIN SPI6_IRQn 0 */



  /* USER CODE END SPI6_IRQn 0 */
  HAL_SPI_IRQHandler(&hspi6);
  /* USER CODE BEGIN SPI6_IRQn 1 */



  /* USER CODE END SPI6_IRQn 1 */
}

------------------------------EDITED---------------------------- I add 2 captures of the SPI register

SPI registers WORKING

SPI registers ERROR

1
Check that both master and slave configure SPI in the same mode. What is in the SR register when SPI errors occur?A.K.
Display as master and the host micro as the slave? Are you sure ?0___________
Thanks for answer. Regarding SR registers , I have added 2 captures of it when transmission is working good and when the error is there.... PeterJ_01, yes, the display is controlled by an atmel uC (SW arduino), it is the human interface, and it is communicated to STM32F429 which is the uC that controles other HW stuffs.Alex _
@Alex_: it seems in both cases you have overrun condition, which means there is more data sent than read. Since it may be hard to debug errors like this, I would eliminate this error first. Maybe you don't enable DMA soon enough for the next transfer... Hard to tell.A.K.

1 Answers

0
votes

I finally got the solution, I found what the problem was!

Usually, the CS signal goes from 1 to 0, then MISO and MOSI communicates, and once the communication finishes CS signal goes from 0 to 1, and the STM32F429 continues with the rest of the tasks...

This was happening every 150 ms, that's the period of thime both uC are communicating. But the STM32 uC has another tasks with more priority than SPI communication.

When one of this higher priority starts during SPI communication, and once this higher priority is done then the uC continues with the task was doing ( it was SPI), obviouslythis frame is lost and "HAL_SPI_ErrorCallback" is executed, and then SPI is restarted.If SPI is restarted when CS signal is 1, (spi idle), then there is no problem, SPI is restarted properly and the next frame will be received without problem. BUT if SPI is restarted when CS signal is 0 (STM32 SPI is selected and ready to communicate) then the STM32 is waiting to send and receive an amount of bytes but it will receives less, so an a mismatch of communication bytes is the key of the PROBLEM.

I have solved this issue just adding:

void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
    if(hspi -> Instance == SPI6)
    {

        while(HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_8) != GPIO_PIN_SET) // CS signal
        {
        }

        HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data,10);
    }
}

I have to modify "WHILE" in order to not stop the processor , but it is the first approximation.

Now the communication is working all the time, but some times a frame is lost (and " HAL_SPI_ErrorCallback" is called) due to higher priority task. But it is normal, a CRC is implemented to note that.

Thanks for helping me and support the support.

I hope this helps to other people.

Best regards.

Alejandro.