1052 lines
33 KiB
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|