/************************************************************************************************/
/**
* @file               ciu32l071_std_spi.h
* @author             MCU Ecosystem Development Team
* @brief              SPI STD库驱动头文件。
*                     提供SPI相关的STD库操作函数声明、数据类型以及常量的定义。
*
*
**************************************************************************************************
* @attention
* Copyright (c) CEC Huada Electronic Design Co.,Ltd. All rights reserved.
*
**************************************************************************************************
*/

/* 避免头文件重复引用 */
#ifndef CIU32L071_STD_SPI_H
#define CIU32L071_STD_SPI_H

/************************************************************************************************/
/** 
* @addtogroup CIU32L071_STD_Driver
* @{
*/

/**
* @defgroup SPI SPI
* @brief 串行外设接口的STD库驱动 
* @{
*/
/************************************************************************************************/



#ifdef __cplusplus
 extern "C" {
#endif

/*------------------------------------------includes--------------------------------------------*/
#include "ciu32l071_std_common.h"


/*-----------------------------------------type define------------------------------------------*/
/************************************************************************************************/
/**
* @defgroup SPI_Types SPI Types
* @brief  SPI数据类型定义
* @{
*
*/
/************************************************************************************************/

/**
* @brief  SPI初始化配置结构体定义
*/
typedef struct
{
    uint32_t mode;                     /**< SPI工作模式
                                                @arg SPI_MODE_SLAVE
                                                @arg SPI_MODE_MASTER                            */

    uint32_t baud_rate_prescaler;      /**< SPI速率配置参数                                    
                                                @arg  SPI_BAUDRATEPRESCALER_2          
                                                @arg  SPI_BAUDRATEPRESCALER_4 ...      
                                                @note 主机输出时钟设置，从机不需要设置          */

    uint32_t clk_polarity;             /**< SPI时钟极性                                
                                                @arg SPI_POLARITY_LOW                  
                                                @arg SPI_POLARITY_HIGH                          */

    uint32_t clk_phase;                /**< SPI时钟相位                                
                                                @arg SPI_PHASE_1EDGE                   
                                                @arg SPI_PHASE_2EDGE                            */

}std_spi_init_t; 


/** 
* @} 
*/


/*--------------------------------------------define--------------------------------------------*/
/************************************************************************************************/
/** 
* @defgroup SPI_Constants SPI Constants
* @brief SPI常量定义及宏定义
* @{
*/
/************************************************************************************************/

/* SPI 工作模式 */
#define SPI_MODE_SLAVE                  (0x00000000U)                      /**< SPI从机模式     */
#define SPI_MODE_MASTER                 SPI_CR1_MSTR                       /**< SPI主机模式     */

/* SPI 速率配置参数 */    
#define SPI_BAUDRATEPRESCALER_2         SPI_CR1_BR_PCLK_DIV_2              /**< SPI速率为fPLCK/2   */
#define SPI_BAUDRATEPRESCALER_4         SPI_CR1_BR_PCLK_DIV_4              /**< SPI速率为fPLCK/4   */
#define SPI_BAUDRATEPRESCALER_8         SPI_CR1_BR_PCLK_DIV_8              /**< SPI速率为fPLCK/8   */
#define SPI_BAUDRATEPRESCALER_16        SPI_CR1_BR_PCLK_DIV_16             /**< SPI速率为fPLCK/16  */
#define SPI_BAUDRATEPRESCALER_32        SPI_CR1_BR_PCLK_DIV_32             /**< SPI速率为fPLCK/32  */
#define SPI_BAUDRATEPRESCALER_64        SPI_CR1_BR_PCLK_DIV_64             /**< SPI速率为fPLCK/64  */
#define SPI_BAUDRATEPRESCALER_128       SPI_CR1_BR_PCLK_DIV_128            /**< SPI速率为fPLCK/128 */

/* SPI 时钟极性 */
#define SPI_POLARITY_LOW                (0x00000000U)                      /**< SPI时钟空闲为低 */
#define SPI_POLARITY_HIGH               SPI_CR1_CPOL                       /**< SPI时钟空闲为高 */

/* SPI 时钟相位 */
#define SPI_PHASE_1EDGE                 (0x00000000U)                      /**< SPI数据采样在第一个时钟沿 */
#define SPI_PHASE_2EDGE                 SPI_CR1_CPHA                       /**< SPI数据采样在第二个时钟沿 */

/* SPI 数据大小端 */
#define SPI_FIRSTBIT_MSB                (0x00000000U)                      /**< SPI数据收发为高位优先 */
#define SPI_FIRSTBIT_LSB                SPI_CR1_LSBFIRST                   /**< SPI数据收发为低位优先 */

/* SPI NSS输出状态*/
#define SPI_NSS_OUTPUT_LOW              (0x00000000U)                      /**< SPI片选信号输出低电平 */
#define SPI_NSS_OUTPUT_HIGH             SPI_CR2_NSSO                       /**< SPI片选信号输出高电平 */

/* SPI 中断事件 */
#define SPI_INTERRUPT_TXFE              SPI_CR1_TXFEIE                     /**< SPI发送数据寄存器为空中断使能 */
#define SPI_INTERRUPT_RXFNE             SPI_CR1_RXFNEIE                    /**< SPI接收数据寄存器非空中断使能 */
#define SPI_INTERRUPT_ERR               SPI_CR1_ERRIE                      /**< SPI错误中断使能                */

/* SPI 硬件状态信息 */
#define SPI_FLAG_TXFE                   SPI_ISR_TXFE                       /**< SPI发送数据寄存器空标志   */
#define SPI_FLAG_RXFNE                  SPI_ISR_RXFNE                      /**< SPI接收数据寄存器非空标志 */
#define SPI_FLAG_BUSY                   SPI_ISR_BUSY                       /**< SPI总线传输状态标志       */
#define SPI_FLAG_OVR                    SPI_ISR_OVR                        /**< SPI接收上溢出标志         */
#define SPI_FLAG_MMF                    SPI_ISR_MMF                        /**< SPI主机模式冲突标志       */

/* SPI 状态清除信息 */
#define SPI_CLEAR_FLAG_OVR              SPI_ICR_OVRCF                      /**< SPI主机上溢标志清除     */
#define SPI_CLEAR_FLAG_MMF              SPI_ICR_MMFCF                      /**< SPI主机模式冲突标志清除 */

/* 数据清空位 */
#define SPI_FLUSH_SEND                  SPI_DATACLR_TXCLR                  /**< SPI清空发送数据寄存器 */
#define SPI_FLUSH_RECEIVE               SPI_DATACLR_RXCLR                  /**< SPI清空接收数据寄存器 */


/** 
* @} 
*/


/*-------------------------------------------functions------------------------------------------*/

/************************************************************************************************/
/**
* @defgroup SPI_External_Functions SPI External Functions
* @brief    SPI对外函数
* @{
*
*/
/************************************************************************************************/


/** 
* @brief  使能SPI
* @param  spix SPI外设   
* @retval 无
*/
__STATIC_INLINE void std_spi_enable(SPI_t *spix)
{
    spix->CR1 |= SPI_CR1_SPE;
}

/** 
* @brief  禁止SPI
* @param  spix SPI外设
* @retval 无
*/
__STATIC_INLINE void std_spi_disable(SPI_t *spix)
{
    spix->CR1 &= (~SPI_CR1_SPE);
}


/** 
* @brief  设置SPI主从模式
* @param  spix SPI外设
* @param  mode SPI主从模式
*             @arg SPI_MODE_SLAVE
*             @arg SPI_MODE_MASTER   
* @retval 无
*/
__STATIC_INLINE void std_spi_set_mode(SPI_t *spix, uint32_t mode)
{
    MODIFY_REG(spix->CR1, SPI_CR1_MSTR, mode);
}


/** 
* @brief  获取SPI主从模式
* @param  spix SPI外设
* @retval uint32_t SPI主从模式
*             @arg SPI_MODE_SLAVE
*             @arg SPI_MODE_MASTER  
*/
__STATIC_INLINE uint32_t std_spi_get_mode(SPI_t *spix)
{
    return (spix->CR1 & SPI_CR1_MSTR);
}


/** 
* @brief  设置SPI波特率
* @param  spix SPI外设
* @param  baud_rate SPI波特率
*             @arg  SPI_BAUDRATEPRESCALER_2      
*             @arg  SPI_BAUDRATEPRESCALER_4
*             @arg  ...  
*             @arg  SPI_BAUDRATEPRESCALER_128
* @note  主机输出时钟设置，从机不需要设置
* @retval 无
*/
__STATIC_INLINE void std_spi_set_baud_rate(SPI_t *spix, uint32_t baud_rate)
{
    MODIFY_REG(spix->CR1, SPI_CR1_BR, baud_rate);
}


/** 
* @brief  获取SPI波特率
* @param  spix SPI外设  
* @retval uint32_t  SPI波特率
*             @arg  SPI_BAUDRATEPRESCALER_2      
*             @arg  SPI_BAUDRATEPRESCALER_4
*             @arg  ...  
*             @arg  SPI_BAUDRATEPRESCALER_128
*/
__STATIC_INLINE uint32_t std_spi_get_baud_rate(SPI_t *spix)
{
    return (spix->CR1 & SPI_CR1_BR);
}


/** 
* @brief  设置SPI时钟极性
* @param  spix SPI外设
* @param  polarity SPI时钟极性
*             @arg SPI_POLARITY_LOW  
*             @arg SPI_POLARITY_HIGH 
* @retval 无
*/
__STATIC_INLINE void std_spi_set_polarity(SPI_t *spix, uint32_t polarity)
{
    MODIFY_REG(spix->CR1, SPI_CR1_CPOL, polarity);
}


/** 
* @brief  获取SPI时钟极性
* @param  spix SPI外设  
* @retval uint32_t SPI时钟极性
*             @arg SPI_POLARITY_LOW  
*             @arg SPI_POLARITY_HIGH 
*/
__STATIC_INLINE uint32_t std_spi_get_polarity(SPI_t *spix)
{
    return (spix->CR1 & SPI_CR1_CPOL);
}


/** 
* @brief  设置SPI时钟相位 
* @param  spix SPI外设
* @param  phase SPI时钟相位
*             @arg SPI_PHASE_1EDGE 
*             @arg SPI_PHASE_2EDGE 
* @retval 无
*/
__STATIC_INLINE void std_spi_set_phase(SPI_t *spix, uint32_t phase)
{
    MODIFY_REG(spix->CR1, SPI_CR1_CPHA, phase);
}


/** 
* @brief  获取SPI时钟相位 
* @param  spix SPI外设 
* @retval uint32_t SPI时钟相位
*             @arg SPI_PHASE_1EDGE 
*             @arg SPI_PHASE_2EDGE 
*/
__STATIC_INLINE uint32_t std_spi_get_phase(SPI_t *spix)
{
    return (spix->CR1 & SPI_CR1_CPHA);
}


/** 
* @brief  设置SPI数据大小端
* @param  spix SPI外设
* @param  first_bit SPI数据大小端
*             @arg SPI_FIRSTBIT_MSB 
*             @arg SPI_FIRSTBIT_LSB 
* @note   仅在禁止SPI（SPE为0）时才可对此位执行写操作
* @retval 无
*/
__STATIC_INLINE void std_spi_set_first_bit(SPI_t *spix, uint32_t first_bit)
{
    MODIFY_REG(spix->CR1, SPI_CR1_LSBFIRST, first_bit);
}


/** 
* @brief  获取SPI数据大小端
* @param  spix SPI外设 
* @retval uint32_t SPI数据大小端
*             @arg SPI_FIRSTBIT_MSB 
*             @arg SPI_FIRSTBIT_LSB 
*/
__STATIC_INLINE uint32_t std_spi_get_first_bit(SPI_t *spix)
{
    return (spix->CR1 & SPI_CR1_LSBFIRST);
}


/** 
* @brief  使能NSS软片选
* @param  spix SPI外设 
* @note   SPI_CR1_SSM位仅在从机模式下设置有效
* @retval 无
*/
__STATIC_INLINE void std_spi_nss_soft_chip_select_enable(SPI_t *spix)
{
    spix->CR1 |= SPI_CR1_SSM;
}

/** 
* @brief  禁止NSS软片选
* @param  spix SPI外设 
* @note   SPI_CR1_SSM位仅在从机模式下设置有效
* @retval 无
*/
__STATIC_INLINE void std_spi_nss_soft_chip_select_disable(SPI_t *spix)
{
    spix->CR1 &= (~SPI_CR1_SSM);
}

/** 
* @brief  使能SPI NSS输出
* @param  spix SPI外设 
* @note   SPI_CR1_NSSOE位仅在主机模式下设置有效
* @retval 无
*/
__STATIC_INLINE void std_spi_nss_output_enable(SPI_t *spix)
{
    spix->CR1 |= SPI_CR1_NSSOE;
}


/** 
* @brief  禁止SPI NSS输出
* @param  spix SPI外设 
* @retval 无
*/
__STATIC_INLINE void std_spi_nss_output_disable(SPI_t *spix)
{
    spix->CR1 &= (~SPI_CR1_NSSOE);
}


/** 
* @brief  使能SPI 中断
* @param  spix SPI外设
* @param  spi_interrupt SPI中断信息
*             @arg SPI_INTERRUPT_TXFE     
*             @arg SPI_INTERRUPT_RXFNE    
*             @arg SPI_INTERRUPT_ERR      
* @retval 无
*/
__STATIC_INLINE void std_spi_interrupt_enable(SPI_t *spix, uint32_t spi_interrupt)
{
    spix->CR1 |= spi_interrupt;
}


/** 
* @brief  禁止SPI 中断
* @param  spix SPI外设
* @param  spi_interrupt SPI中断信息
*             @arg SPI_INTERRUPT_TXFE     
*             @arg SPI_INTERRUPT_RXFNE    
*             @arg SPI_INTERRUPT_ERR      
* @retval 无
*/
__STATIC_INLINE void std_spi_interrupt_disable(SPI_t *spix, uint32_t spi_interrupt)
{
    spix->CR1 &= (~spi_interrupt);
}


/** 
* @brief  获取SPI中断使能状态
* @param  spix SPI外设
* @param  spi_interrupt SPI中断信息
*             @arg SPI_INTERRUPT_TXFE     
*             @arg SPI_INTERRUPT_RXFNE    
*             @arg SPI_INTERRUPT_ERR      
* @retval bool 中断使能状态
*             @arg true 中断使能
*             @arg false 中断禁止
*/
__STATIC_INLINE bool std_spi_get_interrupt_enable(SPI_t *spix, uint32_t spi_interrupt)
{
    return ((spix->CR1 & (spi_interrupt)) == (spi_interrupt));
}


/** 
* @brief  使能SPI DMA发送
* @param  spix SPI外设
* @retval 无
*/
__STATIC_INLINE void std_spi_dma_tx_enable(SPI_t *spix)
{
    spix->CR1 |= SPI_CR1_DMAT;
}


/** 
* @brief  禁止SPI DMA发送
* @param  spix SPI外设
* @retval 无
*/
__STATIC_INLINE void std_spi_dma_tx_disable(SPI_t *spix)
{
    spix->CR1 &= (~SPI_CR1_DMAT);
}


/** 
* @brief  使能SPI DMA接收
* @param  spix SPI外设
* @retval 无
*/
__STATIC_INLINE void std_spi_dma_rx_enable(SPI_t *spix)
{
    spix->CR1 |= SPI_CR1_DMAR;
}


/** 
* @brief  禁止SPI DMA接收
* @param  spix SPI外设
* @retval 无
*/
__STATIC_INLINE void std_spi_dma_rx_disable(SPI_t *spix)
{
    spix->CR1 &= (~SPI_CR1_DMAR);
}


/** 
* @brief  设置SPI NSS输出状态
* @param  spix SPI外设
* @param  nss_output NSS输出状态
*             @arg SPI_NSS_OUTPUT_LOW   
*             @arg SPI_NSS_OUTPUT_HIGH  
* @note   仅在主机模式下且SPE使能的情况下设置有效
* @retval 无
*/
__STATIC_INLINE void std_spi_set_nss_output(SPI_t *spix, uint32_t nss_output)
{
    MODIFY_REG(spix->CR2, SPI_CR2_NSSO, nss_output);
}


/** 
* @brief  获取SPI 状态信息
* @param  spix SPI外设
* @param  flag SPI状态
*             @arg SPI_FLAG_TXFE 
*             @arg SPI_FLAG_RXFNE
*             @arg SPI_FLAG_BUSY 
*             @arg SPI_FLAG_OVR  
*             @arg SPI_FLAG_MMF  
* @retval bool SPI状态
*             true  状态发生
*             false 状态未发生
*/
__STATIC_INLINE bool std_spi_get_flag(SPI_t *spix, uint32_t flag)
{
    return ((spix->ISR & (flag)) == (flag));
}


/** 
* @brief  SPI 标志清零
* @param  spix SPI外设
* @param  flag SPI标志
*             @arg SPI_CLEAR_FLAG_OVR
*             @arg SPI_CLEAR_FLAG_MMF
* @retval 无
*/
__STATIC_INLINE void std_spi_clear_flag(SPI_t *spix, uint32_t flag)
{
    spix->ICR |= (flag);
}


/** 
* @brief  SPI 读数据
* @param  spix SPI外设
* @retval uint8_t: 返回读取的SPI数据寄存器读取的数据
*/
__STATIC_INLINE uint8_t std_spi_read_data(SPI_t *spix)
{
    return (spix->DR);
}

/** 
* @brief  SPI 写数据
* @param  spix SPI外设
* @param  send_data: 写入SPI数据寄存器的数据
* @retval 无
*/
__STATIC_INLINE void std_spi_write_data(SPI_t *spix, uint8_t send_data)
{
    spix->DR = send_data;
}


/** 
* @brief  清空SPI 数据寄存器
* @param  spix SPI外设
* @param  data_type 数据寄存器类型
*             @arg SPI_FLUSH_SEND
*             @arg SPI_FLUSH_RECEIVE
* @retval 无
*/
__STATIC_INLINE void std_spi_clear_data(SPI_t *spix, uint32_t data_type)
{
    MODIFY_REG(spix->DATACLR, (SPI_FLUSH_SEND | SPI_FLUSH_RECEIVE), data_type);
}



void std_spi_init(SPI_t *spix, std_spi_init_t *spi_init_param);
void std_spi_deinit(SPI_t *spix);
void std_spi_struct_init(std_spi_init_t *spi_init_struct);


/** 
* @} 
*/

#ifdef __cplusplus
}
#endif

/** 
* @} 
*/

/** 
* @} 
*/

#endif /* CIU32L071_STD_SPI_H */
