rt-thread/bsp/hc32f4a0/Libraries/HC32F4A0_StdPeriph_Driver/src/hc32f4a0_spi.c

1096 lines
39 KiB
C

/**
*******************************************************************************
* @file hc32f4a0_spi.c
* @brief This file provides firmware functions to manage the Serial Peripheral
* Interface(SPI).
@verbatim
Change Logs:
Date Author Notes
2020-06-12 Wangmin First version
2020-08-31 Wangmin Modify for MISRAC2012
2020-10-13 Wangmin Define variable for count as __IO type
@endverbatim
*******************************************************************************
* Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
*
* This software component is licensed by HDSC under BSD 3-Clause license
* (the "License"); You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
*******************************************************************************
*/
/*******************************************************************************
* Include files
******************************************************************************/
#include "hc32f4a0_spi.h"
#include "hc32f4a0_utility.h"
/**
* @addtogroup HC32F4A0_DDL_Driver
* @{
*/
/**
* @defgroup DDL_SPI SPI
* @brief Serial Peripheral Interface Driver Library
* @{
*/
#if (DDL_SPI_ENABLE == DDL_ON)
/*******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/*******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/**
* @defgroup SPI_Local_Macros SPI Local Macros
* @{
*/
#define SPI_CFG1_DEFAULT (0x00000010UL)
#define SPI_CFG2_DEFAULT (0x00000F1DUL)
#define SPI_SR_DEFAULT (0x00000020UL)
#define SPI_IRQ_MASK ( SPI_INT_ERROR | \
SPI_INT_TX_BUFFER_EMPTY | \
SPI_INT_RX_BUFFER_FULL | \
SPI_INT_IDLE )
#define SPI_GET_STD_MASK ( SPI_FLAG_OVERLOAD | \
SPI_FLAG_IDLE | \
SPI_FLAG_MODE_FAULT | \
SPI_FLAG_PARITY_ERROR | \
SPI_FLAG_UNDERLOAD | \
SPI_FLAG_TX_BUFFER_EMPTY | \
SPI_FLAG_RX_BUFFER_FULL )
#define SPI_CLR_STD_MASK ( SPI_FLAG_OVERLOAD | \
SPI_FLAG_MODE_FAULT | \
SPI_FLAG_PARITY_ERROR | \
SPI_FLAG_UNDERLOAD )
#define SPI_SS0_VALID_CFG (0UL)
#define SPI_SS1_VALID_CFG (SPI_CFG2_SSA_0)
#define SPI_SS2_VALID_CFG (SPI_CFG2_SSA_1)
#define SPI_SS3_VALID_CFG (SPI_CFG2_SSA_0 | SPI_CFG2_SSA_1)
/**
* @defgroup SPI_Check_Parameters_Validity SPI check parameters validity
* @{
*/
/*! Parameter valid check for SPI peripheral */
#define IS_VALID_SPI_UNIT(x) \
( (M4_SPI1 == (x)) || \
(M4_SPI2 == (x)) || \
(M4_SPI3 == (x)) || \
(M4_SPI4 == (x)) || \
(M4_SPI5 == (x)) || \
(M4_SPI6 == (x)))
/*! Parameter valid check for SPI wire mode */
#define IS_SPI_WIRE_MODE(x) \
( ((x) == SPI_WIRE_4) || \
((x) == SPI_WIRE_3))
/*! Parameter valid check for SPI transfer mode */
#define IS_SPI_TRANS_MODE(x) \
( ((x) == SPI_FULL_DUPLEX) || \
((x) == SPI_SEND_ONLY))
/*! Parameter valid check for SPI master slave mode */
#define IS_SPI_MASTER_SLAVE(x) \
( ((x) == SPI_SLAVE) || \
((x) == SPI_MASTER))
/*! Parameter valid check for SPI loopback mode */
#define IS_SPI_SPLPBK(x) \
( ((x) == SPI_SPLPBK_INVALID) || \
((x) == SPI_SPLPBK_MOSI_INVERT) || \
((x) == SPI_SPLPBK_MOSI))
/*! Parameter valid check for SPI communication suspend function status */
#define IS_SPI_SUSP_MODE_STD(x) \
( ((x) == SPI_COM_SUSP_FUNC_OFF) || \
((x) == SPI_COM_SUSP_FUNC_ON))
/*! Parameter valid check for SPI fault dectet function status */
#define IS_SPI_MODFE_CMD(x) \
( ((x) == SPI_MODFE_DISABLE) || \
((x) == SPI_MODFE_ENABLE))
/*! Parameter valid check for SPI parity check mode */
#define IS_SPI_PARITY_CHECK(x) \
( ((x) == SPI_PARITY_INVALID) || \
((x) == SPI_PARITY_EVEN) || \
((x) == SPI_PARITY_ODD))
/*! Parameter valid check for SPI interval time delay */
#define IS_SPI_INTERVAL_DELAY(x) \
( ((x) == SPI_INTERVAL_TIME_1SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_2SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_3SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_4SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_5SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_6SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_7SCK_2PCLK1) || \
((x) == SPI_INTERVAL_TIME_8SCK_2PCLK1))
/*! Parameter valid check for SPI release time delay */
#define IS_SPI_RELEASE_DELAY(x) \
( ((x) == SPI_RELEASE_TIME_1SCK) || \
((x) == SPI_RELEASE_TIME_2SCK) || \
((x) == SPI_RELEASE_TIME_3SCK) || \
((x) == SPI_RELEASE_TIME_4SCK) || \
((x) == SPI_RELEASE_TIME_5SCK) || \
((x) == SPI_RELEASE_TIME_6SCK) || \
((x) == SPI_RELEASE_TIME_7SCK) || \
((x) == SPI_RELEASE_TIME_8SCK))
/*! Parameter valid check for SPI Setup time delay delay */
#define IS_SPI_SETUP_DELAY(x) \
( ((x) == SPI_SETUP_TIME_1SCK) || \
((x) == SPI_SETUP_TIME_2SCK) || \
((x) == SPI_SETUP_TIME_3SCK) || \
((x) == SPI_SETUP_TIME_4SCK) || \
((x) == SPI_SETUP_TIME_5SCK) || \
((x) == SPI_SETUP_TIME_6SCK) || \
((x) == SPI_SETUP_TIME_7SCK) || \
((x) == SPI_SETUP_TIME_8SCK))
/*! Parameter valid check for SPI SS active level */
#define IS_SPI_SS_ACTIVE_LEVEL(x) \
( ((x) == SPI_SS_ACTIVE_LOW) || \
((x) == SPI_SS_ACTIVE_HIGH))
/*! Parameter valid check for SPI read data register target buffer */
#define IS_SPI_RD_TARGET_BUFF(x) \
( ((x) == SPI_RD_TARGET_RD_BUF) || \
((x) == SPI_RD_TARGET_WR_BUF))
/*! Parameter valid check for SPI mode */
#define IS_SPI_SPI_MODE(x) \
( ((x) == SPI_MODE_0) || \
((x) == SPI_MODE_1) || \
((x) == SPI_MODE_2) || \
((x) == SPI_MODE_3))
/*! Parameter valid check for SPI SS signal */
#define IS_SPI_SS_PIN(x) \
( ((x) == SPI_PIN_SS0) || \
((x) == SPI_PIN_SS1) || \
((x) == SPI_PIN_SS2) || \
((x) == SPI_PIN_SS3))
/*! Parameter valid check for SPI baudrate prescaler */
#define IS_SPI_BIT_RATE_DIV(x) \
( ((x) == SPI_BR_PCLK1_DIV2) || \
((x) == SPI_BR_PCLK1_DIV4) || \
((x) == SPI_BR_PCLK1_DIV8) || \
((x) == SPI_BR_PCLK1_DIV16) || \
((x) == SPI_BR_PCLK1_DIV32) || \
((x) == SPI_BR_PCLK1_DIV64) || \
((x) == SPI_BR_PCLK1_DIV128) || \
((x) == SPI_BR_PCLK1_DIV256))
/*! Parameter valid check for SPI data bits */
#define IS_SPI_DATA_SIZE(x) \
( ((x) == SPI_DATA_SIZE_4BIT) || \
((x) == SPI_DATA_SIZE_5BIT) || \
((x) == SPI_DATA_SIZE_6BIT) || \
((x) == SPI_DATA_SIZE_7BIT) || \
((x) == SPI_DATA_SIZE_8BIT) || \
((x) == SPI_DATA_SIZE_9BIT) || \
((x) == SPI_DATA_SIZE_10BIT) || \
((x) == SPI_DATA_SIZE_11BIT) || \
((x) == SPI_DATA_SIZE_12BIT) || \
((x) == SPI_DATA_SIZE_13BIT) || \
((x) == SPI_DATA_SIZE_14BIT) || \
((x) == SPI_DATA_SIZE_15BIT) || \
((x) == SPI_DATA_SIZE_16BIT) || \
((x) == SPI_DATA_SIZE_20BIT) || \
((x) == SPI_DATA_SIZE_24BIT) || \
((x) == SPI_DATA_SIZE_32BIT))
/*! Parameter valid check for SPI data frame level */
#define IS_SPI_DATA_FRAME(x) \
( ((x) == SPI_FRAME_1) || \
((x) == SPI_FRAME_2) || \
((x) == SPI_FRAME_3) || \
((x) == SPI_FRAME_4))
/*! Parameter valid check for SPI LSB MSB mode */
#define IS_SPI_FIRST_BIT(x) \
( ((x) == SPI_FIRST_MSB) || \
((x) == SPI_FIRST_LSB))
/*! Parameter valid check for interrupt flag */
#define IS_SPI_IRQ_FLAG(x) \
( ((x) != 0UL) && \
(((x) | SPI_IRQ_MASK) == SPI_IRQ_MASK))
/*! Parameter valid check for SPI status flag */
#define IS_SPI_STD_FLAG(x) \
( ((x) != 0UL) && \
(((x) | SPI_GET_STD_MASK) == SPI_GET_STD_MASK))
/*! Parameter valid check for SPI status flag for clear */
#define IS_SPI_CLR_STD_FLAG(x) \
( ((x) != 0UL) && \
(((x) | SPI_CLR_STD_MASK) == SPI_CLR_STD_MASK))
/**
* @}
*/
/**
* @}
*/
/*******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
/*******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
/**
* @defgroup SPI_Local_Functions SPI Local Functions
* @{
*/
static en_result_t SPI_TxRx(M4_SPI_TypeDef *SPIx, const void *pvTxBuf, void *pvRxBuf, uint32_t u32Length);
static en_result_t SPI_Tx(M4_SPI_TypeDef *SPIx, const void *pvTxBuf, uint32_t u32Length);
/**
* @}
*/
/*******************************************************************************
* Local variable definitions ('static')
******************************************************************************/
/*******************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
* @defgroup SPI_Global_Functions SPI Global Functions
* @{
*/
/**
* @brief Initializes the SPI peripheral according to the specified parameters
* in the structure stc_spi_init.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pstcInit Pointer to a stc_spi_init_t structure that contains
* the configuration information for the SPI.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred
* @arg ErrorInvalidParameter: pstcInit == NULL or configuration parameter error.
*/
en_result_t SPI_Init(M4_SPI_TypeDef *SPIx, const stc_spi_init_t *pstcInit)
{
en_result_t enRet = ErrorInvalidParameter;
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
if (NULL != pstcInit)
{
DDL_ASSERT(IS_SPI_WIRE_MODE(pstcInit->u32WireMode));
DDL_ASSERT(IS_SPI_TRANS_MODE(pstcInit->u32TransMode));
DDL_ASSERT(IS_SPI_MASTER_SLAVE(pstcInit->u32MasterSlave));
DDL_ASSERT(IS_SPI_SUSP_MODE_STD(pstcInit->u32SuspMode));
DDL_ASSERT(IS_SPI_MODFE_CMD(pstcInit->u32Modfe));
DDL_ASSERT(IS_SPI_PARITY_CHECK(pstcInit->u32Parity));
DDL_ASSERT(IS_SPI_SPI_MODE(pstcInit->u32SpiMode));
DDL_ASSERT(IS_SPI_BIT_RATE_DIV(pstcInit->u32BaudRatePrescaler));
DDL_ASSERT(IS_SPI_DATA_SIZE(pstcInit->u32DataBits));
DDL_ASSERT(IS_SPI_FIRST_BIT(pstcInit->u32FirstBit));
DDL_ASSERT(IS_SPI_DATA_FRAME(pstcInit->u32FrameLevel));
/* Configuration parameter check */
if((SPI_MASTER == pstcInit->u32MasterSlave)&&(SPI_MODFE_ENABLE == pstcInit->u32Modfe))
{
/* pstcInit->u32Modfe can not be SPI_MODFE_ENABLE in master mode */
}
else if((SPI_WIRE_3 == pstcInit->u32WireMode)
&& (SPI_SLAVE == pstcInit->u32MasterSlave)
&&((SPI_MODE_0 == pstcInit->u32SpiMode)||(SPI_MODE_2 == pstcInit->u32SpiMode)))
{
/* SPI_WIRE_3 can not support SPI_MODE_0 and SPI_MODE_2 */
}
else
{
WRITE_REG32(SPIx->CR1, pstcInit->u32WireMode
| pstcInit->u32TransMode
| pstcInit->u32MasterSlave
| pstcInit->u32SuspMode
| pstcInit->u32Modfe
| pstcInit->u32Parity );
MODIFY_REG32(SPIx->CFG1, SPI_CFG1_FTHLV, pstcInit->u32FrameLevel);
WRITE_REG32(SPIx->CFG2, pstcInit->u32SpiMode
| pstcInit->u32BaudRatePrescaler
| pstcInit->u32DataBits
| pstcInit->u32FirstBit);
enRet = Ok;
}
}
return enRet;
}
/**
* @brief De-initializes the SPI peripheral.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @retval None
*/
void SPI_DeInit(M4_SPI_TypeDef *SPIx)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
SPI_FunctionCmd(SPIx, Disable);
WRITE_REG32(SPIx->CR1, 0x00000000UL);
WRITE_REG32(SPIx->CFG1, SPI_CFG1_DEFAULT);
WRITE_REG32(SPIx->CFG2, SPI_CFG2_DEFAULT);
WRITE_REG32(SPIx->SR, SPI_SR_DEFAULT);
}
/**
* @brief Set a default value for the SPI initialization structure.
* @param [in] pstcInit Pointer to a stc_spi_init_t structure that
* contains configuration information.
* @retval An en_result_t enumeration value.
* @arg Ok: No errors occurred.
* @arg ErrorInvalidParameter: pstcInit == NULL.
*/
en_result_t SPI_StructInit(stc_spi_init_t *pstcInit)
{
en_result_t enRet = ErrorInvalidParameter;
if (NULL != pstcInit)
{
pstcInit->u32WireMode = SPI_WIRE_4;
pstcInit->u32TransMode = SPI_FULL_DUPLEX;
pstcInit->u32MasterSlave = SPI_MASTER;
pstcInit->u32SuspMode = SPI_COM_SUSP_FUNC_OFF;
pstcInit->u32Modfe = SPI_MODFE_DISABLE;
pstcInit->u32Parity = SPI_PARITY_INVALID;
pstcInit->u32SpiMode = SPI_MODE_0;
pstcInit->u32BaudRatePrescaler = SPI_BR_PCLK1_DIV8;
pstcInit->u32DataBits = SPI_DATA_SIZE_8BIT;
pstcInit->u32FirstBit = SPI_FIRST_MSB;
pstcInit->u32FrameLevel = SPI_FRAME_1;
enRet = Ok;
}
return enRet;
}
/**
* @brief Enable or disable SPI interrupt.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32IntType SPI interrupt type. Can be one or any
* combination of the parameter @ref SPI_Interrupt_Type_Define
* @arg SPI_INT_ERROR
* @arg SPI_INT_TX_BUFFER_EMPTY
* @arg SPI_INT_RX_BUFFER_FULL
* @arg SPI_INT_IDLE
* @param [in] enNewState An en_functional_state_t enumeration value.
* @arg Enable: Enable the specified interrupt of SPI.
* @arg Disable: Disable the specified interrupt of SPI.
* @retval None
*/
void SPI_IntCmd(M4_SPI_TypeDef *SPIx, uint32_t u32IntType, en_functional_state_t enNewState)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
DDL_ASSERT(IS_SPI_IRQ_FLAG(u32IntType));
if (enNewState == Enable)
{
SET_REG32_BIT(SPIx->CR1, u32IntType);
}
else
{
CLEAR_REG32_BIT(SPIx->CR1, u32IntType);
}
}
/**
* @brief SPI function enable or disable.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] enNewState An en_functional_state_t enumeration value.
* @arg Enable: Enable SPI function.
* @arg Disable: Disable SPI function.
* @retval None
*/
void SPI_FunctionCmd(M4_SPI_TypeDef *SPIx, en_functional_state_t enNewState)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
if(Enable == enNewState)
{
SET_REG32_BIT(SPIx->CR1, SPI_CR1_SPE);
}
else
{
CLEAR_REG32_BIT(SPIx->CR1, SPI_CR1_SPE);
}
}
/**
* @brief Write SPI data register.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32Data The data will be written to the data register.
* @retval None.
*/
void SPI_WriteDataReg(M4_SPI_TypeDef *SPIx, uint32_t u32Data)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
WRITE_REG32(SPIx->DR, u32Data);
}
/**
* @brief Read SPI data register.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @retval A 32-bit data of SPI data register.
*/
uint32_t SPI_ReadDataReg(const M4_SPI_TypeDef *SPIx)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
return READ_REG32(SPIx->DR);
}
/**
* @brief SPI get status flag.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32Flag SPI state flag. Can be one or any
* combination of the parameter of @ref SPI_State_Flag_Define
* @arg SPI_FLAG_OVERLOAD
* @arg SPI_FLAG_IDLE
* @arg SPI_FLAG_MODE_FAULT
* @arg SPI_FLAG_PARITY_ERROR
* @arg SPI_FLAG_UNDERLOAD
* @arg SPI_FLAG_TX_BUFFER_EMPTY
* @arg SPI_FLAG_RX_BUFFER_FULL
* @retval An en_flag_status_t enumeration.
* @arg Set: The specified flag has set.
* @arg Reset: The specified flag has not set.
*/
en_flag_status_t SPI_GetStatus(const M4_SPI_TypeDef *SPIx, uint32_t u32Flag)
{
en_flag_status_t enFlag = Reset;
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_SPI_STD_FLAG(u32Flag));
if(0U != READ_REG32_BIT(SPIx->SR, u32Flag))
{
enFlag = Set;
}
return enFlag;
}
/**
* @brief SPI clear state flag.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32Flag SPI state flag.
* Can be one or any combination of the parameter below
* @arg SPI_FLAG_OVERLOAD
* @arg SPI_FLAG_MODE_FAULT
* @arg SPI_FLAG_PARITY_ERROR
* @arg SPI_FLAG_UNDERLOAD
* @retval None
*/
void SPI_ClearFlag(M4_SPI_TypeDef *SPIx, uint32_t u32Flag)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_SPI_CLR_STD_FLAG(u32Flag));
CLEAR_REG32_BIT(SPIx->SR, u32Flag);
}
/**
* @brief SPI loopback function configuration.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32Mode Loopback mode.
* Can be one parameter @ref SPI_Loopback_Selection_Define
* @arg SPI_SPLPBK_INVALID
* @arg SPI_SPLPBK_MOSI_INVERT
* @arg SPI_SPLPBK_MOSI
* @retval None
*/
void SPI_LoopbackModeCfg(M4_SPI_TypeDef *SPIx, uint32_t u32Mode)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_SPI_SPLPBK(u32Mode));
MODIFY_REG32(SPIx->CR1, SPI_CR1_SPLPBK | SPI_CR1_SPLPBK2, u32Mode);
}
/**
* @brief SPI parity check error self diagnosis function enable or disable.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] enNewState An en_functional_state_t enumeration value.
* @arg Enable: Enable function.
* @arg Disable: Disable function.
* @retval None
*/
void SPI_PateCmd(M4_SPI_TypeDef *SPIx, en_functional_state_t enNewState)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
if(Enable == enNewState)
{
SET_REG32_BIT(SPIx->CR1, SPI_CR1_PATE);
}
else
{
CLEAR_REG32_BIT(SPIx->CR1, SPI_CR1_PATE);
}
}
/**
* @brief SPI signals delay time configuration
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pstcDelayCfg Pointer to a stc_spi_delay_t structure that contains
* the configuration information for the SPI delay time.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred
* @arg ErrorInvalidParameter: pstcDelayCfg == NULL
*/
en_result_t SPI_DelayTimeCfg(M4_SPI_TypeDef *SPIx, const stc_spi_delay_t *pstcDelayCfg)
{
en_result_t enRet = ErrorInvalidParameter;
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
if (NULL != pstcDelayCfg)
{
DDL_ASSERT(IS_SPI_INTERVAL_DELAY(pstcDelayCfg->u32IntervalDelay));
DDL_ASSERT(IS_SPI_RELEASE_DELAY(pstcDelayCfg->u32ReleaseDelay));
DDL_ASSERT(IS_SPI_SETUP_DELAY(pstcDelayCfg->u32SetupDelay));
/* Interval delay */
if(SPI_INTERVAL_TIME_1SCK_2PCLK1 == pstcDelayCfg->u32IntervalDelay)
{
CLEAR_REG32_BIT(SPIx->CFG2, SPI_CFG2_MIDIE);
CLEAR_REG32_BIT(SPIx->CFG1, SPI_CFG1_MIDI);
}
else
{
MODIFY_REG32(SPIx->CFG1, SPI_CFG1_MIDI, pstcDelayCfg->u32IntervalDelay);
SET_REG32_BIT(SPIx->CFG2, SPI_CFG2_MIDIE);
}
/* SCK release delay */
if(SPI_RELEASE_TIME_1SCK == pstcDelayCfg->u32ReleaseDelay)
{
CLEAR_REG32_BIT(SPIx->CFG2, SPI_CFG2_MSSDLE);
CLEAR_REG32_BIT(SPIx->CFG1, SPI_CFG1_MSSDL);
}
else
{
SET_REG32_BIT(SPIx->CFG2, SPI_CFG2_MSSDLE);
MODIFY_REG32(SPIx->CFG1, SPI_CFG1_MSSDL, pstcDelayCfg->u32ReleaseDelay);
}
/* Setup delay */
if(SPI_SETUP_TIME_1SCK == pstcDelayCfg->u32SetupDelay)
{
CLEAR_REG32_BIT(SPIx->CFG2, SPI_CFG2_MSSIE);
CLEAR_REG32_BIT(SPIx->CFG1, SPI_CFG1_MSSI);
}
else
{
SET_REG32_BIT(SPIx->CFG2, SPI_CFG2_MSSIE);
MODIFY_REG32(SPIx->CFG1, SPI_CFG1_MSSI, pstcDelayCfg->u32SetupDelay);
}
enRet = Ok;
}
return enRet;
}
/**
* @brief Set a default value for the SPI delay time configuration structure.
* @param [in] pstcDelayCfg Pointer to a stc_spi_delay_t structure that
* contains configuration information.
* @retval An en_result_t enumeration value.
* @arg Ok: No errors occurred.
* @arg ErrorInvalidParameter: pstcDelayCfg == NULL.
*/
en_result_t SPI_DelayStructInit(stc_spi_delay_t *pstcDelayCfg)
{
en_result_t enRet = ErrorInvalidParameter;
if (NULL != pstcDelayCfg)
{
pstcDelayCfg->u32IntervalDelay = SPI_INTERVAL_TIME_1SCK_2PCLK1;
pstcDelayCfg->u32ReleaseDelay = SPI_RELEASE_TIME_1SCK;
pstcDelayCfg->u32SetupDelay = SPI_SETUP_TIME_1SCK;
enRet = Ok;
}
return enRet;
}
/**
* @brief SPI SS signal valid level configuration
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32SSPin Specify the SS pin @ref SPI_SS_Pin_Define
* @param [in] enNewState An en_functional_state_t enumeration value.
* @arg Enable: SS pin high level valid.
* @arg Disable: SS pin low level valid.
* @retval None
*/
void SPI_SSValidLevelCfg(M4_SPI_TypeDef *SPIx, uint32_t u32SSPin, en_functional_state_t enNewState)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_SPI_SS_PIN(u32SSPin));
DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
if(Enable == enNewState)
{
SET_REG32_BIT(SPIx->CFG1, u32SSPin);
}
else
{
CLEAR_REG32_BIT(SPIx->CFG1, u32SSPin);
}
}
/**
* @brief SPI valid SS signal configuration
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32SSPin Specify the SS pin @ref SPI_SS_Pin_Define
* @retval None
*/
void SPI_SSPinSel(M4_SPI_TypeDef *SPIx, uint32_t u32SSPin)
{
uint32_t u32RegCfg;
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_SPI_SS_PIN(u32SSPin));
switch (u32SSPin)
{
case SPI_PIN_SS0:
u32RegCfg = SPI_SS0_VALID_CFG;
break;
case SPI_PIN_SS1:
u32RegCfg = SPI_SS1_VALID_CFG;
break;
case SPI_PIN_SS2:
u32RegCfg = SPI_SS2_VALID_CFG;
break;
case SPI_PIN_SS3:
u32RegCfg = SPI_SS3_VALID_CFG;
break;
default:
u32RegCfg = SPI_SS0_VALID_CFG;
break;
}
MODIFY_REG32(SPIx->CFG2, SPI_CFG2_SSA, u32RegCfg);
}
/**
* @brief SPI read buffer configuration
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] u32ReadBuf Target buffer for read operation @ref SPI_Read_Target_Buffer_Define
* @retval None
*/
void SPI_ReadBufCfg(M4_SPI_TypeDef *SPIx, uint32_t u32ReadBuf)
{
DDL_ASSERT(IS_VALID_SPI_UNIT(SPIx));
DDL_ASSERT(IS_SPI_RD_TARGET_BUFF(u32ReadBuf));
MODIFY_REG32(SPIx->CFG1, SPI_CFG1_SPRDTD, u32ReadBuf);
}
/**
* @brief SPI transmit data.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pvTxBuf The pointer to the buffer which contains the data to be sent.
* @param [in] u32TxLength The length of the data to be sent.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred
* @arg ErrorTimeout: SPI transmit timeout.
* @arg ErrorInvalidParameter: pvTxBuf == NULL or u32TxLength == 0U
* @note -No SS pin active and inactive operation in 3-wire mode. Add operations of SS pin depending on your application.
* -This function supports full duplex mode and send only mode.
*/
en_result_t SPI_Transmit(M4_SPI_TypeDef *SPIx, const void *pvTxBuf, uint32_t u32TxLength)
{
uint32_t u32Flags;
en_result_t enRet = ErrorInvalidParameter;
if ((pvTxBuf != NULL) && (u32TxLength != 0U))
{
u32Flags = READ_REG32_BIT(SPIx->CR1, SPI_CR1_TXMDS);
if (u32Flags == SPI_SEND_ONLY)
{
/* Transmit data in send only mode. */
enRet = SPI_Tx(SPIx, pvTxBuf, u32TxLength);
}
else
{
/* Transmit data in full duplex mode. */
enRet = SPI_TxRx(SPIx, pvTxBuf, NULL, u32TxLength);
}
}
return enRet;
}
/**
* @brief SPI receive data.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pvRxBuf The pointer to the buffer which the received data to be stored.
* @param [in] u32RxLength The length of the data to be received.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred
* @arg ErrorTimeout: SPI receive timeout.
* @arg ErrorInvalidParameter: pvRxBuf == NULL or u32RxLength == 0U
* @note -No SS pin active and inactive operation in 3-wire mode. Add operations of SS pin depending on your application.
* -This function only works in full duplex master mode.
*/
en_result_t SPI_Receive(M4_SPI_TypeDef *SPIx, void *pvRxBuf, uint32_t u32RxLength)
{
en_result_t enRet = ErrorInvalidParameter;
if ((pvRxBuf != NULL) && (u32RxLength != 0U))
{
/* Receives data in full duplex master mode. */
enRet = SPI_TxRx(SPIx, NULL, pvRxBuf, u32RxLength);
}
return enRet;
}
/**
* @brief SPI transmit and receive data.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pvTxBuf The pointer to the buffer which contains the data to be sent.
* If this pointer is NULL and the pvRxBuf is NOT NULL, the MOSI output high
* and the the received data will be stored in the buffer pointed by pvRxBuf.
* @param [out] pvRxBuf The pointer to the buffer which the received data will be stored.
* This for full duplex transfer.
* @param [in] u32Length The length of the data(in byte or half word) to be sent and received.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred
* @arg ErrorTimeout: SPI transmit and receive timeout.
* @arg ErrorInvalidParameter: pvRxBuf == NULL or pvRxBuf == NULL or u32Length == 0U
* @note SPI receives data while sending data. Only works in full duplex master mode.
*/
en_result_t SPI_TransmitReceive(M4_SPI_TypeDef *SPIx, const void *pvTxBuf, void *pvRxBuf, uint32_t u32Length)
{
en_result_t enRet = ErrorInvalidParameter;
if ((pvTxBuf != NULL) && (pvRxBuf != NULL) && (u32Length != 0U))
{
/* Transmit and receive data in full duplex master mode. */
enRet = SPI_TxRx(SPIx, pvTxBuf, pvRxBuf, u32Length);
}
return enRet;
}
/**
* @}
*/
/**
* @addtogroup SPI_Local_Functions SPI Local Functions
* @{
*/
/**
* @brief SPI transmit and receive data in full duplex mode.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pvTxBuf The pointer to the buffer which contains the data to be sent.
* @param [out] pvRxBuf The pointer to the buffer which the received data will be stored.
* @param [in] u32Length The length of the data in byte or half word.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred
* @arg ErrorTimeout: SPI transmit and receive timeout.
*/
static en_result_t SPI_TxRx(M4_SPI_TypeDef *SPIx, const void *pvTxBuf, void *pvRxBuf, uint32_t u32Length)
{
uint32_t u32BitSize;
__IO uint32_t u32Timecount;
__IO uint32_t u32Count = 0U;
en_result_t enRet = Ok;
uint32_t u32Tmp;
__UNUSED __IO uint32_t u32Read;
/* Get data bit size, SPI_DATA_SIZE_4BIT ~ SPI_DATA_SIZE_32BIT */
u32BitSize = READ_REG32_BIT(SPIx->CFG2, SPI_CFG2_DSIZE);
while (u32Count < u32Length)
{
if (pvTxBuf != NULL)
{
if (u32BitSize <= SPI_DATA_SIZE_8BIT)
{
/* SPI_DATA_SIZE_4BIT ~ SPI_DATA_SIZE_8BIT */
WRITE_REG32(SPIx->DR, ((const uint8_t *)pvTxBuf)[u32Count]);
}
else if(u32BitSize <= SPI_DATA_SIZE_16BIT)
{
/* SPI_DATA_SIZE_9BIT ~ SPI_DATA_SIZE_16BIT */
WRITE_REG32(SPIx->DR, ((const uint16_t *)pvTxBuf)[u32Count]);
}
else
{
/* SPI_DATA_SIZE_20BIT ~ SPI_DATA_SIZE_32BIT */
WRITE_REG32(SPIx->DR, ((const uint32_t *)pvTxBuf)[u32Count]);
}
}
else
{
WRITE_REG32(SPIx->DR, 0xFFFFFFFFUL);
}
/* Delay about 10ms */
u32Timecount = HCLK_VALUE/100UL;
do
{
if(0UL != READ_REG32_BIT(SPIx->SR, SPI_FLAG_RX_BUFFER_FULL))
{
break;
}
u32Timecount--;
} while (u32Timecount != 0U);
if (u32Timecount == 0U)
{
enRet = ErrorTimeout;
break;
}
u32Tmp = READ_REG32(SPIx->DR);
if (pvRxBuf != NULL)
{
if (u32BitSize <= SPI_DATA_SIZE_8BIT)
{
/* SPI_DATA_SIZE_4BIT ~ SPI_DATA_SIZE_8BIT */
((uint8_t *)pvRxBuf)[u32Count] = (uint8_t)u32Tmp;
}
else if(u32BitSize <= SPI_DATA_SIZE_16BIT)
{
/* SPI_DATA_SIZE_9BIT ~ SPI_DATA_SIZE_16BIT */
((uint16_t *)pvRxBuf)[u32Count] = (uint16_t)u32Tmp;
}
else
{
/* SPI_DATA_SIZE_20BIT ~ SPI_DATA_SIZE_32BIT */
((uint32_t *)pvRxBuf)[u32Count] = (uint32_t)u32Tmp;
}
}
else
{
/* Dummy read */
u32Read = READ_REG32(SPIx->DR);
}
u32Count++;
}
return enRet;
}
/**
* @brief SPI send data only.
* @param [in] SPIx SPI unit
* @arg M4_SPI1
* @arg M4_SPI2
* @arg M4_SPI3
* @arg M4_SPI4
* @arg M4_SPI5
* @arg M4_SPI6
* @param [in] pvTxBuf The pointer to the buffer which contains the data to be sent.
* @param [in] u32Length The length of the data in byte or half word or word.
* @retval An en_result_t enumeration value:
* @arg Ok: No errors occurred.
* @arg ErrorTimeout: SPI transmit timeout.
*/
static en_result_t SPI_Tx(M4_SPI_TypeDef *SPIx, const void *pvTxBuf, uint32_t u32Length)
{
__IO uint32_t u32Count = 0U;
__IO uint32_t u32Timecount;
uint32_t u32BitSize;
en_result_t enRet = Ok;
/* Get data bit size, SPI_DATA_SIZE_4BIT ~ SPI_DATA_SIZE_32BIT */
u32BitSize = READ_REG32_BIT(SPIx->CFG2, SPI_CFG2_DSIZE);
while (u32Count < u32Length)
{
if (u32BitSize <= SPI_DATA_SIZE_8BIT)
{
/* SPI_DATA_SIZE_4BIT ~ SPI_DATA_SIZE_8BIT */
WRITE_REG32(SPIx->DR, ((const uint8_t *)pvTxBuf)[u32Count]);
}
else if(u32BitSize <= SPI_DATA_SIZE_16BIT)
{
/* SPI_DATA_SIZE_9BIT ~ SPI_DATA_SIZE_16BIT */
WRITE_REG32(SPIx->DR, ((const uint16_t *)pvTxBuf)[u32Count]);
}
else
{
/* SPI_DATA_SIZE_20BIT ~ SPI_DATA_SIZE_32BIT */
WRITE_REG32(SPIx->DR, ((const uint32_t *)pvTxBuf)[u32Count]);
}
/* Delay about 10ms */
u32Timecount = HCLK_VALUE/100UL;
do
{
if(0UL != READ_REG32_BIT(SPIx->SR, SPI_FLAG_TX_BUFFER_EMPTY))
{
break;
}
u32Timecount--;
} while (u32Timecount != 0U);
if (u32Timecount == 0U)
{
enRet = ErrorTimeout;
}
u32Count++;
}
return enRet;
}
/**
* @}
*/
#endif /* DDL_SPI_ENABLE */
/**
* @}
*/
/**
* @}
*/
/******************************************************************************
* EOF (not truncated)
*****************************************************************************/