/*********************************************************************************************************************
 * COPYRIGHT NOTICE
 * Copyright (c) 2020,逐飞科技
 * All rights reserved.
 * 技术讨论QQ群：三群：824575535
 *
 * 以下所有内容版权均属逐飞科技所有，未经允许不得用于商业用途，
 * 欢迎各位使用并传播本程序，修改内容时必须保留逐飞科技的版权声明。
 *
 * @file       		eru_dma
 * @company	   		成都逐飞科技有限公司
 * @author     		逐飞科技(QQ3184284598)
 * @version    		查看doc内version文件 版本说明
 * @Software 		ADS v1.2.2
 * @Target core		TC264D
 * @Taobao   		https://seekfree.taobao.com/
 * @date       		2020-3-23
 ********************************************************************************************************************/
 

#include "IfxDma_Dma.h"
#include "IfxScuEru.h"
#include "isr_config.h"
#include "zf_assert.h"
#include "zf_eru_dma.h"


typedef struct
{
    Ifx_DMA_CH linked_list[8];//DMA链表
    IfxDma_Dma_Channel channel;              //DMA通道句柄
}DMA_LINK;

#if(0 == ERU_DMA_INT_SERVICE)
#pragma section all "cpu0_dsram"
IFX_ALIGN(256) DMA_LINK dma_link_list;

#elif(1 == ERU_DMA_INT_SERVICE)
#pragma section all "cpu1_dsram"
IFX_ALIGN(256) DMA_LINK dma_link_list;

#endif
#pragma section all restore


//-------------------------------------------------------------------------------------------------------------------
//  @brief      eru触发dma初始化
//  @param      dma_ch           	选择DMA通道
//  @param      source_addr         设置源地址
//  @param      destination_addr    设置目的地址
//  @param      eru_pin				设置触发的eru通道
//  @param      trigger				设置触发方式
//  @param      dma_count			设置dma搬移次数
//	@return		void
//  Sample usage:
//-------------------------------------------------------------------------------------------------------------------
uint8 eru_dma_init(IfxDma_ChannelId dma_ch, uint8 *source_addr, uint8 *destination_addr, ERU_PIN_enum eru_pin, TRIGGER_enum trigger, uint16 dma_count)
{
	IfxDma_Dma_Channel dmaChn;
	//eru触发DMA通道号   在eru文件中设置eru的优先级，即为触发的通道
	eru_init(eru_pin, trigger);

	IfxDma_Dma_Config        dmaConfig;
    IfxDma_Dma_initModuleConfig(&dmaConfig, &MODULE_DMA);

    IfxDma_Dma               dma;
    IfxDma_Dma_initModule(&dma, &dmaConfig);

    IfxDma_Dma_ChannelConfig cfg;
    IfxDma_Dma_initChannelConfig(&cfg, &dma);

	uint8  list_num, i;
	uint16 single_channel_dma_count;

	ZF_ASSERT(!(dma_count%8));//传输次数必须为8的倍数


	list_num = 1;
	single_channel_dma_count = dma_count / list_num;
	if(16384 < single_channel_dma_count)
	{
		while(TRUE)
		{
			single_channel_dma_count = dma_count / list_num;
			if((single_channel_dma_count <= 16384) && !(dma_count % list_num))
			{
				break;
			}
			list_num++;
			if(list_num > 8) ZF_ASSERT(FALSE);
		}
	}


	if(1 == list_num)
	{
		cfg.shadowControl 				= IfxDma_ChannelShadow_none;
		cfg.operationMode       	    = IfxDma_ChannelOperationMode_single;
		cfg.shadowAddress				= 0;
	}
	else
	{
		cfg.shadowControl 				= IfxDma_ChannelShadow_linkedList;
		cfg.operationMode       		= IfxDma_ChannelOperationMode_continuous;
		cfg.shadowAddress 				= IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), (unsigned)&dma_link_list.linked_list[1]);
	}

    cfg.requestMode                     = IfxDma_ChannelRequestMode_oneTransferPerRequest;
    cfg.moveSize                        = IfxDma_ChannelMoveSize_8bit;
    cfg.busPriority 					= IfxDma_ChannelBusPriority_high;

    cfg.sourceAddress      				= IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), source_addr);
    cfg.sourceAddressCircularRange      = IfxDma_ChannelIncrementCircular_none;
    cfg.sourceCircularBufferEnabled     = TRUE;

    cfg.destinationAddressIncrementStep = IfxDma_ChannelIncrementStep_1;

	cfg.channelId          				= (IfxDma_ChannelId)dma_ch;
	cfg.hardwareRequestEnabled  		= FALSE;
	cfg.channelInterruptEnabled       	= TRUE;
	cfg.channelInterruptPriority      	= ERU_DMA_INT_PRIO;
	cfg.channelInterruptTypeOfService 	= ERU_DMA_INT_SERVICE;



	cfg.destinationAddress 				= IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), destination_addr);

	cfg.transferCount                   = single_channel_dma_count;

	IfxDma_Dma_initChannel(&dmaChn, &cfg);

	if(1 < list_num)
	{
		i = 0;
		while(i < list_num)
		{
			cfg.destinationAddress 		= IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), destination_addr + single_channel_dma_count * i);
			if(i == (list_num - 1))	cfg.shadowAddress = IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), (unsigned)&dma_link_list.linked_list[0]);
			else					cfg.shadowAddress = IFXCPU_GLB_ADDR_DSPR(IfxCpu_getCoreId(), (unsigned)&dma_link_list.linked_list[i+1]);
			cfg.transferCount           = single_channel_dma_count;

			IfxDma_Dma_initLinkedListEntry((void *)&dma_link_list.linked_list[i], &cfg);
			i++;
		}
	}


	IfxDma_Dma_getSrcPointer(&dma_link_list.channel)->B.CLRR = 1;

	return list_num;
}


//-------------------------------------------------------------------------------------------------------------------
//  @brief      dma停止
//  @param      dma_ch           	选择DMA通道
//	@return		void
//  Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void dma_stop(IfxDma_ChannelId dma_ch)
{
	IfxDma_disableChannelTransaction(&MODULE_DMA, dma_ch);
}


//-------------------------------------------------------------------------------------------------------------------
//  @brief      dma启动
//  @param      dma_ch           	选择DMA通道
//	@return		void
//  Sample usage:
//-------------------------------------------------------------------------------------------------------------------
void dma_start(IfxDma_ChannelId dma_ch)
{
	IfxDma_enableChannelTransaction(&MODULE_DMA, dma_ch);
}
