STM32F-带DMA的SPI“;ErrorCallback";帧移动了

STM32F-带DMA的SPI“;ErrorCallback";帧移动了,stm32,spi,dma,stm32f4discovery,stm32f4,Stm32,Spi,Dma,Stm32f4discovery,Stm32f4,我正在通信2个uC(一个arduino显示器作为主显示器,STM32F429作为从显示器)。它的通信由10个字节组成,通过使用DMA的SPI全双工,每150ms一次 在几分钟内,通信进行得非常顺利,两个uC都正确地发送了10个字节。在这段时间里,我注意到调用了“HAL_SPI_ErrorCallback”函数,因为我在其中添加了一个计数器,并且它一点一点地增加,但是通信仍然进行得很顺利 我的第一个问题是:有时随机调用ErrorCallback函数是否正常?由于噪音或其他原因,通讯出现瞬时错误。。

我正在通信2个uC(一个arduino显示器作为主显示器,STM32F429作为从显示器)。它的通信由10个字节组成,通过使用DMA的SPI全双工,每150ms一次

在几分钟内,通信进行得非常顺利,两个uC都正确地发送了10个字节。在这段时间里,我注意到调用了“HAL_SPI_ErrorCallback”函数,因为我在其中添加了一个计数器,并且它一点一点地增加,但是通信仍然进行得很顺利

我的第一个问题是:有时随机调用ErrorCallback函数是否正常?由于噪音或其他原因,通讯出现瞬时错误。。。我想

另一方面,在一段时间(随机10分钟,1h…)之后,仅在MISO信号中通信被破坏,STM32发送10字节帧,但不是发送字节0字节1字节2字节3字节4字节5字节6字节7字节8字节9字节10,(LSB优先)

它发送:

字节10字节0字节1字节2字节3字节4字节5字节6字节7字节8字节9,它被移动到右1字节

附加您可以看到捕获“Working.jpg”,字节0=0x02,其余字节=0。在另一个捕获中,“NOT_working.jpg”是一个有问题的捕获。两个uC都正常工作了一段时间,突然STM32 uC开始一直发送此帧(通信帧为字节=0x02,其余字节=0,以便轻松查看此错误)

我尝试了以下沟通方式: “Init.Mode=DMA_NORMAL”和“DMA_CIRCULAR”,这两种配置具有相同的行为。 为了找出问题,我对两个变量进行了验证:

    DMA_counter_RX = __HAL_DMA_GET_COUNTER(&hdma_spi6_rx);
    DMA_counter_TX = __HAL_DMA_GET_COUNTER(&hdma_spi6_tx); 
通信进展顺利,DMA_计数器_RX=10,但DMA_计数器_TX=9。该值为正常值。但一旦发生移位错误,两个DMA计数器都将=10

此外,在调试模式下,当我单击“暂停”(暂停)和“恢复”(播放)时,此问题总是会发生。一旦我单击“恢复”,处理器继续执行程序,MISO信号将永远移动

此外,我使用TIM1,TIM5,TIM2,TIM3和TIM4的其他东西,如PWM和中断,但不涉及SPI

我试图解决这个问题,修改所有中断的NVIC优先级等,但问题变得更糟

我正在使用System Workbench for STM32最新版本

任何帮助都是感激的!提前感谢并致以最良好的问候

亚历杭德罗

很抱歉问了这么长时间…:(

下面您可以看到我的SPI和DMA配置,如果它可以帮助您:

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);
      }
}
在初始化代码期间,我按照前面所述配置SPI6和DMA,然后使用以下方式启用通信:

HAL_SPI_TransmitReceive_DMA(&hspi6, (uint8_t*)HMI_slave_TX_data, (uint8_t*)HMI_slave_RX_data, 10);
此外,还添加了与SPI通信相关的以下2个功能:

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多维数据集mx:

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 */
}
------------------------------编辑---------------------------- 我添加了2个SPI寄存器的捕获


我终于找到了解决办法,我找到了问题所在

通常,CS信号从1变为0,然后MISO和MOSI通信,一旦通信完成,CS信号从0变为1,STM32F429继续执行其余任务

这种情况每150毫秒发生一次,这是两个uC通信的时间段。但是STM32 uC还有比SPI通信优先级更高的任务

在SPI通信期间,当其中一个较高优先级启动时,一旦完成该较高优先级,则uC继续执行正在执行的任务(它是SPI),很明显,该帧丢失,执行“HAL_SPI_ErrorCallback”,然后重新启动SPI。如果在CS信号为1时重新启动SPI,(SPI空闲),则没有问题,SPI已正确重新启动,下一帧将无问题接收。但如果在CS信号为0时重新启动SPI(已选择STM32 SPI并准备好通信)然后,STM32正在等待发送和接收一定数量的字节,但接收的字节会更少,因此通信字节不匹配是问题的关键

我已经解决了这个问题,只需添加:

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);
    }
}
为了不停止处理器,我必须修改“WHILE”,但这是第一个近似值

现在,通信一直在工作,但有时由于更高优先级的任务而丢失帧(并调用“HAL_SPI_ErrorCallback”)。但这是正常的,需要实现CRC来注意这一点

谢谢你对我的帮助和支持

我希望这对其他人有帮助

致以最良好的祝愿


亚历杭德罗。

我终于找到了解决办法,我找到了问题所在

通常,CS信号从1变为0,然后MISO和MOSI通信,一旦通信完成,CS信号从0变为1,STM32F429继续执行其余任务

这种情况每150毫秒发生一次,这是两个uC通信的时间段。但是STM32 uC还有比SPI通信优先级更高的任务

在SPI通信期间,当其中一个较高优先级启动时,一旦完成该较高优先级,则uC继续执行正在执行的任务(它是SPI),很明显,该帧丢失,执行“HAL_SPI_ErrorCallback”,然后重新启动SPI。如果在CS信号为1时重新启动SPI,(SPI空闲),则没有问题,SPI已正确重新启动,下一帧将无问题接收。但如果在CS信号为0时重新启动SPI(已选择STM32 SPI并准备好通信)然后,STM32正在等待发送和接收一定数量的字节,但接收的字节会更少,因此通信字节不匹配是问题的关键

我已经解决了这个问题,只需添加:

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);
    }
}
为了不停止处理器,我必须修改“WHILE”,但这是第一个近似值

现在,通信一直在工作,但有时会丢失一帧(和“HAL_SPI_Erro”)