打印
[DemoCode下载]

定时器触发PDMA传输到DAC转换方法

[复制链接]
484|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gejigeji521|  楼主 | 2024-7-13 16:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
pd, DMA, DM, DAC, AC
/*************************************************************************//**
* [url=home.php?mod=space&uid=288409]@file[/url]     main.c
* [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
* [url=home.php?mod=space&uid=247401]@brief[/url]    Demonstrate how to PDMA and trigger DAC by Timer.
*
* [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2017 Nuvoton Technology Corp. All rights reserved.
*
******************************************************************************/
#include "stdio.h"
#include "NuMicro.h"

#if defined (__GNUC__) && !defined(__ARMCC_VERSION) && defined(OS_USE_SEMIHOSTING)
extern void initialise_monitor_handles(void);
#endif

const uint16_t sine[] = {2047, 2251, 2453, 2651, 2844, 3028, 3202, 3365, 3515, 3650, 3769, 3871, 3954,
                         4019, 4064, 4088, 4095, 4076, 4040, 3984, 3908, 3813, 3701, 3573, 3429, 3272,
                         3102, 2921, 2732, 2536, 2335, 2132, 1927, 1724, 1523, 1328, 1141,  962,  794,
                         639,  497,  371,  262,  171,   99,   45,   12,    0,    7,   35,   84,  151,
                         238,  343,  465,  602,  754,  919, 1095, 1281, 1475, 1674, 1876
                        };
const uint32_t array_size = sizeof(sine) / sizeof(uint16_t);

void SYS_Init(void)
{
    /* Unlock protected registers */
    SYS_UnlockReg();

    /* Set XT1_OUT(PF.2) and XT1_IN(PF.3) to input mode */
    PF->MODE &= ~(GPIO_MODE_MODE2_Msk | GPIO_MODE_MODE3_Msk);

    /* Enable HXT clock (external XTAL 12MHz) */
    CLK_EnableXtalRC(CLK_PWRCTL_HXTEN_Msk);

    /* Wait for HXT clock ready */
    CLK_WaitClockReady(CLK_STATUS_HXTSTB_Msk);

    /* Set core clock as PLL_CLOCK from PLL */
    CLK_SetCoreClock(FREQ_192MHZ);

    /* Set both PCLK0 and PCLK1 as HCLK/2 */
    CLK->PCLKDIV = CLK_PCLKDIV_APB0DIV_DIV2 | CLK_PCLKDIV_APB1DIV_DIV2;

    /* Enable DAC module clock */
    CLK_EnableModuleClock(DAC_MODULE);

    /* Enable Timer 0 module clock */
    CLK_EnableModuleClock(TMR0_MODULE);

    /* Enable PDMA module clock */
    CLK_EnableModuleClock(PDMA_MODULE);

    /* Set PB.12 and PB.13 to input mode */
    PB->MODE &= ~(GPIO_MODE_MODE12_Msk | GPIO_MODE_MODE13_Msk);
    /* Set PB multi-function pins for DAC voltage output */
    SYS->GPB_MFPH |= SYS_GPB_MFPH_PB12MFP_DAC0_OUT | SYS_GPB_MFPH_PB13MFP_DAC1_OUT;

    /* Disable digital input path of analog pin DAC0_OUT to prevent leakage */
    GPIO_DISABLE_DIGITAL_PATH(PB, (1ul << 12));
    /* Lock protected registers */
    SYS_LockReg();
}

int32_t main(void)
{
    /* Init System, IP clock and multi-function I/O */
    SYS_Init();

#if defined (__GNUC__) && !defined(__ARMCC_VERSION) && defined(OS_USE_SEMIHOSTING)
    initialise_monitor_handles();
#endif

    printf("This sample code use PDMA and trigger DAC0 output sine wave by Timer 0.\n");

    /* Open Channel 0 */
    PDMA_Open(PDMA,0x1);

    /* Set transfer data width, and transfer count */
    PDMA_SetTransferCnt(PDMA,0, PDMA_WIDTH_16, array_size);

    /* transfer width is one word(32 bit) */
    PDMA_SetTransferAddr(PDMA,0, (uint32_t)&sine[0], PDMA_SAR_INC, (uint32_t)&DAC0->DAT, PDMA_DAR_FIX);

    /* Select channel 0 request source from DAC */
    PDMA_SetTransferMode(PDMA,0, PDMA_DAC0_TX, FALSE, 0);

    /* Set transfer type and burst size */
    PDMA_SetBurstType(PDMA,0, PDMA_REQ_SINGLE, PDMA_BURST_128);

    /* Set the timer 0 trigger DAC and enable D/A converter */
    DAC_Open(DAC0, 0, DAC_TIMER0_TRIGGER);

    /* The DAC conversion settling time is 1us */
    DAC_SetDelayTime(DAC0, 1);

    /* Clear the DAC conversion complete finish flag for safe */
    DAC_CLR_INT_FLAG(DAC0, 0);

    /* Enable the PDMA Mode */
    DAC_ENABLE_PDMA(DAC0);

    /* Enable Timer0 counting to start D/A conversion */
    TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 1000);
    TIMER_SetTriggerTarget(TIMER0, TIMER_TRG_TO_DAC);
    TIMER_Start(TIMER0);

    while(1)
    {
        if (PDMA_GET_TD_STS(PDMA) == 0x1)
        {
            /* Re-Set transfer count and basic operation mode */
            PDMA_SetTransferCnt(PDMA,0, PDMA_WIDTH_16, array_size);
            PDMA_SetTransferMode(PDMA,0, PDMA_DAC0_TX, FALSE, 0);

            /* Clear PDMA channel 0 transfer done flag */
            PDMA_CLR_TD_FLAG(PDMA,0x1);
        }
    }
}
概述:

程序通过 PDMA(外设直接存储器访问)和定时器触发 DAC 转换。
使用 PDMA 将数据传输到 DAC,从而减轻 CPU 负载。
关键部分:

使用定时器 0 触发 DAC 转换。
配置 PDMA 以传输数据到 DAC。
初始化系统时钟、定时器、DAC 和 PDMA 模块。
在主循环中监视 PDMA 传输完成标志,重新配置 PDMA 以进行下一次传输。

使用特权

评论回复
沙发
gejigeji521|  楼主 | 2024-7-13 16:55 | 只看该作者
关键的主要步骤如下:
/* 主要步骤 */
SYS_Init();
PDMA_Open(PDMA, 0x1);
PDMA_SetTransferCnt(PDMA, 0, PDMA_WIDTH_16, array_size);
PDMA_SetTransferAddr(PDMA, 0, (uint32_t)&sine[0], PDMA_SAR_INC, (uint32_t)&DAC0->DAT, PDMA_DAR_FIX);
PDMA_SetTransferMode(PDMA, 0, PDMA_DAC0_TX, FALSE, 0);
PDMA_SetBurstType(PDMA, 0, PDMA_REQ_SINGLE, PDMA_BURST_128);
DAC_Open(DAC0, 0, DAC_TIMER0_TRIGGER);
DAC_SetDelayTime(DAC0, 1);
DAC_CLR_INT_FLAG(DAC0, 0);
DAC_ENABLE_PDMA(DAC0);
TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 1000);
TIMER_SetTriggerTarget(TIMER0, TIMER_TRG_TO_DAC);
TIMER_Start(TIMER0);

while(1) {
    if (PDMA_GET_TD_STS(PDMA) == 0x1) {
        PDMA_SetTransferCnt(PDMA, 0, PDMA_WIDTH_16, array_size);
        PDMA_SetTransferMode(PDMA, 0, PDMA_DAC0_TX, FALSE, 0);
        PDMA_CLR_TD_FLAG(PDMA, 0x1);
    }
}

使用特权

评论回复
板凳
gejigeji521|  楼主 | 2024-7-13 17:05 | 只看该作者
关键函数说明:
/**
* @brief       设置 PDMA 传输地址
*
* @param[in]   pdma            指向指定 PDMA 模块的指针
* @param[in]   u32Ch           选定的通道
* @param[in]   u32SrcAddr      源地址
* @param[in]   u32SrcCtrl      源控制属性。有效值为:
*                - \ref PDMA_SAR_INC(源地址递增)
*                - \ref PDMA_SAR_FIX(源地址固定)
* @param[in]   u32DstAddr      目标地址
* @param[in]   u32DstCtrl      目标控制属性。有效值为:
*                - \ref PDMA_DAR_INC(目标地址递增)
*                - \ref PDMA_DAR_FIX(目标地址固定)
*
* [url=home.php?mod=space&uid=266161]@return[/url]      无
*
* [url=home.php?mod=space&uid=1543424]@Details[/url]     此函数设置选定通道的源地址/目标地址和属性。
*/
void PDMA_SetTransferAddr(PDMA_T * pdma, uint32_t u32Ch, uint32_t u32SrcAddr, uint32_t u32SrcCtrl, uint32_t u32DstAddr, uint32_t u32DstCtrl);


使用特权

评论回复
地板
gejigeji521|  楼主 | 2024-7-13 17:06 | 只看该作者
对比上面的函数说明,再回头看示例中的操作思路就很明确了。

使用特权

评论回复
5
gejigeji521|  楼主 | 2024-7-13 17:06 | 只看该作者
函数参数说明
pdma:指向指定 PDMA 模块的指针。
u32Ch:选定的通道。
u32SrcAddr:源地址。
u32SrcCtrl:源控制属性,指示源地址是否递增或固定,有效值为 PDMA_SAR_INC(源地址递增)和 PDMA_SAR_FIX(源地址固定)。
u32DstAddr:目标地址。
u32DstCtrl:目标控制属性,指示目标地址是否递增或固定,有效值为 PDMA_DAR_INC(目标地址递增)和 PDMA_DAR_FIX(目标地址固定)。
函数作用
此函数用于设置选定 PDMA 通道的源地址和目标地址及其相应的控制属性。源地址和目标地址可以设定为递增或固定,根据传输的具体需求进行设置。

使用特权

评论回复
6
gejigeji521|  楼主 | 2024-7-13 17:21 | 只看该作者
PDMA_SetTransferMode 函数解释
/**
* @brief       设置 PDMA 传输模式
*
* @param[in]   pdma            指向指定 PDMA 模块的指针
* @param[in]   u32Ch           选定的通道
* @param[in]   u32Peripheral   选定的外设。有效值包括:
*                - \ref PDMA_MEM
*                - \ref PDMA_USB_TX
*                - \ref PDMA_USB_RX
*                - \ref PDMA_UART0_TX
*                - \ref PDMA_UART0_RX
*                - \ref PDMA_UART1_TX
*                - \ref PDMA_UART1_RX
*                - \ref PDMA_UART2_TX
*                - \ref PDMA_UART2_RX
*                - \ref PDMA_UART3_TX
*                - \ref PDMA_UART3_RX
*                - \ref PDMA_UART4_TX
*                - \ref PDMA_UART4_RX
*                - \ref PDMA_UART5_TX
*                - \ref PDMA_UART5_RX
*                - \ref PDMA_USCI0_TX
*                - \ref PDMA_USCI0_RX
*                - \ref PDMA_USCI1_TX
*                - \ref PDMA_USCI1_RX
*                - \ref PDMA_QSPI0_TX
*                - \ref PDMA_QSPI0_RX
*                - \ref PDMA_SPI0_TX
*                - \ref PDMA_SPI0_RX
*                - \ref PDMA_SPI1_TX
*                - \ref PDMA_SPI1_RX
*                - \ref PDMA_SPI2_TX
*                - \ref PDMA_SPI2_RX
*                - \ref PDMA_SPI3_TX
*                - \ref PDMA_SPI3_RX
*                - \ref PDMA_EPWM0_P1_RX
*                - \ref PDMA_EPWM0_P2_RX
*                - \ref PDMA_EPWM0_P3_RX
*                - \ref PDMA_EPWM1_P1_RX
*                - \ref PDMA_EPWM1_P2_RX
*                - \ref PDMA_EPWM1_P3_RX
*                - \ref PDMA_I2C0_TX
*                - \ref PDMA_I2C0_RX
*                - \ref PDMA_I2C1_TX
*                - \ref PDMA_I2C1_RX
*                - \ref PDMA_I2C2_TX
*                - \ref PDMA_I2C2_RX
*                - \ref PDMA_I2S0_TX
*                - \ref PDMA_I2S0_RX
*                - \ref PDMA_TMR0
*                - \ref PDMA_TMR1
*                - \ref PDMA_TMR2
*                - \ref PDMA_TMR3
*                - \ref PDMA_EADC0_RX
*                - \ref PDMA_DAC0_TX
*                - \ref PDMA_DAC1_TX
*                - \ref PDMA_EPWM0_CH0_TX
*                - \ref PDMA_EPWM0_CH1_TX
*                - \ref PDMA_EPWM0_CH2_TX
*                - \ref PDMA_EPWM0_CH3_TX
*                - \ref PDMA_EPWM0_CH4_TX
*                - \ref PDMA_EPWM0_CH5_TX
*                - \ref PDMA_EPWM1_CH0_TX
*                - \ref PDMA_EPWM1_CH1_TX
*                - \ref PDMA_EPWM1_CH2_TX
*                - \ref PDMA_EPWM1_CH3_TX
*                - \ref PDMA_EPWM1_CH4_TX
*                - \ref PDMA_EPWM1_CH5_TX
*                - \ref PDMA_UART6_TX
*                - \ref PDMA_UART6_RX
*                - \ref PDMA_UART7_TX
*                - \ref PDMA_UART7_RX
*                - \ref PDMA_EADC1_RX
* @param[in]   u32ScatterEn    是否启用散播聚集模式
* @param[in]   u32DescAddr     散播聚集描述符地址
*
* @return      无
*
* @details     此函数设置选定通道的传输模式,包括外设设置。
*/
void PDMA_SetTransferMode(PDMA_T * pdma, uint32_t u32Ch, uint32_t u32Peripheral, uint32_t u32ScatterEn, uint32_t u32DescAddr);

使用特权

评论回复
7
gejigeji521|  楼主 | 2024-7-13 17:21 | 只看该作者
函数参数说明
pdma:指向指定 PDMA 模块的指针。
u32Ch:选定的通道。
u32Peripheral:选定的外设。有效值为多个定义的常量,如 PDMA_MEM、PDMA_UART0_TX 等等,这些常量定义了特定的外设接口。
u32ScatterEn:是否启用散播聚集模式(Scatter-gather mode),用于复杂的传输需求。
u32DescAddr:散播聚集描述符地址,用于指向散播聚集模式下的描述符表。
函数作用
此函数用于设置选定 PDMA 通道的传输模式,包括与外设相关的设置。它可以配置传输的外设接口,并选择是否启用散播聚集模式,以满足不同的传输需求。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

172

主题

2194

帖子

8

粉丝