[牛人杂谈] 采用EPWM触发PDMA发送执行DAC功能

[复制链接]
1261|7
 楼主| gejigeji521 发表于 2024-7-13 18:24 | 显示全部楼层 |阅读模式
PWM, DMA, DM, DAC, AC
  1. /*************************************************************************//**
  2. * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  3. * [url=home.php?mod=space&uid=895143]@version[/url]  V1.00
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]    Demonstrate how to use PDMA and trigger DAC0 by EPWM.
  5. *
  6. * [url=home.php?mod=space&uid=17282]@CopyRight[/url] (C) 2017 Nuvoton Technology Corp. All rights reserved.
  7. *
  8. ******************************************************************************/
  9. #include "stdio.h"
  10. #include "NuMicro.h"

  11. #if defined (__GNUC__) && !defined(__ARMCC_VERSION) && defined(OS_USE_SEMIHOSTING)
  12. extern void initialise_monitor_handles(void);
  13. #endif

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


  20. const uint32_t array_size = sizeof(sine) / sizeof(uint16_t);

  21. void SYS_Init(void)
  22. {
  23.     /* Unlock protected registers */
  24.     SYS_UnlockReg();

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

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

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

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

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

  35.     /* Enable DAC module clock */
  36.     CLK_EnableModuleClock(DAC_MODULE);

  37.     /* Enable EPWM0 module clock */
  38.     CLK_EnableModuleClock(EPWM0_MODULE);

  39.     /* Enable PDMA clock source */
  40.     CLK_EnableModuleClock(PDMA_MODULE);

  41.     /* Select EPWM0 module clock source as PCLK0 */
  42.     CLK_SetModuleClock(EPWM0_MODULE, CLK_CLKSEL2_EPWM0SEL_PCLK0, 0);

  43.     /* Set PB.12 to input mode */
  44.     PB->MODE &= ~GPIO_MODE_MODE12_Msk;
  45.     /* Set PB multi-function pin for DAC voltage output */
  46.     SYS->GPB_MFPH |= SYS_GPB_MFPH_PB12MFP_DAC0_OUT;
  47.     /* Disable digital input path of analog pin DAC0_OUT to prevent leakage */
  48.     GPIO_DISABLE_DIGITAL_PATH(PB, (1ul << 12));
  49.     /* Set PG multi-function pins for EPWMA Channel 0 */
  50.     SYS->GPG_MFPH |= SYS_GPG_MFPH_PG8MFP_EPWM0_CH0;
  51.     /* Lock protected registers */
  52.     SYS_LockReg();
  53. }

  54. void EPWM0_Init()
  55. {

  56.     /* Set EPWM0 Timer clock prescaler */
  57.     EPWM_SET_PRESCALER(EPWM0, 0, 100);

  58.     /* Set up counter type */
  59.     EPWM0->CTL1 &= ~EPWM_CTL1_CNTTYPE0_Msk;

  60.     /* Set EPWM0 timer duty */
  61.     EPWM_SET_CMR(EPWM0, 0, 360);

  62.     /* Set EPWM0 timer period */
  63.     EPWM_SET_CNR(EPWM0, 0, 1720);

  64.     /* EPWM period point trigger DAC enable */
  65.     EPWM_EnableDACTrigger(EPWM0, 0, EPWM_TRIGGER_DAC_PERIOD);

  66.     /* Set output level at zero, compare up, period(center) and compare down of channel 0 */
  67.     EPWM_SET_OUTPUT_LEVEL(EPWM0, 0x1, EPWM_OUTPUT_HIGH, EPWM_OUTPUT_LOW, EPWM_OUTPUT_NOTHING, EPWM_OUTPUT_NOTHING);

  68.     /* Enable output of EPWM0 channel 0 */
  69.     EPWM_EnableOutput(EPWM0, 0x1);
  70. }



  71. int32_t main(void)
  72. {

  73.     /* Init System, IP clock and multi-function I/O */
  74.     SYS_Init();

  75. #if defined (__GNUC__) && !defined(__ARMCC_VERSION) && defined(OS_USE_SEMIHOSTING)
  76.     initialise_monitor_handles();
  77. #endif

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


  79.     /* Init EPWM0 trigger for DAC */
  80.     EPWM0_Init();

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

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

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

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

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

  91.     /* Set the EPWM0 trigger DAC and enable D/A converter */
  92.     DAC_Open(DAC0, 0, DAC_EPWM0_TRIGGER);

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

  95.     /* Enable the PDMA Mode */
  96.     DAC_ENABLE_PDMA(DAC0);

  97.     /* Enable EPWM0 channel 0 to start D/A conversion */
  98.     EPWM_Start(EPWM0, 0x1);

  99.     while(1)
  100.     {
  101.         if (PDMA_GET_TD_STS(PDMA) == 0x1)
  102.         {
  103.             /* Re-Set transfer count and basic operation mode */
  104.             PDMA_SetTransferCnt(PDMA,0, PDMA_WIDTH_16, array_size);
  105.             PDMA_SetTransferMode(PDMA,0, PDMA_DAC0_TX, FALSE, 0);

  106.             /* Clear PDMA channel 0 transfer done flag */
  107.             PDMA_CLR_TD_FLAG(PDMA,0x1);
  108.         }

  109.     }


  110. }

除了定时器可以定时触发PDMA执行DAC输出任务,EPWM也可以实现定时触发。
在这个初始化函数中:
  • 定时器设置:

    • 设置 EPWM 的预分频器,使得计时更精确。
    • 设置 EPWM 的计数器和周期。
    • 配置 EPWM 在每个周期触发 DAC 更新。
  • PWM 波形输出:

    • 设置 EPWM 输出的高低电平,使得在特定比较值时输出高电平或低电平。
    • 启用 EPWM 输出,使得信号在硬件引脚上输出。

 楼主| gejigeji521 发表于 2024-7-13 18:25 | 显示全部楼层
在这个程序中,EPWM 的作用不仅限于提供定时控制,还包括输出 PWM 波形。EPWM 的定时功能用于触发 DAC 更新,使得 DAC 可以输出稳定的正弦波信号;同时,EPWM 还可以在特定引脚上输出 PWM 波形,满足系统的其他需求。这样一来,EPWM 就在一个程序中实现了多重功能,提高了系统的灵活性和效率。
 楼主| gejigeji521 发表于 2024-7-13 18:25 | 显示全部楼层
在该示例中,EPWM触发PDMA的具体位置是在EPWM波形的周期点(period point)。这意味着在每个PWM周期结束时,触发一次PDMA传输。这样,EPWM可以在每个周期的结尾触发一次DAC更新,从而输出新的DAC值。
 楼主| gejigeji521 发表于 2024-7-13 18:25 | 显示全部楼层
请注意以下代码
  1. void EPWM0_Init()
  2. {
  3.     /* Set EPWM0 Timer clock prescaler */
  4.     EPWM_SET_PRESCALER(EPWM0, 0, 100);

  5.     /* Set up counter type */
  6.     EPWM0->CTL1 &= ~EPWM_CTL1_CNTTYPE0_Msk;

  7.     /* Set EPWM0 timer duty */
  8.     EPWM_SET_CMR(EPWM0, 0, 360);

  9.     /* Set EPWM0 timer period */
  10.     EPWM_SET_CNR(EPWM0, 0, 1720);

  11.     /* EPWM period point trigger DAC enable */
  12.     EPWM_EnableDACTrigger(EPWM0, 0, EPWM_TRIGGER_DAC_PERIOD);

  13.     /* Set output level at zero, compare up, period(center) and compare down of channel 0 */
  14.     EPWM_SET_OUTPUT_LEVEL(EPWM0, 0x1, EPWM_OUTPUT_HIGH, EPWM_OUTPUT_LOW, EPWM_OUTPUT_NOTHING, EPWM_OUTPUT_NOTHING);

  15.     /* Enable output of EPWM0 channel 0 */
  16.     EPWM_EnableOutput(EPWM0, 0x1);
  17. }
 楼主| gejigeji521 发表于 2024-7-13 18:25 | 显示全部楼层
触发的方式设置
  1. /* EPWM period point trigger DAC enable */
  2. EPWM_EnableDACTrigger(EPWM0, 0, EPWM_TRIGGER_DAC_PERIOD);
 楼主| gejigeji521 发表于 2024-7-13 18:26 | 显示全部楼层
EPWM_EnableDACTrigger 函数
EPWM_EnableDACTrigger 函数的第三个参数 EPWM_TRIGGER_DAC_PERIOD 表示在每个PWM周期结束时触发DAC。这是一个宏定义,指定了触发事件发生的位置:

EPWM_TRIGGER_DAC_PERIOD:在PWM周期点(period point)触发。
因此,每当EPWM的计数器达到其周期计数值(即一个PWM周期的结束点)时,EPWM将生成一个触发信号,触发PDMA传输。这使得PDMA能够在每个周期结束时,将新的正弦波数据传输到DAC,从而更新DAC的输出。
 楼主| gejigeji521 发表于 2024-7-13 18:26 | 显示全部楼层
EPWM在PWM波形的周期点(period point)触发PDMA。这意味着在每个PWM周期结束时,触发一次PDMA传输,从而确保DAC能够在每个周期更新其输出值,实现稳定的正弦波输出。
 楼主| gejigeji521 发表于 2024-7-13 18:27 | 显示全部楼层
EPWM触发和定时器触发在微控制器中的应用有着不同的特点和优缺点,主要区别如下:

EPWM触发
工作原理:

EPWM(Enhanced Pulse Width Modulation)模块可以生成可调节的PWM波形,用于控制电机驱动、LED亮度调节等应用。EPWM可以通过设置比较匹配和定时器计数器来生成不同的PWM波形。
EPWM可以配置为在特定的事件(如周期点、上升/下降沿等)时触发其他外设,如DAC、ADC、PDMA等。这种触发方式可以实现精确的时间控制和同步操作。
优点:

提供精确的时间控制,可以在PWM波形的特定点上触发外设操作,例如在周期结束时更新DAC值。
可以实现复杂的PWM波形生成和精确的同步控制。
缺点:

需要专门的硬件支持,相对于简单的定时器,配置和使用上可能稍显复杂。
占用一定的硬件资源。
定时器触发
工作原理:

定时器用于生成精确的时间基准,例如周期性地产生中断或触发事件。定时器可以配置为在达到特定的计数值时触发其他操作。
可以用于定时任务、延时计时、时间测量等。
优点:

简单易用,通常只需配置计数器和预分频器即可实现基本功能。
适用于需要周期性执行的简单任务,如定时中断、延时操作等。
缺点:

通常只能提供固定的时间间隔或触发点,灵活性不如EPWM触发。
不能直接生成PWM波形,而是用于生成时间基准。
总结
EPWM触发适合需要精确同步和控制的应用,例如在特定时刻更新外设数据(如DAC输出)。
定时器触发适用于周期性任务和基本的时间测量,配置简单,但灵活性不如EPWM触发。
选择使用哪种触发方式取决于具体的应用需求:如果需要PWM波形控制和精确的同步操作,EPWM触发是更好的选择;如果只需要基本的定时或延时功能,定时器触发则更为合适。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

196

主题

2465

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部