rt-thread/bsp/acm32f0x0-nucleo/libraries/HAL_Driver/Src/HAL_SPI.c

1052 lines
33 KiB
C

/*
******************************************************************************
* @file HAL_Spi.c
* @version V1.0.0
* @date 2020
* @brief SPI HAL module driver.
* This file provides firmware functions to manage the following
* functionalities of the Serial Peripheral Interface (SPI) peripheral.
* @ Initialization and de-initialization functions
* @ IO operation functions
* @ Peripheral Control functions
******************************************************************************
*/
#include "ACM32Fxx_HAL.h"
#define SPI_RX_TIMEOUT 2000
#define SPI_TX_DMA_TIMEOUT 2000
volatile uint32_t lu32_ReceiveTimeOut = SPI_RX_TIMEOUT;
volatile uint32_t lu32_TX_DMA_TimeOut = SPI_TX_DMA_TIMEOUT;
/************************************************************************
* function : HAL_SPI_IRQHandler
* Description: This function handles SPI interrupt request.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
************************************************************************/
__weak void HAL_SPI_IRQHandler(SPI_HandleTypeDef *hspi)
{
/*
NOTE : This function should be modified by the user.
*/
if ( (hspi->Instance->STATUS & SPI_STATUS_RX_NOT_EMPTY) && ((hspi->Instance->IE) & SPI_STATUS_RX_NOT_EMPTY) )
{
/* In master mode */
if (hspi->Instance->CTL & SPI_CTL_MST_MODE)
{
while (hspi->Instance->STATUS & SPI_STATUS_RX_NOT_EMPTY)
{
hspi->Rx_Buffer[hspi->Rx_Count++] = hspi->Instance->DAT;
if (hspi->Rx_Count >= hspi->Rx_Size)
{
/* Wait Transmit Done */
while (!(hspi->Instance->STATUS & SPI_STATUS_RX_BATCH_DONE));
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
/* Receive End */
hspi->Instance->CS &= (~SPI_CS_CS0);
/* Disable Rx Not Empty Interrupt */
CLEAR_BIT(hspi->Instance->IE, SPI_STATUS_RX_NOT_EMPTY);
if(hspi->Instance == SPI1)
NVIC_ClearPendingIRQ(SPI1_IRQn);
else if(hspi->Instance == SPI2)
NVIC_ClearPendingIRQ(SPI2_IRQn);
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Set machine is DILE */
hspi->RxState = SPI_RX_STATE_IDLE;
}
}
}
/* In Slave mode */
else
{
while ((hspi->Rx_Count < hspi->Rx_Size) && (lu32_ReceiveTimeOut > 0) )
{
if (hspi->Instance->STATUS & SPI_STATUS_RX_NOT_EMPTY)
{
hspi->Rx_Buffer[hspi->Rx_Count++] = hspi->Instance->DAT;
lu32_ReceiveTimeOut = SPI_RX_TIMEOUT; //If recieve data, Reset the timeout value
}
else
{
lu32_ReceiveTimeOut--;
}
}
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
/* Disable Rx Not Empty Interrupt */
CLEAR_BIT(hspi->Instance->IE, SPI_STATUS_RX_NOT_EMPTY);
if(hspi->Instance == SPI1)
NVIC_ClearPendingIRQ(SPI1_IRQn);
else if(hspi->Instance == SPI2)
NVIC_ClearPendingIRQ(SPI2_IRQn);
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Set machine is DILE */
hspi->RxState = SPI_RX_STATE_IDLE;
}
}
if ( (hspi->Instance->STATUS & SPI_STATUS_TX_FIFO_HALF_EMPTY) && ((hspi->Instance->IE) & SPI_IE_TX_FIFO_HALF_EMPTY_EN) )
{
while (hspi->Tx_Count < hspi->Tx_Size)
{
if (!(hspi->Instance->STATUS & SPI_STATUS_TX_FIFO_FULL))
{
hspi->Instance->DAT = hspi->Tx_Buffer[hspi->Tx_Count++];
}
else
{
break;
}
}
/* Clear Tx FIFO half empty Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_FIFO_HALF_EMPTY);
if(hspi->Tx_Count == hspi->Tx_Size)
{
/* Disable Tx FIFO half empty Interrupt */
CLEAR_BIT(hspi->Instance->IE, SPI_IE_TX_FIFO_HALF_EMPTY_EN);
}
}
if ((hspi->Instance->STATUS & SPI_STATUS_TX_BATCH_DONE) && ((hspi->Instance->IE) & SPI_IE_TX_BATCH_DONE_EN) )
{
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Disable TX Batch Done Interrupt */
CLEAR_BIT(hspi->Instance->IE, SPI_STATUS_TX_BATCH_DONE);
/* Disable Tx FIFO half empty Interrupt */
CLEAR_BIT(hspi->Instance->IE, SPI_IE_TX_FIFO_HALF_EMPTY_EN);
if(hspi->Instance == SPI1)
NVIC_ClearPendingIRQ(SPI1_IRQn);
else if(hspi->Instance == SPI2)
NVIC_ClearPendingIRQ(SPI2_IRQn);
lu32_TX_DMA_TimeOut = SPI_TX_DMA_TIMEOUT;
while (hspi->Instance->STATUS & SPI_STATUS_TX_BUSY)
{
lu32_TX_DMA_TimeOut--;
if(0 == lu32_TX_DMA_TimeOut)
{
break;
}
}
/* Tx Disable */
hspi->Instance->TX_CTL &= (~SPI_TX_CTL_EN);
hspi->Instance->TX_CTL &= (~SPI_TX_CTL_DMA_REQ_EN);
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Transmit End */
hspi->Instance->CS &= (~SPI_CS_CS0);
}
/* Tx Disable */
hspi->Instance->TX_CTL &= (~SPI_TX_CTL_EN);
hspi->TxState = SPI_TX_STATE_IDLE;
}
if ( (hspi->Instance->STATUS & SPI_STATUS_RX_BATCH_DONE) && ((hspi->Instance->IE) & SPI_STATUS_RX_BATCH_DONE) )
{
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Disable RX Batch Done Interrupt */
CLEAR_BIT(hspi->Instance->IE, SPI_STATUS_RX_BATCH_DONE);
if(hspi->Instance == SPI1)
NVIC_ClearPendingIRQ(SPI1_IRQn);
else if(hspi->Instance == SPI2)
NVIC_ClearPendingIRQ(SPI2_IRQn);
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_DMA_REQ_EN);
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Receive End */
hspi->Instance->CS &= (~SPI_CS_CS0);
}
hspi->RxState = SPI_RX_STATE_IDLE;
}
}
/************************************************************************
* function : HAL_SPI_MspInit
* Description:
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
************************************************************************/
__weak void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
/*
NOTE : This function should be modified by the user.
*/
/* For Example */
GPIO_InitTypeDef GPIO_Handle;
/* SPI1 */
if (hspi->Instance == SPI1)
{
}
/* SPI2 */
else if (hspi->Instance == SPI2)
{
/* Enable Clock */
System_Module_Enable(EN_SPI2);
/* SPI2 CS PB12 */
/* SPI2 SCK PB13 */
/* SPI2 MOSI PB15 */
/* SPI2 MISO PB14 */
GPIO_Handle.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_Handle.Mode = GPIO_MODE_AF_PP;
GPIO_Handle.Pull = GPIO_PULLUP;
GPIO_Handle.Alternate = GPIO_FUNCTION_4;
HAL_GPIO_Init(GPIOB, &GPIO_Handle);
if (hspi->Init.X_Mode == SPI_4X_MODE)
{
/* SPI2 IO3 PC6 */
/* SPI2 IO2 PC7 */
GPIO_Handle.Pin = GPIO_PIN_6 | GPIO_PIN_7;
GPIO_Handle.Mode = GPIO_MODE_AF_PP;
GPIO_Handle.Pull = GPIO_PULLUP;
GPIO_Handle.Alternate = GPIO_FUNCTION_2;
HAL_GPIO_Init(GPIOC, &GPIO_Handle);
}
/* Clear Pending Interrupt */
NVIC_ClearPendingIRQ(SPI2_IRQn);
/* Enable External Interrupt */
NVIC_EnableIRQ(SPI2_IRQn);
}
}
/************************************************************************
* function : HAL_SPI_MspDeInit
* Description: SPI De-Initialize the SPI clock, GPIO, IRQ.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
************************************************************************/
__weak void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
/*
NOTE : This function should be modified by the user.
*/
/* For Example */
/* SPI1 */
if (hspi->Instance == SPI1)
{
}
/* SPI2 */
else if (hspi->Instance == SPI2)
{
/* Disable Clock */
System_Module_Disable(EN_SPI2);
/* Reset the used GPIO to analog */
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
if (hspi->Init.X_Mode == SPI_4X_MODE)
{
HAL_GPIO_DeInit(GPIOC, GPIO_PIN_6 | GPIO_PIN_7);
}
/* Clear Pending Interrupt */
NVIC_ClearPendingIRQ(SPI2_IRQn);
/* Disable External Interrupt */
NVIC_DisableIRQ(SPI2_IRQn);
}
}
/************************************************************************
* function : HAL_SPI_Init
* Description: SPI initial with parameters.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
{
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
if (!IS_SPI_ALL_MODE(hspi->Init.SPI_Mode)) return HAL_ERROR;
if (!IS_SPI_WORK_MODE(hspi->Init.SPI_Work_Mode)) return HAL_ERROR;
if (!IS_SPI_X_MODE(hspi->Init.X_Mode)) return HAL_ERROR;
if (!IS_SPI_FIRST_BIT(hspi->Init.First_Bit)) return HAL_ERROR;
if (!IS_SPI_BAUDRATE_PRESCALER(hspi->Init.BaudRate_Prescaler)) return HAL_ERROR;
/* Init the low level hardware : GPIO, CLOCK, NVIC */
HAL_SPI_MspInit(hspi);
/* Automatic change direction */
hspi->Instance->CTL |= (SPI_CTL_IO_MODE);
/* Set SPI Work mode */
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
SET_BIT(hspi->Instance->CTL, SPI_CTL_MST_MODE);
}
else
{
CLEAR_BIT(hspi->Instance->CTL, SPI_CTL_MST_MODE);
hspi->Instance->BATCH = (hspi->Instance->BATCH & (~0x000FFFFFU)) | (1 << 0);
hspi->Instance->TX_CTL |= SPI_TX_CTL_MODE | (0x88 << 8); // dummy data = 0x88
if (hspi->Init.X_Mode != SPI_1X_MODE)
{
hspi->Instance->CTL |= SPI_CTL_SFILTER;
}
/* Slave Alternate Enable */
hspi->Instance->CTL |= SPI_CTL_SLAVE_EN;
/* Slave Mode Enable Rx By Default */
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
}
/* Set SPI First Bit */
if (hspi->Init.First_Bit == SPI_FIRSTBIT_LSB)
SET_BIT(hspi->Instance->CTL, SPI_CTL_LSB_FIRST);
else
CLEAR_BIT(hspi->Instance->CTL, SPI_CTL_LSB_FIRST);
/* Set SPI Work Mode */
hspi->Instance->CTL = ((hspi->Instance->CTL) & (~(SPI_CTL_CPHA | SPI_CTL_CPOL))) | (hspi->Init.SPI_Work_Mode);
/* Set SPI X_Mode */
hspi->Instance->CTL = ((hspi->Instance->CTL) & (~SPI_CTL_X_MODE)) | (hspi->Init.X_Mode);
/* Set SPI BaudRate Prescaler */
hspi->Instance->BAUD = ((hspi->Instance->BAUD) & (~0x0000FFFF)) | (hspi->Init.BaudRate_Prescaler);
/* Disable All Interrupt */
hspi->Instance->IE = 0x00000000;
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_DeInit
* Description: De-Initialize the SPI peripheral.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* return : HAL_StatusTypeDef : HAL status
************************************************************************/
HAL_StatusTypeDef HAL_SPI_DeInit(SPI_HandleTypeDef *hspi)
{
/* Check the SPI handle allocation */
if (hspi == NULL)
{
return HAL_ERROR;
}
/* Check SPI Instance parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
hspi->RxState = SPI_RX_STATE_IDLE;
hspi->TxState = SPI_TX_STATE_IDLE;
/* DeInit the low level hardware: GPIO, CLOCK, NVIC... */
HAL_SPI_MspDeInit(hspi);
hspi->Rx_Size = 0;
hspi->Tx_Size = 0;
hspi->Rx_Count = 0;
hspi->Tx_Count = 0;
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_Transmit
* Description: Transmits an amount of data in blocking mode.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pData : Pointer to data buffer
* Size : Amount of data to be sent
* Timeout : Transmit Timeout
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout)
{
HAL_StatusTypeDef Status = HAL_OK;
__IO uint32_t uiTimeout;
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
if(!Size) return HAL_ERROR;
if (pData == NULL) return HAL_ERROR;
hspi->Tx_Count = 0;
hspi->Tx_Size = Size;
hspi->Tx_Buffer = pData;
uiTimeout = Timeout;
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Clear TX FIFO */
SET_BIT(hspi->Instance->TX_CTL, SPI_TX_CTL_FIFO_RESET);
CLEAR_BIT(hspi->Instance->TX_CTL, SPI_TX_CTL_FIFO_RESET);
/* Set Data Size */
hspi->Instance->BATCH = Size;
/* Tx Enable */
hspi->Instance->TX_CTL |= SPI_TX_CTL_EN;
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Transmit Start */
hspi->Instance->CS |= SPI_CS_CS0;
}
else
{
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
}
while(hspi->Tx_Size > 0)
{
/* Wait Tx FIFO Not Full */
while (hspi->Instance->STATUS & SPI_STATUS_TX_FIFO_FULL)
{
if(uiTimeout)
{
uiTimeout--;
if (uiTimeout == 0)
{
Status = HAL_TIMEOUT;
goto End;
}
}
}
hspi->Instance->DAT = hspi->Tx_Buffer[hspi->Tx_Count++];
hspi->Tx_Size--;
uiTimeout = Timeout;
}
if (hspi->Init.SPI_Mode == SPI_MODE_SLAVE)
{
/* Wait Transmit Done */
while (!(hspi->Instance->STATUS & SPI_STATUS_TX_BUSY));
while (hspi->Instance->STATUS & SPI_STATUS_TX_BUSY)
{
if(uiTimeout)
{
uiTimeout--;
if (uiTimeout == 0)
{
Status = HAL_TIMEOUT;
goto End;
}
}
}
}
else
{
/* Wait Transmit Done */
while (!(hspi->Instance->STATUS & SPI_STATUS_TX_BATCH_DONE));
Status = HAL_OK;
}
End:
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Tx Disable */
hspi->Instance->TX_CTL &= (~SPI_TX_CTL_EN);
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Transmit End */
hspi->Instance->CS &= (~SPI_CS_CS0);
}
return Status;
}
/************************************************************************
* function : HAL_SPI_Transmit_DMA
* Description: Transmits an amount of data in blocking mode with DMA.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pData : Pointer to data buffer
* Size : Amount of data to be sent
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
/* Rx machine is running */
if (hspi->TxState != SPI_TX_STATE_IDLE)
{
return HAL_ERROR;
}
/* Set machine is Sending */
hspi->TxState = SPI_TX_STATE_SENDING;
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Enable Tx Batch Done Interrupt */
SET_BIT(hspi->Instance->IE, SPI_STATUS_TX_BATCH_DONE);
/* Set Data Size */
hspi->Instance->BATCH = Size;
/* Tx FIFO */
hspi->Instance->TX_CTL &= ~SPI_TX_CTL_DMA_LEVEL;
hspi->Instance->TX_CTL |= SPI_TX_CTL_DMA_LEVEL_0;
/* Tx Enable */
hspi->Instance->TX_CTL |= SPI_TX_CTL_EN;
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Transmit Start */
hspi->Instance->CS |= SPI_CS_CS0;
}
else
{
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
}
HAL_DMA_Start(hspi->HDMA_Tx, (uint32_t)pData, (uint32_t)&hspi->Instance->DAT, Size);
hspi->Instance->TX_CTL |= SPI_TX_CTL_DMA_REQ_EN;
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_Receive
* Description: Receive an amount of data in blocking mode.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pData : Pointer to data buffer
* Size : Amount of data to be Receive
* Timeout : Receive Timeout
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size, uint32_t Timeout)
{
HAL_StatusTypeDef Status = HAL_OK;
__IO uint32_t uiTimeout;
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
if (pData == NULL) return HAL_ERROR;
hspi->Rx_Count = 0;
hspi->Rx_Size = Size;
hspi->Rx_Buffer = pData;
uiTimeout = Timeout;
if (hspi->Init.SPI_Mode == SPI_MODE_SLAVE)
{
hspi->Instance->BATCH = 1;
/* Rx Enable */
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
while ( hspi->Rx_Size > 0)
{
while (READ_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_FIFO_EMPTY))
{
if(uiTimeout)
{
uiTimeout--;
if (uiTimeout == 0)
{
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
return HAL_TIMEOUT;
}
}
}
hspi->Rx_Buffer[hspi->Rx_Count++] = hspi->Instance->DAT;
hspi->Rx_Size--;
uiTimeout = Timeout;
}
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
return HAL_OK;
}
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Set Data Size */
hspi->Instance->BATCH = Size;
/* Rx Enable */
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
/* Receive Start */
hspi->Instance->CS |= SPI_CS_CS0;
while(hspi->Rx_Size > 0)
{
/* have no timeout */
if (uiTimeout == 0)
{
/* Wait Rx FIFO Not Empty */
while (hspi->Instance->STATUS & SPI_STATUS_RX_FIFO_EMPTY);
}
else
{
while (hspi->Instance->STATUS & SPI_STATUS_RX_FIFO_EMPTY)
{
if (uiTimeout-- == 0)
{
Status = HAL_TIMEOUT;
goto End;
}
}
}
hspi->Rx_Buffer[hspi->Rx_Count++] = hspi->Instance->DAT;
hspi->Rx_Size--;
}
Status = HAL_OK;
/* Wait Transmit Done */
while (!(hspi->Instance->STATUS & SPI_STATUS_RX_BATCH_DONE));
End:
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
/* Receive End */
hspi->Instance->CS &= (~SPI_CS_CS0);
return Status;
}
/************************************************************************
* function : HAL_SPI_Receive_DMA
* Description: Receive an amount of data in blocking mode with DMA.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pData : Pointer to data buffer
* Size : Amount of data to be Receive
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
/* Rx machine is running */
if (hspi->RxState != SPI_RX_STATE_IDLE)
{
return HAL_ERROR;
}
/* Set Slave machine is receiving */
hspi->RxState = SPI_RX_STATE_RECEIVING;
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Enable Rx Batch Done Interrupt */
SET_BIT(hspi->Instance->IE, SPI_STATUS_RX_BATCH_DONE);
/* Set Data Size */
hspi->Instance->BATCH = Size;
/* Rx Enable */
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
/* Rx FIFO */
hspi->Instance->RX_CTL |= SPI_RX_CTL_DMA_LEVEL_0;
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Receive Start */
hspi->Instance->CS |= SPI_CS_CS0;
}
HAL_DMA_Start(hspi->HDMA_Rx, (uint32_t)&hspi->Instance->DAT, (uint32_t)pData, Size);
hspi->Instance->RX_CTL |= SPI_RX_CTL_DMA_REQ_EN;
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_Wire_Config
* Description: SPI Wire Config
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* Mode : This parameter can be a value of @ref X_MODE
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Wire_Config(SPI_HandleTypeDef *hspi, uint32_t X_Mode)
{
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
/* Set SPI X_Mode */
hspi->Instance->CTL = ((hspi->Instance->CTL) & (~SPI_CTL_X_MODE)) | X_Mode;
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_Transmit_IT
* Description: Transmit an amount of data in blocking mode with interrupt.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pData : Pointer to data buffer
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Transmit_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
/* Tx machine is running */
if (hspi->TxState != SPI_TX_STATE_IDLE)
{
return HAL_ERROR;
}
hspi->Tx_Size = Size;
hspi->Tx_Buffer = pData;
hspi->Tx_Count = 0;
/* Set machine is Sending */
hspi->TxState = SPI_TX_STATE_SENDING;
/* Clear TX FIFO */
SET_BIT(hspi->Instance->TX_CTL, SPI_TX_CTL_FIFO_RESET);
CLEAR_BIT(hspi->Instance->TX_CTL, SPI_TX_CTL_FIFO_RESET);
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Set Data Size */
hspi->Instance->BATCH = Size;
/* Tx Enable */
hspi->Instance->TX_CTL |= SPI_TX_CTL_EN;
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Transmit Start */
hspi->Instance->CS |= SPI_CS_CS0;
}
else
{
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
}
while (hspi->Tx_Count < hspi->Tx_Size)
{
if (!(hspi->Instance->STATUS & SPI_STATUS_TX_FIFO_FULL))
hspi->Instance->DAT = hspi->Tx_Buffer[hspi->Tx_Count++];
else
break;
}
/* Clear Tx FIFO half empty Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_FIFO_HALF_EMPTY);
/* Enable Tx FIFO half empty Interrupt and Tx batch done Interrupt*/
SET_BIT(hspi->Instance->IE, (SPI_IE_TX_FIFO_HALF_EMPTY_EN | SPI_IE_TX_BATCH_DONE_EN));
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_Receive_IT
* Description: Receive an amount of data in blocking mode with interrupt.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pData : Pointer to data buffer
************************************************************************/
HAL_StatusTypeDef HAL_SPI_Receive_IT(SPI_HandleTypeDef *hspi, uint8_t *pData, uint32_t Size)
{
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
/* Rx machine is running */
if (hspi->RxState != SPI_RX_STATE_IDLE)
{
return HAL_ERROR;
}
/* Set Slave machine is receiving */
hspi->RxState = SPI_RX_STATE_RECEIVING;
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_RX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Set Data Size */
hspi->Instance->BATCH = Size;
/* Rx Enable */
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
/* Receive Start */
hspi->Instance->CS |= SPI_CS_CS0;
}
else
{
/* Reset BATCH register */
hspi->Instance->BATCH = 1;
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
}
hspi->Rx_Size = Size;
hspi->Rx_Buffer = pData;
hspi->Rx_Count = 0;
lu32_ReceiveTimeOut = SPI_RX_TIMEOUT;
/* Enable Rx FIFO Not Empty Interrupt */
SET_BIT(hspi->Instance->IE, SPI_STATUS_RX_NOT_EMPTY);
return HAL_OK;
}
/************************************************************************
* function : HAL_SPI_TransmitReceive
* Description: Transmits and recieve an amount of data in blocking mode.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
* pTxData : Pointer to transmit data buffer
* pRxData : Pointer to recieve data buffer
* Size : Amount of data to be sent
* Timeout : TransmitReceive Timeout
************************************************************************/
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint32_t Size, uint32_t Timeout)
{
__IO uint32_t TxFlag = 1U, uiTimeout, uiRegTemp;
HAL_StatusTypeDef Status = HAL_OK;
/* Check SPI Parameter */
if (!IS_SPI_ALL_INSTANCE(hspi->Instance)) return HAL_ERROR;
if ((pTxData == NULL)||(pRxData == NULL)) return HAL_ERROR;
hspi->Tx_Count = 0;
hspi->Rx_Count = 0;
hspi->Tx_Buffer = pTxData;
hspi->Rx_Buffer = pRxData;
hspi->Tx_Size = Size;
hspi->Rx_Size = Size;
uiTimeout = Timeout;
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Tx Enable */
hspi->Instance->TX_CTL |= SPI_TX_CTL_EN;
/* Rx Enable */
hspi->Instance->RX_CTL |= SPI_RX_CTL_EN;
/* Clear TX FIFO */
SET_BIT(hspi->Instance->TX_CTL, SPI_TX_CTL_FIFO_RESET);
CLEAR_BIT(hspi->Instance->TX_CTL, SPI_TX_CTL_FIFO_RESET);
if (hspi->Init.SPI_Mode == SPI_MODE_SLAVE)
{
while((!(hspi->Instance->STATUS & SPI_STATUS_TX_FIFO_FULL)) && (hspi->Tx_Size>0))
{
hspi->Instance->DAT = hspi->Tx_Buffer[hspi->Tx_Count++];
hspi->Tx_Size--;
}
TxFlag = 0;
}
else
{
/* Set Data Size */
hspi->Instance->BATCH = hspi->Tx_Size;
/* Transmit Start */
hspi->Instance->CS |= SPI_CS_CS0;
TxFlag = 1;
}
while((hspi->Tx_Size>0) || (hspi->Rx_Size>0))
{
uiRegTemp = hspi->Instance->STATUS;
if (hspi->Init.SPI_Mode == SPI_MODE_SLAVE)
{
/* Wait Rx FIFO Not Empty */
if((!(uiRegTemp & SPI_STATUS_RX_FIFO_EMPTY)) && (hspi->Rx_Size>0))
{
hspi->Rx_Buffer[hspi->Rx_Count++] = hspi->Instance->DAT;
hspi->Rx_Size--;
TxFlag = 1U;
}
/* Wait Tx FIFO Not Full */
if(((uiRegTemp & SPI_STATUS_TX_FIFO_HALF_EMPTY)) && (hspi->Tx_Size>0) && (TxFlag == 1U))
{
while((!(hspi->Instance->STATUS & SPI_STATUS_TX_FIFO_FULL)) && (hspi->Tx_Size>0))
{
hspi->Instance->DAT = hspi->Tx_Buffer[hspi->Tx_Count++];
hspi->Tx_Size--;
}
TxFlag = 0;
}
}
else
{
/* Wait Tx FIFO Not Full */
if((!(uiRegTemp & SPI_STATUS_TX_FIFO_FULL)) && (hspi->Tx_Size>0) && (TxFlag == 1U))
{
hspi->Instance->DAT = hspi->Tx_Buffer[hspi->Tx_Count++];
hspi->Tx_Size--;
TxFlag = 0;
}
/* Wait Rx FIFO Not Empty */
if((!(uiRegTemp & SPI_STATUS_RX_FIFO_EMPTY)) && (hspi->Rx_Size>0))
{
hspi->Rx_Buffer[hspi->Rx_Count++] = hspi->Instance->DAT;
hspi->Rx_Size--;
TxFlag = 1U;
}
}
/* Wait Timeout */
if(uiTimeout)
{
uiTimeout--;
if(uiTimeout == 0)
{
Status = HAL_TIMEOUT;
goto End;
}
}
}
/* Wait Transmit Done */
while (!(hspi->Instance->STATUS & SPI_STATUS_TX_BATCH_DONE));
Status = HAL_OK;
End:
/* Clear Batch Done Flag */
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_TX_BATCH_DONE);
SET_BIT(hspi->Instance->STATUS, SPI_STATUS_BATCH_DONE);
/* Tx Disable */
hspi->Instance->TX_CTL &= (~SPI_TX_CTL_EN);
/* Rx Disable */
hspi->Instance->RX_CTL &= (~SPI_RX_CTL_EN);
if (hspi->Init.SPI_Mode == SPI_MODE_MASTER)
{
/* Transmit End */
hspi->Instance->CS &= (~SPI_CS_CS0);
}
return Status;
}
/************************************************************************
* function : HAL_SPI_GetTxState
* Description: Get Tx state.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
************************************************************************/
uint8_t HAL_SPI_GetTxState(SPI_HandleTypeDef *hspi)
{
return hspi->TxState;
}
/************************************************************************
* function : HAL_SPI_GetRxState
* Description: Get Rx state.
* input : hspi : pointer to a SPI_HandleTypeDef structure that contains
* the configuration information for SPI module
************************************************************************/
uint8_t HAL_SPI_GetRxState(SPI_HandleTypeDef *hspi)
{
return hspi->RxState;
}