You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM8无HAL_SPI_Transmit函数,如何实现SPI数组传输?

关于STM8实现SPI数组传输的解决方案

问题背景

我试图在STM8上编写类STM32的SPI代码,但发现STM8没有HAL_SPI_Transmit函数,仅有SPI_SendData函数,需要实现SPI数组传输功能。

STM32的HAL_SPI_Transmit函数

HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
  uint32_t tickstart;
  HAL_StatusTypeDef errorcode = HAL_OK;
  uint16_t initial_TxXferCount;

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

  /* Process Locked */
  __HAL_LOCK(hspi);

  /* Init tickstart for timeout management*/
  tickstart = HAL_GetTick();
  initial_TxXferCount = Size;

  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->RxXferSize  = 0U;
  hspi->RxXferCount = 0U;
  hspi->TxISR       = NULL;
  hspi->RxISR       = NULL;

  /* Configure communication direction : 1Line */
  if (hspi->Init.Direction == SPI_DIRECTION_1LINE)
  {
    /* Disable SPI Peripheral before set 1Line direction (BIDIOE bit) */
    __HAL_SPI_DISABLE(hspi);
    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 */

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

  /* Transmit data in 16 Bit mode */
  if (hspi->Init.DataSize == SPI_DATASIZE_16BIT)
  {
    if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U))
    {
      hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
      hspi->pTxBuffPtr += sizeof(uint16_t);
      hspi->TxXferCount--;
    }
    /* Transmit data in 16 Bit mode */
    while (hspi->TxXferCount > 0U)
    {
      /* Wait until TXE flag is set to send data */
      if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
      {
        hspi->Instance->DR = *((uint16_t *)hspi->pTxBuffPtr);
        hspi->pTxBuffPtr += sizeof(uint16_t);
        hspi->TxXferCount--;
      }
      else
      {
        /* Timeout management */
        if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }
  /* Transmit data in 8 Bit mode */
  else
  {
    if ((hspi->Init.Mode == SPI_MODE_SLAVE) || (initial_TxXferCount == 0x01U))
    {
      *((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr);
      hspi->pTxBuffPtr += sizeof(uint8_t);
      hspi->TxXferCount--;
    }
    while (hspi->TxXferCount > 0U)
    {
      /* Wait until TXE flag is set to send data */
      if (__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_TXE))
      {
        *((__IO uint8_t *)&hspi->Instance->DR) = (*hspi->pTxBuffPtr);
        hspi->pTxBuffPtr += sizeof(uint8_t);
        hspi->TxXferCount--;
      }
      else
      {
        /* Timeout management */
        if ((((HAL_GetTick() - tickstart) >=  Timeout) && (Timeout != HAL_MAX_DELAY)) || (Timeout == 0U))
        {
          errorcode = HAL_TIMEOUT;
          goto error;
        }
      }
    }
  }
#if (USE_SPI_CRC != 0U)
  /* Enable CRC Transmission */
  if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
  {
    SET_BIT(hspi->Instance->CR1, SPI_CR1_CRCNEXT);
  }
#endif /* USE_SPI_CRC */

  /* Check the end of the transaction */
  if (SPI_EndRxTxTransaction(hspi, Timeout, tickstart) != HAL_OK)
  {
    hspi->ErrorCode = HAL_SPI_ERROR_FLAG;
  }

  /* Clear overrun flag in 2 Lines communication mode because received is not read */
  if (hspi->Init.Direction == SPI_DIRECTION_2LINES)
  {
    __HAL_SPI_CLEAR_OVRFLAG(hspi);
  }

  if (hspi->ErrorCode != HAL_SPI_ERROR_NONE)
  {
    errorcode = HAL_ERROR;
  }

error:
  hspi->State = HAL_SPI_STATE_READY;
  /* Process Unlocked */
  __HAL_UNLOCK(hspi);
  return errorcode;
}

STM8的SPI_SendData函数

void SPI_SendData(SPI_TypeDef* SPIx, uint8_t Data)
{
  SPIx->DR = Data; /* Write in the DR register the data to be sent*/
}

目前不确定是否必须自行定义新函数来实现数组传输,想询问是否有其他解决办法?


解决方案

由于STM8的标准库没有提供现成的数组传输函数,自行封装是最直接且可靠的方式,没有其他更简便的替代方案。以下提供两种封装实现:

1. 基础轮询版(无超时)

适合对可靠性要求一般、无需超时处理的场景:

void SPI_Transmit(SPI_TypeDef* SPIx, uint8_t* pData, uint16_t Size)
{
  while(Size--)
  {
    // 等待发送寄存器为空
    while(!(SPIx->SR & SPI_SR_TXE));
    SPI_SendData(SPIx, *pData++);
    // 可选:等待当前字节完全发送完成
    while(!(SPIx->SR & SPI_SR_BSY));
  }
}

2. 带超时的增强版(类STM32 HAL风格)

如果需要超时机制避免死等,可基于STM8系统定时器实现:

// 假设已实现获取系统滴答的函数GetSysTick(),返回毫秒数
#define SPI_TIMEOUT_MAX 1000 // 最大超时时间,单位ms

typedef enum
{
  SPI_OK = 0,
  SPI_ERROR_TIMEOUT,
  SPI_ERROR_PARAM
} SPI_StatusTypeDef;

SPI_StatusTypeDef SPI_Transmit_WithTimeout(SPI_TypeDef* SPIx, uint8_t* pData, uint16_t Size, uint32_t Timeout)
{
  uint32_t tickStart = GetSysTick();
  
  if(pData == NULL || Size == 0)
  {
    return SPI_ERROR_PARAM;
  }
  
  while(Size--)
  {
    // 等待TXE标志置位,带超时判断
    while(!(SPIx->SR & SPI_SR_TXE))
    {
      if((GetSysTick() - tickStart) >= Timeout)
      {
        return SPI_ERROR_TIMEOUT;
      }
    }
    SPI_SendData(SPIx, *pData++);
    
    // 可选:等待发送完成,带超时判断
    while(!(SPIx->SR & SPI_SR_BSY))
    {
      if((GetSysTick() - tickStart) >= Timeout)
      {
        return SPI_ERROR_TIMEOUT;
      }
    }
  }
  
  return SPI_OK;
}

注意事项

  • 确保SPI外设已完成正确初始化(波特率、主从模式、数据位宽度等参数)
  • 若工作在从机模式,发送时机需配合主机的同步时钟信号
  • 部分STM8型号支持SPI DMA传输,适合大数据量场景,但实现复杂度更高

内容的提问来源于stack exchange,提问作者user20560622

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 10:35:25