/**
 *******************************************************************************
 * @file    dpm32m0xx_spi.h
 *
 * @brief   Header file for SPI firmware driver.
 *
 * @author  DPM
 *
 * @version V1.0.0
 *
 * @date    2023-11-01
 *
 *******************************************************************************/

#ifndef __DPM32M0XX_SPI_H__
#define __DPM32M0XX_SPI_H__

#ifdef __cplusplus
extern "C"
{
#endif

#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
#endif

#include "dpm32m0xx.h"



/**
 ******************************************************************************
 * @brief SPI mode (Master/Slave) enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_MODE_SLAVE = 0x00UL,                              /*!< SPI slave mode.  */
  SPI_MODE_MASTER                                       /*!< SPI master mode. */
} SPI_ModeEnum;


/**
 ******************************************************************************
 * @brief SPI data size enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_DATASIZE_4BIT = 0x03UL,                           /*!< 4 bit data size.  */
  SPI_DATASIZE_5BIT,                                    /*!< 5 bit data size.  */
  SPI_DATASIZE_6BIT,                                    /*!< 6 bit data size.  */
  SPI_DATASIZE_7BIT,                                    /*!< 7 bit data size.  */
  SPI_DATASIZE_8BIT,                                    /*!< 8 bit data size.  */
  SPI_DATASIZE_9BIT,                                    /*!< 9 bit data size.  */
  SPI_DATASIZE_10BIT,                                   /*!< 10 bit data size. */
  SPI_DATASIZE_11BIT,                                   /*!< 11 bit data size. */
  SPI_DATASIZE_12BIT,                                   /*!< 12 bit data size. */
  SPI_DATASIZE_13BIT,                                   /*!< 13 bit data size. */
  SPI_DATASIZE_14BIT,                                   /*!< 14 bit data size. */
  SPI_DATASIZE_15BIT,                                   /*!< 15 bit data size. */
  SPI_DATASIZE_16BIT                                    /*!< 16 bit data size. */
} SPI_DataSizeEnum;


/**
 ******************************************************************************
 * @brief SPI clock polarity enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_CPOL_LOW  = 0x00UL,                               /*!< SIP clock polarity is low.  */
  SPI_CPOL_HIGH                                         /*!< SIP clock polarity is high. */
} SPI_CPOLEnum;


/**
 ******************************************************************************
 * @brief SPI clock phase enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_CPHA_1EDGE = 0x00UL,                              /*!< SPI clock phase is edge 1. */
  SPI_CPHA_2EDGE                                        /*!< SPI clock phase is edge 2. */
} SPI_CPHAEnum;


/**
 ******************************************************************************
 * @brief SPI clock phase enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_BAUDRATE_PRESCALER_2   =   0UL,                   /*!< SPI baud rate prescaler 2.   */
  SPI_BAUDRATE_PRESCALER_4   =   1UL,                   /*!< SPI baud rate prescaler 4.   */
  SPI_BAUDRATE_PRESCALER_6   =   2UL,                   /*!< SPI baud rate prescaler 6.   */
  SPI_BAUDRATE_PRESCALER_8   =   3UL,                   /*!< SPI baud rate prescaler 8.   */
  SPI_BAUDRATE_PRESCALER_16  =   7UL,                   /*!< SPI baud rate prescaler 16.  */
  SPI_BAUDRATE_PRESCALER_32  =  15UL,                   /*!< SPI baud rate prescaler 32.  */
  SPI_BAUDRATE_PRESCALER_64  =  31UL,                   /*!< SPI baud rate prescaler 64.  */
  SPI_BAUDRATE_PRESCALER_128 =  63UL,                   /*!< SPI baud rate prescaler 128. */
  SPI_BAUDRATE_PRESCALER_256 = 127UL                    /*!< SPI baud rate prescaler 256. */
} SPI_BaudRatePrescalerEnum;


/**
 ******************************************************************************
 * @brief SPI first bit enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_FRIST_BIT_MSB = 0x00UL,                            /*!< SPI data transfer starts with MSB bit. */
  SPI_FRIST_BIT_LSB                                      /*!< SPI data transfer starts with LSB bit. */
} SPI_FirstBitEnum;


/**
 ******************************************************************************
 * @brief SPI always checks NSS enable enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_NSS_SELECT_DISABLE = 0x00UL,                       /*!< Disable NSS_SELECT.    */
  SPI_NSS_SELECT_ENABLE                                  /*!< Enable NSS NSS_SELECT. */
} SPI_NSSSlectEnEnum;

#if defined (DPM32M08x) || defined (DPM32M05x)
/**
 ******************************************************************************
 * @brief SPI DMA request enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_DMA_REQ_TX = SPI_CR_TX_DMAEN_Msk,            /*!< Tx buffer DMA transfer request. */
  SPI_DMA_REQ_RX = SPI_CR_RX_DMAEN_Msk             /*!< Rx buffer DMA transfer request. */
} SPI_DMAReqEnum;
#endif  /* DPM32M08x || DPM32M05x */

/**
 ******************************************************************************
 * @brief SPI interrupt type enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_INT_TYPE_RXNE = SPI_CR_RXNE_IE_Msk,           /*!< Rx FIFO not empty interrupt.                                 */
  SPI_INT_TYPE_TXE  = SPI_CR_TXE_IE_Msk,            /*!< Tx FIFO empty interrupt.                                     */
  SPI_INT_TYPE_ERR  = SPI_CR_ERR_IE_Msk,            /*!< SPI error interrupt.                                         */

#if defined (DPM32M08x) || defined (DPM32M05x) || defined (DPM32M03x)
  SPI_INT_TYPE_UDRR = SPI_CR_UDRR_IE_Msk,           /*!< Send invalid data interrupt in slave mode.
                                                         @note In the slave mode, the clock edge is received,
                                                               but the data is not moved to tx_buf in time, resulting
                                                               in an interrupt when the sent data is invalid.         */
#endif /* DPM32M08x || DPM32M05x || DPM32M03x */

} SPI_IntTypeEnum;


/**
 ******************************************************************************
 * @brief SPI interrupt flag type enumeration.
 *****************************************************************************/
typedef enum
{
  SPI_INT_FLAG_RXNE  = SPI_ISR_RXNE_Msk,             /*!< Rx FIFO is not empty interrupt flag.                                         */
  SPI_INT_FLAG_TXE   = SPI_ISR_TXE_Msk,              /*!< Tx FIFO is empty interrupt flag.                                             */
  SPI_INT_FLAG_OVRR  = SPI_ISR_OVRR_ERR_Msk,         /*!< RX_BUFF data unread overflow interrupt flag.                                 */
  SPI_INT_FLAG_FAULT = SPI_ISR_FAULT_ERR_Msk,        /*!< NSS interference interrupt in slave mode.
                                                          @note In slave mode, during data transmission, i_nss_in changes from 0 to 1,
                                                                resulting in a mode error                                              */
#if defined (DPM32M08x) || defined (DPM32M05x) || defined (DPM32M03x)
  SPI_INT_FLAG_UDRR  = SPI_ISR_UDRR_Msk,             /*!< Slave mode send data invalid interrupt flag.                                 */
#endif /* DPM32M08x || DPM32M05x || DPM32M03x */
} SPI_IntFlagEnum;



/**
 ******************************************************************************
 * @brief SPI initialization structure definition.
 *****************************************************************************/
typedef struct
{
  uint32_t SPI_Mode;                 /*!< Specifies the SPI mode (Master/Slave).
                                          This parameter can be a value of @ref SPI_ModeEnum             */

  uint32_t SPI_DataSize;             /*!< Specifies the SPI data size.
                                          This parameter can be a value of @ref SPI_DataSizeEnum         */

  uint32_t SPI_CPOL;                 /*!< Specifies the serial clock steady state.
                                          This parameter can be a value of @ref SPI_CPOLEnum             */

  uint32_t SPI_CPHA;                 /*!< Specifies the clock active edge for the bit capture.
                                          This parameter can be a value of @ref SPI_CPHAEnum             */

  uint32_t SPI_BaudRatePrescaler;    /*!< Specifies the Baud Rate prescaler value which will be
                                         used to configure the transmit and receive SCK clock.
                                         This parameter can be a value of @ref SPI_BaudRatePrescalerEnum
                                         @note The communication clock is derived from the master
                                               clock. The slave clock does not need to be set.           */

  uint32_t SPI_FirstBit;             /*!< Specifies whether data transfers start from MSB or LSB bit.
                                         This parameter can be a value of @ref SPI_FirstBitEnum          */

  uint32_t SPI_NSSSlectEn;           /*!< Specifies whether NSS is always selected in slave mode.
                                          This parameter can be a value of @ref SPI_NSSSlectEnEnum
                                          @note Valid in slave mode, active low, not affected by
                                                external NSS value.                                      */
} SPI_InitTypeStruct;



/* SPI Param Check. */
#if defined (DPM32M08x) || defined (DPM32M05x)
#define IS_SPI_PERIPH(x)              (((x) == SPI0) ||  \
                                       ((x) == SPI1))
#endif /* DPM32M08x || DPM32M05x */

#if defined (DPM32M03x) || defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015)
#define IS_SPI_PERIPH(x)              (((x) == SPI0))
#endif /* DPM32M03x || DPM32M036 || DPM32M030 || DPM32M015 */

#define IS_SPI_MODE(x)                (((x) == SPI_MODE_SLAVE) ||  \
                                       ((x) == SPI_MODE_MASTER))


#define IS_SPI_DATASIZE(x)            (((x) == SPI_DATASIZE_4BIT) ||  \
                                       ((x) == SPI_DATASIZE_5BIT) ||  \
                                       ((x) == SPI_DATASIZE_6BIT) ||  \
                                       ((x) == SPI_DATASIZE_7BIT) ||  \
                                       ((x) == SPI_DATASIZE_8BIT) ||  \
                                       ((x) == SPI_DATASIZE_9BIT) ||  \
                                       ((x) == SPI_DATASIZE_10BIT) ||  \
                                       ((x) == SPI_DATASIZE_11BIT) ||  \
                                       ((x) == SPI_DATASIZE_12BIT) ||  \
                                       ((x) == SPI_DATASIZE_13BIT) ||  \
                                       ((x) == SPI_DATASIZE_14BIT) ||  \
                                       ((x) == SPI_DATASIZE_15BIT) ||  \
                                       ((x) == SPI_DATASIZE_16BIT))


#define IS_SPI_CPOL(x)                (((x) == SPI_CPOL_LOW) ||  \
                                       ((x) == SPI_CPOL_HIGH))


#define IS_SPI_CPHA(x)                (((x) == SPI_CPHA_1EDGE) ||  \
                                       ((x) == SPI_CPHA_2EDGE))


#define IS_SPI_BAUDRATE_PRESCALER(x)  (((x) == SPI_BAUDRATE_PRESCALER_2) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_4) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_8) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_16) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_32) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_64) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_128) ||  \
                                       ((x) == SPI_BAUDRATE_PRESCALER_256))


#define IS_SPI_FIRST_BIT(x)           (((x) == SPI_FRIST_BIT_MSB) ||  \
                                       ((x) == SPI_FRIST_BIT_LSB))


#define IS_SPI_NSS_SELECT(x)          (((x) == SPI_NSS_SELECT_DISABLE) ||  \
                                       ((x) == SPI_NSS_SELECT_ENABLE))



/* Initialization and Configuration functions. */
void                  SPI_DeInit(SPI_Type *SPIx);
void                  SPI_Init(SPI_Type *SPIx, SPI_InitTypeStruct *SPI_InitType);
void                  SPI_StructInit(SPI_InitTypeStruct *SPI_InitType);
void                  SPI_Cmd(SPI_Type *SPIx, FunctionalState Newstate);
void                  SPI_DataSizeConfig(SPI_Type *SPIx, SPI_DataSizeEnum SPI_DataSize);

#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015)   
void                  SPI_MasterFrameIntervalConfig(SPI_Type *SPIx, uint8_t SPI_FrameInterval);
void                  SPI_MasterContinueRecvCmd(SPI_Type *SPIx, FunctionalState Newstate);
void                  SPI_SlaveHighSpeedCmd(SPI_Type *SPIx, FunctionalState Newstate);
#endif /* DPM32M036 || DPM32M030 || DPM32M015 */

void                  SPI_TransmitCmd(SPI_Type *SPIx, FunctionalState Newstate);
void                  SPI_ReceiveCmd(SPI_Type *SPIx, FunctionalState Newstate);
/* Data transfers functions ***************************************************/
void                  SPI_SendData(SPI_Type *SPIx, uint16_t Data);
uint16_t              SPI_ReceiveData(SPI_Type *SPIx);


#if defined (DPM32M08x) || defined (DPM32M05x)
/* DMA transfers management functions *****************************************/
void                  SPI_DMACmd(SPI_Type *SPIx, SPI_DMAReqEnum SPI_DMAReq, FunctionalState Newstate);
#endif  /* DPM32M08x || DPM32M05x */

/* Interrupts and flags management functions **********************************/
void                  SPI_IntCmd(SPI_Type *SPIx, SPI_IntTypeEnum SPI_IntType, FunctionalState Newstate);
FunctionalState       SPI_GetIntCmdStatus(SPI_Type *SPIx, SPI_IntTypeEnum SPI_IntType);
FlagState             SPI_GetIntFlagStatus(SPI_Type *SPIx, SPI_IntFlagEnum SPI_IntFlag);
void                  SPI_ClearIntFlag(SPI_Type *SPIx, SPI_IntFlagEnum SPI_IntFlag);

FlagState             SPI_GetBusyFlagStatus(SPI_Type *SPIx);

#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang diagnostic pop
#endif

#ifdef __cplusplus
}

#endif

#endif /* __DPM32M0XX_SPI_H__ */
