[STM32H7] SPI CLK响应较慢

[复制链接]
5244|87
belindagraham 发表于 2023-10-17 21:56 | 显示全部楼层
如果SPI主从设备的通信速率不匹配,可能会导致SPI CLK响应较慢。
qiufengsd 发表于 2023-10-17 22:23 | 显示全部楼层
可能是SPI接收卡死问题,这可能会导致程序运行异常。
 楼主| Hufei1994 发表于 2023-10-18 08:55 | 显示全部楼层
belindagraham 发表于 2023-10-17 21:56
如果SPI主从设备的通信速率不匹配,可能会导致SPI CLK响应较慢。

我在俩个从设备上试过,分别是DRV8305和AMS5047P,都是这个现象。从设备的CLK是主设备发的为啥会不匹配呢?
 楼主| Hufei1994 发表于 2023-10-18 14:51 | 显示全部楼层
呐咯密密 发表于 2023-10-17 10:43
不用任何怀疑,是你的SPI发送函数有问题,在你的CS下拉之后,你并没有立刻传输数据,而是执行了各种校验工 ...

那这个是HAL库的正常现象了吧,实际传输时间是预期的3倍,效率有点低
 楼主| Hufei1994 发表于 2023-10-18 14:53 | 显示全部楼层
chenjun89 发表于 2023-10-17 19:46
几十个时钟周期也太夸张了吧,你是用的软片选还是硬片选。

软件写GPIO来控制的CS
 楼主| Hufei1994 发表于 2023-10-18 14:53 | 显示全部楼层
macpherson 发表于 2023-10-17 21:29
数据传输速率和 CLK 信号频率不匹配

CLK是主机给的怎么会不匹配呢?
 楼主| Hufei1994 发表于 2023-10-18 14:56 | 显示全部楼层
玄德 发表于 2023-10-13 19:50
往 SPI ->DR 寄存器写入数据,SCK 才会出现。
你的 CS 是用 IO 方式产生的,它的边沿和 SCK 没有任何关系 ...

软件写完CS就立刻运行SPI HAL函数了,但是是放在主循环里面跑的。实际再有个100us的中断在运行(运行时间大概在20us左右),可能是中断导致了SPI运行变慢嘛?
 楼主| Hufei1994 发表于 2023-10-18 14:59 | 显示全部楼层
呐咯密密 发表于 2023-10-17 10:43
不用任何怀疑,是你的SPI发送函数有问题,在你的CS下拉之后,你并没有立刻传输数据,而是执行了各种校验工 ...

// SPI发送读取函数
uint16_t SPI_ReadWrite_OneByte(uint16_t _txdata)
{

        HAL_GPIO_WritePin(SPI5_CS_GPIO_Port, SPI5_CS_Pin, GPIO_PIN_RESET);
        uint16_t rxdata;
        if(HAL_SPI_TransmitReceive(&hspi5,(uint8_t *)&_txdata,(uint8_t *)&rxdata,1,100) !=HAL_OK)
                {
                        rxdata=0;
                }
               
    HAL_GPIO_WritePin(SPI5_CS_GPIO_Port, SPI5_CS_Pin, GPIO_PIN_SET);
        return rxdata;
}
uint16_t AS5047_read(uint16_t add)
{
        uint16_t data;
        add |= 0x4000;        //读指令 bit14 置1
        if(Parity_bit_Calculate(add)==1) add=add|0x8000; //如果前15位 1的个数位偶数,则Bit15 置1
        SPI_ReadWrite_OneByte(add);                //发送一条指令,不管读回的数据
        data=SPI_ReadWrite_OneByte(NOP|0x4000); //发送一条空指令,读取上一次指令返回的数据。
        data &=0x3fff;
        return data;
}
代码是这么实现的,中间没有其他操作了
呐咯密密 发表于 2023-10-18 17:02 | 显示全部楼层
Hufei1994 发表于 2023-10-18 14:59
// SPI发送读取函数
uint16_t SPI_ReadWrite_OneByte(uint16_t _txdata)
{

问题在这个函数:HAL_SPI_TransmitReceive,你贴一下这个函数,这个函数在发送数据前应该是做了某些操作
呐咯密密 发表于 2023-10-18 17:21 | 显示全部楼层
Hufei1994 发表于 2023-10-18 14:59
// SPI发送读取函数
uint16_t SPI_ReadWrite_OneByte(uint16_t _txdata)
{
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Transmit and Receive an amount of data in blocking mode.
  3.   * @param  hspi: pointer to a SPI_HandleTypeDef structure that contains
  4.   *               the configuration information for SPI module.
  5.   * @param  pTxData: pointer to transmission data buffer
  6.   * @param  pRxData: pointer to reception data buffer
  7.   * @param  Size: amount of data to be sent and received
  8.   * @param  Timeout: Timeout duration
  9.   * @retval HAL status
  10.   */
  11. HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size,
  12.                                           uint32_t Timeout)
  13. {
  14.   uint32_t tickstart = 0U;
  15.   HAL_StatusTypeDef errorcode = HAL_OK;

  16.   /* Check Direction parameter */
  17.   assert_param(IS_SPI_DIRECTION_2LINES(hspi->Init.Direction));

  18.   /* Process Locked */
  19.   __HAL_LOCK(hspi);

  20.   /* Init tickstart for timeout management*/
  21.   tickstart = HAL_GetTick();

  22.   if (!((hspi->State == HAL_SPI_STATE_READY) || \
  23.         ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LINES) && (hspi->State == HAL_SPI_STATE_BUSY_RX))))
  24.   {
  25.     errorcode = HAL_BUSY;
  26.     __HAL_UNLOCK(hspi);
  27.     return errorcode;
  28.   }

  29.   if ((pTxData == NULL) || (pRxData == NULL) || (Size == 0U))
  30.   {
  31.     errorcode = HAL_ERROR;
  32.     __HAL_UNLOCK(hspi);
  33.     return errorcode;
  34.   }

  35.   /* Don't overwrite in case of HAL_SPI_STATE_BUSY_RX */
  36.   if (hspi->State != HAL_SPI_STATE_BUSY_RX)
  37.   {
  38.     hspi->State = HAL_SPI_STATE_BUSY_TX_RX;
  39.   }

  40.   /* Set the transaction information */
  41.   hspi->ErrorCode   = HAL_SPI_ERROR_NONE;
  42.   hspi->pRxBuffPtr  = (uint8_t *)pRxData;
  43.   hspi->RxXferCount = Size;
  44.   hspi->RxXferSize  = Size;
  45.   hspi->pTxBuffPtr  = (uint8_t *)pTxData;
  46.   hspi->TxXferCount = Size;
  47.   hspi->TxXferSize  = Size;

  48.   /*Init field not used in handle to zero */
  49.   hspi->RxISR       = NULL;
  50.   hspi->TxISR       = NULL;

  51.   /* Set the number if data at current transfer */
  52.   MODIFY_REG(hspi->Instance->CR2, SPI_CR2_TSIZE, Size);

  53.   __HAL_SPI_ENABLE(hspi);

  54.   if (hspi->Init.Mode == SPI_MODE_MASTER)
  55.   {
  56.     /* Master transfer start */
  57.     SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
  58.   }

  59.   /* Transmit and Receive data in 32 Bit mode */
  60.   if (hspi->Init.DataSize > SPI_DATASIZE_16BIT)
  61.   {
  62.     while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
  63.     {
  64.       /* Check TXE flag */
  65.       if ((hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)))
  66.       {
  67.         *((__IO uint32_t *)&hspi->Instance->TXDR) = *((uint32_t *)hspi->pTxBuffPtr);
  68.         hspi->pTxBuffPtr += sizeof(uint32_t);
  69.         hspi->TxXferCount --;
  70.       }

  71.       /* Check RXWNE/EOT flag */
  72.       if ((hspi->RxXferCount > 0U) && (hspi->Instance->SR & (SPI_FLAG_RXWNE|SPI_FLAG_EOT)))
  73.       {
  74.         *((uint32_t *)hspi->pRxBuffPtr) = *((__IO uint32_t *)&hspi->Instance->RXDR);
  75.         hspi->pRxBuffPtr += sizeof(uint32_t);
  76.         hspi->RxXferCount --;
  77.       }

  78.       if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >=  Timeout))
  79.       {
  80.         /* Call standard close procedure with error check */
  81.         SPI_CloseTransfer(hspi);

  82.         /* Process Unlocked */
  83.         __HAL_UNLOCK(hspi);

  84.         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
  85.         hspi->State = HAL_SPI_STATE_READY;
  86.         return HAL_ERROR;
  87.       }
  88.     }
  89.   }
  90.   /* Transmit and Receive data in 16 Bit mode */
  91.   else if (hspi->Init.DataSize > SPI_DATASIZE_8BIT)
  92.   {
  93.     while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
  94.     {
  95.       /* Check TXE flag */
  96.       if ((hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)))
  97.       {
  98.         if ( (hspi->TxXferCount > 1U) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_01DATA))
  99.         {
  100.           *((__IO uint32_t *)&hspi->Instance->TXDR) = *((uint32_t *)hspi->pTxBuffPtr);
  101.           hspi->pTxBuffPtr += sizeof(uint32_t);
  102.           hspi->TxXferCount-=2;
  103.         }
  104.         else
  105.         {
  106.           *((__IO uint16_t *)&hspi->Instance->TXDR) = *((uint16_t *)hspi->pTxBuffPtr);
  107.           hspi->pTxBuffPtr += sizeof(uint16_t);
  108.           hspi->TxXferCount--;
  109.         }
  110.       }

  111.       /* Check RXWNE/FRLVL flag */
  112.       if ((hspi->RxXferCount > 0U) && (hspi->Instance->SR & (SPI_FLAG_RXWNE|SPI_FLAG_FRLVL)))
  113.       {
  114.         if (hspi->Instance->SR & SPI_FLAG_RXWNE)
  115.         {
  116.           *((uint32_t *)hspi->pRxBuffPtr) = *((__IO uint32_t *)&hspi->Instance->RXDR);
  117.           hspi->pRxBuffPtr += sizeof(uint32_t);
  118.           hspi->RxXferCount-=2;
  119.         }
  120.         else
  121.         {
  122.           *((uint16_t *)hspi->pRxBuffPtr) = *((__IO uint16_t *)&hspi->Instance->RXDR);
  123.           hspi->pRxBuffPtr += sizeof(uint16_t);
  124.           hspi->RxXferCount--;
  125.         }
  126.       }

  127.       if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >=  Timeout))
  128.       {
  129.         /* Call standard close procedure with error check */
  130.         SPI_CloseTransfer(hspi);

  131.         /* Process Unlocked */
  132.         __HAL_UNLOCK(hspi);

  133.         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
  134.         hspi->State = HAL_SPI_STATE_READY;
  135.         return HAL_ERROR;
  136.       }
  137.     }
  138.   }
  139.   /* Transmit and Receive data in 8 Bit mode */
  140.   else
  141.   {
  142.     while ((hspi->TxXferCount > 0U) || (hspi->RxXferCount > 0U))
  143.     {
  144.       /* check TXE flag */
  145.       if ((hspi->TxXferCount > 0U) && (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE)))
  146.       {
  147.         if ((hspi->TxXferCount > 3U) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_03DATA))
  148.         {
  149.           *((__IO uint32_t *)&hspi->Instance->TXDR) = *((uint32_t *)hspi->pTxBuffPtr);
  150.           hspi->pTxBuffPtr += sizeof(uint32_t);
  151.           hspi->TxXferCount-=4;
  152.         }
  153.         else if ((hspi->TxXferCount > 1U) && (hspi->Init.FifoThreshold > SPI_FIFO_THRESHOLD_01DATA))
  154.         {
  155.           *((__IO uint16_t *)&hspi->Instance->TXDR) = *((uint16_t *)hspi->pTxBuffPtr);
  156.           hspi->pTxBuffPtr += sizeof(uint16_t);
  157.           hspi->TxXferCount-=2;
  158.         }
  159.         else
  160.         {
  161.           *((__IO uint8_t *)&hspi->Instance->TXDR) = *((uint8_t *)hspi->pTxBuffPtr);
  162.           hspi->pTxBuffPtr += sizeof(uint8_t);
  163.           hspi->TxXferCount--;
  164.         }
  165.       }

  166.       /* Wait until RXWNE/FRLVL flag is reset */
  167.       if ((hspi->RxXferCount > 0U) && (hspi->Instance->SR & (SPI_FLAG_RXWNE|SPI_FLAG_FRLVL)))
  168.       {
  169.         if (hspi->Instance->SR & SPI_FLAG_RXWNE)
  170.         {
  171.           *((uint32_t *)hspi->pRxBuffPtr) = *((__IO uint32_t *)&hspi->Instance->RXDR);
  172.           hspi->pRxBuffPtr += sizeof(uint32_t);
  173.           hspi->RxXferCount-=4;
  174.         }
  175.         else if ((hspi->Instance->SR & SPI_FLAG_FRLVL) > SPI_FRLVL_QUARTER_FULL)
  176.         {
  177.           *((uint16_t *)hspi->pRxBuffPtr) = *((__IO uint16_t *)&hspi->Instance->RXDR);
  178.           hspi->pRxBuffPtr += sizeof(uint16_t);
  179.           hspi->RxXferCount-=2;
  180.         }
  181.         else
  182.         {
  183.           *((uint8_t *)hspi->pRxBuffPtr) = *((__IO uint8_t *)&hspi->Instance->RXDR);
  184.           hspi->pRxBuffPtr += sizeof(uint8_t);
  185.           hspi->RxXferCount--;
  186.         }
  187.       }

  188.       if ((Timeout != HAL_MAX_DELAY) && ((HAL_GetTick() - tickstart) >=  Timeout))
  189.       {
  190.         /* Call standard close procedure with error check */
  191.         SPI_CloseTransfer(hspi);

  192.         /* Process Unlocked */
  193.         __HAL_UNLOCK(hspi);

  194.         SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_TIMEOUT);
  195.         hspi->State = HAL_SPI_STATE_READY;
  196.         return HAL_ERROR;
  197.       }
  198.     }
  199.   }

  200.   /* Wait for Tx/Rx (and CRC) data to be sent/received */
  201.   if (SPI_WaitOnFlagUntilTimeout(hspi, SPI_FLAG_EOT, RESET, tickstart, Timeout) != HAL_OK)
  202.   {
  203.     SET_BIT(hspi->ErrorCode, HAL_SPI_ERROR_FLAG);
  204.   }

  205.   /* Call standard close procedure with error check */
  206.   SPI_CloseTransfer(hspi);

  207.        /* Process Unlocked */
  208.   __HAL_UNLOCK(hspi);

  209.   hspi->State = HAL_SPI_STATE_READY;

  210.   if (hspi->ErrorCode != HAL_SPI_ERROR_NONE)
  211.   {
  212.     return HAL_ERROR;
  213.   }
  214.   return HAL_OK;
  215. }
这是我从STM32H743的HALL库里面找出来的的SPI发送接收函数,从你进入函数开始到真正将数据开始送出,前面经历了多少校验和查询,这写都会导致时钟延时。下面我贴寄存器方式的你看看,除了定义一个局部变量,之后马上使能SPI,然后会等待一个发送区空,然后立马向数据寄存器写值,此时时钟开始响应,开始发送数据。
  1. u8 SPI2_ReadWriteByte(u8 TxData)
  2. {                                   
  3.         u8 RxData=0;       
  4.         SPI2->CR1|=1<<0;                                //SPE=1,使能SPI2
  5.         SPI2->CR1|=1<<9;                                  //CSTART=1,启动传输
  6.        
  7.         while((SPI2->SR&1<<1)==0);                //等待发送区空
  8.         *(vu8 *)&SPI2->TXDR=TxData;                //发送一个byte,以传输长度访问TXDR寄存器   
  9.         while((SPI2->SR&1<<0)==0);                //等待接收完一个byte  
  10.         RxData=*(vu8 *)&SPI2->RXDR;                //接收一个byte,以传输长度访问RXDR寄存器       
  11.        
  12.         SPI2->IFCR|=3<<3;                                //EOTC和TXTFC置1,清除EOT和TXTFC位
  13.         SPI2->CR1&=~(1<<0);                                //SPE=0,关闭SPI2,会执行状态机复位/FIFO重置等操作
  14.         return RxData;                                        //返回收到的数据
  15. }
如果你想更快,初始化的时候就使能SPI,不检测发送区,直接给TXDR送数据,就会更快的让时钟起来。自己测试就知道了。还是那句话,HALL库只能保证你的代码安稳的运行,并检测出在哪出错,但是实时性巨差,是所有方式里面最慢的。如果向高速运行代码,要学会交叉使用,需要快速就自己写寄存器。其他初始化可以用HALL
1988020566 发表于 2023-10-18 19:46 | 显示全部楼层
SPI接口的信号线连接不良可能会导致SPI CLK响应较慢。
pixhw 发表于 2023-10-18 20:25 | 显示全部楼层
SPI接口的时钟频率是SPI通信速度的关键因素之一,如果时钟频率设置过低,可能会导致SPI CLK响应较慢。
louliana 发表于 2023-10-18 20:56 | 显示全部楼层
SPI协议是一种同步串行数据协议,数据一位一位地传输,需要时钟线来同步。如果传输速度提高,则时钟频率也会提高,会导致硬件电路上的延迟,从而降低了SPI CLK的响应速度。
mnynt121 发表于 2023-10-18 21:17 | 显示全部楼层
没有正确配置SPI的时钟频率,或者没有正确初始化SPI。
eefas 发表于 2023-10-18 22:07 | 显示全部楼层
如果数据传输模式配置不正确,可能会导致响应时间变慢,需要检查数据传输模式的配置。
 楼主| Hufei1994 发表于 2023-10-18 23:04 | 显示全部楼层
呐咯密密 发表于 2023-10-18 17:21
这是我从STM32H743的HALL库里面找出来的的SPI发送接收函数,从你进入函数开始到真正将数据开始送出,前面 ...

感谢解惑,改日我使用寄存器来重写一下看看速度能否提升
呐咯密密 发表于 2023-10-19 09:14 | 显示全部楼层
Hufei1994 发表于 2023-10-18 23:04
感谢解惑,改日我使用寄存器来重写一下看看速度能否提升

测试完记得回来结贴,给问题一个答案
abotomson 发表于 2023-10-22 10:50 | 显示全部楼层
减小硬件电路延迟对SPI CLK响应速度的影响。
10299823 发表于 2023-10-22 11:44 | 显示全部楼层
可以优化程序结构,减少系统资源占用,提高响应速度。
modesty3jonah 发表于 2023-10-22 11:53 | 显示全部楼层
如果STM32单片机同时运行多个任务或程序,可能会导致系统资源占用过多,从而影响SPI接口的响应速度。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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