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

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
//DMA传输参数
#define  DMA_TRANSFER_SIZE             10           // 传输数据数量
#define  DMA_DATA_WIDTH                32           // 数据位宽: 32bit

/******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

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

/******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/
static void RCC_Configuration(void);
static void DMA_TransferTest(void);
static void CompareData(const uint32_t* src, const uint32_t* dst, uint32_t count);


/******************************************************************************
 * Local variable definitions ('static')                                      *
 ******************************************************************************/
// 定义源缓冲区和目标缓冲区，使用32位对齐
__attribute__((aligned(4))) static uint32_t g_SrcBuffer[DMA_TRANSFER_SIZE];
__attribute__((aligned(4))) static uint32_t g_DstBuffer[DMA_TRANSFER_SIZE];

/******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/

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

/**
 ******************************************************************************
 ** \brief  Main function of project
 **
 ** \return int32_t return value, if needed
 **
 ******************************************************************************/
int32_t main(void)
{
    //配置RCC
    RCC_Configuration();
    
    Bsp_Init(8000000);   

    printf("\r\n=== DMA Memory to Memory Transfer Demo ===\r\n");
    printf("Mode: Software Trigger, BLOCK Transfer\r\n");
    printf("Data Size: %d uint32_t values\r\n\r\n", DMA_TRANSFER_SIZE);

    // 执行DMA传输测试
    DMA_TransferTest();

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

/**
 * @brief 配置RCC
 *
 */
static void RCC_Configuration(void)
{
    //SYSCLK = HSI = 8MHz = HCLK = PCLK
    SYSCTRL_HSI_Enable(SYSCTRL_HSIOSC_DIV12);   

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


/**
 * @brief 执行DMA内存到内存传输测试
 *        使用软件触发BLOCK模式
 *
 */
static void DMA_TransferTest(void)
{
    DMA_InitTypeDef DMA_InitStruct = {0};
    uint32_t i;

    // 初始化源缓冲区数据
    printf("--- Initializing Source Buffer ---\r\n");
    for(i = 0; i < DMA_TRANSFER_SIZE; i++)
    {
        g_SrcBuffer[i] = (i + 1) * 0x12345678;
        g_DstBuffer[i] = 0;  // 清零目标缓冲区
        printf("Src[%2d] = 0x%08lX\r\n", (int)i, (unsigned long)g_SrcBuffer[i]);
    }
    printf("\r\n");

    // 配置DMA通道1
    // 传输模式: BLOCK (有传输间隙，可被高优先级打断)
    // 触发方式: 软件触发
    // 数据位宽: 32bit
    // 地址模式: 源地址和目的地址均自增
    DMA_InitStruct.TransferMode = DMA_MODE_BLOCK;           // BLOCK传输模式
    DMA_InitStruct.TriggerType = DMA_TRIGGER_SOFTWARE;      // 软件触发
    DMA_InitStruct.TriggerSource = DMA_TRIGGER_SRC_UART1_RX;// 软件触发时此值无效，但需设置
    DMA_InitStruct.DataSize = DMA_DATA_SIZE_32BITS;         // 32位数据宽度
    DMA_InitStruct.SrcIncrement = DMA_ADDRESS_INCREMENT;    // 源地址自增
    DMA_InitStruct.DstIncrement = DMA_ADDRESS_INCREMENT;    // 目的地址自增
    DMA_InitStruct.SrcAddress = (uint32_t)g_SrcBuffer;      // 源地址
    DMA_InitStruct.DstAddress = (uint32_t)g_DstBuffer;      // 目的地址
    DMA_InitStruct.TransferCount = DMA_TRANSFER_SIZE;       // 传输数据块数量
    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);

    printf("--- Starting DMA Transfer ---\r\n");

    // 软件触发DMA传输
    DMA_StartTransfer(DMA_CHANNEL_1);

    // 等待DMA传输完成（BLOCK模式传输较快，轮询等待）
    while(DMA_CheckStatus(DMA_CHANNEL_1) != DMA_STATUS_COMPLETE)
    {
        // 等待传输完成
    }

    printf("--- DMA Transfer Complete ---\r\n\r\n");

    // 打印目标缓冲区数据并验证
    printf("--- Destination Buffer ---\r\n");
    CompareData(g_SrcBuffer, g_DstBuffer, DMA_TRANSFER_SIZE);
}

/**
 * @brief 比较源数据和目标数据，验证DMA传输是否正确
 *
 * @param src 源数据指针
 * @param dst 目标数据指针
 * @param count 数据数量
 */
static void CompareData(const uint32_t* src, const uint32_t* dst, uint32_t count)
{
    uint32_t i;
    uint8_t match = 1;

    for(i = 0; i < count; i++)
    {
        printf("Dst[%2d] = 0x%08lX", (int)i, (unsigned long)dst[i]);
        
        if(src[i] == dst[i])
        {
            printf(" [OK]\r\n");
        }
        else
        {
            printf(" [MISMATCH! Expected: 0x%08lX]\r\n", (unsigned long)src[i]);
            match = 0;
        }
    }
    
    printf("\r\n");
    if(match)
    {
        printf("=== DMA Transfer Verification: SUCCESS ===\r\n");
    }
    else
    {
        printf("=== DMA Transfer Verification: FAILED ===\r\n");
    }
}



/******************************************************************************
 * 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 */
