/**
* @file main.c
* @author WHXY
* @brief
* @version 0.1
* @date 2026-04-13
*
* @copyright Copyright (c) 2026
*
*/
/*******************************************************************************
*
* 代码许可和免责信息
* 武汉芯源半导体有限公司授予您使用所有编程代码示例的非专属的版权许可，您可以由此
* 生成根据您的特定需要而定制的相似功能。根据不能被排除的任何法定保证，武汉芯源半
* 导体有限公司及其程序开发商和供应商对程序或技术支持（如果有）不提供任何明示或暗
* 含的保证或条件，包括但不限于暗含的有关适销性、适用于某种特定用途和非侵权的保证
* 或条件。
* 无论何种情形，武汉芯源半导体有限公司及其程序开发商或供应商均不对下列各项负责，
* 即使被告知其发生的可能性时，也是如此：数据的丢失或损坏；直接的、特别的、附带的
* 或间接的损害，或任何后果性经济损害；或利润、业务、收入、商誉或预期可节省金额的
* 损失。
* 某些司法辖区不允许对直接的、附带的或后果性的损害有任何的排除或限制，因此某些或
* 全部上述排除或限制可能并不适用于您。
*
*******************************************************************************/
#include "..\inc\main.h"
#include <stdint.h>
#include <string.h>

/******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/******************************************************************************
 * Local variable definitions ('static')                                      *
 ******************************************************************************/

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
//#define HSI48MHZ_EN                          // Set 48MHz HSI

#ifndef HSI48MHZ_EN
#define HSI8MHZ_EN                             // Set 8MHz HSI
#endif

//#define BAUD_RATE_100K_EN                    // Set I2C 100K baud rate, default is 400KHz
//#define BAUD_RATE_1000K_EN                   // Set I2C 1000K baud rate

#define I2C1_SCL_GPIO_PORT                     CW_GPIOB
#define I2C1_SCL_GPIO_PIN                      GPIO_PIN_6
#define I2C1_SDA_GPIO_PORT                     CW_GPIOB
#define I2C1_SDA_GPIO_PIN                      GPIO_PIN_7

#define I2C1_SCL_LOW()                         PB06_SETLOW()
#define I2C1_SDA_LOW()                         PB07_SETLOW()
#define I2C1_SCL_HIGH()                        PB06_SETHIGH()
#define I2C1_SDA_HIGH()                        PB07_SETHIGH()

#define I2C1_SCL2GPIO()                        PB06_AFx_GPIO()
#define I2C1_SDA2GPIO()                        PB07_AFx_GPIO()
#define GPIO2I2C1_SCL()                        PB06_AFx_I2C1SCL()
#define GPIO2I2C1_SDA()                        PB07_AFx_I2C1SDA()

#define DEV_ADDR_SLAVE_7B                      0x70                 //I2C从机设备地址：7bits.
#define DEV_ADDR_SLAVE_10B                     0x3F0                //I2C从机设备地址：10bits.
#define RAM_ADDR_OFFSET_SLAVE                  0x0800               //I2C从机RAM目标地址:0x20000000 + 0x0800.

/******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/
uint8_t u8DataSent[LEN_DATA_RAM] = {0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0};
//...
volatile boolean_t g_TransferDone = FALSE;
volatile boolean_t g_ReceiveDone = FALSE;
uint32_t g_DMA_TxBuffer[LEN_SLAVE_ADDRESS + LEN_DATA_ADDRESS + LEN_DATA_RAM + 1];
uint32_t g_DMA_RxBuffer[LEN_DATA_ADDRESS + LEN_DATA_RAM];
uint8_t g_RegAddress[LEN_DATA_ADDRESS];
uint16_t g_DataIndex;
//...
I2C_SlaveRegTypeDef I2C_SlaveDataStruct;
I2C_MasterDataTypeDef I2C_MasterDataStruct;

/*****************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/

/**
 * @brief 初始化LPI2C主机模式（DMA方式）
 *
 * 配置I2C为主机模式，并使能DMA传输功能。根据编译宏设置波特率
 * 和时钟频率。
 */
void LPI2C_MasterInit(void)
{
    I2C_MasterConfigTypeDef I2C_InitStruct;

    I2C_MasterDeinit(CW_I2C1);

    // I2C default values
    I2C_MasterInitDefault(&I2C_InitStruct);
#ifdef BAUD_RATE_100K_EN
    I2C_InitStruct.I2C_BaudRate_Hz = 100000UL;
#elif defined (BAUD_RATE_1000K_EN)
    I2C_InitStruct.I2C_BaudRate_Hz = 1000000UL;
#else
    // Default: 400KHz
#endif

    // 初始化模块
#ifdef HSI48MHZ_EN
    I2C_MasterInit(CW_I2C1, &I2C_InitStruct, 48000000UL);
#elif defined (HSI8MHZ_EN)
    I2C_MasterInit(CW_I2C1, &I2C_InitStruct, 8000000UL);
#else
#endif

    LPI2C_MasterEnableDMA(CW_I2C1, ENABLE, ENABLE); // 使能TX & RX DMA
}

/**
 * @brief 发送重复起始信号和从机地址（读模式）
 *
 * @param I2C_SlaveData 从机数据结构体指针，包含从机地址等信息
 * @param I2C_MasterData 主机数据结构体指针，包含DMA索引等信息
 * @return uint8_t 返回I2C操作状态（I2C_Status_Success表示成功）
 */
uint8_t LPI2C_MasterTransferDataRestartCmd(I2C_SlaveRegTypeDef *I2C_SlaveData, I2C_MasterDataTypeDef *I2C_MasterData)
{
    uint16_t index = *I2C_MasterData->pu16DataIndexDMA;
    // 发送重复起始信号和从机地址（读模式）
    if (I2C_SlaveData->slaveAddr & I2C_SLAVE_ADDR10B_MSB_MASK)
    {
        // 10-bit地址
        // 发送start+SLA_MSB+R命令
        g_DMA_TxBuffer[index++] = I2C_Cmd_Tx_RepSTART_Data_Rx_ACK | ((uint8_t)((I2C_SlaveData->slaveAddr & I2C_SLAVE_ADDR10B_MSB_MASK) >> (8 - 1))) | I2C_SLAVE_ADDR10B_MSB | I2C_MODE_READ;
    }
    else
    {
        // 7-bit地址
        // 发送start+SLA+R命令
        g_DMA_TxBuffer[index++] = I2C_Cmd_Tx_RepSTART_Data_Rx_ACK | (I2C_SlaveData->slaveAddr << 1) | I2C_MODE_READ;
    }
    *I2C_MasterData->pu16DataIndexDMA = index;
    return I2C_Status_Success;
}

/**
 * 准备I2C主机DMA传输数据
 *
 * 根据从设备地址类型和寄存器地址类型，构建DMA传输缓冲区数据
 *
 * @param I2C_SlaveData  从设备寄存器信息结构体指针
 * @param I2C_MasterData 主机数据传输信息结构体指针
 * @return uint8_t 返回I2C状态(I2C_Status_Success或I2C_Status_Error)
 */
uint8_t LPI2C_MasterTransferDataPreProcess(I2C_SlaveRegTypeDef *I2C_SlaveData, I2C_MasterDataTypeDef *I2C_MasterData)
{
    uint16_t index = 0;
    uint16_t i;
    uint8_t j;

    // Prepare DMA transfer data for I2C page write operation
    if (I2C_SlaveData->slaveAddr & I2C_SLAVE_ADDR10B_MSB_MASK)
    {
        // 10-bit地址
        g_DMA_TxBuffer[index++] = I2C_Cmd_Tx_RepSTART_Data_Rx_ACK | ((uint8_t)((I2C_SlaveData->slaveAddr & I2C_SLAVE_ADDR10B_MSB_MASK) >> (8 - 1))) | I2C_SLAVE_ADDR10B_MSB | I2C_MODE_WRITE; // start+SLA_MSB+W命令
        g_DMA_TxBuffer[index++] = I2C_SlaveData->slaveAddr & I2C_SLAVE_ADDR10B_LSB_MASK; // 发送SLA_LSB命令
    }
    else
    {
        // 7-bit地址
        g_DMA_TxBuffer[index++] = I2C_Cmd_Tx_RepSTART_Data_Rx_ACK | (I2C_SlaveData->slaveAddr << 1) | I2C_MODE_WRITE; // 发送start+SLA+W命令
    }

    switch (I2C_SlaveData->regAddrType)
    {
    case I2C_REG_ADDR_8BIT:
        j = 1;
        break;
    case I2C_REG_ADDR_16BIT:
        j = 2;
        break;
    case I2C_REG_ADDR_24BIT:
        j = 3;
        break;
    case I2C_REG_ADDR_32BIT:
        j = 4;
        break;
    default:
        return I2C_Status_Error;
    }

    for (i = 0; i < j; i++)
    {
        g_DMA_TxBuffer[index++] = *I2C_SlaveData->pu8RegAddr++;           // 发送数据地址1~4 bytes
    }
    *I2C_MasterData->pu16DataIndexDMA = index;
    return I2C_Status_Success;
}

/**
 * @brief  I2C主机DMA中断模式数据发送函数
 *
 * 通过DMA中断方式向I2C从机发送数据,包括寄存器地址和数据部分,
 * 发送完成后自动插入STOP命令并启动DMA传输
 *
 * @param  I2C_SlaveData: 从机寄存器配置结构体,包含从机地址、寄存器地址及地址类型
 * @param  I2C_MasterData: 主机数据结构体,包含数据缓冲区、数据长度及DMA索引
 * @return I2C状态码(I2C_Status_Success成功,其他失败)
 */
uint8_t LPI2C_MasterTransferIT(I2C_SlaveRegTypeDef *I2C_SlaveData, I2C_MasterDataTypeDef *I2C_MasterData)
{
    uint16_t index;
    uint16_t i;

    LPI2C_MasterTransferDataPreProcess(I2C_SlaveData, I2C_MasterData);    // I2C数据写操作
    index = *I2C_MasterData->pu16DataIndexDMA;

    for (i = 0; i < I2C_MasterData->u16Len; i++)
    {
        g_DMA_TxBuffer[index + i] = (uint32_t)I2C_MasterData->pu8Data[i]; // 发送N字节数据
    }
    index += I2C_MasterData->u16Len;
    g_DMA_TxBuffer[index++] = I2C_Cmd_Tx_STOP;                            // 发送STOP命令

    // Set DMA transfer count for I2C write operation because of last read operation
    CW_DMA->CNT1_f.CNT = index;
    DMA_Cmd(DMA_CHANNEL_1, ENABLE);

    return I2C_Status_Success;
}

/**
 * @brief I2C主机中断模式接收数据（DMA方式）
 *
 * 使用DMA进行I2C主机随机地址顺序读操作的数据接收
 *
 * @param I2C_SlaveData  I2C从机寄存器数据结构指针
 * @param I2C_MasterData I2C主机数据结构指针
 * @return uint8_t 返回I2C操作状态（I2C_Status_Success表示成功）
 */
uint8_t LPI2C_MasterReceiveIT(I2C_SlaveRegTypeDef *I2C_SlaveData, I2C_MasterDataTypeDef *I2C_MasterData)
{
    // Prepare DMA transfer data for I2C random address & sequential read operation
    DMA_Cmd(DMA_CHANNEL_2, ENABLE);

    LPI2C_MasterTransferDataPreProcess(I2C_SlaveData, I2C_MasterData); // I2C数据写操作，包括数据地址

    //FirmwareDelay(1000); // Maybe need a delay here to comply with I2C protocol

    LPI2C_MasterTransferDataRestartCmd(I2C_SlaveData, I2C_MasterData); // I2C数据读操作

    g_DMA_TxBuffer[*I2C_MasterData->pu16DataIndexDMA] = I2C_Cmd_Rx_DataToMRDR | (LEN_DATA_ADDRESS + LEN_DATA_RAM - 1); // 发送接收数据命令，包括数据地址
    CW_DMA->CNT1_f.CNT = (*I2C_MasterData->pu16DataIndexDMA) + 1;      // Set DMA transfer count for I2C read operation
    DMA_Cmd(DMA_CHANNEL_1, ENABLE);

    return I2C_Status_Success;
}

/**
 * @brief 发送I2C主机STOP命令（中断模式）
 *
 * 该函数通过DMA方式发送I2C停止信号，用于终止当前的I2C通信会话。
 * 首先将STOP命令写入DMA发送缓冲区，然后配置DMA传输计数并使能DMA通道。
 */
void LPI2C_MasterStopIT(void)
{
    g_DMA_TxBuffer[0] = I2C_Cmd_Tx_STOP; // 发送STOP命令
    CW_DMA->CNT1_f.CNT = 1;
    DMA_Cmd(DMA_CHANNEL_1, ENABLE);
}

/**
 * @brief 重置DMA数据传输包
 *
 * 将数据索引寄存器重置为0，并将I2C从机数据结构中的
 * 寄存器地址指针重新指向数组起始位置。
 */
void DMA_DataPacketReset(void)
{
    g_DataIndex = 0;
    I2C_SlaveDataStruct.pu8RegAddr = &g_RegAddress[0]; // Reset register address pointer
}

/**
* @brief main函数
*
* 本函数实现了I2C通信的初始化及数据读写操作。
*
* @return int32_t 返回0表示程序正常结束
*/
int32_t main(void)
{
    uint16_t cntTemp = 0 ;

    // 时钟初始化
    SYSCTRL_Configuration();

    // IO口初始化
    GPIO_Configuration();

    // I2C主设备初始化
    LPI2C_MasterInit();

    // DMA配置
    DMA_Configuration();

    // 中断设置
    NVIC_Configuration();
    I2C_MasterCmd(CW_I2C1, ENABLE); // I2C模块使能
    if (I2C_MasterPollingFlag(CW_I2C1, I2C_IT_BUSBUSY) == I2C_Status_Success)
    {
        I2C_ExceptionHandling();
    }

    g_RegAddress[0] = (uint8_t)((RAM_ADDR_OFFSET_SLAVE & 0xFF00) >> 8); // 写数据高字节
    g_RegAddress[1] = (uint8_t)(RAM_ADDR_OFFSET_SLAVE & 0x00FF);        // 写数据低字节

#ifdef ADDR_SLAVE_10B_EN
    I2C_SlaveDataStruct.slaveAddr = DEV_ADDR_SLAVE_10B;   // 10-bit地址
#else
    I2C_SlaveDataStruct.slaveAddr = DEV_ADDR_SLAVE_7B;    // 7-bit地址
#endif
    I2C_SlaveDataStruct.regAddrType = I2C_REG_ADDR_16BIT; // Register address type
    I2C_SlaveDataStruct.pu8RegAddr = &g_RegAddress[0];    // Register address pointer

    I2C_MasterDataStruct.pu16DataIndexDMA = &g_DataIndex; // Data index pointer
    I2C_MasterDataStruct.pu8Data = u8DataSent;            // Data pointer
    I2C_MasterDataStruct.u16Len = LEN_DATA_RAM;           // Data length


    while (1)
    {
        while(I2C_MasterPollingFlag(CW_I2C1, I2C_IT_TXE) != I2C_Status_Success);
        DMA_DataPacketReset(); // Reset DMA data packet for next transfer
        LPI2C_MasterTransferIT(&I2C_SlaveDataStruct, &I2C_MasterDataStruct);  // I2C数据写操作

        while (!g_TransferDone)
        {
            ;
        }
        g_TransferDone = FALSE;

        // Data transfer is ok, then read I2C slave's RAM data.
        while(I2C_MasterPollingFlag(CW_I2C1, I2C_IT_TXE) != I2C_Status_Success); // Wait for all data to be sent
        DMA_DataPacketReset(); // Reset DMA data packet for next transfer
        LPI2C_MasterReceiveIT(&I2C_SlaveDataStruct, &I2C_MasterDataStruct);      // I2C数据随机地址顺序读操作

        while ((FALSE == g_TransferDone) || (FALSE == g_ReceiveDone))
        {
            ;
        }
        g_TransferDone = FALSE;
        g_ReceiveDone = FALSE;
        while(I2C_MasterPollingFlagReverse(CW_I2C1, I2C_IT_RXNE) != I2C_Status_Success); // Can comment it.

        I2C_MasterSTOP(CW_I2C1); // I2C数据随机地址顺序读操作停止

        //检查Write/Read数据一致性
        for(uint8_t i = 0; i < LEN_DATA_RAM; i++)
        {
            if (u8DataSent[i] != g_DMA_RxBuffer[LEN_DATA_ADDRESS + i])
            {
                //LED1灭/LED2亮  //FAILED
                PB09_SETLOW();
                PB08_SETHIGH();

                I2C_MasterSoftReset(CW_I2C1);
                // I2C初始化
                LPI2C_MasterInit();
                I2C_MasterCmd(CW_I2C1, ENABLE); // I2C模块使能

                if (I2C_MasterPollingFlag(CW_I2C1, I2C_IT_BUSBUSY) == I2C_Status_Success)
                {
                    I2C_ExceptionHandling();
                }

                break;
            }
            else if (i == LEN_DATA_RAM - 1)
            {
                //LED1亮/LED2灭  //PASSED
                PB09_SETHIGH();
                PB08_SETLOW();
            }
            else{}
        }

        ++cntTemp;
        for (uint8_t i = 0; i < sizeof(u8DataSent); ++i)
        {
            u8DataSent[i] = cntTemp + i;
        }

#ifdef HSI48MHZ_EN
        FirmwareDelay(3000);
#else
        FirmwareDelay(500);
#endif
    }

}

/**
 * @brief  配置系统时钟
 *
 * @param  无
 * @retval 无
 */
void SYSCTRL_Configuration(void)
{
#ifdef HSI48MHZ_EN
    __SYSCTRL_FLASH_CLK_ENABLE();
    FLASH_SetLatency(FLASH_Latency_2);
    SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV2);  // 48MHz
    CW_FLASH->CR2 |= (0x5A5A0000 | 0x18);     // Enable FLASH Prefetch and Cache.
    __SYSCTRL_FLASH_CLK_DISABLE();
#elif defined(HSI8MHZ_EN)
    SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV12); // 8MHz
#else
    // Default HSI4MHz
#endif
    __SYSCTRL_I2C1_CLK_ENABLE();
}

/**
 * @brief  配置GPIO引脚
 *
 * @param  无
 * @retval 无
 */
void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};

    __SYSCTRL_GPIOB_CLK_ENABLE();

    GPIO2I2C1_SCL();
    GPIO2I2C1_SDA();
    GPIO_InitStructure.Pins = I2C1_SCL_GPIO_PIN | I2C1_SDA_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_Init(I2C1_SCL_GPIO_PORT, &GPIO_InitStructure);

    /* Configure the GPIO_LED pins */
    GPIO_InitStructure.Pins = GPIO_PIN_8 | GPIO_PIN_9;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);

    //LEDs灭
    PB08_SETLOW(); // LED2灭
    PB09_SETLOW(); // LED1灭
}

/**
 * @brief I2C软停止信号生成函数
 *
 * 通过软件控制IO模拟I2C STOP条件时序
*/
static void I2C_Stop_SW(void)
{
    I2C1_SCL_LOW();
    I2C1_SDA_LOW();
#ifdef HSI48MHZ_EN
    FirmwareDelay(24); // delay 4us@48MHz
    I2C1_SCL_HIGH();
    FirmwareDelay(24);
#else
    FirmwareDelay(4);  // delay 4us@8MHz
    I2C1_SCL_HIGH();
    FirmwareDelay(4);
#endif
    I2C1_SDA_HIGH();
}

/**
 * @brief  I2C异常处理函数
 *
 *         该函数用于处理I2C总线异常情况。将I2C引脚切换为GPIO模式，
 *         通过软件发送停止信号，延时后再恢复为I2C功能，从而恢复总线正常状态。
 *
 * @param  无
 * @retval 无
 */
void I2C_ExceptionHandling(void)
{
    I2C1_SCL2GPIO();
    I2C1_SDA2GPIO();
    I2C_Stop_SW();
#ifdef HSI48MHZ_EN
    FirmwareDelay(6000); // delay 1ms@48MHz
#else
    FirmwareDelay(1000); // delay 1ms@8MHz
#endif
    GPIO2I2C1_SCL();
    GPIO2I2C1_SDA();
}

/**
 * @brief  配置嵌套向量中断控制器（NVIC）
 * @param  无
 * @retval 无
 */
void NVIC_Configuration(void)
{
    __disable_irq();
    NVIC_SetPriority(I2C1_IRQn, 0);    //Highest priority
    NVIC_ClearPendingIRQ(I2C1_IRQn);
    //NVIC_EnableIRQ(I2C1_IRQn);

    NVIC_SetPriority(DMACH12_IRQn, 3); //Lowest priority
    NVIC_ClearPendingIRQ(DMACH12_IRQn);
    NVIC_EnableIRQ(DMACH12_IRQn);
    __enable_irq();
}

/**
 * @brief 配置I2C的DMA传输通道
 *
 * 配置DMA的两个通道用于I2C主机的发送和接收操作。
 * 通道1用于发送数据从内存到I2C1 MTDR寄存器，通道2用于从I2C1 MRDR寄存器接收数据到内存。
 * 同时启用两个通道的传输完成中断。
 */
void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure = {0};

    __SYSCTRL_DMA_CLK_ENABLE();

    // 配置DMA发送参数
    DMA_InitStructure.BlockCount = 1;
    DMA_InitStructure.TransferCount =  sizeof(g_DMA_TxBuffer)/sizeof(g_DMA_TxBuffer[0]);
    DMA_InitStructure.DataSize = DMA_DATA_SIZE_32BITS;
    DMA_InitStructure.DstAddress = (uint32_t)&CW_I2C1->MTDR;
    DMA_InitStructure.DstIncrement = DMA_ADDRESS_FIXED;
    DMA_InitStructure.RestartEnable = TRUE;
    DMA_InitStructure.SrcAddress = (uint32_t)&g_DMA_TxBuffer[0];
    DMA_InitStructure.SrcIncrement = DMA_ADDRESS_INCREMENT;
    DMA_InitStructure.TransferMode = DMA_MODE_BLOCK;
    DMA_InitStructure.TriggerSource = DMA_TRIGGER_SRC_LPI2C1_TX;
    DMA_InitStructure.TriggerType = DMA_TRIGGER_HARDWARE;
    DMA_Init(DMA_CHANNEL_1, &DMA_InitStructure);

    // 配置DMA接收参数
    DMA_InitStructure.BlockCount = 1;
    DMA_InitStructure.TransferCount =  LEN_DATA_ADDRESS + LEN_DATA_RAM;
    DMA_InitStructure.DataSize = DMA_DATA_SIZE_32BITS;
    DMA_InitStructure.DstAddress = (uint32_t)&g_DMA_RxBuffer[0];
    DMA_InitStructure.DstIncrement = DMA_ADDRESS_INCREMENT;
    DMA_InitStructure.RestartEnable = TRUE;
    DMA_InitStructure.SrcAddress = (uint32_t)&CW_I2C1->MRDR;
    DMA_InitStructure.SrcIncrement = DMA_ADDRESS_FIXED;
    DMA_InitStructure.TransferMode = DMA_MODE_BLOCK;
    DMA_InitStructure.TriggerSource = DMA_TRIGGER_SRC_LPI2C1_RX;
    DMA_InitStructure.TriggerType = DMA_TRIGGER_HARDWARE;
    DMA_Init(DMA_CHANNEL_2, &DMA_InitStructure);

    //配置DMA中断
    DMA_ITConfig(DMA_CHANNEL_1, DMA_INTERRUPT_TC, ENABLE);
    DMA_ITConfig(DMA_CHANNEL_2, DMA_INTERRUPT_TC, ENABLE);

}

/**
 * DMA通道1和通道2的中断回调函数
 *
 */
void DMACH12_Callback(void)
{
    if (CW_DMA->ISR & (1 << DMA_ISR_TC1_Pos))
    {
        CW_DMA->ICR_f.TC1 = 0;
        DMA_Cmd(DMA_CHANNEL_1, DISABLE);
        g_TransferDone = TRUE; // Set transfer done flag
    }
    if (CW_DMA->ISR & (1 << DMA_ISR_TC2_Pos))
    {
        CW_DMA->ICR_f.TC2 = 0;
        g_ReceiveDone = TRUE;  // Set receive done flag
    }

}

/******************************************************************************
* EOF (not truncated)
******************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief  Reports the name of the source file and the source line number
*         where the assert_param error has occurred.
* @param  file: pointer to the source file name
* @param  line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number */
    printf("Wrong parameters value: file %s on line %d\r\n", file, line);
    /* USER CODE END 6 */
}
#endif
