#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_UART2_RX  BIT20
#define DMA_REN_UART2_TX  BIT21
#define DMA_REN_HALL0     BIT24
#define DMA_REN_SIF       BIT25
#define DMA_REN_CMP       BIT26
#define DMA_REN_GPIO      BIT29
#define DMA_REN_SW        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_REN_x
} 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

// 兼容写法
#define DMA_REQ_SW       DMA_REQ_SW       ///< SW 触发
#define DMA_REQ_GPIO     DMA_REQ_GPIO     ///< GPIO 触发
#define DMA_REQ_CMP      DMA_REQ_CMP      ///< CMP 触发
#define DMA_REQ_SIF      DMA_REQ_SIF      ///< SIF 触发
#define DMA_REQ_HALL     DMA_REQ_HALL     ///< HALL0 触发
#define DMA_REQ_UART1_TX DMA_REQ_UART1_TX ///< UART1_TX 触发
#define DMA_REQ_UART1_RX DMA_REQ_UART1_RX ///< UART1_RX 触发
#define DMA_REQ_UART0_TX DMA_REQ_UART0_TX ///< UART0_TX 触发
#define DMA_REQ_UART0_RX DMA_REQ_UART0_RX ///< UART0_RX 触发
#define DMA_REQ_I2C0_TX  DMA_REQ_I2C0_TX  ///< I2C0_TX 触发
#define DMA_REQ_I2C0_RX  DMA_REQ_I2C0_RX  ///< I2C0_RX 触发
#define DMA_REQ_MCPWM1   DMA_REQ_MCPWM1   ///< MCPWM1 触发
#define DMA_REQ_MCPWM0   DMA_REQ_MCPWM0   ///< MCPWM0 触发
#define DMA_REQ_SPI_TX   DMA_REQ_SPI_TX   ///< SPI_TX 触发
#define DMA_REQ_SPI_RX   DMA_REQ_SPI_RX   ///< SPI_RX 触发
#define DMA_REQ_TIMER3   DMA_REQ_TIMER3   ///< TIMER3 触发
#define DMA_REQ_TIMER2   DMA_REQ_TIMER2   ///< TIMER2 触发
#define DMA_REQ_TIMER1   DMA_REQ_TIMER1   ///< TIMER1 触发
#define DMA_REQ_TIMER0   DMA_REQ_TIMER0   ///< TIMER0 触发
#define DMA_REQ_DSP      DMA_REQ_DSP      ///< DSP 触发
#define DMA_REQ_ADC1     DMA_REQ_ADC1     ///< ADC1 触发
#define DMA_REQ_ADC0     DMA_REQ_ADC0     ///< 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
