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

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

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

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

/************************************************************************
 * Function     : spi1_init
 * Description  : spi1_init
 * Input        : uint8_t work_mode: select spi1 work mode  0,1,2,3
 *                uint8_t spi1_clk_div：spi1 baud rate
 *                uint8_t spi1_cs：SPI1_CS0 or SPI1_CS1
 * Return       : none
 ************************************************************************/
void spi1_init(uint8_t work_mode,uint8_t spi1_clk_div,uint8_t spi1_cs)  
{
	REG_SCU_PERICLKEN |= (1<<21);								        //spi1模块时钟使能
	REG_SCU_PERIRESET |= (1<<21);								        //spi1模块正常工作
        
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; 						        //清除IO写保护
	if(spi1_cs == SPI1_CS0)     
	{       
		REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<16)))|(0xC<<16);	        //PF4复用为SPI1_SCK
		REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<24)))|(0xC<<24);	        //PF6复用为SPI1_MOSI
		REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<20)))|(0xA<<20);	        //PF5复用为SPI1_MISO
        REG_SCU_PADIE1 |= (1<<13);                                      //PF5输入使能
		REG_SCU_PFSEL = (REG_SCU_PFSEL&(~(0xF<<12)))|(0xA<<12);	        //PF3复用为SPI1_CSN0

		REG_SCU_IOCTRLPROTECT = 0xFFFFFFFF; 	                        //开启IO写保护
		REG_SPI1_SPICS0 = 0x00;	 				                        //初始化spi1主模式控制寄存器0				
		REG_SPI1_SPICS0 &= ~(1<<2);				                        //先发送MSB
		REG_SPI1_SPICS0 |= (spi1_clk_div<<3);  	                        //spi1主模式下，CS0对应Master模式波特率配置分频PCLK/div	
		REG_SPI1_SPICS0 |= work_mode;    		                        //工作模式设置
	}
	else																//若选用CS1，则配置SPICS1寄存器
	{
		REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<8)))|(0x3<<8);	        //PE2复用为SPI1_SCK	
		REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<4)))|(0x4<<4);	        //PE1复用为SPI1_MOSI
		REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<0)))|(0x4<<0);	        //PE0复用为SPI1_MI1	
        REG_SCU_PADIE1 |= (1<<0);                                       //PE0输入使能
		REG_SCU_PESEL = (REG_SCU_PESEL&(~(0xF<<20)))|(0x3<<20);	        //PE5复用为SPI1_CSN1	
					
		REG_SCU_IOCTRLPROTECT = 0xFFFFFFFF;                             //开启IO写保护
		REG_SPI1_SPICS1 = 0x00;	 			                            //初始化spi1主模式控制寄存器1
		REG_SPI1_SPICS1 &= ~(1<<2);			                            //先发送MSB
		REG_SPI1_SPICS1 |= (spi1_clk_div<<3);                           //spi1主模式下，CS1对应Master模式波特率配置分频PCLK/div
		REG_SPI1_SPICS1 |= work_mode;    	                            //工作模式设置
	}
	
	REG_SPI1_SPICR = 0x00;			                                    //初始化spi1配置寄存器
	REG_SPI1_SPICR |= (1<<5);											//主机模式
	REG_SPI1_SPICR |= (1<<1);		                                    //Master模式下SSN输出由软件控制
	REG_SPI1_SPICR |= (1<<7);	
	REG_SPI0_SPICR |= (3<<3);                                           //该配置项用于4分频及4分频以下的场景
    
    REG_SPI1_SPIIE = 0x00;			                                    //默认状态下关闭所有中断功能	
	REG_SPI1_SPIOPCR = 0x0F; 		                                    //开始传输时，先清空内部所有缓存
	
    REG_SPI1_SPICR |= (1<<0);	 	                                    //使能spi1
	
}


/************************************************************************
 * Function     : spi1_irq_init
 * Description  : spi1 irq init
 * Input        : uint8_t irq_enable: irq enable or disable
 *                uint32_t spi1_intr：spi1 interrupt type
 *                void (*pfunc)()：spi1 interrupt callback function
 * Return       : none
 ************************************************************************/
void spi1_irq_init(uint8_t irq_enable,uint32_t spi1_intr,void (*pfunc)())
{
	if(irq_enable == SPI1_IRQ_ENABLE)
	{
		spi1func = pfunc;
	
		NVIC_ClearPendingIRQ(SPI1_IRQn); 
		NVIC_EnableIRQ(SPI1_IRQn);
	
		REG_SPI1_SPIIE |= (1<<spi1_intr);     					        //中断使能	
	}
	else
	{
		REG_SPI1_SPIIE &= ~(0xFF<<0);     							    //中断关闭
		
		spi1func = NULL;
	}
}

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


#ifdef FULL_DUPLEX_MODE							                        //全双工传输
/************************************************************************
 * Function     : spi1_master_full_duplex_tranfer
 * Description  : spi1_master_full_duplex_tranfer spi1全双工传输
 * 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 spi1_master_full_duplex_tranfer(uint8_t *send_data, uint8_t *rec_buff, uint32_t length)
{
	while(length--)
	{
		
		REG_SPI1_SPITXBUF = *send_data++;			                    //写入数据
        while(!(REG_SPI1_SPIIF & (1<<SPIIF_TXBE)));                     //1发送缓存无数据，等待发送缓存有数据
		
        while(!(REG_SPI1_SPIIF & (1<<SPIIF_RXBF)));	                    //1接收缓存有数据,等待接收缓存有数据
		*rec_buff++ = REG_SPI1_SPIRXBUF;
        
        spi1_wait_idle();
       
	}
	
	return 0;
}

#else					                                                //半双工传输
/************************************************************************
 * Function     : spi1_master_half_duplex_send_bytes
 * Description  : spi1_master_half_duplex_send_bytes
 * Input        : uint8_t *buff：tx data buff
 *                uint32_t length：data length
 * Return       : 正常发送返回	：0
 *                异常发送返回 	：1
 ************************************************************************/
uint8_t spi1_master_half_duplex_send_bytes(uint8_t *buff, uint32_t length)
{
    
#ifndef SPI_RX_INT_MODE
	REG_SPI1_SPICR |= (1 << 8);							                //打开TXONLY
#endif
    
	while(length--)
	{
		REG_SPI1_SPITXBUF = *buff++;
		while(!(REG_SPI1_SPIIF & (1<<SPIIF_TXBE)));                     //1发送缓存无数据，等待发送缓存有数据

        spi1_wait_idle();                                               //等待发送空闲
	}
	REG_SPI1_SPICR &= ~(1 << 8);						                //关闭TXONLY

	return 0;
}

/************************************************************************
 * Function     : spi1_master_half_duplex_receive_bytes
 * Description  : spi1_master_half_duplex_receive_bytes 	接收多个byte数据
 * Input        : uint8_t *buff：rx data buff
 *                uint32_t length：data length
 * Return       : 正常发送返回	：0
 *                异常发送返回 	：1
 ************************************************************************/
uint8_t spi1_master_half_duplex_receive_bytes(uint8_t *buff,uint32_t length)
{
    
	while(length--)
	{
		REG_SPI1_SPITXBUF = 0xFF;										
		while(!(REG_SPI1_SPIIF & (1<<SPIIF_TXBE)));                     //1发送缓存无数据，等待发送缓存有数据

		while(!(REG_SPI1_SPIIF & (1<<SPIIF_RXBF)));	                    //1接收缓存有数据,等待接收缓存有数据
		*buff++ = REG_SPI1_SPIRXBUF;
        
        spi1_wait_idle(); 
	}
    	
	return 0;
}


#endif

/************************************************************************
 * Function     : spi1_cs_enable
 * Description  : spi1_cs_enable CS片选设置
 * Input        : uint8_t cs_enable：enable or disable
 *                uint8_t cs_select：spi1 cs0 or spi1 cs1
 * Return       : none
 ************************************************************************/
void spi1_cs_enable(uint8_t cs_enable, uint8_t cs_select)
{
	if(cs_enable == SPI1_CS_ENABLE)
	{
		if(cs_select == SPI1_CS0)
		{
			REG_SPI1_SPICS0 |= (1<<6); 	                                //CS0片选拉低开始工作
		}                               
		else                                
		{                               
			REG_SPI1_SPICS1 |= (1<<6);	                                //CS1片选拉低开始工作
		}                               
	}                               
	else                                
	{                               
		REG_SPI1_SPICS0 &= ~(1<<6); 	                                //CS0片选拉高停止工作
		REG_SPI1_SPICS1 &= ~(1<<6);		                                //CS1片选拉高停止工作
	}
}
