
/******************************************************************************
*@file  : hal_dma.c
*@brief : DMA HAL module driver.
******************************************************************************/

#include "hal.h" 

#ifdef HAL_DMA_MODULE_ENABLED

/******************************************************************************
*@brief : This function handles DMA interrupt request.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for DMA module.
*@return: None
******************************************************************************/
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
    uint32_t ChannelIndex;
    DMA_TypeDef *DmaBaseAddress;
    
    if (hdma == NULL)
        return;
    
    if (hdma->Instance == NULL)
        return;
    
    /* calculation of the channel index */
	if ((uint32_t)(hdma->Instance) < (uint32_t)(DMA2_Channel0))
	{
		ChannelIndex = ((uint32_t)(hdma->Instance) - (uint32_t)(DMA1_Channel0)) >> 5;
		DmaBaseAddress = DMA1;
	}
	else
	{
		ChannelIndex = ((uint32_t)(hdma->Instance) - (uint32_t)(DMA2_Channel0)) >> 5;
		DmaBaseAddress = DMA2;
	}
    
    /* Channel has been interrupted */
    if (DmaBaseAddress->INTSTATUS & (1U << ChannelIndex))
    {
		/* Transfer half interrupt */
        if ((__HAL_DMA_GET_HFTC_IT_FLAG(hdma)) && (__HAL_DMA_GET_HFTC_IT_SOURCE(hdma)))
		{
			DmaBaseAddress->INTTCCLR = (1U << (ChannelIndex + 8U));
			if (NULL != hdma->XferHalfCpltCallback)
            {
                hdma->XferHalfCpltCallback(hdma);
            }
		}
        /* Transfer complete interrupt */
        if ((__HAL_DMA_GET_TC_IT_FLAG(hdma)) && (__HAL_DMA_GET_TC_IT_SOURCE(hdma)))
        {
            DmaBaseAddress->INTTCCLR = (1U << ChannelIndex);
            if (NULL != hdma->XferCpltCallback)
            {
                hdma->XferCpltCallback(hdma);
            }
        }
        
        /* Transfer error interrupt */
        if ((__HAL_DMA_GET_ERR_IT_FLAG(hdma)) && (__HAL_DMA_GET_ERR_IT_SOURCE(hdma)))
        {
            DmaBaseAddress->INTERRCLR = (1 << ChannelIndex);
            if (NULL != hdma->XferErrorCallback)
            {
                hdma->XferErrorCallback(hdma);
            }
        }
    }
}

/******************************************************************************
*@brief : Initialize the DMA according to the specified.
*         parameters in the DMA_InitTypeDef and create the associated handle.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma) 
{
	uint32_t RequestID;
	
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_MODE(hdma->Init.Mode));
	assert_param(IS_DMA_DATAFLOW(hdma->Init.DataFlow));
	assert_param(IS_DMA_SRCINC(hdma->Init.SrcInc));
	assert_param(IS_DMA_DESTINC(hdma->Init.DestInc));
	assert_param(IS_DMA_SRCWIDTH(hdma->Init.SrcWidth));
	assert_param(IS_DMA_DESTWIDTH(hdma->Init.DestWidth));
	assert_param(IS_DMA_SRCBURST(hdma->Init.SrcBurst));
	assert_param(IS_DMA_DESTBURST(hdma->Init.DestBurst));

    /* Init the low level hardware : clock */
    HAL_DMA_MspInit(hdma);
    
    /* calculation of the channel index */
	if ((uint32_t)(hdma->Instance) < (uint32_t)(DMA2_Channel0))
	{
        /* Check the parameters */
        assert_param(IS_DMA_REQ1ID(hdma->Init.DataFlow, hdma->Init.ReqID));
        
	    /* DMA1 */
		hdma->ChannelIndex = ((uint32_t)(hdma->Instance) - (uint32_t)(DMA1_Channel0)) >> 5;
		hdma->DmaBaseAddress = DMA1;
	}
	else
	{
        /* Check the parameters */
        assert_param(IS_DMA_REQ2ID(hdma->Init.DataFlow, hdma->Init.ReqID));
        
	    /* DMA2 */
		hdma->ChannelIndex = ((uint32_t)(hdma->Instance) - (uint32_t)(DMA2_Channel0)) >> 5;
		hdma->DmaBaseAddress = DMA2;
	}
	
    /* Enable DMA */
    hdma->DmaBaseAddress->CONFIG |= DMA_CONFIG_EN;
	
    /* Clear Channel Config */
    hdma->Instance->CHCONFIG = 0; 
    
    if (hdma->Init.DataFlow == DMA_DATAFLOW_M2P) 
    {
        RequestID = hdma->Init.ReqID << DMA_CHCONFIG_DESTPERIPH_Pos;
    }
    else if (hdma->Init.DataFlow == DMA_DATAFLOW_P2M) 
    {
        RequestID = hdma->Init.ReqID << DMA_CHCONFIG_SRCPERIPH_Pos;
    }
	else
	{
		RequestID = 0;
	}

    hdma->Instance->CHCONFIG = hdma->Init.DataFlow | RequestID;
    
    /* Config Channel Control */
    hdma->Instance->CHCTRL = DMA_CHCTRL_ITC;
	
    /* Source or Desination address increase */
    hdma->Instance->CHCTRL |= (hdma->Init.DestInc | hdma->Init.SrcInc);
	
    /* Source or Desination date width */
    hdma->Instance->CHCTRL |= (hdma->Init.DestWidth | hdma->Init.SrcWidth);

    /* Source or Desination burst size */
    hdma->Instance->CHCTRL |= hdma->Init.SrcBurst | hdma->Init.DestBurst;
    
    return HAL_OK;
}

/******************************************************************************
*@brief : DeInitializes the DMA peripheral.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_DeInit(DMA_HandleTypeDef *hdma)
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	
	hdma->Instance->CHCONFIG    = 0U;
	hdma->Instance->CHCTRL		= 0U;
	hdma->Instance->CHSRCADDR	= 0U;
	hdma->Instance->CHDESTADDR	= 0U;
	hdma->Instance->CHLLI       = 0U;
	
    /* DeInit the low level hardware */
    HAL_DMA_MspDeInit(hdma);
    
    hdma->XferCpltCallback		= NULL;
    hdma->XferHalfCpltCallback	= NULL;
	hdma->XferErrorCallback		= NULL;
	hdma->XferAbortCallback		= NULL;
	
	hdma->DmaBaseAddress		= 0U;
	hdma->ChannelIndex			= 0U;

    return HAL_OK;
}


/******************************************************************************
*@brief : Initialize the DMA MSP.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@return: None
******************************************************************************/
__weak void HAL_DMA_MspInit(DMA_HandleTypeDef *hdma)
{
    UNUSED(hdma);
}

/******************************************************************************
*@brief : DeInitialize the DMA MSP.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@return: None
******************************************************************************/
__weak void HAL_DMA_MspDeInit(DMA_HandleTypeDef *hdma)
{
    UNUSED(hdma);
}

/******************************************************************************
*@brief : Register callbacks.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : CallbackID: User Callback identifier
*                     This parameter can be a combination of @ref DMA_XfeCallbackID.
*                     @arg DMA_XFER_CPLT_CB_ID: Transfer completion interrupt callback function.
*                     @arg DMA_XFER_HALFCPLT_CB_ID: Half transfer completion interrupt callback function.
*                     @arg DMA_XFER_ERROR_CB_ID: Error interrupt callback function.
*                     @arg DMA_XFER_ABORT_CB_ID: Abort callback function.
*@param : pCallback: callback function.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_RegisterCallback(DMA_HandleTypeDef *hdma, uint32_t CallbackID, \
                                     void (* pCallback)(struct __DMA_HandleTypeDef * hdma))
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_CALLBACK_ID(CallbackID));
	
	switch (CallbackID)
	{
		case  DMA_XFER_CPLT_CB_ID:
			
			hdma->XferCpltCallback = pCallback;
			break;

		case  DMA_XFER_HALFCPLT_CB_ID:
			
			hdma->XferHalfCpltCallback = pCallback;
			break;

		case  DMA_XFER_ERROR_CB_ID:
			
			hdma->XferErrorCallback = pCallback;
			break;

		case  DMA_XFER_ABORT_CB_ID:
			
			hdma->XferAbortCallback = pCallback;
			break;

		default:
			return HAL_ERROR;
	}
	
	return HAL_OK;
}

/******************************************************************************
*@brief : UnRegister callbacks.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : CallbackID: User Callback identifier
*                     This parameter can be a combination of @ref DMA_XfeCallbackID.
*                     @arg DMA_XFER_CPLT_CB_ID: Transfer completion interrupt callback function.
*                     @arg DMA_XFER_HALFCPLT_CB_ID: Half transfer completion interrupt callback function.
*                     @arg DMA_XFER_ERROR_CB_ID: Error interrupt callback function.
*                     @arg DMA_XFER_ABORT_CB_ID: Abort callback function.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_UnRegisterCallback(DMA_HandleTypeDef *hdma, uint32_t CallbackID)
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_CALLBACK_ID(CallbackID));
	
	switch (CallbackID)
	{
		case  DMA_XFER_CPLT_CB_ID:
			
			hdma->XferCpltCallback = NULL;
			break;

		case  DMA_XFER_HALFCPLT_CB_ID:
			
			hdma->XferHalfCpltCallback = NULL;
			break;

		case  DMA_XFER_ERROR_CB_ID:
			
			hdma->XferErrorCallback = NULL;
			break;

		case  DMA_XFER_ABORT_CB_ID:
			
			hdma->XferAbortCallback = NULL;
			break;

		default:
			return HAL_ERROR;
	}
	
	return HAL_OK;
}

/******************************************************************************
*@brief : Starts the DMA Transfer.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : SrcAddr: The source memory Buffer address.
*@param : DestAddr: The destination memory Buffer address.
*@param : Size: The length of data to be transferred from source to destination.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddr, uint32_t DestAddr, uint32_t Size)
{
	uint32_t temp;
	
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_MODE(hdma->Init.Mode));
	assert_param(IS_DMA_SRCADDR(SrcAddr));
	assert_param(IS_DMA_DESTADDR(DestAddr));
	assert_param(IS_DMA_SIZE(Size));
	
    if ((Size == 0) || (Size > DMA_TRANSFER_SIZE))
        return HAL_ERROR;

    /* DMA Channel Disable */
    hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_EN;
	
    /* Set source address and desination address */
    hdma->Instance->CHSRCADDR  = SrcAddr;
    hdma->Instance->CHDESTADDR = DestAddr;
	
    /* Set Transfer Size */
	temp = hdma->Instance->CHCTRL;
	temp &= ~DMA_TRANSFER_SIZE;
	temp |= Size;
    hdma->Instance->CHCTRL = temp;
    
    /* Set Next Link */
    if (hdma->Init.Mode == DMA_MODE_NORMAL)
    {
        hdma->Instance->CHLLI = 0;
    }
    else if (hdma->Init.Mode == DMA_MODE_CIRCULAR)
    {
        hdma->Link.SrcAddr = hdma->Instance->CHSRCADDR;
        hdma->Link.DestAddr = hdma->Instance->CHDESTADDR;
        hdma->Link.Next = &hdma->Link;
        hdma->Link.Ctrl = (hdma->Instance->CHCTRL & ~DMA_TRANSFER_SIZE) | Size;
        
        hdma->Instance->CHLLI = (uint32_t)(&hdma->Link);
    }
    
    /* DMA Channel Enable */
    hdma->Instance->CHCONFIG |= DMA_CHCONFIG_EN;

    return HAL_OK;
}

/******************************************************************************
*@brief : Start the DMA Transfer with interrupt enabled.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : SrcAddr: The source memory Buffer address.
*@param : DestAddr: The destination memory Buffer address.
*@param : Size: The length of data to be transferred from source to destination.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddr, \
									uint32_t DestAddr, uint32_t Size)
{
	uint32_t temp;
	
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_MODE(hdma->Init.Mode));
	assert_param(IS_DMA_SRCADDR(SrcAddr));
	assert_param(IS_DMA_DESTADDR(DestAddr));
	assert_param(IS_DMA_SIZE(Size));
    
    /* DMA Channel Disable */
    hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_EN;
	
    /* Set source address and desination address */
    hdma->Instance->CHSRCADDR  = SrcAddr;
    hdma->Instance->CHDESTADDR = DestAddr;
	
    /* Set Next Link */
    hdma->Instance->CHLLI = 0;

    /* Set Transfer Size and enable LLI interrupt */
	temp = hdma->Instance->CHCTRL;
	temp &= ~DMA_TRANSFER_SIZE;
	temp |= Size;
    hdma->Instance->CHCTRL = temp;

    /* Enable interrupt */
	hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_IHFTC;
	hdma->Instance->CHCONFIG |= DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE;	
	
    if(NULL != hdma->XferHalfCpltCallback)
	{
		hdma->Instance->CHCONFIG |= DMA_CHCONFIG_IHFTC;	
	}

    /* Set Next Link */
    if (hdma->Init.Mode == DMA_MODE_NORMAL)
    {
        hdma->Instance->CHLLI = 0;
    }
    else if (hdma->Init.Mode == DMA_MODE_CIRCULAR)
    {
        hdma->Link.SrcAddr = hdma->Instance->CHSRCADDR;
        hdma->Link.DestAddr = hdma->Instance->CHDESTADDR;
        hdma->Link.Next = &hdma->Link;
        hdma->Link.Ctrl = (hdma->Instance->CHCTRL & ~DMA_TRANSFER_SIZE) | Size;
        
        hdma->Instance->CHLLI = (uint32_t)(&hdma->Link);
    }
    
    /* DMA Channel Enable */
    hdma->Instance->CHCONFIG |= DMA_CHCONFIG_EN;
	
    return HAL_OK;
}

/******************************************************************************
*@brief : Initialize linked list.
*@param : Link: Initialize linked list node.
*@param : Link_Init: pointer to an DMA_LinkInitTypeDef structure that contains 
*                    the configuration information for the specified Link.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_InitLink(DMA_LinkTypeDef *Link, DMA_LinkInitTypeDef *Link_Init)
{
    /* Check the parameters */
	assert_param(IS_DMA_SRCADDR(Link_Init->SrcAddr));
	assert_param(IS_DMA_DESTADDR(Link_Init->DestAddr));
	assert_param(IS_DMA_RAWIT(Link_Init->RawInt));
	assert_param(IS_DMA_SRCINC(Link_Init->SrcInc));
	assert_param(IS_DMA_DESTINC(Link_Init->DestInc));
	assert_param(IS_DMA_SRCWIDTH(Link_Init->SrcWidth));
	assert_param(IS_DMA_DESTWIDTH(Link_Init->DestWidth));
	assert_param(IS_DMA_SRCBURST(Link_Init->SrcBurst));
	assert_param(IS_DMA_DESTBURST(Link_Init->DestBurst));
	assert_param(IS_DMA_SIZE(Link_Init->Size));

	if ((Link == NULL) || (Link_Init == NULL))
        return HAL_ERROR;
    
	Link->SrcAddr = Link_Init->SrcAddr;
	Link->DestAddr = Link_Init->DestAddr;
	Link->Next = Link_Init->Next;
	Link->Ctrl = Link_Init->RawInt | Link_Init->SrcInc | Link_Init->DestInc | \
                 Link_Init->SrcWidth | Link_Init->DestWidth | Link_Init->SrcBurst | \
                 Link_Init->DestBurst | Link_Init->Size ;

    return HAL_OK;
}

/******************************************************************************
*@brief : Set the next node of the linked node.
*@param : Curr: current linked node.
*@param : Next: next linked node.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_SetLinkNext(DMA_LinkTypeDef *Curr, DMA_LinkTypeDef *Next)
{
//	uint32_t temp;
	
	if (Curr == NULL)
        return HAL_ERROR;
	
    Curr->Next = Next;

    return HAL_OK;
}

/******************************************************************************
*@brief : DMA link transfer start.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : Link: First node of linked list.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_Start_Link(DMA_HandleTypeDef *hdma, DMA_LinkTypeDef *Link)
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));

    if (Link == 0)
        return HAL_ERROR;
    
    /* DMA Channel Disable */
    hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_EN;
	
    /* Set source address and desination address */
    hdma->Instance->CHSRCADDR  = Link->SrcAddr;
    hdma->Instance->CHDESTADDR = Link->DestAddr;

    /* Set Next Link */
    hdma->Instance->CHLLI = (uint32_t)Link->Next;

    /* Set Transfer Size */
    hdma->Instance->CHCTRL = Link->Ctrl;

	hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_IHFTC;
	hdma->Instance->CHCONFIG |= DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE;	
	
    if(NULL != hdma->XferHalfCpltCallback)
		hdma->Instance->CHCONFIG |= DMA_CHCONFIG_IHFTC;
    else
		hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_IHFTC;
    
    /* DMA Channel Enable */
    hdma->Instance->CHCONFIG |= DMA_CHCONFIG_EN;

    return HAL_OK;
}


/*********************************************************************************
* Function    : HAL_DMA_TwoBuffer_Start_IT
* Description : Transfer two buffers by DMA, generates interrupt every complete of buffer
* Input       : hdma : pointer to a DMA_HandleTypeDef structure that contains
*                      the configuration information for DMA module
* Input       : pNode: Used for DMA List 
* Input       : p_twobffer_info: two buffer information, running_mode = 1 means DMA will run until halt or disabled by application 
* Output      : 
* Author      : xwl                       Date : 2024-11
**********************************************************************************/
HAL_StatusTypeDef HAL_DMA_TwoBuffer_Start_IT(DMA_HandleTypeDef *hdma, DMA_LinkTypeDef *pNode, DMA_Two_Buffer_TypeDef *p_twobffer_info)
{   
    pNode[0].SrcAddr = p_twobffer_info->SrcAddr1;
    pNode[0].DestAddr = p_twobffer_info->DstAddr1;
    pNode[0].Ctrl = (hdma->Instance->CHCTRL & (~0xFFFU)) | p_twobffer_info->size1;
    pNode[0].Next = &pNode[1];  
    
    pNode[1].SrcAddr = p_twobffer_info->SrcAddr2;
    pNode[1].DestAddr = p_twobffer_info->DstAddr2;
    pNode[1].Ctrl = (hdma->Instance->CHCTRL & (~0xFFFU)) | p_twobffer_info->size2;  
    if (p_twobffer_info->running_always)
    {
        pNode[1].Next = &pNode[0];   
    }
    else
    {
        pNode[1].Next = NULL;  
    }
    
    /* Set source address and desination address */
    hdma->Instance->CHSRCADDR  = pNode[0].SrcAddr;
    hdma->Instance->CHDESTADDR = pNode[0].DestAddr; 

    /* Set Next Link */
    hdma->Instance->CHLLI = (uint32_t)&pNode[1];  

    /* Set Transfer Size */
    hdma->Instance->CHCTRL = (hdma->Instance->CHCTRL & (~0xFFFU)) | p_twobffer_info->size1;  

    /* DMA Channel Enable and enable transfer error interrupt and transfer complete interrupt*/
    hdma->Instance->CHCONFIG |= DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE | DMA_CHCONFIG_EN;  

    return HAL_OK; 
}


/******************************************************************************
*@brief : Abort the DMA Transfer .
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
{
    uint32_t timeout;
    uint32_t ChannelIndex;
    DMA_TypeDef *DmaBaseAddress;
    
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
    
    /* calculation of the channel index */
	if ((uint32_t)(hdma->Instance) < (uint32_t)(DMA2_Channel0))
	{
		ChannelIndex = ((uint32_t)(hdma->Instance) - (uint32_t)(DMA1_Channel0)) >> 5;
		DmaBaseAddress = DMA1;
	}
	else
	{
		ChannelIndex = ((uint32_t)(hdma->Instance) - (uint32_t)(DMA2_Channel0)) >> 5;
		DmaBaseAddress = DMA2;
	}
    
    /* Check the parameters */
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));

    /* DMA Channel Abort */
    hdma->Instance->CHCONFIG |= DMA_CHCONFIG_HALT;
    
    /* Wait until data clearing in FIFO  */
    timeout = DMA_TIMEOUT;
    while (hdma->Instance->CHCONFIG & DMA_CHCONFIG_ACTIVE)
    {
        if (--timeout == 0u)
            break;
    }
    
    hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_HALT;
    
    /* DMA Channel Disable */
    hdma->Instance->CHCONFIG &= ~DMA_CHCONFIG_EN;
    
    /* Disable interrupt */
    hdma->Instance->CHCONFIG &= ~(DMA_CHCONFIG_ITC | DMA_CHCONFIG_IE | DMA_CHCONFIG_IHFTC);
    
    /* Clear TC ERR Falg */
    DmaBaseAddress->INTTCCLR  |= (1U << ChannelIndex) | (1U << (ChannelIndex + 8U));
    DmaBaseAddress->INTERRCLR |= (1U << ChannelIndex);

    /* Wait until the channel is closed  */
    timeout = DMA_TIMEOUT;
    while (DmaBaseAddress->ENCHSTATUS & ChannelIndex)
    {
        if (--timeout == 0u)
            return HAL_TIMEOUT;
    }
    
    return HAL_OK;
}

/******************************************************************************
*@brief : Enable interrupt.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : IT: interrupt
*             This parameter can be a combination of @ref DMA_IT.
*             @arg DMA_IT_TC: transmission completion interrupt.
*             @arg DMA_IT_HTC: indicating half transmission completion interrupt.
*             @arg DMA_IT_ERR: error interrupt.
*             @arg DMA_IT_RAW: raw interrupt.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_EnableIT(DMA_HandleTypeDef *hdma, uint32_t IT)
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_IT(IT));

	if (IT & DMA_IT_RAW)
		hdma->Instance->CHCTRL |= DMA_IT_RAW;
	
	IT &= ~DMA_IT_RAW;
    
	if (IT)
		hdma->Instance->CHCONFIG |= IT;
    
	return HAL_OK;
}

/******************************************************************************
*@brief : Disable interrupt.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : IT: interrupt
*             This parameter can be a combination of @ref DMA_IT.
*             @arg DMA_IT_TC: transmission completion interrupt.
*             @arg DMA_IT_HTC: indicating half transmission completion interrupt.
*             @arg DMA_IT_ERR: error interrupt.
*             @arg DMA_IT_RAW: raw interrupt.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_DisableIT(DMA_HandleTypeDef *hdma, uint32_t IT)
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_IT(IT));

    if (IT & DMA_IT_RAW)
        hdma->Instance->CHCTRL &= ~DMA_IT_RAW;
	
    IT &= ~DMA_IT_RAW;
    
	if (IT)
		hdma->Instance->CHCONFIG &= ~IT;
    
    return HAL_OK;
}

/******************************************************************************
*@brief : Clear the DMA flag.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : Flag: DMA flag
*               This parameter can be a combination of the following:
*               @arg DMA_FLAG_TC: indicating transmission completion interrupt occur.
*               @arg DMA_FLAG_HTC: indicating half transmission completion interrupt occur.
*               @arg DMA_FLAG_ERR: indicating error interrupt occur.
*               @arg DMA_FLAG_RTC: indicating raw transmission completion interrupt occur.
*               @arg DMA_FLAG_RHTC: indicating raw half transmission completion interrupt occur.
*               @arg DMA_FLAG_RERR: indicating raw error interrupt occur.
*@return: HAL status
******************************************************************************/
HAL_StatusTypeDef HAL_DMA_ClearFlag(DMA_HandleTypeDef *hdma, uint32_t Flag)
{
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(Flag != DMA_FLAG_IT);
	assert_param(IS_DMA_FLAG(Flag));

	if (Flag &( DMA_FLAG_TC | DMA_FLAG_RTC))
	{
		hdma->DmaBaseAddress->INTTCCLR = 1UL << hdma->ChannelIndex;
	}
	if (Flag &( DMA_FLAG_HTC | DMA_FLAG_RHTC))
	{
		hdma->DmaBaseAddress->INTTCCLR = 1UL << (hdma->ChannelIndex + 8U);
	}
	if (Flag &( DMA_FLAG_ERR | DMA_FLAG_RERR))
	{
		hdma->DmaBaseAddress->INTERRCLR = 1UL << hdma->ChannelIndex;
	}
	
	return HAL_OK;
}

/******************************************************************************
*@brief : Returns the DMA flag.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : Flag: DMA flag
*               This parameter can be a combination of the following:
*               @arg DMA_FLAG_IT: indicating transmission completion interrupt or error interrupt occur.
*               @arg DMA_FLAG_TC: indicating transmission completion interrupt occur.
*               @arg DMA_FLAG_HTC: indicating half transmission completion interrupt occur.
*               @arg DMA_FLAG_ERR: indicating error interrupt occur.
*               @arg DMA_FLAG_RTC: indicating raw transmission completion interrupt occur.
*               @arg DMA_FLAG_RHTC: indicating raw half transmission completion interrupt occur.
*               @arg DMA_FLAG_RERR: indicating raw error interrupt occur.
*@return: DMA flag
******************************************************************************/
FlagStatus HAL_DMA_GetFlag(DMA_HandleTypeDef *hdma, uint32_t Flag)
{
    uint32_t Status;
    
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_FLAG(Flag));

    Status = 0;
	if (Flag & DMA_FLAG_IT)
	{
		if (hdma->DmaBaseAddress->INTSTATUS & (1U << hdma->ChannelIndex))
            Status |= DMA_FLAG_IT;
	}
    
	if (Flag & DMA_FLAG_TC)
	{
		if (hdma->DmaBaseAddress->INTTCSTATUS & (1U << hdma->ChannelIndex))
            Status |= DMA_FLAG_TC;
	}
	if (Flag & DMA_FLAG_HTC)
	{
		if (hdma->DmaBaseAddress->INTTCSTATUS & (1U << (hdma->ChannelIndex + 8U)))
            Status |= DMA_FLAG_HTC;
	}
	if (Flag & DMA_FLAG_ERR)
	{
		if (hdma->DmaBaseAddress->INTERRSTATUS & (1U << hdma->ChannelIndex))
            Status |= DMA_FLAG_ERR;
	}
	if (Flag & DMA_FLAG_RTC)
	{
		if (hdma->DmaBaseAddress->RAWINTTCSTATUS & (1U << hdma->ChannelIndex))
            Status |= DMA_FLAG_RTC;
	}
	if (Flag & DMA_FLAG_RHTC)
	{
		if (hdma->DmaBaseAddress->RAWINTTCSTATUS & (1U << (hdma->ChannelIndex + 8U)))
            Status |= DMA_FLAG_RHTC;
	}
	if (Flag & DMA_FLAG_RERR)
	{
		if (hdma->DmaBaseAddress->RAWINTERRSTATUS & (1U << hdma->ChannelIndex))
            Status |= DMA_FLAG_RERR;
	}
	
	return (Status);
}

/******************************************************************************
*@brief : Returns the DMA state.
*@param : hdma: pointer to a DMA_HandleTypeDef structure that contains
*               the configuration information for the specified DMA Channel.
*@param : Flag: DMA flag
*               This parameter can be a combination of @ref DMA_Flag.
*               @arg DMA_FLAG_IT: indicating transmission completion interrupt or error interrupt occur.
*               @arg DMA_FLAG_TC: indicating transmission completion interrupt occur.
*               @arg DMA_FLAG_HTC: indicating half transmission completion interrupt occur.
*               @arg DMA_FLAG_ERR: indicating error interrupt occur.
*               @arg DMA_FLAG_RTC: indicating raw transmission completion interrupt occur.
*               @arg DMA_FLAG_RHTC: indicating raw half transmission completion interrupt occur.
*               @arg DMA_FLAG_RERR: indicating raw error interrupt occur.
*@return: DMA status
******************************************************************************/
FlagStatus HAL_DMA_GetState(DMA_HandleTypeDef *hdma, uint32_t Flag)
{
    uint32_t Status;
    
    /* Check the parameters */
	assert_param(IS_DMA_HANDLE(hdma));
	assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
	assert_param(IS_DMA_STATE(Flag));

	if (Flag == DMA_FLAG_IT)
	{
		Status = hdma->DmaBaseAddress->INTSTATUS & (1U << hdma->ChannelIndex);
	}
	else if (Flag == DMA_FLAG_TC)
	{
		Status = hdma->DmaBaseAddress->INTTCSTATUS & (1U << hdma->ChannelIndex);
	}
	else if (Flag == DMA_FLAG_HTC)
	{
		Status = hdma->DmaBaseAddress->INTTCSTATUS & (1U << (hdma->ChannelIndex + 8U));
	}
	else if (Flag == DMA_FLAG_ERR)
	{
		Status = hdma->DmaBaseAddress->INTERRSTATUS & (1U << hdma->ChannelIndex);
	}
	else if (Flag == DMA_FLAG_RTC)
	{
		Status = hdma->DmaBaseAddress->RAWINTTCSTATUS & (1U << hdma->ChannelIndex);
	}
	else if (Flag == DMA_FLAG_RHTC)
	{
		Status = hdma->DmaBaseAddress->RAWINTTCSTATUS & (1U << (hdma->ChannelIndex + 8U));
	}
	else if (Flag == DMA_FLAG_RERR)
	{
		Status = hdma->DmaBaseAddress->RAWINTERRSTATUS & (1U << hdma->ChannelIndex);
	}
	else
		Status = 0;
	
	if (Status)
		return (SET);
	else
		return (RESET);
}

#endif /* HAL_DMA_MODULE_ENABLED */

/************************ (C) COPYRIGHT AISINOCHIP *****END OF FILE****/

