/***********************************************************************
 * Copyright (c)  2017 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : spi0_slave.c
 * Description : spi0 slave source file
 * Author(s)   : Mason
 * version     : V1.0
 * Modify date : 2022-08-04
 ***********************************************************************/
#include "spi0_slave.h"

void (*spi0func)(void) = { 0 };

/************************************************************************
 * Function     : SPI0_IRQHandler
 * Description  : SPI0_IRQHandler
 * Input        : none
 * Return       : none
 ************************************************************************/
void SPI0_IRQHandler(void)
{
	if(REG_SPI0_SPIIF & (0x01 << 0))		                            //接收缓存溢出中断标志
	{                   
		if(spi0func != NULL)                    
		{                   
			((void(*)())(spi0func))();                  
			REG_SPI0_SPIIF = 0x10;					                    //清接收缓存溢出中断
		}                   
	}                   
	else                    
	{                   
		REG_SPI0_SPIIF = 0x18;						                    //清发送、接收缓存溢出中断
	}     						
}

/************************************************************************
 * Function     : spi0_init
 * Description  : spi0_init
 * Input        : uint8_t work_mode: select spi0 work mode  0,1,2,3
 * Return       : none
 ************************************************************************/
void spi0_init(uint8_t work_mode)  
{
	REG_SCU_PERICLKEN |= (1<<4);						                //SPI0模块时钟使能
	REG_SCU_PERIRESET |= (1<<4);						                //SPI0模块正常工作
                
    REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; 				                //清除IO写保护

    REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<4)))|(0x3<<4);	            //PE1复用为SPI0_SCK
    REG_SCU_PADIE1 |= (1<<1);                                           //PE1输入使能
    REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<12)))|(0x2<<12);	            //PE3复用为SPI0_MOSI	
    REG_SCU_PADIE1 |= (1<<3);                                           //PE3输入使能
    REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<24)))|(0xB<<24);	            //PF6复用为SPI0_MISO	
    REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<12)))|(0x9<<12);	            //PF3复用为SPI0_CSN0

    REG_SCU_IOCTRLPROTECT = 0xFFFFFFFF;                                 //开启IO写保护
    REG_SPI0_SPICS0 = 0x00;
    REG_SPI0_SPICR = 0x00;                                              //初始化SPI0配置寄存器
    
	REG_SPI0_SPICR &= ~(1<<5);                                          //从机模式
    
    REG_SPI0_SPICS0 |= work_mode;                                       //工作模式设置

	REG_SPI0_SPIIE = 0x00;                                              //默认状态下关闭所有中断功能	
	REG_SPI0_SPIOPCR = 0x0F;                                            //开始传输时，先清空内部所有缓存
                                            
	REG_SPI0_SPICR |= (1<<0);                                           //使能spi0
}

/************************************************************************
 * Function     : spi0_irq_init
 * Description  : spi0 irq init
 * Input        : uint8_t irq_enable: irq enable or disable
 *                uint32_t spi0_intr：spi0 interrupt type
 *                void (*pfunc)()：spi0 interrupt callback function
 * Return       : none
 ************************************************************************/
void spi0_irq_init(uint8_t irq_enable,uint32_t spi0_intr,void (*pfunc)())
{
	if(irq_enable == SPI0_IRQ_ENABLE)
	{
		spi0func = pfunc;
		
		NVIC_ClearPendingIRQ(SPI0_IRQn); 
		NVIC_EnableIRQ(SPI0_IRQn);
		
		REG_SPI0_SPIIE |= (1<<spi0_intr);     					        //中断使能	
	}       
	else        
	{       
		REG_SPI0_SPIIE &= ~(0xFF<<0);        					        //中断关闭
		
		spi0func = NULL;
	}
}

/************************************************************************
 * Function     : spi0_irq_receive_byte
 * Description  : receive a byte in interrupt
 * Input        : none
 * Return       : spi rx buff
 ************************************************************************/
uint8_t spi0_irq_receive_byte(void)
{
	return REG_SPI0_SPIRXBUF;									        //返回读取寄存器的值
}

#ifdef FULL_DUPLEX_MODE							                        //全双工传输
/************************************************************************
 * Function     : spi0_slave_full_duplex_tranfer
 * Description  : spi0_slave_full_duplex_tranfer spi0全双工传输
 * Input        : uint8_t *send_data：tx data buff
 *                uint8_t *rec_buff：rx data buff
 *                uint32_t length：data length
 * Return       : 正常发送返回	：0
 *                异常发送返回 	：1
 ************************************************************************/
uint8_t spi0_slave_full_duplex_tranfer(uint8_t *send_data, uint8_t *rec_buff, uint32_t length)
{

	while(length--)
	{
		while(!(REG_SPI0_SPIIF & (1<<SPIIF_TNF)));		                //等待tx Fifo未满

		REG_SPI0_SPITXBUF = *send_data++;				                //写入数据寄存器，把要写入的数据写入发送缓存	
		
		while(!(REG_SPI0_SPIIF & (1<<SPIIF_RXBF)));		                //等待接收缓存非空

		*rec_buff++ = REG_SPI0_SPIRXBUF;	
	}
	return 0;
}

#else					                                                //半双工传输
/************************************************************************
 * Function     : spi0_slave_half_duplex_send_bytes
 * Description  : spi0_slave_half_duplex_send_bytes
 * Input        : uint8_t *buff：tx data buff
 *                uint32_t length：data length
 * Return       : 正常发送返回	：0
 *                异常发送返回 	：1
 ************************************************************************/
uint8_t spi0_slave_half_duplex_send_bytes(uint8_t *buff, uint32_t length)
{
    
#ifndef SPI_RX_INT_MODE
	REG_SPI0_SPICR |= (1 << 8);							                //打开TXONLY
#endif              
	while(length--)             
	{		                
		while(!(REG_SPI0_SPIIF & (1<<SPIIF_TNF)));		                //等待tx Fifo未满
                
		REG_SPI0_SPITXBUF = *buff++;                
                        
	}               
                    
	while(!(REG_SPI0_SPIIF & (1<<SPIIF_IDLE)));			                //等待发送空闲
                    
    REG_SPI0_SPICR &= ~(1 << 8);						                //关闭TXONLY
    
	return 0;
}

/************************************************************************
 * Function     : spi0_slave_half_duplex_receive_bytes
 * Description  : spi0_slave_half_duplex_receive_bytes 	接收多个byte数据
 * Input        : uint8_t *buff：rx data buff
 *                uint32_t length：data length
 * Return       : 正常发送返回	：0
 *                异常发送返回 	：1
 ************************************************************************/
uint8_t spi0_slave_half_duplex_receive_bytes(uint8_t *buff, uint32_t length)
{
	while(length--)
	{
		while(!(REG_SPI0_SPIIF & (1<<SPIIF_RXBF)));                     //等待接收缓存非空，RXBF事件
                
		*buff++ =  REG_SPI0_SPIRXBUF;					                //返回读取寄存器的值
	}	
	return 0;
}

#endif

/************************************************************************
 * Function     : spi0_wait_idle
 * Description  : spi0_wait_idle 等待SPI0空闲
 * Input        : none
 * Return       : none
 ************************************************************************/
void spi0_wait_idle(void)
{
	while(!(REG_SPI0_SPIIF & (1<<SPIIF_IDLE)));					        //等待发送完成
}

