/**
* @file         spv40xx_hal_dma.c
* @brief        DMA HAL module driver.
* @details
  *          This file provides firmware functions to manage the following
  *          functionalities of the Direct Memory Access (DMA) peripheral:
  *           + Initialization and de-initialization functions
  *           + IO operation functions
  *           + Peripheral State functions
* @author       涂龙
* @date         2023-05-10 14:16
* @version      V0.0
* @copyright    Copyright (c) 2017-2023  SpaceTouch Inc.
*/

#include "hal_dma.h"
#include "hal_def.h"
#include  "hal_gpio.h"
#include "debug.h"
static void DMA_SetConfig(DMA_HandleTypeDef *hdma,
                          uint32_t srca_ddress,
                          uint32_t dst_address,
                          uint32_t data_length);


/**
* @brief    通过在DMA_HandleTypeDef中的参数初始化dma，和关联中断回调函数
* @details  会将dma状态切回HAL_DMA_STATE_READY状态，关闭dma中断
* @param    hdma    DMA_HandleTypeDef结构体指针
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_OK：     成功
*
* @note     无论dma处于什么状态，都会强行切回ready状态。如果对应dma正在搬运数据，会中止搬运。
*/
HAL_StatusTypeDef hal_dma_init(DMA_HandleTypeDef *hdma)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    assert_param(IS_DMA_CHANNEL(hdma->init.channel));
    assert_param(IS_DMA_INC_STATE(hdma->init.src_inc));
    assert_param(IS_DMA_INC_STATE(hdma->init.dst_inc));
    assert_param(IS_DMA_DATA_WIDTH(hdma->init.src_data_width));
    assert_param(IS_DMA_DATA_WIDTH(hdma->init.dst_data_width));
    assert_param(IS_DMA_DATA_LOCATION(hdma->init.src_data_loc));
    assert_param(IS_DMA_DATA_LOCATION(hdma->init.dst_data_loc));
    assert_param(IS_DMA_MEMORY_BURST(hdma->init.memory_burst));
    assert_param(IS_DMA_MODE(hdma->init.mode));
    assert_param(IS_DMA_PRIORITY(hdma->init.priority));
    hdma->init.channel = DMA_CHANNLE_DEFAULT;
    hdma->state = HAL_DMA_STATE_READY;
    return HAL_OK;
}

/**
* @brief    去初始化dma
* @details  将对应dma寄存器复位,错误码复位，状态复位 HAL_DMA_STATE_RESET
* @param    hdma    DMA_HandleTypeDef结构体指针
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_READY状态进行初始化
*           HAL_OK：     成功
*
* @note     只有对应dma处于HAL_DMA_STATE_READY状态，去初始化才能成功
*/
HAL_StatusTypeDef hal_dma_deinit(DMA_HandleTypeDef *hdma)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

//  HAL_DMA_StateTypeDef dma_status=hal_dma_get_state(hdma);
//  /* Check the DMA peripheral state */
//  if(dma_status != HAL_DMA_STATE_READY )
//  {
//      /* Return error status */
//      return HAL_BUSY;
//  }
//  DEV_CMU->CLKEN0 &= ~DEV_CMU_CLKEN0_DMA;
//  DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_DMA;
//  DEV_RMU->RSTEN0 |=  DEV_RMU_RSTEN0_DMA;
//  DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_DMA;
    __HAL_DMA_DISABLE(hdma);
    uint32_t chx = hdma->init.channel;

    if (chx >= DMA_CHANNLE_DEFAULT)
    {
        return HAL_ERROR;
    }

    DEV_DMAC->DMA_CHN[chx].SSA = 0;
    DEV_DMAC->DMA_CHN[chx].SOA = 0;
    DEV_DMAC->DMA_CHN[chx].DSA = 0;
    DEV_DMAC->DMA_CHN[chx].DOA = 0;
    DEV_DMAC->DMA_CHN[chx].CFG = 0;
    DEV_DMAC->DMA_CHN[chx].LEN = 0;
    DEV_GLOBAL->DVDD_GLOBAL7 &= ~((DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx);
    DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
    DEV_DMAC->DMA_PD = ((DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx);
    hdma->xfer_cplt_callback = NULL;
    hdma->xfer_half_cplt_callback = NULL;
    hdma->state = HAL_DMA_STATE_RESET;
    hal_dma_ch_free(hdma, NULL);
    return HAL_OK;
}

/**
* @brief    开始dma搬运
* @details  在init函数后，只需要填入源地址，目的地址，搬运长度就可搬运数据，不会产生中断。
* @param    hdma：     DMA_HandleTypeDef结构体指针
*           srca_ddress：源地址，可以是内存地址或外设fifo地址
*           dst_address：目的地址，可以是内存地址或外设地址
*           data_length：单次从源空间搬运至目的空间的数据长度，单位byte，最大65536。但当数据宽度是24bit时，最大49152
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_READY状态开始dma
*           HAL_OK：     成功
*
* @note     单次搬运数据长度最大64kbyte，但当数据宽度时24bit，而非8，16，32bit时，最大搬运48kbyte
* @note     只有在准备状态HAL_DMA_STATE_READY下的dma才可以开始搬运数据。
*/
HAL_StatusTypeDef hal_dma_start(DMA_HandleTypeDef *hdma, uint32_t srca_ddress, uint32_t dst_address, uint32_t data_length, void *param)
{
    HAL_StatusTypeDef status = HAL_OK;
    assert_param(IS_DMA_BUFFER_SIZE(data_length));

    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    //rt_kprintf("1DEV_GLOBAL->DVDD_GLOBAL7:%x\r\n",DEV_GLOBAL->DVDD_GLOBAL7);
    //rt_kprintf("1hdma->init.channel:%x\r\n",hdma->init.channel);
    if (HAL_OK != hal_dma_ch_alloc(hdma, param))
    {
        return HAL_ERROR;
    }

    //rt_kprintf("2DEV_GLOBAL->DVDD_GLOBAL7:%x\r\n",DEV_GLOBAL->DVDD_GLOBAL7);
    //rt_kprintf("2hdma->init.channel:%x\r\n",hdma->init.channel);
    __HAL_DMA_DISABLE(hdma);
    uint32_t chx = hdma->init.channel;
    DEV_GLOBAL->DVDD_GLOBAL7 &= ~((DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx);
    DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
    //DEV_DMAC->DMA_IE &= ~((DMA_Half_Transfer_End|DMA_Transfer_End)<<chx);
    DEV_DMAC->DMA_PD = (DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx;
    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    //rt_kprintf("3DEV_GLOBAL->DVDD_GLOBAL7:%x\r\n",DEV_GLOBAL->DVDD_GLOBAL7);
    //rt_kprintf("3hdma->init.channel:%x\r\n",hdma->init.channel);
    if (HAL_DMA_STATE_READY == dma_status)
    {
        hdma->state = HAL_DMA_STATE_BUSY;
        DMA_SetConfig(hdma, srca_ddress, dst_address, data_length);
        __HAL_DMA_ENABLE(hdma);
    }
    else
    {
        /* Return error status */
        status = HAL_BUSY;
    }

    return status;
}
/**
* @brief    在中断使能情况下开始dma搬运
* @details  在init函数后，只需要填入源地址，目的地址，搬运长度就可搬运数据，会产生中断，并在中断处理函数中调用搬运完成和半完成回调函数。
* @param    hdma：     DMA_HandleTypeDef结构体指针
*           srca_ddress：源地址，可以是内存地址或外设fifo地址
*           dst_address：目的地址，可以是内存地址或外设地址
*           data_length：单次从源空间搬运至目的空间的数据长度，单位byte，最大65536。但当数据宽度是24bit时，最大49152
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空，或此搬运数量半完成中断不可配
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_READY状态开始dma
*           HAL_OK：     成功
*
* @note     单次搬运数据长度最大64kbyte，但当数据宽度时24bit，而非8，16，32bit时，最大搬运48kbyte
* @note     只有在准备状态HAL_DMA_STATE_READY下的dma才可以开始搬运数据。
* @note     ！！！当搬运数据data_length为奇数搬运单位，没有半搬运完成中断。
*/
__ILM HAL_StatusTypeDef hal_dma_start_it(DMA_HandleTypeDef *hdma, uint32_t src_address, uint32_t dst_address, uint32_t data_length, void *param)
{
    HAL_StatusTypeDef status = HAL_OK;
    assert_param(IS_DMA_BUFFER_SIZE(data_length));

    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    if (HAL_OK != hal_dma_ch_alloc(hdma, param))
    {
        return HAL_ERROR;
    }

    __HAL_DMA_DISABLE(hdma);
    uint32_t chx = hdma->init.channel;
    DEV_DMAC->DMA_PD = (DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx;
    DEV_GLOBAL->DVDD_GLOBAL7 &= ~((DMA_Half_Transfer_End | DMA_Transfer_End) << chx);
    DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    if (HAL_DMA_STATE_READY == dma_status)
    {
        hdma->state = HAL_DMA_STATE_BUSY;
        uint32_t chx = hdma->init.channel;
        DMA_SetConfig(hdma, src_address, dst_address, data_length);
        DEV_DMAC->DMA_PD = (DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx;
        DEV_GLOBAL->DVDD_GLOBAL7 |= (DMA_Transfer_End << chx);
        DEV_GLOBAL->DVDD_GLOBAL7 &= ~(DMA_Half_Transfer_End << chx);
        DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;

        if (hdma->xfer_half_cplt_callback != NULL)
        {
            if (hdma->xfer_half_cplt_flag)
            {
                DEV_GLOBAL->DVDD_GLOBAL7 |= (DMA_Half_Transfer_End << chx);
                DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
            }
            else
            {
                status = HAL_ERROR;
            }
        }

        __HAL_DMA_ENABLE(hdma);
    }
    else
    {
        status = HAL_BUSY;
    }

    return status;
}
/**
* @brief    中止dma搬运
* @details  中止正在搬运的dma，并关闭中断，回到准备状态HAL_DMA_STATE_READY。
* @param    hdma    DMA_HandleTypeDef结构体指针
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_BUSY状态中止搬运
*           HAL_OK：     成功
*
* @note     只有处于忙状态HAL_DMA_STATE_BUSY的dma经行中止操作
* @note     中止搬运后，目的数据应认为无效
*/
HAL_StatusTypeDef hal_dma_abort(DMA_HandleTypeDef *hdma)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    if (dma_status != HAL_DMA_STATE_BUSY)
    {
        return HAL_BUSY;
    }
    else
    {
        uint32_t chx = hdma->init.channel;
        DEV_GLOBAL->DVDD_GLOBAL7 &= ~((DMA_Half_Transfer_End | DMA_Transfer_End) << chx);
        DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
        __HAL_DMA_DISABLE(hdma);
        DEV_DMAC->DMA_PD = (DMA_Slot_Transfer_End | DMA_Half_Transfer_End | DMA_Transfer_End) << chx;
        hdma->state = HAL_DMA_STATE_READY;
    }

    return HAL_OK;
}
/**
* @brief    暂停dma搬运
* @details  暂停dma搬运，将状态切至暂停状态HAL_DMA_STATE_PAUSE
* @param    hdma    DMA_HandleTypeDef结构体指针
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_BUSY状态暂停搬运
*           HAL_OK：     成功
*
* @note     只有在忙状态HAL_DMA_STATE_BUSY的dma可以经行暂停操作
* @note     hal_dma_pause暂停的dma搬运，使用hal_dma_resume函数后可接停止处，继续完成搬运
*/
HAL_StatusTypeDef hal_dma_pause(DMA_HandleTypeDef *hdma)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    if (dma_status != HAL_DMA_STATE_BUSY)
    {
        return HAL_BUSY;
    }
    else
    {
        __HAL_DMA_PAUSE(hdma);
        hdma->state = HAL_DMA_STATE_PAUSE;
    }

    return HAL_OK;
}
/**
* @brief    恢复dma搬运
* @details  从暂停状态下，恢复搬运
* @param    hdma    DMA_HandleTypeDef结构体指针
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_PAUSE状态恢复搬运
*           HAL_OK：     成功
*
* @note     只有暂停状态HAL_DMA_STATE_PAUSE下的dma可以经行恢复操作
* @note     hal_dma_pause暂停的dma搬运，使用hal_dma_resume函数后可接停止处，继续完成搬运
*/
HAL_StatusTypeDef hal_dma_resume(DMA_HandleTypeDef *hdma)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    if (dma_status != HAL_DMA_STATE_PAUSE)
    {
        return HAL_BUSY;
    }
    else
    {
        __HAL_DMA_RESUME(hdma);
        hdma->state = HAL_DMA_STATE_BUSY;
    }

    return HAL_OK;
}

__ILM void hal_dma_handle(void)
{
    for (uint32_t i = 0; i < TOTAL_DMA_CH_NUM ; i++)
    {
        if (dma_ch_status[i].handle == NULL)
        {
            continue;
        }

        if (dma_ch_status[i].handle->init.channel < DMA_CHANNLE_DEFAULT)
        {
            hal_dma_irqhandler(dma_ch_status[i].handle, dma_ch_status[i].param);

            if (dma_ch_status[i].handle->init.mode == DMA_Mode_Single)
            {
                dma_ch_status[i].ch_status = CH_FREE;
            }
        }
    }
}
/**
* @brief    处理dma中断需求
* @details  根据情况调用搬运完成回调函数和半完成回调函数。对于单次搬运模式，在完成中断处理后，会将中断关闭。
* @param    hdma    DMA_HandleTypeDef结构体指针
* @return   None
*
* @note     此函数需要在dma的函数中调用。
*/
__ILM void hal_dma_irqhandler(DMA_HandleTypeDef *hdma, void *param)
{
    if (hdma == NULL)
    {
        return;
    }

    uint32_t chx = hdma->init.channel;

    // IE的half transfer 只可写，不可读
    //if(__HAL_DMA_GET_IT_SOURCE(hdma,DMA_HALF_TRANSFER_END) != RESET)
    //if((hdma->xfer_half_cplt_callback != NULL) && (hdma->xfer_half_cplt_flag!=0))
    if ((DEV_GLOBAL->DVDD_GLOBAL7 & (DMA_Half_Transfer_End << chx)) != RESET)
    {
        if ((DEV_DMAC->DMA_PD & (DMA_Half_Transfer_End << chx)) != RESET)
        {
            DEV_DMAC->DMA_PD = DMA_Half_Transfer_End << chx;

            /* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
            if (DEV_DMAC->DMA_CHN[chx].CFG_f.RELOAD == 0)
            {
                DEV_GLOBAL->DVDD_GLOBAL7 &= ~(DMA_Half_Transfer_End << chx);
                DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
            }

            if (hdma->xfer_half_cplt_callback != NULL)
            {
                /* Half transfer callback */
                hdma->xfer_half_cplt_callback(hdma, param);
            }
        }
    }

    if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_Transfer_End) != RESET)
    {
        if ((DEV_DMAC->DMA_PD & (DMA_Transfer_End << chx)) != RESET)
        {
            /* Clear all interrupt flags */
            DEV_DMAC->DMA_PD = ((DMA_Transfer_End | DMA_Slot_Transfer_End) << chx);

            /* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */
            if (DEV_DMAC->DMA_CHN[chx].CFG_f.RELOAD == 0)
            {
                DEV_DMAC->DMA_PD = (DMA_Transfer_End << chx);
                DEV_GLOBAL->DVDD_GLOBAL7 &= ~(DMA_Transfer_End << chx);
                DEV_DMAC->DMA_IE = DEV_GLOBAL->DVDD_GLOBAL7;
                hdma->state = HAL_DMA_STATE_READY;
            }

            if (hdma->xfer_cplt_callback != NULL)
            {
                /* Half transfer callback */
                hdma->xfer_cplt_callback(hdma, param);
            }
        }
    }
}
/**
* @brief    注册回调函数
* @details  None
* @param    hdma        DMA_HandleTypeDef结构体指针
*           CallbackID  用户回调标识。
*           pcall_back  回调函数指针。
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空，或此搬运数量半完成中断不可配
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_READY状态修改回调函数
*           HAL_OK：     成功
*
* @note     只可在准备状态下修改回调函数。
*           ！！！当搬运数据为奇数搬运单位，没有半搬运完成中断。
*/
HAL_StatusTypeDef hal_dma_register_callback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef callback_id, void (* pcall_back)(struct __DMA_HandleTypeDef *hdma, void *param))
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    HAL_StatusTypeDef status = HAL_OK;
    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    if (HAL_DMA_STATE_READY == dma_status)
    {
        switch (callback_id)
        {
        case  HAL_DMA_XFER_CPLT_CB_ID:
            hdma->xfer_cplt_callback = pcall_back;
            break;

        case HAL_DMA_XFER_HALFCPLT_CB_ID:
            hdma->xfer_half_cplt_callback = pcall_back;

            if (hdma->xfer_half_cplt_flag == 0)
            {
                status =  HAL_ERROR;
            }

            break;

        default:
            break;
        }
    }
    else
    {
        status =  HAL_BUSY;
    }

    return status;
}
/**
* @brief    取消注册回调函数
* @details  None
* @param    hdma        DMA_HandleTypeDef结构体指针
*           CallbackID  用户回调标识。
* @return   HAL_ERROR：失败，对应dma操作结构体指针为空
*           HAL_BUSY： 失败，在非HAL_DMA_STATE_READY状态修改回调函数
*           HAL_OK：     成功
* @return
*
* @note
*/
HAL_StatusTypeDef hal_dma_unregister_callback(DMA_HandleTypeDef *hdma, HAL_DMA_CallbackIDTypeDef CallbackID)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    HAL_StatusTypeDef status = HAL_OK;
    HAL_DMA_StateTypeDef dma_status = hal_dma_get_state(hdma);

    if (HAL_DMA_STATE_READY == dma_status)
    {
        switch (CallbackID)
        {
        case  HAL_DMA_XFER_CPLT_CB_ID:
            hdma->xfer_cplt_callback = NULL;
            break;

        case HAL_DMA_XFER_HALFCPLT_CB_ID:
            hdma->xfer_half_cplt_callback = NULL;
            break;

        case HAL_DMA_XFER_ALL_CB_ID:
            hdma->xfer_cplt_callback = NULL;
            hdma->xfer_half_cplt_callback = NULL;
            break;

        default:
            status = HAL_ERROR;
            break;
        }
    }
    else
    {
        status = HAL_BUSY;
    }

    return status;
}
/**
* @brief    获取dma状态
* @details
* @param    hdma        DMA_HandleTypeDef结构体指针
* @return   dma状态 HAL_DMA_StateTypeDef
*
* @note     不对hdma指针为空检测
*/
HAL_DMA_StateTypeDef hal_dma_get_state(DMA_HandleTypeDef *hdma)
{
    HAL_DMA_StateTypeDef status;
    status = hdma->state;

    if (status == HAL_DMA_STATE_BUSY)
    {
        uint32_t chx = hdma->init.channel;

        if ((DEV_DMAC->DMA_EN & (1UL << (chx))) == RESET)
        {
            status = HAL_DMA_STATE_READY;
            hdma->state = HAL_DMA_STATE_READY;
        }
    }

    return status;
}


HAL_DMA_Handle_CH_TypeDef   dma_ch_status[TOTAL_DMA_CH_NUM];
HAL_StatusTypeDef  hal_dma_ch_alloc(DMA_HandleTypeDef *hdma, void *param)
{
    uint32_t result, temp_ch = DMA_CHANNLE_DEFAULT;
    uint32_t priority_min = DMA_CHANNLE_DEFAULT;

    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    /*如果该句柄没分配通道号，检查通道号码列表中是否有未被分配的通道，如果有则直接分配,如果没有，则找一个优先级最低的空闲通道分配*/
    /*如果该句柄有分配好的通道号，检查通道号当前是否为空闲：
     *如果空闲，则直接使用，
     *如果不空闲，则找一个优先级最低的空闲通道*/
    if (hdma->init.channel < DMA_CHANNLE_DEFAULT) /*之前有配过通道*/
    {
        return HAL_OK;/*直接使用*/
    }
    else/*首次使用，先分配一个通道*/
    {
        for (uint8_t i = 0; i < TOTAL_DMA_CH_NUM; i++)
        {
            if (dma_ch_status[i].handle == NULL) /*如果有通道为未注册状态，直接注册使用*/
            {
                dma_ch_status[i].ch = i;
                dma_ch_status[i].handle = hdma;
                dma_ch_status[i].ch_status = CH_BUSY;
                dma_ch_status[i].handle->init.channel = i;
                dma_ch_status[i].param = param;
                return HAL_OK;
            }
        }

        /*没有找到未被注册的通道,则抢占一个优先级最低通道*/
        result = 0;

        for (uint8_t i = 0; i < TOTAL_DMA_CH_NUM; i++)
        {
            if ((priority_min < dma_ch_status[i].handle->init.priority) && (dma_ch_status[i].ch_status = CH_FREE)) /*数字越大，优先级越高*/
            {
                priority_min = dma_ch_status[i].handle->init.priority;
                temp_ch = dma_ch_status[i].handle->init.channel;
                result = 1;
            }
        }

        /*已经找到低优先级的通道了，然后抢占它*/
        if (result)
        {
            dma_ch_status[temp_ch].handle->init.channel = DMA_CHANNLE_DEFAULT;/*清除原始通道*/
            dma_ch_status[temp_ch].handle = hdma;
            dma_ch_status[temp_ch].ch_status = CH_BUSY;
            dma_ch_status[temp_ch].handle->init.channel = temp_ch;
            dma_ch_status[temp_ch].param = param;
            return HAL_OK;
        }
        else
        {
            return HAL_BUSY;
        }
    }

    return HAL_ERROR;
}

HAL_StatusTypeDef  hal_dma_ch_free(DMA_HandleTypeDef *hdma, void *param)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    for (uint8_t i = 0; i < TOTAL_DMA_CH_NUM; i++)
    {
        if (hdma == dma_ch_status[i].handle)
        {
            hdma->init.channel = DMA_CHANNLE_DEFAULT;
            dma_ch_status[i].handle->init.channel = DMA_CHANNLE_DEFAULT;/*清除原始通道*/
            dma_ch_status[i].handle = NULL;
            dma_ch_status[i].ch_status = CH_FREE;
            dma_ch_status[i].param = param;
            return HAL_OK;
        }
    }

    return HAL_ERROR;
}

HAL_StatusTypeDef hal_dma_set_default(DMA_HandleTypeDef *hdma, void *param)
{
    if (hdma == NULL)
    {
        return HAL_ERROR;
    }

    hdma->init.channel = DMA_CHANNLE_DEFAULT;
    return HAL_OK;
}

uint32_t hal_dma_get_pd(uint32_t chx)
{
    return (DEV_DMAC->DMA_PD & (1 << chx));
}
void hal_dma_clear_pd(uint32_t chx)
{
    DEV_DMAC->DMA_PD = (1 << chx);
}

typedef enum
{
    DMA_SPI0_TX_ADDR = (uint32_t)(&DEV_SPI0->TX_DATA),
    DMA_SPI1_TX_ADDR = (uint32_t)(&DEV_SPI1->TX_DATA),
    DMA_UART0_TX_ADDR = (uint32_t)(&DEV_UART0->TX_DAT),
    DMA_UART1_TX_ADDR = (uint32_t)(&DEV_UART1->TX_DAT),
    DMA_UART2_TX_ADDR = (uint32_t)(&DEV_UART2->TX_DAT),
    DMA_ASI0_TX_ADDR = (uint32_t)(&DEV_ASI0->TX_BUF),
    DMA_ASI1_TX_ADDR = (uint32_t)(&DEV_ASI1->TX_BUF),
    DMA_PWM_FIFO0_TX_ADDR = (uint32_t)(&DEV_PWM->PWM0_TX_DAT),
    DMA_PWM_FIFO1_TX_ADDR = (uint32_t)(&DEV_PWM->PWM2_TX_DAT),
    DMA_SDC_TX_ADDR = (uint32_t)(0x200C0000UL + 0x200UL),
    DMA_DAC_TX_ADDR = (uint32_t)(&DEV_DAC->TBUF),
    DMA_SRC_CH0_TX_ADDR = (uint32_t)(&DEV_SRC->CHN[0].WBUF),
    DMA_SRC_CH1_TX_ADDR = (uint32_t)(&DEV_SRC->CHN[1].WBUF),
    DMA_USB_TX1_ADDR = (uint32_t)(0x200d000UL + 0x24UL),
    DMA_USB_TX2_ADDR = (uint32_t)(0x200d000UL + 0x28UL),
    DMA_USB_TX3_ADDR = (uint32_t)(0x200d000UL + 0x28UL),
    DMA_USB_TX4_ADDR = (uint32_t)(0x200d000UL + 0x30UL),
    DMA_USB_TX5_ADDR = (uint32_t)(0x200d000UL + 0x34UL),
    DMA_USB_TX6_ADDR = (uint32_t)(0x200d000UL + 0x38UL),
    DMA_USB_TX7_ADDR = (uint32_t)(0x200d000UL + 0x3cUL),
    DMA_UART3_TX_ADDR = (uint32_t)(&DEV_UART3->TX_DAT),

    DMA_SPI0_RX_ADDR = (uint32_t)(&DEV_SPI0->RX_DATA),
    DMA_SPI1_RX_ADDR = (uint32_t)(&DEV_SPI1->RX_DATA),
    DMA_UART0_RX_ADDR = (uint32_t)(&DEV_UART0->RX_DAT),
    DMA_UART1_RX_ADDR = (uint32_t)(&DEV_UART1->RX_DAT),
    DMA_UART2_RX_ADDR = (uint32_t)(&DEV_UART2->RX_DAT),
    DMA_ASI0_RX_ADDR = (uint32_t)(&DEV_ASI0->RX_BUF),
    DMA_ASI1_RX_ADDR = (uint32_t)(&DEV_ASI1->RX_BUF),
    DMA_SDC_RX_ADDR = (uint32_t)(0x200C0000UL + 0x200UL),
    DMA_ADC_RX_ADDR = (uint32_t)(&DEV_ADC->RBUF),
    DMA_NOR_RX_ADDR = (uint32_t)(&DEV_NORC->SOFT_DATA),
    DMA_SRC_CH0_RX_ADDR = (uint32_t)(&DEV_SRC->CHN[0].RBUF),
    DMA_SRC_CH1_RX_ADDR = (uint32_t)(&DEV_SRC->CHN[1].RBUF),
    DMA_USB_RX1_ADDR = (uint32_t)(0x200d000UL + 0x24UL),
    DMA_USB_RX2_ADDR = (uint32_t)(0x200d000UL + 0x28UL),
    DMA_USB_RX3_ADDR = (uint32_t)(0x200d000UL + 0x2cUL),
    DMA_USB_RX4_ADDR = (uint32_t)(0x200d000UL + 0x30UL),
    DMA_USB_RX5_ADDR = (uint32_t)(0x200d000UL + 0x34UL),
    DMA_USB_RX6_ADDR = (uint32_t)(0x200d000UL + 0x38UL),
    DMA_USB_RX7_ADDR = (uint32_t)(0x200d000UL + 0x3cUL),
    DMA_TIMER0_RX_ADDR = (uint32_t)(&DEV_TIMER->TIMER[0].CAP),
    DMA_TIMER1_RX_ADDR = (uint32_t)(&DEV_TIMER->TIMER[1].CAP),
    DMA_TIMER2_RX_ADDR = (uint32_t)(&DEV_TIMER->TIMER[2].CAP),
    DMA_TIMER3_RX_ADDR = (uint32_t)(&DEV_TIMER->TIMER[3].CAP),
    DMA_CAMERA_RX_ADDR = (uint32_t)(&DEV_CAMERA->RX_DATA),
    DMA_UART3_RX_ADDR = (uint32_t)(&DEV_UART3->RX_DAT),
} DMA_PeripheralAddrEnum;


#define DMA_PERIPHERAL_ADDR_TABLE_LEN 31UL
const static uint32_t DMA_PeripheralAddrTable[DMA_PERIPHERAL_ADDR_TABLE_LEN][3] =
{
    {DMA_SPI0_TX_ADDR, DMA_SPI0_RX_ADDR, 0xffffffffUL},
    {DMA_SPI1_TX_ADDR, DMA_SPI1_RX_ADDR, 0xffffffffUL},
    {DMA_UART0_TX_ADDR, DMA_UART0_RX_ADDR, 0xffffffffUL},
    {DMA_UART1_TX_ADDR, DMA_UART1_RX_ADDR, 0xffffffffUL},
    {DMA_UART2_TX_ADDR, DMA_UART2_RX_ADDR, 0xffffffffUL},
    {DMA_ASI0_TX_ADDR, DMA_ASI0_RX_ADDR, 0xffffffffUL},
    {DMA_ASI1_TX_ADDR, DMA_ASI1_RX_ADDR, 0xffffffffUL},
    {DMA_PWM_FIFO0_TX_ADDR, 0xffffffffUL, 0xffffffffUL},
    {DMA_PWM_FIFO1_TX_ADDR, 0xffffffffUL, 0xffffffffUL},
    {DMA_SDC_TX_ADDR, DMA_SDC_RX_ADDR, 0xffffffffUL},
    {DMA_DAC_TX_ADDR, DMA_ADC_RX_ADDR, DMA_ADC_RX_ADDR + 2},
    {0xffffffffUL, DMA_NOR_RX_ADDR, 0xffffffffUL},
    {DMA_SRC_CH0_TX_ADDR, DMA_SRC_CH0_RX_ADDR, 0xffffffffUL},
    {DMA_SRC_CH1_TX_ADDR, DMA_SRC_CH1_RX_ADDR, 0xffffffffUL},
    {0xffffffffUL, 0xffffffffUL, 0xffffffffUL},
    {0xffffffffUL, 0xffffffffUL, 0xffffffffUL},
    {DMA_USB_TX1_ADDR, DMA_USB_RX1_ADDR, 0xffffffffUL},
    {DMA_USB_TX2_ADDR, DMA_USB_RX2_ADDR, 0xffffffffUL},
    {DMA_USB_TX3_ADDR, DMA_USB_RX3_ADDR, 0xffffffffUL},
    {DMA_USB_TX4_ADDR, DMA_USB_RX4_ADDR, 0xffffffffUL},
    {DMA_USB_TX5_ADDR, DMA_USB_RX5_ADDR, 0xffffffffUL},
    {DMA_USB_TX6_ADDR, DMA_USB_RX6_ADDR, 0xffffffffUL},
    {DMA_USB_TX7_ADDR, DMA_USB_RX7_ADDR, 0xffffffffUL},
    {0xffffffffUL, 0xffffffffUL, 0xffffffffUL},
    {0xffffffffUL, DMA_TIMER0_RX_ADDR, 0xffffffffUL},
    {0xffffffffUL, DMA_TIMER1_RX_ADDR, 0xffffffffUL},
    {0xffffffffUL, DMA_TIMER2_RX_ADDR, 0xffffffffUL},
    {0xffffffffUL, DMA_TIMER3_RX_ADDR, 0xffffffffUL},
    {0xffffffffUL, DMA_CAMERA_RX_ADDR, 0xffffffffUL},
    {DMA_UART3_TX_ADDR, DMA_UART3_RX_ADDR, 0xffffffffUL},
    {0xffffffffUL, 0xffffffffUL, 0xffffffffUL},
};
/**
* @brief        根据地址获取DMA device interface select 值
* @details      根据地址判断是否为外设fifo地址。根据地址获取ifs
* @param        addr: 空间地址
* @return       none
* @note         不对外调用
*/
static int32_t dma_set_ifs(uint32_t addr)
{
    int32_t i = 0;

    for (i = 0; i < DMA_PERIPHERAL_ADDR_TABLE_LEN; i++)
    {
        if ((addr == DMA_PeripheralAddrTable[i][0])
                || (addr == DMA_PeripheralAddrTable[i][1]) ||
                (addr == DMA_PeripheralAddrTable[i][2]))
        {
            break;
        }
    }
    return i;
}

/**
* @brief        配置dma通道，配置参数在结构体 hdma->init 中
* @details      只支持连续最大64kbyte空间的搬运（24bit时最大48kbyte）
* @param        hdma：     DMA_HandleTypeDef结构体指针
*               srca_ddress：源地址，可以是内存地址或外设fifo地址
*               dst_address：目的地址，可以是内存地址或外设地址
*               data_length：单次从源空间搬运至目的空间的数据长度，单位byte，最大65536。但当数据宽度是24bit时，最大49152
* @return       none
* @note         64kbyte空间的搬运，24bit时最大48kbyte
* @note         不对外调用
*/
static void DMA_SetConfig(DMA_HandleTypeDef *hdma,
                          uint32_t srca_ddress,
                          uint32_t dst_address,
                          uint32_t data_length)
{
    uint32_t src_addr, dst_addr;
    uint32_t src_burst, dst_burst;
    uint32_t src_ifs, dst_ifs;
    uint32_t src_type, dst_type;
    uint32_t src_data_size, dst_data_size;
    uint32_t src_total_size, dst_total_size;
    uint32_t half_flag = 0UL; //1:可以有half pending
    src_type = DMA_Address_Slave_Device;
    dst_type = DMA_Address_Slave_Device;
    src_burst = DMA_Burst_Length_Burst1;
    dst_burst = DMA_Burst_Length_Burst1;
    src_addr = srca_ddress;
    dst_addr = dst_address;
    src_ifs = dma_set_ifs(src_addr);
    dst_ifs = dma_set_ifs(dst_addr);

    //内存地址
    if (src_ifs == DMA_PERIPHERAL_ADDR_TABLE_LEN && dst_ifs == DMA_PERIPHERAL_ADDR_TABLE_LEN)
    {
        src_burst = hdma->init.memory_burst;
        dst_burst = hdma->init.memory_burst;
    }

    if (src_ifs == DMA_PERIPHERAL_ADDR_TABLE_LEN)
    {
        src_type = DMA_Address_Slave_Memory;
        src_ifs = DMA_Device_Sel_None;
    }

    if (dst_ifs == DMA_PERIPHERAL_ADDR_TABLE_LEN)
    {
        dst_type = DMA_Address_Slave_Memory;
        dst_ifs = DMA_Device_Sel_None;
    }

    //24bit存放在32bit slot大小需要比实际搬运空间大
    src_total_size = data_length;
    dst_total_size = data_length;
    //判断是否可以分为两个slot
    half_flag = data_length & 1UL ? 0UL : 1UL; //偶数

    if (half_flag == 1UL)
    {
        //每个slot中数量可为源数据宽度整除，
        half_flag = (data_length >> 1UL) % (hdma->init.src_data_width + 1UL);
        half_flag = half_flag == 0UL ? 1UL : 0UL;
    }

    if (half_flag == 1UL)
    {
        //每个slot中数量可为目的数据宽度整除，
        half_flag = (data_length >> 1UL) % (hdma->init.dst_data_width + 1UL);
        half_flag = half_flag == 0UL ? 1UL : 0UL;
    }

    hdma->xfer_half_cplt_flag = half_flag;
    src_data_size = hdma->init.src_data_width + 1UL;

    if (hdma->init.src_data_width == DMA_Data_Width_24Bit)
    {
        src_data_size = 4UL;
        src_total_size = src_total_size / 3UL * 4UL;
    }

    dst_data_size = hdma->init.dst_data_width + 1UL;

    if (hdma->init.dst_data_width == DMA_Data_Width_24Bit)
    {
        dst_data_size = 4UL;
        dst_total_size = dst_total_size / 3UL * 4UL;
    }

    uint32_t chx = hdma->init.channel;

    DEV_DMAC->DMA_CHN[chx].SSA = src_addr;
    DEV_DMAC->DMA_CHN[chx].SOA = DEV_DMAC_DMA_CHNn_SOA_SRC_SLOT_OFFSET(src_total_size >> half_flag) ///<源数据存储形式中每个槽之间（头到头）的间距偏移
                                 | DEV_DMAC_DMA_CHNn_SOA_SRC_WORD_OFFSET(src_data_size); ///<源数据在每个槽中的有效数据间（头到头）的间距偏移
    DEV_DMAC->DMA_CHN[chx].DSA = dst_addr;///<目的地址
    DEV_DMAC->DMA_CHN[chx].DOA = DEV_DMAC_DMA_CHNn_DOA_DST_SLOT_OFFSET(dst_total_size >> half_flag) ///<目的数据存储形式中每个槽之间（头到头）的间距偏移
                                 | DEV_DMAC_DMA_CHNn_DOA_DST_WORD_OFFSET(dst_data_size); ///<目的数据在每个槽中的有效数据间（头到头）的间距偏移
    DEV_DMAC->DMA_CHN[chx].CFG = hdma->init.src_data_width << 10 ///<源数据搬运宽度
                                 | hdma->init.src_data_loc << 9 ///<源地址设置，当src_width为24比特有效
                                 | src_ifs << 4 ///<源地址选择，需要与src_start_addr相符合
                                 | src_burst << 2 ///<源每次搬运的长度
                                 | hdma->init.src_inc << 1 ///<源地址增长方式
                                 | src_type ///<源数据存放的存储位置（memory或外设）
                                 | hdma->init.mode << 15 ///<重载使能
                                 | hdma->init.priority << 12 ///<优先级
                                 | hdma->init.dst_data_width << 26 ///<目的数据搬运宽度
                                 | hdma->init.dst_data_loc << 25 ///<目的地址设置，当src_width为24比特有效
                                 | dst_ifs << 20 ///<目的地址选择，需要与src_start_addr相符合
                                 | dst_burst << 18 ///<目的每次搬运的长度
                                 | hdma->init.dst_inc << 17 ///<目的地址增长方式
                                 | dst_type << 16; ///<目的数据存放的存储位置（memory或外设）
    DEV_DMAC->DMA_CHN[chx].LEN =  DEV_DMAC_DMA_CHNn_LEN_SLOT_NUM(1UL + half_flag) ///<搬运总数据存储形式槽的数量，1-0x10000
                                  | DEV_DMAC_DMA_CHNn_LEN_BYTE_NUM(data_length >> half_flag) ; ///<数据总数据存储形式槽中的数据数量，1-0x10000

    //CCTL
    if (((src_addr >> 24) == 0x40UL) || ((src_addr >> 24) == 0x50UL))
    {
        //write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL);
        //将D-cache空间写入memory,但不会将D-cache空间内容无效化
        //影响:花时间将cache数据写回sram
        write_csr(NDS_MCCTLCOMMAND, 7UL);
    }

    if (((dst_addr >> 24) == 0x40UL) || ((dst_addr >> 24) == 0x50UL))
    {
        //write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_INVAL_ALL);
        //将D-cache空间无效化
        //影响：后续cpu拿取整个sram空间数据都会miss
        write_csr(NDS_MCCTLCOMMAND, 23UL);
    }
}

__ILM void dma_irq_handler(void)
{
    hal_dma_handle();
}
