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
相关产品推荐
相关产品推荐

