简体   繁体   English

两个SPI传输之间的延迟问题(使用DMA)STM32F0

[英]Delay problem between two SPI transmission (using DMA) STM32F0

I am currently learning on STM32F0k6 board (ARM Cortex M0) using DMA and SPI.我目前正在使用 DMA 和 SPI 在 STM32F0k6 板(ARM Cortex M0)上学习。 I transmit a 72 bytes data from memory to peripheral, but after each transmission, during 86us, my signal is 0 logic (image bellow).我从 memory 向外围设备传输了一个 72 字节的数据,但每次传输后,在 86us 期间,我的信号为 0 逻辑(下图)。

signal from oscilloscope来自示波器的信号

I am using STM32CubeIDE software and for data transmission I used HAL_SPI_Transmit_DMA() function.我正在使用 STM32CubeIDE 软件,对于数据传输,我使用了 HAL_SPI_Transmit_DMA() function。 Data is correctly transmitted, but I want the second data to be transmitted immediately after the first one ( in other words, I want to avoid the 86 us time).数据正确传输,但我希望在第一个数据之后立即传输第二个数据(换句话说,我想避免 86 us 时间)。

What approach should I adopt?我应该采用什么方法? Do you suppose that an interrupt occurs after each transmission?您是否认为每次传输后都会发生中断?

Here is my code:这是我的代码:

    uint8_t buffer[72] ={
        0b11111111, 0b11111111, 0b00000000, 0b11111111, 0b11111111, 0b00000000, 0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111111, 0b11111111, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000,
        0b11111110, 0b00000000, 0b00000000, 0b11111111, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111111, 0b11111111, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000,
        0b11111110, 0b00000000, 0b00000000, 0b11111111, 0b00000000, 0b00000000, 0b11111111, 0b11111111, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111111, 0b11111111, 0b00000000,0b11111110, 0b00000000, 0b00000000,0b11111110, 0b00000000, 0b00000000
};

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SPI1_Init();

  
  while (1)
  {
      for(unit8_t i =0 ; i <=3; i++)
      {
          HAL_SPI_Transmit_DMA(&hspi1, buffer, 72);
          HAL_SPI_Transmit_DMA(&hspi1, buffer, 72);
      }
      
      // wait 0.5 seconds
      HAL_Delay(500);
  }
}

HAL_SPI_Transmit_DMA() function: HAL_SPI_Transmit_DMA() function:

 /**
  * @brief  Transmit an amount of data in non-blocking mode with DMA.
  * @param  hspi pointer to a SPI_HandleTypeDef structure that contains
  *               the configuration information for SPI module.
  * @param  pData pointer to data buffer
  * @param  Size amount of data to be sent
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size)
{
  HAL_StatusTypeDef errorcode = HAL_OK;

  /* Check tx dma handle */
  assert_param(IS_SPI_DMA_HANDLE(hspi->hdmatx));

  /* Check Direction parameter */
  assert_param(IS_SPI_DIRECTION_2LINES_OR_1LINE(hspi->Init.Direction));

  /* Process Locked */
  __HAL_LOCK(hspi);

  if (hspi->State != HAL_SPI_STATE_READY)
  {
    errorcode = HAL_BUSY;
    goto error;
  }

  if ((pData == NULL) || (Size == 0U))
  {
    errorcode = HAL_ERROR;
    goto error;
  }

  /* Set the transaction information */
  hspi->State       = HAL_SPI_STATE_BUSY_TX;
  hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  hspi->pTxBuffPtr  = (uint8_t *)pData;
  hspi->TxXferSize  = Size;
  hspi->TxXferCount = Size;

  /* Init field not used in handle to zero */
  hspi->pRxBuffPtr  = (uint8_t *)NULL;
  hspi->TxISR       = NULL;
  hspi->RxISR       = NULL;
  hspi->RxXferSize  = 0U;
  hspi->RxXferCount = 0U;

  /* Configure communication direction : 1Line */
  if (hspi->Init.Direction == SPI_DIRECTION_1LINE)
  {
    SPI_1LINE_TX(hspi);
  }

#if (USE_SPI_CRC != 0U)
  /* Reset CRC Calculation */
  if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    SPI_RESET_CRC(hspi);
  }
#endif /* USE_SPI_CRC */

  /* Set the SPI TxDMA Half transfer complete callback */
  hspi->hdmatx->XferHalfCpltCallback = SPI_DMAHalfTransmitCplt;

  /* Set the SPI TxDMA transfer complete callback */
  hspi->hdmatx->XferCpltCallback = SPI_DMATransmitCplt;

  /* Set the DMA error callback */
  hspi->hdmatx->XferErrorCallback = SPI_DMAError;

  /* Set the DMA AbortCpltCallback */
  hspi->hdmatx->XferAbortCallback = NULL;

  CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_LDMATX);
  /* Packing mode is enabled only if the DMA setting is HALWORD */
  if ((hspi->Init.DataSize <= SPI_DATASIZE_8BIT) && (hspi->hdmatx->Init.MemDataAlignment == DMA_MDATAALIGN_HALFWORD))
  {
    /* Check the even/odd of the data size + crc if enabled */
    if ((hspi->TxXferCount & 0x1U) == 0U)
    {
      CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_LDMATX);
      hspi->TxXferCount = (hspi->TxXferCount >> 1U);
    }
    else
    {
      SET_BIT(hspi->Instance->CR2, SPI_CR2_LDMATX);
      hspi->TxXferCount = (hspi->TxXferCount >> 1U) + 1U;
    }
  }

  /* Enable the Tx DMA Stream/Channel */
  if (HAL_OK != HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)hspi->pTxBuffPtr, (uint32_t)&hspi->Instance->DR,
                                 hspi->TxXferCount))
  {
    /* Update SPI error code */
    SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_DMA);
    errorcode = HAL_ERROR;

    hspi->State = HAL_SPI_STATE_READY;
    goto error;
  }

  /* Check if the SPI is already enabled */
  if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
  {
    /* Enable SPI peripheral */
    __HAL_SPI_ENABLE(hspi);
  }

  /* Enable the SPI Error Interrupt Bit */
  __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_ERR));

  /* Enable Tx DMA Request */
  SET_BIT(hspi->Instance->CR2, SPI_CR2_TXDMAEN);

error :
  /* Process Unlocked */
  __HAL_UNLOCK(hspi);
  return errorcode;
}

Most people would agree that the STM32 HAL library is poorly document.大多数人都会同意 STM32 HAL 库的文档很差。 The documentation of HAL_SPI_Transmit_DMA : HAL_SPI_Transmit_DMA的文档:

  • does not mention that it will fail if there is already an operation in progress on the SPI bus没有提到如果 SPI 总线上已经有一个操作在进行中会失败
  • does not mention what happens when the SPI transfer has completed没有提到 SPI 传输完成后会发生什么
  • fails to mention many other things.没有提及许多其他事情。

Your code tries to submit 6 times 72 bytes to the SPI bus and then waits for half a second.您的代码尝试向 SPI 总线提交 6 次 72 字节,然后等待半秒。 I'm not sure how many of these 6 transfer are started at all as most will fail because there is still an SPI operation in progress.我不确定这 6 次传输中有多少启动了,因为大多数传输都会失败,因为仍在进行 SPI 操作。 Test the return value for HAL_BUSY .测试HAL_BUSY的返回值。

Just a single DMA transfer can be submitted at any time.任何时候都可以只提交一个 DMA 传输。 When the transfer is completed, an interrupt occurs and some code is executed, which at least puts the SPI bus back into the ready state so the next DMA transfer can start.传输完成后,会发生中断并执行一些代码,这至少会将 SPI 总线放回就绪的 state 以便可以开始下一次 DMA 传输。

I'm not sure what exactly you want to achieve.我不确定你到底想要达到什么目的。 For the moment, I'm assuming you want to transfer many blocks of data as quickly as possible.目前,我假设您希望尽快传输许多数据块。 So you have several options:所以你有几个选择:

  1. Hook into the DMA transfer completed interrupt handler, ie implement HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) .挂钩到 DMA 传输完成中断处理程序,即实现HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) This callback will be called when the transfer has completed and you can immediately submit the next transfer.转账完成后会调用此回调,您可以立即提交下一笔转账。 You will still have a considerable gap between transfers as executing the interrupt handler takes time.由于执行中断处理程序需要时间,因此传输之间仍然会有相当大的差距。

  2. Configure a ring buffer and additionally hook into the half transfer completed handler ( HAL_SPI_TxHalfCpltCallback ).配置一个环形缓冲区并另外挂钩到半传输完成处理程序( HAL_SPI_TxHalfCpltCallback )。 That way the DMA transfer can go on continuously and every half transfer you are notified and can refill half the ring buffer.这样,DMA 传输可以连续进行 go 并且每半个传输都会通知您并且可以重新填充一半的环形缓冲区。 It's not trivial though.虽然这不是微不足道的。

Other MCUs have the option to chain several DMA transfers, ie a next transfer is started immediately without executing code.其他 MCU 可以选择链接多个 DMA 传输,即立即开始下一次传输而不执行代码。 I don't think STM32 MCUs support that.我认为 STM32 MCU 不支持这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM