/********************************** (C) COPYRIGHT *******************************
* File Name          : CH57x_SPI0.c
* Author             : WCH
* Version            : V1.0
* Date               : 2018/12/15
* Description 
*******************************************************************************/

#include "CH57x_common.h"

uint32_t spi_tick = 0;
#define SPI_TIMEOUT 100
/*******************************************************************************
* Function Name  : SPI0_MasterDefInit
* Description    : 主机模式默认初始化：模式0+3线全双工+8MHz
* Input          : None			   				
* Return         : None
*******************************************************************************/
void SPI0_MasterDefInit( void )
{
    R8_SPI0_CLOCK_DIV = 4;		// 主频时钟4分频
    R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
    R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_SCK_OE ;
    R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF;		   // 访问BUFFER/FIFO自动清除IF_BYTE_END标志
    R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;    // 不启动DMA方式 
}

/*******************************************************************************
* Function Name  : SPI0_CLKCfg
* Description    : SPI0 基准时钟配置，= d*Tsys
* Input          : c: 时钟分频系数			   				
* Return         : None
*******************************************************************************/
void SPI0_CLKCfg( UINT8 c )
{
    if(c==2)
        R8_SPI0_CTRL_CFG |= RB_SPI_MST_DLY_EN;
    else 
        R8_SPI0_CTRL_CFG &= ~RB_SPI_MST_DLY_EN;
    R8_SPI0_CLOCK_DIV = c;
}

/*******************************************************************************
* Function Name  : SPI0_DataMode
* Description    : 设置数据流模式
* Input          : m: 数据流模式
					refer to ModeBitOrderTypeDef
* Return         : None
*******************************************************************************/
void SPI0_DataMode( ModeBitOrderTypeDef m )
{
    switch( m )
    {
        case Mode0_LowBitINFront:
            R8_SPI0_CTRL_MOD &= ~RB_SPI_MST_SCK_MOD;
            R8_SPI0_CTRL_CFG |= RB_SPI_BIT_ORDER;
            break;
        case Mode0_HighBitINFront:
            R8_SPI0_CTRL_MOD &= ~RB_SPI_MST_SCK_MOD;
            R8_SPI0_CTRL_CFG &= ~RB_SPI_BIT_ORDER;
            break;
        case Mode3_LowBitINFront:
            R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
            R8_SPI0_CTRL_CFG |= RB_SPI_BIT_ORDER;
            break;
        case Mode3_HighBitINFront:
            R8_SPI0_CTRL_MOD |= RB_SPI_MST_SCK_MOD;
            R8_SPI0_CTRL_CFG &= ~RB_SPI_BIT_ORDER;
            break;
        default:
            break;
    }
}

/*******************************************************************************
* Function Name  : SPI0_MasterSendByte
* Description    : 发送单字节 (buffer)
* Input          : d: 发送字节
* Return         : None
*******************************************************************************/
void SPI0_MasterSendByte( UINT8 d )
{
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
    R8_SPI0_BUFFER = d;
	spi_tick = SysTick_100us;
    while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE) )
	{
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
	}	
}

/*******************************************************************************
* Function Name  : SPI0_MasterRecvByte
* Description    : 接收单字节 (buffer)
* Input          : None
* Return         : 接收到的字节
*******************************************************************************/
UINT8 SPI0_MasterRecvByte( void )
{
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;
    R8_SPI0_BUFFER = 0xFF;           // 启动传输
	spi_tick = SysTick_100us;
    while( !(R8_SPI0_INT_FLAG & RB_SPI_FREE) )
	{
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
	}
    return ( R8_SPI0_BUFFER );
}


/*******************************************************************************
* Function Name  : SPI0_MasterTrans
* Description    : 使用FIFO连续发送多字节
* Input          : pbuf: 待发送的数据内容首地址
                   len: 请求发送的数据长度，最大4095				   
* Return         : None
*******************************************************************************/
void SPI0_MasterTrans( UINT8 *pbuf, UINT16 len )
{
    UINT16 sendlen;

    sendlen = len;
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;                     // 设置数据方向为输出 
    R16_SPI0_TOTAL_CNT = sendlen;                             // 设置要发送的数据长度	
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
	
	spi_tick = SysTick_100us;
    while( sendlen )
    {                                         
        if( R8_SPI0_FIFO_COUNT < SPI_FIFO_SIZE )
        {                              
            R8_SPI0_FIFO = *pbuf;
            pbuf++;
            sendlen--;
			spi_tick = SysTick_100us;
        }
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
    }
	spi_tick = SysTick_100us;
    while( R8_SPI0_FIFO_COUNT != 0 )                         // 等待FIFO中的数据全部发送完成 
	{
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
	}
}

/*******************************************************************************
* Function Name  : SPI0_MasterRecv
* Description    : 使用FIFO连续接收多字节
* Input          : pbuf: 待发送的数据内容首地址
                   len: 请求发送的数据长度，最大4095
* Return         : None
*******************************************************************************/
void SPI0_MasterRecv( UINT8 *pbuf, UINT16 len )
{
    UINT16  readlen;

    readlen = len;
    R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;                     // 设置数据方向为输入 
    R16_SPI0_TOTAL_CNT = len;                                // 设置需要接收的数据长度，FIFO方向为输入长度不为0则会启动传输 */
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
    
	spi_tick = SysTick_100us;
	while( readlen )
    {                                                          
        if( R8_SPI0_FIFO_COUNT )
        {                                               
            *pbuf = R8_SPI0_FIFO;                                             
            pbuf++;
            readlen--;
			spi_tick = SysTick_100us;
        }
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
    }
}

/*******************************************************************************
* Function Name  : SPI0_MasterDMATrans
* Description    : DMA方式连续发送数据  
* Input          : pbuf: 待发送数据起始地址
*                  len : 待发送数据长度
* Return         : None
*******************************************************************************/
void SPI0_MasterDMATrans( PUINT8 pbuf, UINT16 len)
{                                    
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;     
    R16_SPI0_DMA_BEG = (UINT32)pbuf;                                           
    R16_SPI0_DMA_END = (UINT32)(pbuf + len);
    R16_SPI0_TOTAL_CNT = len;
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END|RB_SPI_IF_DMA_END;
    R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
	spi_tick = SysTick_100us;
    while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END))
	{
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
	}
    R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}

/*******************************************************************************
* Function Name  : SPI0_MasterDMARecv
* Description    : DMA方式连续接收数据  
* Input          : pbuf: 待接收数据存放起始地址
*                  len : 待接收数据长度
* Return         : None
*******************************************************************************/
void SPI0_MasterDMARecv( PUINT8 pbuf, UINT16 len)
{
    R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;                                      
    R16_SPI0_DMA_BEG = (UINT32)pbuf;                                           
    R16_SPI0_DMA_END = (UINT32)(pbuf + len);                                 
    R16_SPI0_TOTAL_CNT = len; 
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END|RB_SPI_IF_DMA_END;
    R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
	spi_tick = SysTick_100us;
    while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END))
	{
		if(SysTick_100us - spi_tick > SPI_TIMEOUT) break;	//超时退出
	}
    R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}



/*******************************************************************************
* Function Name  : SPI0_SlaveInit
* Description    : 设备模式默认初始化，建议设置MISO的GPIO对应为输入模式
* Input          : None
* Return         : None
*******************************************************************************/
void SPI0_SlaveInit( void )
{  
    R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR;
    R8_SPI0_CTRL_MOD = RB_SPI_MISO_OE | RB_SPI_MODE_SLAVE;	
    R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF;
}

/*******************************************************************************
* Function Name  : SPI0_SlaveRecvByte
* Description    : 从机模式，接收一字节数据  
* Input          : None
* Return         : 接收到数据
*******************************************************************************/
UINT8 SPI0_SlaveRecvByte( void )
{
    R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
    while( R8_SPI0_FIFO_COUNT == 0 );          
    return R8_SPI0_FIFO; 
}

/*******************************************************************************
* Function Name  : SPI0_SlaveSendByte
* Description    : 从机模式，发送一字节数据  
* Input          : d -待发送数据 
* Return         : None
*******************************************************************************/
void SPI0_SlaveSendByte( UINT8 d )
{
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;                                              
    R8_SPI0_FIFO = d;                    
    while( R8_SPI0_FIFO_COUNT != 0 );               // 等待发送完成 
}

/*******************************************************************************
* Function Name  : SPI0_SlaveRecv
* Description    : 从机模式，接收多字节数据  
* Input          : pbuf: 接收收数据存放起始地址
*                  len : 请求接收数据长度
* Return         : None
*******************************************************************************/
void SPI0_SlaveRecv( PUINT8 pbuf, UINT16 len )
{
    UINT16 revlen;
    
    revlen = len;
    R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
    while( revlen )
    {
        if( R8_SPI0_FIFO_COUNT )
        {            
            *pbuf = R8_SPI0_FIFO;
            pbuf++;
            revlen--;
        }
    }        
}

/*******************************************************************************
* Function Name  : SPI0_SlaveTrans
* Description    : 从机模式，发送多字节数据
* Input          : pbuf: 待发送的数据内容首地址
                   len: 请求发送的数据长度，最大4095				   
* Return         : None
*******************************************************************************/
void SPI0_SlaveTrans( UINT8 *pbuf, UINT16 len )
{
    UINT16 sendlen;

    sendlen = len;
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;                     // 设置数据方向为输出 
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END;
    while( sendlen )
    {                                         
        if( R8_SPI0_FIFO_COUNT < SPI_FIFO_SIZE )
        {                              
            R8_SPI0_FIFO = *pbuf;
            pbuf++;
            sendlen--;
        }
    }
    while( R8_SPI0_FIFO_COUNT != 0 );                         // 等待FIFO中的数据全部发送完成 
}

/*******************************************************************************
* Function Name  : SPI0_SlaveDMARecv
* Description    : DMA方式连续接收数据  
* Input          : pbuf: 待接收数据存放起始地址
*                  len : 待接收数据长度
* Return         : None
*******************************************************************************/
void SPI0_SlaveDMARecv( PUINT8 pbuf, UINT16 len)
{
    R8_SPI0_CTRL_MOD |= RB_SPI_FIFO_DIR;                                      
    R16_SPI0_DMA_BEG = (UINT32)pbuf;                                           
    R16_SPI0_DMA_END = (UINT32)(pbuf + len); 
    R16_SPI0_TOTAL_CNT = len; 
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END|RB_SPI_IF_DMA_END;
    R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
    while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
    R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}

/*******************************************************************************
* Function Name  : SPI0_SlaveDMATrans
* Description    : DMA方式连续发送数据  
* Input          : pbuf: 待发送数据起始地址
*                  len : 待发送数据长度
* Return         : None
*******************************************************************************/
void SPI0_SlaveDMATrans( PUINT8 pbuf, UINT16 len)
{                                    
    R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR;     
    R16_SPI0_DMA_BEG = (UINT32)pbuf;                                           
    R16_SPI0_DMA_END = (UINT32)(pbuf + len);
    R16_SPI0_TOTAL_CNT = len; 
    R8_SPI0_INT_FLAG = RB_SPI_IF_CNT_END|RB_SPI_IF_DMA_END;
    R8_SPI0_CTRL_CFG |= RB_SPI_DMA_ENABLE;
    while(!(R8_SPI0_INT_FLAG & RB_SPI_IF_CNT_END));
    R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE;
}



