#ifndef __LKS32MC09X_DMA_H__
#define __LKS32MC09X_DMA_H__

#include "lks32mc09x_reg.h"

/**
 * DMA搬运使能源定义
 */
#define DMA_REN_ADC0      BIT0
#define DMA_REN_ADC1      BIT1
#define DMA_REN_DSP       BIT3
#define DMA_REN_TIMER0    BIT4
#define DMA_REN_TIMER1    BIT5
#define DMA_REN_TIMER2    BIT6
#define DMA_REN_TIMER3    BIT7
#define DMA_REN_SPI_RX    BIT10
#define DMA_REN_SPI_TX    BIT11
#define DMA_REN_MCPWM_RE0 BIT12
#define DMA_REN_MCPWM_RE1 BIT13
#define DMA_REN_I2C0_RX   BIT14
#define DMA_REN_I2C0_TX   BIT15
#define DMA_REN_UART0_RX  BIT16
#define DMA_REN_UART0_TX  BIT17
#define DMA_REN_UART1_RX  BIT18
#define DMA_REN_UART1_TX  BIT19
#define DMA_REN_HALL0     BIT24
#define DMA_REN_SIF       BIT25
#define DMA_REN_CMP       BIT26
#define DMA_REN_GPIO      BIT29
#define DMA_REN_SW_TRIG   BIT31

/**
 * @brief DMA初始化结构体句柄，初始化时请定义该句柄，并用其它地址来传参
 */
typedef struct
{
    uint8_t IRQ_EN;
    uint8_t SBTW;  ///< 源地址访问位宽 0: Byte 1: Halfword 2: Word
    uint8_t DBTW;  ///< 目的地址访问位宽 0: Byte 1: Halfword 2: Word
    uint8_t SINC;  ///< 源地址递增使能
    uint8_t DINC;  ///< 目的地址递增使能
    uint8_t CIRC;  ///< 循环模式使能
    uint8_t RMODE; ///< 多轮传输使能，多个DMA 请求完成传输
    uint8_t EN;    ///< 通道使能
    uint16_t TMS;  ///< DMA 通道 x 数据搬运次数。
    uint32_t SADR; ///< DMA 通道 x 源地址
    uint32_t DADR; ///< DMA 通道 x 目的地址
    uint32_t REN;  ///< DMA 请求使能
} DMA_InitTypeDef;

#define DMA_TCIE           BIT0 ///< 传输完成中断使能，高有效
#define DMA_TEIE           BIT1 ///< 错误中断使能，高有效

#define DMA_PERI_2_MEMORY  0 ///< 外设至内存
#define DMA_MEMORY_2_PERI  1 ///< 内存至外设

#define DMA_BYTE_TRANS     0 ///< 访问位宽， 0:byte
#define DMA_HALFWORD_TRANS 1 ///< 访问位宽， 1:half-word
#define DMA_WORD_TRANS     2 ///< 访问位宽， 2:word

/**
 * @brief DMA搬运触发源位宏定义
 */
#define DMA_REQ_SW       BIT31 ///< SW 触发
#define DMA_REQ_GPIO     BIT29 ///< GPIO 触发
#define DMA_REQ_CMP      BIT26 ///< CMP 触发
#define DMA_REQ_SIF      BIT25 ///< SIF 触发
#define DMA_REQ_HALL     BIT24 ///< HALL0 触发
#define DMA_REQ_UART1_TX BIT19 ///< UART1_TX 触发
#define DMA_REQ_UART1_RX BIT18 ///< UART1_RX 触发
#define DMA_REQ_UART0_TX BIT17 ///< UART0_TX 触发
#define DMA_REQ_UART0_RX BIT16 ///< UART0_RX 触发
#define DMA_REQ_I2C0_TX  BIT15 ///< I2C0_TX 触发
#define DMA_REQ_I2C0_RX  BIT14 ///< I2C0_RX 触发
#define DMA_REQ_MCPWM1   BIT13 ///< MCPWM1 触发
#define DMA_REQ_MCPWM0   BIT12 ///< MCPWM0 触发
#define DMA_REQ_SPI_TX   BIT11 ///< SPI_TX 触发
#define DMA_REQ_SPI_RX   BIT10 ///< SPI_RX 触发
#define DMA_REQ_TIMER3   BIT7  ///< TIMER3 触发
#define DMA_REQ_TIMER2   BIT6  ///< TIMER2 触发
#define DMA_REQ_TIMER1   BIT5  ///< TIMER1 触发
#define DMA_REQ_TIMER0   BIT4  ///< TIMER0 触发
#define DMA_REQ_DSP      BIT3  ///< DSP 触发
#define DMA_REQ_ADC1     BIT1  ///< ADC1 触发
#define DMA_REQ_ADC0     BIT0  ///< ADC0 触发

/**
 * @brief DMA中断标志位MASK
 */
#define DMA_IF_CH0 BIT0
#define DMA_IF_CH1 BIT1
#define DMA_IF_CH2 BIT2
#define DMA_IF_CH3 BIT3

/**
 * @brief DMA中断使能位MASK
 */
#define DMA_IE_CH0 BIT0
#define DMA_IE_CH1 BIT1
#define DMA_IE_CH2 BIT2
#define DMA_IE_CH3 BIT3

/**
 * @brief 初始化DMA模块
 *
 * @param DMAx DMA寄存器基地址
 * @param DMAInitStruct 初始化结构体指针
 */
void DMA_Init(DMA_TypeDef *DMAx, DMA_InitTypeDef *DMAInitStruct);

/**
 * @brief 将DMA初始化结构体重置为默认值
 *
 * @param DMAInitStruct 初始化结构体指针
 */
void DMA_StructInit(DMA_InitTypeDef *DMAInitStruct);

/**
 * @brief 获取DMA中断标志位状态
 *
 * @param DMA_IF_x 中断标志位MASK
 * @return 中断标志位状态
 */
uint32_t DMA_GetIRQFlag(uint32_t DMA_IF_x);

/**
 * @brief 清除DMA中断标志位
 *
 * @param DMA_IF_x 中断标志位MASK
 */
void DMA_ClearIRQFlag(uint32_t DMA_IF_x);

/**
 * @brief 获取DMA标志位状态
 *
 * @param DMA_IF_x 标志位MASK
 * @return 标志位状态
 */
uint32_t DMA_GetFlag(uint32_t DMA_IF_x);

/**
 * @brief 使能DMA模块
 */
void DMA_Enable(void);

/**
 * @brief 禁用DMA模块
 */
void DMA_Disable(void);

/**
 * @brief 复位DMA模块
 */
void DMA_Reset(void);

/**
 * @brief 设置DMA通道源地址和目的地址
 *
 * @param DMA_CHx DMA通道寄存器基地址
 * @param addr1 源地址
 * @param addr2 目的地址
 */
void DMA_SetAddr(DMA_TypeDef *DMA_CHx, uint32_t addr1, uint32_t addr2);

/**
 * @brief 设置DMA通道传输长度
 *
 * @param DMA_CHx DMA通道寄存器基地址
 * @param len 传输长度
 */
void DMA_SetLength(DMA_TypeDef *DMA_CHx, uint32_t len);

/**
 * @brief 触发DMA通道传输
 *
 * @param DMA_CHx DMA通道寄存器基地址
 */
void DMA_Trigger(DMA_TypeDef *DMA_CHx);

/**
 * @brief 设置DMA通道请求源
 *
 * @param DMA_CHx DMA通道寄存器基地址
 * @param DMA_REQ_x 请求源MASK
 */
void DMA_SetRequest(DMA_TypeDef *DMA_CHx, uint32_t DMA_REQ_x);

/**
 * @brief 使能或禁用DMA通道
 *
 * @param DMAx DMA寄存器基地址
 * @param Channel_EN 通道使能MASK
 */
void DMA_CHx_EN(DMA_TypeDef *DMAx, uint32_t Channel_EN);

/**
 * @brief 使用dma实现的内存拷贝
 * @param DMAx DMA寄存器基地址
 * @param dest 目标内存指针
 * @param src 源内存指针
 * @param n 要复制的字节数，如果使用dma1或dma2，字节数应小于0xff，如果使用dma0或dma3，字节数小于0xffff
 */
void DMA_Memcpy(DMA_TypeDef *DMAx, void *dest, void *src, uint32_t n);
/**
 * @brief 使用dma向特定寄存器写入多个数据，可用于crc计算等需要连续对单个寄存器写入数据的情况
 * @param DMAx DMA寄存器基地址
 * @param dest 目标内存指针
 * @param src 源内存指针
 * @param n 要复制的字节数，如果使用dma1或dma2，字节数应小于0xff，如果使用dma0或dma3，字节数小于0xffff
 * @param DMA_TRANS_x 位宽，输入输出位宽一致
 */
void DMA_Mem2Reg(DMA_TypeDef *DMAx, void *dest, void *src, uint32_t n, uint8_t DMA_TRANS_x);
#endif
