[STM32F0] 关于SPI+DMA的使用问题

[复制链接]
6108|30
 楼主| chenyuanjiyi 发表于 2021-12-2 17:26 | 显示全部楼层
呐咯密密 发表于 2021-12-2 17:10
关于两个数据之间的时间间隔不要用逻辑分析仪去抓,用示波器去抓,抓完拍照给我看一下。 ...

刚试完F103,发现用hal库,两包数据间距还是有13个us,目前手上只有逻辑分析仪,而且这个逻辑分析仪最大支持500M,我用F103配的18M,这个时钟基本是一直连上的,只能怀疑是HAL的运行效率更低了


snipaste_20211202_172125.png
snipaste_20211202_172449.png
呐咯密密 发表于 2021-12-2 17:31 | 显示全部楼层
chenyuanjiyi 发表于 2021-12-2 17:26
刚试完F103,发现用hal库,两包数据间距还是有13个us,目前手上只有逻辑分析仪,而且这个逻辑分析仪最大支 ...

我好像误会你的意思了,你的目的是加快两次SPI数据读取之间的时间是吧。这里的时间是DMA启动时间过长,这个是有办法解决的。你在代码里是连续采集的吗?中间有没有其他干扰,如果没有。你把HAL库所有的都换成寄存器操作。然后尝试自己去进件代码。有问题我明天上班给你解决,我先下班了。
 楼主| chenyuanjiyi 发表于 2021-12-2 17:46 | 显示全部楼层
呐咯密密 发表于 2021-12-2 17:31
我好像误会你的意思了,你的目的是加快两次SPI数据读取之间的时间是吧。这里的时间是DMA启动时间过长,这 ...

好的  谢谢啦
不是很理解你说的连续采集是啥意思,DMA配置为循环模式吗?
我DMA目前配置的是普通模式,至于寄存器操作,我现在基本都将他封装的进一步分解了,现在是直接对他定义的那些结构体操作了(离寄存器操作就差一步了),像这个DMA的通道配置
  1. //    DMA_SetConfig(hdma_spi1_tx, SrcAddress, DstAddress, DataLength);
  2. {
  3. /* Clear all flags */
  4.   hdma_spi1_tx.DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma_spi1_tx.ChannelIndex);

  5.   /* Configure DMA Channel data length */
  6.   hdma_spi1_tx.Instance->CNDTR = Size;

  7. /* Memory to Peripheral */
  8. //  if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH)
  9.   {
  10.     /* Configure DMA Channel destination address */
  11.     hdma_spi1_tx.Instance->CPAR = (uint32_t)&hspi->Instance->DR;

  12.     /* Configure DMA Channel source address */
  13.     hdma_spi1_tx.Instance->CMAR = (uint32_t)pTxData;
  14.   }
  15. }

我现在再试试,还有点时间下班
首先还是要感谢大佬的帮忙,谢谢啦!
呐咯密密 发表于 2021-12-3 09:29 | 显示全部楼层
chenyuanjiyi 发表于 2021-12-2 17:46
好的  谢谢啦
不是很理解你说的连续采集是啥意思,DMA配置为循环模式吗?
我DMA目前配置的是普通模式,至 ...

看起来是没啥问题,现在你就是想缩短这个13.6us吗
 楼主| chenyuanjiyi 发表于 2021-12-3 09:42 | 显示全部楼层
呐咯密密 发表于 2021-12-3 09:29
看起来是没啥问题,现在你就是想缩短这个13.6us吗

恩恩  对的
  1. HAL_StatusTypeDef HAL_SPI_MY_TransmitReceive_DMA0(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData,uint16_t Size)
  2. {
  3.   HAL_StatusTypeDef errorcode = HAL_OK;
  4.   static uint8_t Flag=0;
  5.   /* Process locked */
  6. //  __HAL_LOCK(hspi);

  7.   /* Reset the threshold bit */
  8.   CLEAR_BIT(hspi->Instance->CR2, SPI_CR2_LDMATX | SPI_CR2_LDMARX);

  9.   /* Set fiforxthresold according the reception data length: 8bit */
  10.   SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);

  11.   /* Enable the Rx DMA Stream/Channel  */
  12. //  HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)pRxData, Size);
  13. {
  14. /* Disable the peripheral */
  15.           hdma_spi1_rx.Instance->CCR &= ~DMA_CCR_EN;
  16.          
  17.           /* Configure the source, destination address and the data length */  
  18. //          DMA_SetConfig(hdma_spi1_rx, (uint32_t)&hspi->Instance->DR, (uint32_t)pRxData, Size);
  19. {
  20. /* Clear all flags */
  21.   hdma_spi1_rx.DmaBaseAddress->IFCR  = (DMA_FLAG_GL1 << hdma_spi1_rx.ChannelIndex);
  22.   
  23.   /* Configure DMA Channel data length */
  24.   hdma_spi1_rx.Instance->CNDTR = Size;
  25.   
  26.   /* Peripheral to Memory */
  27.   {
  28.     /* Configure DMA Channel source address */
  29.     hdma_spi1_rx.Instance->CPAR = (uint32_t)&hspi->Instance->DR;
  30.    
  31.     /* Configure DMA Channel destination address */
  32.     hdma_spi1_rx.Instance->CMAR = (uint32_t)pRxData;
  33.   }
  34. }
  35.           /* Enable the transfer complete, & transfer error interrupts */
  36.           /* Half transfer interrupt is optional: enable it only if associated callback is available */
  37.       hdma_spi1_rx.Instance->CCR |= (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE);
  38.          
  39.           /* Enable the Peripheral */
  40.           hdma_spi1_rx.Instance->CCR |= DMA_CCR_EN;

  41. }
  42.   
  43.   /* Enable Rx DMA Request */
  44.   SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN);
  45.   
  46.   /* Enable the Tx DMA Stream/Channel  */
  47. //  HAL_DMA_Start_IT(hspi->hdmatx, (uint32_t)pTxData, (uint32_t)&hspi->Instance->DR,Size);
  48. {
  49. /* Disable the peripheral */
  50.           hdma_spi1_tx.Instance->CCR &= ~DMA_CCR_EN;
  51.          
  52.           /* Configure the source, destination address and the data length */  
  53. //          DMA_SetConfig(hdma_spi1_rx, (uint32_t)&hspi->Instance->DR, (uint32_t)pRxData, Size);
  54. {
  55. /* Clear all flags */
  56.   hdma_spi1_tx.DmaBaseAddress->IFCR  = (DMA_FLAG_GL1 << hdma_spi1_rx.ChannelIndex);
  57.   
  58.   /* Configure DMA Channel data length */
  59.   hdma_spi1_tx.Instance->CNDTR = Size;
  60.   
  61. /* Memory to Peripheral */
  62.   {   
  63.     /* Configure DMA Channel destination address */
  64.     hdma_spi1_tx.Instance->CPAR = (uint32_t)&hspi->Instance->DR;
  65.    
  66.     /* Configure DMA Channel source address */
  67.     hdma_spi1_tx.Instance->CMAR = (uint32_t)pTxData;
  68.   }
  69.   
  70. }
  71.           /* Enable the transfer complete, & transfer error interrupts */
  72.           /* Half transfer interrupt is optional: enable it only if associated callback is available */
  73.       hdma_spi1_tx.Instance->CCR |= (DMA_IT_TC | DMA_IT_HT | DMA_IT_TE);

  74.           HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
  75.           /* Enable the Peripheral */
  76.           hdma_spi1_tx.Instance->CCR |= DMA_CCR_EN;

  77. }
  78.   /* Check if the SPI is already enabled */
  79.   if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
  80.   {
  81.     /* Enable SPI peripheral */
  82.     __HAL_SPI_ENABLE(hspi);
  83.   }
  84.   /* Enable the SPI Error Interrupt Bit */
  85.   __HAL_SPI_ENABLE_IT(hspi, (SPI_IT_ERR));

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

  88. error :
  89.   /* Process Unlocked */
  90. //  __HAL_UNLOCK(hspi);
  91.   return errorcode;
  92. }
这是我修改后的DMA_SPI的读写函数,几乎是操作寄存器了,结果两包数据间距还是有13.6us,采用F103使用这种方法也差不多有10几us,现在想缩短两包数据间的这个时间


呐咯密密 发表于 2021-12-3 09:52 | 显示全部楼层
你这个CSN的间隔这么长明显不是SPI的问题,是你有其他代码影响了两次SPI之间的时间,你的代码上传了没,我拉取一下看看

 楼主| chenyuanjiyi 发表于 2021-12-3 10:03 | 显示全部楼层
呐咯密密 发表于 2021-12-3 09:52
你这个CSN的间隔这么长明显不是SPI的问题,是你有其他代码影响了两次SPI之间的时间,你的代码上传了没,我 ...

上传上去了:https://github.com/Gu-Yue-Hu/SPI_DMA_HAL.git
master分支,这个后面要整理下,不太会玩
或者QQ:1364465583
谢谢啦
呐咯密密 发表于 2021-12-3 10:06 | 显示全部楼层
4254461a97adb8cd51.png
额,兄弟,你这while(1)里面有个延时啊,你这肯定会高的。你把这个延时删除
 楼主| chenyuanjiyi 发表于 2021-12-3 10:19 | 显示全部楼层
呐咯密密 发表于 2021-12-3 10:06
额,兄弟,你这while(1)里面有个延时啊,你这肯定会高的。你把这个延时删除
...

这个延时不是点灯的吗

最新的工程上传了 不能直接git clone 出来.....

可以加我QQ ,我发给你,github等后面再弄了
snipaste_20211203_101617.png
snipaste_20211203_101753.png
呐咯密密 发表于 2021-12-3 10:22 | 显示全部楼层
chenyuanjiyi 发表于 2021-12-3 10:03
上传上去了:https://github.com/Gu-Yue-Hu/SPI_DMA_HAL.git
master分支,这个后面要整理下,不太会玩
或 ...

另外有个概念需要搞清楚,DMA的启动时间是指你的CSN下降沿到你第一个CLK的上升沿/下降沿。
3977861a97e3c30155.png
你把启动函数改为寄存器方式影响的是你的这个时间,而你的13.6us,是你的上一次dma处理完成到下一次DMA启动所耗费的时间,这个时间内如果你没有添加其他代码,那就是一个GPIO下拉所需的时间。
6450261a97ec903ad6.png
就类似我这个,就是在主循环里面只有一句DMA-spi的函数,所呈现的波形就是这样,两次DMA之间只有几百纳秒,而从CSN下拉到第一个CLK发出只有860ns。效率很高的。
 楼主| chenyuanjiyi 发表于 2021-12-3 10:22 | 显示全部楼层
呐咯密密 发表于 2021-12-3 10:06
额,兄弟,你这while(1)里面有个延时啊,你这肯定会高的。你把这个延时删除
...

去掉延时后的效果
snipaste_20211203_102124.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部