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

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
#define TRANSFER_SIZE          512          // 传输数据大小（字节）
#define BTIM_CLOCK_DIV         1            // BTIM分频系数（不分频，8MHz）
#define BTIM_PERIOD            0xFFFF       // BTIM重载值

/******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/
static void BTIM_Init(void);
static void StartTimer(void);
static uint16_t StopTimer(void);
static void DMA_TransferTest(void);
static void CPU_TransferTest(void);
static uint8_t VerifyData(const uint8_t* src, const uint8_t* dst, uint32_t count);
static void PrintResult(void);

/******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/
// FLASH数据源（使用const关键字存储在Flash中）
__attribute__((section(".ARM.const"))) const uint8_t g_flashSrcData[TRANSFER_SIZE] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
    0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
    0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
};

// RAM目标缓冲区
__attribute__((aligned(4))) uint8_t g_ramDstData[TRANSFER_SIZE];

// 时间测量结果（单位：BTIM时钟周期）
volatile uint16_t g_dmaTimeTicks = 0;
volatile uint16_t g_cpuTimeTicks = 0;

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

/**
 ******************************************************************************
 ** \brief  Main function of project
 **
 ** \return int32_t return value, if needed
 **
 ******************************************************************************/
int32_t main(void)
{
    uint8_t verifyResult = 0;
    // 初始化时钟：HSI 8MHz (96MHz/12)
    SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV12);

    // 初始化BSP（包含调试UART配置）
    Bsp_Init(8000000);

    // 初始化BTIM1用于时间测量
    BTIM_Init();

    printf("\r\n=== DMA FLASH to RAM Transfer Demo ===\r\n");
    printf("Transfer Size: %d bytes\r\n", TRANSFER_SIZE);
    printf("DMA Mode: BULK (Non-preemptible)\r\n");
    printf("BTIM Clock: 8MHz (1 tick = 0.125us)\r\n\r\n");

    // 执行DMA传输测试
    DMA_TransferTest();
    // 验证DMA传输结果
    verifyResult = VerifyData(g_flashSrcData, g_ramDstData, TRANSFER_SIZE);
    printf("Data Verification: %s\r\n", verifyResult ? "PASSED" : "FAILED");

    // 执行CPU传输测试
    CPU_TransferTest();

    // 验证DMA传输结果
    verifyResult = VerifyData(g_flashSrcData, g_ramDstData, TRANSFER_SIZE);
    printf("Data Verification: %s\r\n", verifyResult ? "PASSED" : "FAILED");

    // 打印结果
    PrintResult();    

    while(1)
    {
        // 主循环空转
    }
}

/**
 * @brief 初始化BTIM1用于时间测量
 *        使用PCLK 8MHz不分频作为计数时钟
 */
static void BTIM_Init(void)
{
    BTIM_TimeBaseInitTypeDef BTIM_InitStruct = {0};

    // 使能BTIM1时钟
    SYSCTRL_APBPeriphClk_Enable2(SYSCTRL_APB2_PERIPH_BTIM123, ENABLE);

    // 配置BTIM1
    BTIM_InitStruct.BTIM_Prescaler = BTIM_CLOCK_DIV - 1;    // 不分频
    BTIM_InitStruct.BTIM_Mode = BTIM_MODE_TIMER;            // 定时器模式
    BTIM_InitStruct.BTIM_Period = BTIM_PERIOD;              // 最大周期
    BTIM_InitStruct.BTIM_CountMode = BTIM_COUNT_MODE_SINGLE;// 单次模式
    BTIM_TimeBaseInit(CW_BTIM1, &BTIM_InitStruct);
}

/**
 * @brief 启动BTIM1计时器
 */
static void StartTimer(void)
{
    // 清除计数器
    BTIM_SetCounter(CW_BTIM1, 0);
    // 启动计时
    BTIM_Cmd(CW_BTIM1, ENABLE);
}

/**
 * @brief 停止BTIM1计时器并返回计数值
 *
 * @return uint16_t BTIM计数值
 */
static uint16_t StopTimer(void)
{
    uint16_t count;

    // 停止计时
    BTIM_Cmd(CW_BTIM1, DISABLE);
    // 读取计数值
    count = BTIM_GetCounter(CW_BTIM1);

    return count;
}

/**
 * @brief 执行DMA传输测试
 *        使用软件触发BULK模式，从FLASH到RAM传输512字节
 */
static void DMA_TransferTest(void)
{
    DMA_InitTypeDef DMA_InitStruct = {0};

    // 清零目的缓冲区
    for(uint32_t i = 0; i < TRANSFER_SIZE; i++)
    {
        g_ramDstData[i] = 0;
    }

    // 使能DMA时钟
    SYSCTRL_AHBPeriphClk_Enable(SYSCTRL_AHB_PERIPH_DMA, ENABLE);

    // 配置DMA通道1参数
    DMA_InitStruct.TransferMode = DMA_MODE_BULK;               // BULK传输模式
    DMA_InitStruct.TriggerType = DMA_TRIGGER_SOFTWARE;         // 软件触发
    DMA_InitStruct.TriggerSource = DMA_TRIGGER_SRC_UART1_RX;   // 软件触发时此值无效
    DMA_InitStruct.DataSize = DMA_DATA_SIZE_8BITS;             // 8位数据宽度（字节）
    DMA_InitStruct.SrcIncrement = DMA_ADDRESS_INCREMENT;       // 源地址自增（FLASH）
    DMA_InitStruct.DstIncrement = DMA_ADDRESS_INCREMENT;       // 目的地址自增（RAM）
    DMA_InitStruct.SrcAddress = (uint32_t)g_flashSrcData;      // 源地址（FLASH）
    DMA_InitStruct.DstAddress = (uint32_t)g_ramDstData;        // 目的地址（RAM）
    DMA_InitStruct.TransferCount = TRANSFER_SIZE;              // 传输数量（512字节）
    DMA_InitStruct.BlockCount = 1;                             // 数据块数量
    DMA_InitStruct.RestartEnable = DISABLE;                    // 不自动重传

    // 初始化DMA通道1
    DMA_Init(DMA_CHANNEL_1, &DMA_InitStruct);

    // 使能DMA通道1
    DMA_Cmd(DMA_CHANNEL_1, ENABLE);

    // 开始计时
    StartTimer();

    // 软件启动DMA传输
    DMA_StartTransfer(DMA_CHANNEL_1);

    // 轮询等待传输完成
    while(DMA_STATUS_COMPLETE != DMA_CheckStatus(DMA_CHANNEL_1))
    {
        // 等待DMA传输完成
    }

    // 停止计时
    g_dmaTimeTicks = StopTimer();

    // 清除传输完成和传输错误标志
    DMA_ClearInterruptFlag(DMA_CHANNEL_1, DMA_INTERRUPT_TC | DMA_INTERRUPT_TE);
}

/**
 * @brief 执行CPU传输测试
 *        使用for循环从FLASH到RAM传输512字节
 */
static void CPU_TransferTest(void)
{
    uint32_t i;

    // 清零目的缓冲区
    for(i = 0; i < TRANSFER_SIZE; i++)
    {
        g_ramDstData[i] = 0;
    }

    // 开始计时
    StartTimer();

    // CPU搬运数据（逐字节拷贝）
    for(i = 0; i < TRANSFER_SIZE; i++)
    {
        g_ramDstData[i] = g_flashSrcData[i];
    }

    // 停止计时
    g_cpuTimeTicks = StopTimer();
}

/**
 * @brief 验证传输数据是否正确
 *
 * @param src 源数据指针
 * @param dst 目的数据指针
 * @param count 数据数量
 * @return uint8_t 1=成功, 0=失败
 */
static uint8_t VerifyData(const uint8_t* src, const uint8_t* dst, uint32_t count)
{
    uint32_t i;
    uint8_t match = 1;

    for(i = 0; i < count; i++)
    {
        if(src[i] != dst[i])
        {
            match = 0;
            break;
        }
    }

    return match;
}

/**
 * @brief 打印传输结果和时间对比
 */
static void PrintResult(void)
{
    // 计算实际时间（单位：微秒）
    // BTIM时钟 = 8MHz, 1 tick = 0.125us
    float dmaTimeUs = (float)g_dmaTimeTicks * 0.125f;
    float cpuTimeUs = (float)g_cpuTimeTicks * 0.125f;
    float speedup = (g_dmaTimeTicks > 0) ? (float)g_cpuTimeTicks / g_dmaTimeTicks : 0;

    printf("--- Transfer Result ---\r\n");
    printf("[DMA] Ticks: %d, Time: %.2f us\r\n", g_dmaTimeTicks, dmaTimeUs);
    printf("[CPU] Ticks: %d, Time: %.2f us\r\n", g_cpuTimeTicks, cpuTimeUs);
    printf("Speedup: %.2fx (DMA vs CPU)\r\n\r\n", speedup);
}

/******************************************************************************
 * 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 can add his own implementation to report the file name and line number */
    printf("Wrong parameters value: file %s on line %ld\r\n", file, (long)line);
}
#endif /* USE_FULL_ASSERT */
