STM32F - 带DMA的SPI" ErrorCallback"和帧移位

时间:2017-11-15 11:45:19

标签: stm32 spi dma stm32f4discovery stm32f4

我正在通信2 uC(arduino显示为MASTER,STM32F429为从属)。它通过SPI使用DMA,每隔150ms进行全双工10字节。

在几分钟内,通信非常好,uC正在正确发送10个字节。在此期间,我注意到" HAL_SPI_ErrorCallback"函数被称为因为我已经添加了一个计数器并且它一点一点地增加,但是通信仍然很顺利。

我的第一个问题是:有时候随机调用ErrorCallback函数是否正常?由于噪音或任何通讯有瞬间错误......我猜..

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

另一方面,一段时间后(随机10分钟,1小时......)通信在MISO信号中被破坏,STM32发送10字节帧但不发送Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10,(LSB优先)

它发送:

Byte10 Byte0 Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9,它被移动到1字节!?!?

附上你可以看到捕获" Working.jpg" byte0 = 0x02,其余字节= 0.在另一个捕获" NOT_working.jpg"是一个有问题的捕获。两个uC都正常工作了一段时间,突然STM32 uC开始一直发送这个帧(通信帧是字节= 0x02,其余的字节= 0,以便轻易看到这个错误)。

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

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

我尝试过以下方面的沟通: " Init.Mode = DMA_NORMAL"和" DMA_CIRCULAR",并且两种配置都具有相同的行为。 为了找出问题,我创建了2个变量:

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

并且通信顺利,DMA_counter_RX = 10但是DMA_counter_TX = 9.这个值是正常的。但是一旦发生移位错误,两个DMA计数器都是= 10。

当我点击"暂停"此问题也总是在调试模式下发生。 (暂停)和"恢复"(播放)我一点击"恢复"并且处理器继续该程序,MISO信号永远移位。

此外,我将TIM1,TIM5,TIM2,TIM3和TIM4用于其他事情,如PWM和中断,但与SPI无关......

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

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

任何帮助都很感激!在此先感谢和最诚挚的问候。

亚历

很抱歉很长的问题...... :(

Bellow你可以看到我的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 cube 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 */
}

------------------------------ EDITED ---------------- ------------ 我添加了2个SPI寄存器的捕获

SPI registers WORKING

SPI registers ERROR

1 个答案:

答案 0 :(得分:0)

我终于得到了解决方案,我发现了问题所在!

通常,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(STM32 SPI被选择并准备好通信)时,如果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是为了注意到这一点。

感谢您帮助我并支持我们。

我希望这对其他人有帮助。

最好的问候。

亚历。