/***********************************************************************
 * Copyright (c)  2017 - 2021, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : dma.c
 * Description : dma driver source file
 * Author(s)   : Will
 * version     : V1.0
 * Modify date : 2021-9-18
 ***********************************************************************/
#include  "dma_spi.h"

void (*dmac_callback[8])(void) = { 0 };

/*******************************************************************
* Function		: DMA_IRQHandler
* Description	: dma interrupt handling
* Input			: none
* Output		: none
* Return		: none
********************************************************************/
void DMA_IRQHandler(void)
{
	if(REG_DMA_INTSTATUS & (1<<2))       					//通道0块传输结束中断指示 
	{
		if(dmac_callback[0]!= NULL)
		{
			((void(*)())(dmac_callback[0]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<2);							//清除通道0块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<3))       				//通道1块传输结束中断指示 
	{
		if(dmac_callback[1]!= NULL)
		{
			((void(*)())(dmac_callback[1]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<3);							//清除通道1块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<6))       				//通道2块传输结束中断指示 
	{
		if(dmac_callback[2]!= NULL)
		{
			((void(*)())(dmac_callback[2]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<6);							//清除通道2块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<7))       				//通道3块传输结束中断指示 
	{
		if(dmac_callback[3]!= NULL)
		{
			((void(*)())(dmac_callback[3]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<7);							//清除通道4块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<10))       				//通道4块传输结束中断指示 
	{
		if(dmac_callback[4]!= NULL)
		{
			((void(*)())(dmac_callback[4]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<10);							//清除通道4块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<11))       				//通道5块传输结束中断指示 
	{
		if(dmac_callback[5]!= NULL)
		{
			((void(*)())(dmac_callback[5]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<11);							//清除通道5块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<14))       				//通道6块传输结束中断指示 
	{
		if(dmac_callback[6]!= NULL)
		{
			((void(*)())(dmac_callback[6]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<14);							//清除通道6块传输结束中断指示标志位
	}	
	else if(REG_DMA_INTSTATUS & (1<<15))       				//通道7块传输结束中断指示 
	{
		if(dmac_callback[7]!= NULL)
		{
			((void(*)())(dmac_callback[7]))();  			//dma的中断处理回调函数
		}	
		REG_DMA_INTSTATUS = (1<<15);							//清除通道7块传输结束中断指示标志位
	}	
	
	else
	{
		REG_DMA_INTSTATUS = 0xFFFF;							//清除所有中断
	}
}

/*******************************************************************
* Function		: dmac_int
* Description	: dmac_int		DMA初始化，配置数据位宽、传输模式等
* Input			: uint8_t channel_index		DMA通道号
* Output		: none
* Return		: none
********************************************************************/
void dma_init(uint8_t channel_index)
{
	REG_SCU_PERIRESET  |= ((uint32_t)0x01<<22);       		//释放dma复位 
    REG_SCU_PERICLKEN  |= ((uint32_t)0x01<<22);       		//使能dma时钟 

	REG_DMA_CHCTRLC(channel_index) = 0;		
			
	REG_DMA_CHCTRLC(channel_index) |= DMA_TR_WIDTH_8;  		//数据位宽8位
				
	REG_DMA_CHCTRLC(channel_index) |= DMA_MEM_TO_PERIP;     //传输模式M to P	
	
	REG_DMA_SPEC(channel_index) |= DMA_SRC_PER_MEMORY;     	//选择源设备
	REG_DMA_DPEC(channel_index) |= DMA_DST_PER_SPI1_TX; 	//选择目标设备
	REG_DMA_CHCTRLC(channel_index) |= DMA_SINC_INC;  		//源地址递增
	REG_DMA_CHCTRLC(channel_index) |= DMA_DINC_NOC;   		//目的地址不变
	
	REG_DMA_EN = 1;											//使能DMA控制器
}


void dma_init2(uint8_t channel_index)
{
	REG_SCU_PERIRESET  |= ((uint32_t)0x01<<22);       		//释放dma复位 
    REG_SCU_PERICLKEN  |= ((uint32_t)0x01<<22);       		//使能dma时钟 
			
	REG_DMA_CHCTRLC(channel_index) = 0;		
			
	REG_DMA_CHCTRLC(channel_index) |= DMA_TR_WIDTH_8;  			//数据位宽8位
				
	REG_DMA_CHCTRLC(channel_index) |= DMA_PERIP_TO_MEM;  		  //传输模式P to M
	
	REG_DMA_SPEC(channel_index) |= DMA_SRC_PER_SPI1_RX;     	//选择源设备
	REG_DMA_DPEC(channel_index) |= DMA_DST_PER_MEMORY; 				//选择目标设备
	REG_DMA_CHCTRLC(channel_index) |= DMA_SINC_NOC;  					//源地址不变
	REG_DMA_CHCTRLC(channel_index) |= DMA_DINC_INC;   				//目的地址递增
	
	REG_DMA_EN = 1;													//使能DMA控制器
}

/*******************************************************************
* Function		: dma_irq_init
* Description	: dma_irq_init DMA中断初始化
* Input			: uint8_t channel_index   DMA通道号
*                 uint8_t irq_enable      DMA中断使能开关
*                 void (*pfunc_tc)()      DMA中断回调函数
* Output		: none
* Return		: none
********************************************************************/
void dma_irq_init(uint8_t channel_index,uint8_t irq_enable,void (*pfunc_tc)())
{
	if(irq_enable == DMA_IRQ_ENABLE)
	{
		dmac_callback[channel_index] = pfunc_tc;
		REG_DMA_INTMASK |= (1<<((channel_index/2)*4+channel_index%2+2));   	//打开对应的通道的块传输结束中断
	
		NVIC_ClearPendingIRQ(DMA_IRQn);
		NVIC_EnableIRQ(DMA_IRQn);
	}
	else
	{
		dmac_callback[channel_index] = NULL;
		REG_DMA_INTMASK &= ~(1<<((channel_index/2)*4+channel_index%2+2));   //禁止对应的通道的块传输结束中断
	}
	
}


/************************************************************************
 * Function   	: dma_irq_transfer
 * Description	: dma_irq_transfer 	中断方式时使用此函数启动DMA转换
 * Input 		:  uint8_t channel_index DMA通道编号
 *         		   uint32_t src_addr   源地址
 *                 uint32_t dest_addr   目的地址
 *  	           uint16_t length     传输数据长度，最大为2^15-1
 * Output		: none
 * Return		: none
 ************************************************************************/
void dma_irq_transfer(uint8_t channel_index, uint32_t src_addr, uint32_t dest_addr, uint16_t length)
{
	REG_DMA_SRCADDRC(channel_index) = (uint32_t)src_addr;					
	REG_DMA_DSTADDRC(channel_index) = (uint32_t)dest_addr;
	
	length &= 0x7FFF;
	
	REG_DMA_CHCTRLC(channel_index) = (REG_DMA_CHCTRLC(channel_index) & ~(0x7FFF<<15)) | (length<<15);  	//传输块大小
	
	REG_DMA_CHCTRLC(channel_index) |= (1<<0);   		//通道使能标志，对于DMA流控时，块传送结束后自动清0
}
 
/************************************************************************
 * Function   	: dma_poll_transfer
 * Description	: dma_poll_transfer 	查询方式时使用此函数启动DMA转换
 * Input 		:  uint8_t channel_index DMA通道编号
 *         		   uint32_t src_addr   源地址
 *                 uint32_t dest_addr   目的地址
 *  	           uint16_t length     传输数据长度，最大为2^15-1
 * Output		: none
 * Return		: none
 ************************************************************************/
void dma_poll_transfer(uint8_t channel_index, uint32_t src_addr, uint32_t dest_addr, uint16_t length)
{
	REG_DMA_SRCADDRC(channel_index) = (uint32_t)src_addr;					
	REG_DMA_DSTADDRC(channel_index) = (uint32_t)dest_addr;
	
	length &= 0x7FFF;

	REG_DMA_CHCTRLC(channel_index) = (REG_DMA_CHCTRLC(channel_index) & ~(0x7FFF<<15)) | (length<<15);  	//传输块大小

	REG_DMA_CHCTRLC(channel_index) |= (1<<0);   		//通道使能标志，对于DMA流控时，块传送结束后自动清0  
	
}
  

 
 


