[开发板与模块] 【ESK32-30519 + ESK32-21001测评】ADC+PDMA采集数据并显示

[复制链接]
 楼主| lgnstar 发表于 2022-9-21 09:57 | 显示全部楼层 |阅读模式
<
本帖最后由 lgnstar 于 2022-9-21 10:04 编辑

首先感谢21ic和合泰能给我这次测评的机会!
此次测试内容为使用ADC采集模拟数据并显示在4位数码管上,采用ADC+PDMA方式,模拟量使用ESK32-21001底板的Potentiometer电位计获得。
核心板需要与底板连接3根线, VDD33、VSS、Potentiometer(VR)。我在焊连接器插针的时候脑子短路,把连接器焊反了,只能使用连接线了
20220921082137.jpg
项目工程直接使用\HT32_STD_5xxxx_FWLib_V1.1.1_5938\project_template\IP\Example\MDK_ARMv5\Project_54253.uvprojx修改。
这里使用软件触发ADC,PDMA循环模式,初始化程序如下:
  1. static void PDMA_Configuration(void)
  2. {
  3.     { /* Enable peripheral clock                                                                              */
  4.       CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  5.       CKCUClock.Bit.PDMA = 1;
  6.       CKCU_PeripClockConfig(CKCUClock, ENABLE);
  7.     }

  8.     { /* Configure PDMA channel to move ADC result from ADC->DR[0] to TM CHnCCR                               */
  9.       PDMACH_InitTypeDef PDMACH_InitStructure;
  10.       PDMACH_InitStructure.PDMACH_SrcAddr = (u32)&HTCFG_ADC_PORT->DR[0];
  11.       PDMACH_InitStructure.PDMACH_DstAddr = (u32)(adc_buf);   //采样数据缓冲区
  12.       PDMACH_InitStructure.PDMACH_BlkCnt = 1;
  13.       PDMACH_InitStructure.PDMACH_BlkLen = ADC_SAMPLE_CNT;    //连续采样数据个数
  14.       PDMACH_InitStructure.PDMACH_DataSize = WIDTH_16BIT;
  15.       PDMACH_InitStructure.PDMACH_Priority = VH_PRIO;
  16.       PDMACH_InitStructure.PDMACH_AdrMod = SRC_ADR_FIX | DST_ADR_LIN_INC | AUTO_RELOAD;
  17.       PDMA_Config(HTCFG_DMA_PORT, &PDMACH_InitStructure);
  18.       PDMA_EnaCmd(HTCFG_DMA_PORT, ENABLE);
  19.     }
  20. }

  21. static void ADC_Configuration(void)
  22. {
  23.     { /* Enable peripheral clock                                                                              */
  24.       CKCU_PeripClockConfig_TypeDef CKCUClock = {{ 0 }};
  25.       CKCUClock.Bit.AFIO = 1;
  26.       CKCUClock.Bit.HTCFG_ADC_IPN = 1;
  27.       CKCU_PeripClockConfig(CKCUClock, ENABLE);
  28.     }
  29.     /* Configure AFIO mode as ADC function                                                                    */
  30.     AFIO_GPxConfig(HTCFG_VR_GPIO_ID, HTCFG_VR_AFIO_PIN, HTCFG_VR_AFIO_MODE);
  31.    
  32.     { /* ADC related settings                                                                                 */
  33.       /* CK_ADC frequency is set to (CK_AHB / 64)                                                             */
  34.       CKCU_SetADCnPrescaler(HTCFG_ADC_CKCU_ADCPRE, CKCU_ADCPRE_DIV64);

  35.       /* One Shot mode, sequence length = 1                                                                   */
  36.       //ADC_RegularGroupConfig(HTCFG_ADC_PORT, ONE_SHOT_MODE, 1, 0);
  37.       ADC_RegularGroupConfig(HTCFG_ADC_PORT, CONTINUOUS_MODE, 1, 0);

  38.       /* ADC conversion time = (Sampling time + Latency) / CK_ADC = (1.5 + ADST + 12.5) / CK_ADC              */
  39.       /* Set ADST = 0, sampling time = 1.5 + ADST                                                             */
  40.       #if (LIBCFG_ADC_SAMPLE_TIME_BY_CH)
  41.         // The sampling time is set by the last parameter of the function "ADC_RegularChannelConfig()".
  42.       #else
  43.       ADC_SamplingTimeConfig(HTCFG_ADC_PORT, 0);
  44.       #endif

  45.       /* Set ADC conversion sequence as channel n                                                             */
  46.       ADC_RegularChannelConfig(HTCFG_ADC_PORT, HTCFG_VR_ADC_CH, 0, 0);

  47.       #if 1
  48.       /* Set TM MTO as ADC trigger source                                                                     */
  49.       //ADC_RegularTrigConfig(HTCFG_ADC_PORT, HTCFG_ADC_TRIG_TM);
  50.       ADC_RegularTrigConfig(HTCFG_ADC_PORT, ADC_TRIG_SOFTWARE);       //使能软件触发转换
  51.       #endif
  52.     }

  53.     /* Issue ADC DMA request when cycle end of conversion occur                                               */
  54.     ADC_PDMAConfig(HTCFG_ADC_PORT, ADC_PDMA_REGULAR_CYCLE, ENABLE);   //使能连续模式

  55.     ADC_Cmd(HTCFG_ADC_PORT, ENABLE);
  56.     ADC_SoftwareStartConvCmd(HTCFG_ADC_PORT, ENABLE);                 //触发ADC开始转换
  57. }
ADC转换开始后就会不间断的进行转换,转换结果会放入adc_buf缓冲区,循环更新。
接下来及就是在数码管上显示ADC转换的结果。这里只显示ADC转换后的值(0~4095)。
  1. const u8 NumberChar[]={
  2.   /* a: Seg4(0x10), b: Seg7(0x80), c: Seg2(0x04), d: Seg5(0x20),
  3.      e: Seg3(0x08), f: Seg0(0x01), g: Seg6(0x40), dp: Seg1(0x02) */
  4.   0xBD, /* '0' = a+b+c+d+e+f      = 0x10 + 0x80 + 0x04 + 0x20 + 0x08 + 0x01               = 0xBD */
  5.   0x84, /* '1' =   b+c+           =        0x80 + 0x04                                    = 0x84 */
  6.   0xF8, /* '2' = a+b  +d+e  +g    = 0x10 + 0x80 +        0x20 + 0x08 +      + 0x40        = 0xF8 */
  7.   0xF4, /* '3' = a+b+c+d    +g    = 0x10 + 0x80 + 0x04 + 0x20 +             + 0x40        = 0xF4 */
  8.   0xC5, /* '4' =   b+c    +f+g    =        0x80 + 0x04               + 0x01 + 0x40        = 0xC5 */
  9.   0x75, /* '5' = a  +c+d  +f+g    = 0x10        + 0x04 + 0x20        + 0x01 + 0x40        = 0x75 */
  10.   0x7D, /* '6' = a  +c+d+e+f+g    = 0x10        + 0x04 + 0x20 + 0x08 + 0x01 + 0x40        = 0x7D */
  11.   0x95, /* '7' = a+b+c    +f      = 0x10 + 0x80 + 0x04               + 0x01               = 0x95 */
  12.   0xFD, /* '8' = a+b+c+d+e+f+g    = 0x10 + 0x80 + 0x04 + 0x20 + 0x08 + 0x01 + 0x40        = 0xFD */
  13.   0xF5, /* '9' = a+b+c+d  +f+g    = 0x10 + 0x80 + 0x04 + 0x20        + 0x01 + 0x40        = 0xF5 */
  14.   0x02  /* '.' =               dp =                                                  0x02 = 0x02 */
  15. };


  16. /*********************************************************************************************************//**
  17.   * [url=home.php?mod=space&uid=247401]@brief[/url]  Configure the LEDC.
  18.   * @retval None
  19.   ***********************************************************************************************************/
  20. void bsp_ledc_config(void)
  21. {
  22.   {
  23.     /* Turn on the APB clock of AFIO. */
  24.     CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
  25.     CKCUClock.Bit.AFIO       = 1;
  26.     CKCU_PeripClockConfig(CKCUClock, ENABLE);

  27.     /* SEG0~7 */
  28.     AFIO_GPxConfig(HTCFG_LEDC_SEG0_GPIO_ID, HTCFG_LEDC_SEG0_AFIO_PIN, AFIO_FUN_LEDC);
  29.     AFIO_GPxConfig(HTCFG_LEDC_SEG1_GPIO_ID, HTCFG_LEDC_SEG1_AFIO_PIN, AFIO_FUN_LEDC);
  30.     AFIO_GPxConfig(HTCFG_LEDC_SEG2_GPIO_ID, HTCFG_LEDC_SEG2_AFIO_PIN, AFIO_FUN_LEDC);
  31.     AFIO_GPxConfig(HTCFG_LEDC_SEG3_GPIO_ID, HTCFG_LEDC_SEG3_AFIO_PIN, AFIO_FUN_LEDC);
  32.     AFIO_GPxConfig(HTCFG_LEDC_SEG4_GPIO_ID, HTCFG_LEDC_SEG4_AFIO_PIN, AFIO_FUN_LEDC);
  33.     AFIO_GPxConfig(HTCFG_LEDC_SEG5_GPIO_ID, HTCFG_LEDC_SEG5_AFIO_PIN, AFIO_FUN_LEDC);
  34.     AFIO_GPxConfig(HTCFG_LEDC_SEG6_GPIO_ID, HTCFG_LEDC_SEG6_AFIO_PIN, AFIO_FUN_LEDC);
  35.     AFIO_GPxConfig(HTCFG_LEDC_SEG7_GPIO_ID, HTCFG_LEDC_SEG7_AFIO_PIN, AFIO_FUN_LEDC);

  36.     /* COM0~4 */
  37.     AFIO_GPxConfig(HTCFG_LEDC_COM0_GPIO_ID, HTCFG_LEDC_COM0_AFIO_PIN, AFIO_FUN_LEDC);
  38.     AFIO_GPxConfig(HTCFG_LEDC_COM1_GPIO_ID, HTCFG_LEDC_COM1_AFIO_PIN, AFIO_FUN_LEDC);
  39.     AFIO_GPxConfig(HTCFG_LEDC_COM2_GPIO_ID, HTCFG_LEDC_COM2_AFIO_PIN, AFIO_FUN_LEDC);
  40.     AFIO_GPxConfig(HTCFG_LEDC_COM3_GPIO_ID, HTCFG_LEDC_COM3_AFIO_PIN, AFIO_FUN_LEDC);
  41.   }

  42.   {
  43.     LEDC_InitTypeDef LEDC_InitStruct;
  44.     /* Turn on the APB clock of LEDC. */
  45.     CKCU_PeripClockConfig_TypeDef CKCUClock = {{0}};
  46.     CKCUClock.Bit.LEDC       = 1;
  47.     CKCU_PeripClockConfig(CKCUClock, ENABLE);

  48.     /* Frame = fCK_LED / (LEDC_DutyClockNumber * COM Number) */
  49.     /*       = 1600 / (8*4)  =  50Hz */
  50.     LEDC_InitStruct.LEDC_ClockSource    = LEDC_SRC_LSI;                    /* LSI = 32Khz */
  51.     LEDC_InitStruct.LEDC_ClockPrescaler = HTCFG_LEDC_CLOCK_PRESCAL - 1;    /* fCK_LED = 32Khz / 20 = 1600 Hz */
  52.     LEDC_InitStruct.LEDC_DutyClockNumber = HTCFG_LEDC_DUTY_CLOCK_NUMBER;   /* Duty CLock Number = 8 Clock */
  53.     LEDC_InitStruct.LEDC_COMxEN = HTCFG_LEDC_COM1EN | HTCFG_LEDC_COM2EN |\
  54.                                   HTCFG_LEDC_COM3EN | HTCFG_LEDC_COM4EN;   /* Enable COMx */

  55.     /* Change the brightness, the parameter range is 0~Duty (CLock Number-1.) */
  56.     /* 0: the brightest, 7: the darkest.                                      */
  57.     LEDC_InitStruct.LEDC_DeadTime = 0;
  58.     LEDC_Init(&LEDC_InitStruct);                                            /* LEC initialization. */

  59.     /* Set the LEDC mode to COMMON_CATHODE. */
  60.     LEDC_SetPolarityMode(HTCFG_LEDC_COM1POL | HTCFG_LEDC_COM2POL | HTCFG_LEDC_COM3POL | HTCFG_LEDC_COM4POL,
  61.                          LEDC_SEG0POL | LEDC_SEG1POL | LEDC_SEG2POL | LEDC_SEG3POL |\
  62.                          LEDC_SEG4POL | LEDC_SEG5POL | LEDC_SEG6POL | LEDC_SEG7POL,
  63.                          COMMON_CATHODE);

  64.     //LEDC_IntConfig(ENABLE);                                                 /* Enable frame interrupt. */
  65.     //NVIC_EnableIRQ(LEDC_IRQn); /* Enable LECD IRQ. */
  66.     LEDC_Cmd(ENABLE);          /* LEDC Start. */
  67.   }
  68. }

  69. void bsp_ledc_display(u16 val)
  70. {
  71.   LEDC_SetData(HTCFG_LEDC_COM_D1, NumberChar[val/1000%10]);
  72.   LEDC_SetData(HTCFG_LEDC_COM_D2, NumberChar[val/100%10]);
  73.   LEDC_SetData(HTCFG_LEDC_COM_D3, NumberChar[val/10%10]);
  74.   LEDC_SetData(HTCFG_LEDC_COM_D4, NumberChar[val%10]);
  75. }
使用systick产生1ms定时中断,作为软件定时器的基准。
  1.   {
  2.           /* SYSTICK configuration */
  3.     SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK);       // Default : CK_AHB/8
  4.     SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000); // (CK_AHB/8/1000) = 1ms on chip
  5.     SYSTICK_IntConfig(ENABLE);                          // Enable SYSTICK Interrupt
  6.     SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
  7.   }
定义软件定时器,(此处代码参考安富莱例程)。
  1. //bsp_stimer.h

  2. #ifndef __BSP_STIMER_H
  3. #define __BSP_STIMER_H

  4. #define TMR_COUNT        2                /* 软件定时器的个数 (定时器ID范围 0 - 3) */

  5. #define TMR_REFRESH_DISPLAY   0   //用户更新数码管显示
  6. #define TMR_ADC_SAMPLE        1   //用于ADC滤波,计算转换结果

  7. typedef enum
  8. {
  9.         TMR_MODE_ONCE = 0,                /* 一次工作模式 */
  10.         TMR_MODE_AUTO = 1,          /* 自动定时工作模式 */
  11.         TMR_MODE_STOP = 2,
  12. }tmr_mode_t;

  13. typedef struct
  14. {
  15.         volatile u8   Mode;                    /* 计数器模式,1次性 */
  16.         volatile u8   Flag;                    /* 定时到达标志  */
  17.         volatile u32  Count;            /* 计数器 */
  18.         volatile u32  PreLoad;          /* 计数器预装值 */
  19. }soft_tmr_t;

  20. void bsp_stimer_init(void);
  21. void bsp_stimer_start(u8 _id, u32 _period, tmr_mode_t mode);
  22. void bsp_stimer_stop(u8 _id);
  23. u8 bsp_stimer_check(u8 _id);

  24. void bsp_stimer_dec(void);

  25. #endif
  1. // bsp_stimer.c

  2. #include "ht32.h"
  3. #include "bsp_stimer.h"

  4. /* 定于软件定时器结构体变量 */
  5. static soft_tmr_t s_tTmr[TMR_COUNT] = {0};

  6. /*
  7. *********************************************************************************************************
  8. *        函 数 名: bsp_stimer_init
  9. *        功能说明: 配置systick中断,并初始化软件定时器变量
  10. *        形    参:  无
  11. *        返 回 值: 无
  12. *********************************************************************************************************
  13. */
  14. void bsp_stimer_init(void)
  15. {
  16.   /* SYSTICK configuration */
  17.   SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK);       // Default : CK_AHB/8
  18.   SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000); // (CK_AHB/8/1000) = 1ms on chip
  19.   SYSTICK_IntConfig(ENABLE);                          // Enable SYSTICK Interrupt
  20.   SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
  21. }

  22. /*
  23. *********************************************************************************************************
  24. *        函 数 名: bsp_stimer_init
  25. *        功能说明: 每隔1ms对所有定时器变量减1。必须被SysTick_Handler中断函数周期性调用。
  26. *        形    参:
  27. *        返 回 值: 无
  28. *********************************************************************************************************
  29. */
  30. void bsp_stimer_dec(void)
  31. {
  32.   u8 i;
  33.         for (i = 0; i < TMR_COUNT; i++)
  34.         {
  35.     if(s_tTmr[i].Mode != TMR_MODE_STOP)
  36.     {
  37.       if (s_tTmr[i].Count > 0)
  38.       {
  39.         if (--s_tTmr[i].Count == 0)
  40.         {
  41.           s_tTmr[i].Flag = 1;
  42.           if(s_tTmr[i].Mode == TMR_MODE_AUTO)
  43.           {
  44.             s_tTmr[i].Count = s_tTmr[i].PreLoad;
  45.           }
  46.         }
  47.       }
  48.     }
  49.         }
  50. }

  51. /*
  52. *********************************************************************************************************
  53. *        函 数 名: bsp_stimer_start
  54. *        功能说明: 启动一个定时器,并设置定时周期。
  55. *        形    参:          _id     : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
  56. *                                _period : 定时周期,单位1ms
  57. *       _mode   : 定时器工作模式,一次性、连续
  58. *        返 回 值: 无
  59. *********************************************************************************************************
  60. */
  61. void bsp_stimer_start(u8 _id, u32 _period, tmr_mode_t _mode)
  62. {
  63.         if (_id >= TMR_COUNT)
  64.         {
  65.                 while(1); /* 参数异常,死机等待看门狗复位 */
  66.         }

  67.         __disable_irq();                          /* 关中断 */

  68.         s_tTmr[_id].Count = _period;                /* 实时计数器初值 */
  69.         s_tTmr[_id].PreLoad = _period;  /* 计数器自动重装值,仅自动模式起作用 */
  70.         s_tTmr[_id].Flag = 0;                                    /* 定时时间到标志 */
  71.         s_tTmr[_id].Mode = _mode;              /* 工作模式 */

  72.         __enable_irq();                                  /* 开中断 */
  73. }

  74. /*
  75. *********************************************************************************************************
  76. *        函 数 名: bsp_stimer_stop
  77. *        功能说明: 停止一个定时器
  78. *        形    参:          _id     : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
  79. *        返 回 值: 无
  80. *********************************************************************************************************
  81. */
  82. void bsp_stimer_stop(u8 _id)
  83. {
  84.         if (_id >= TMR_COUNT)
  85.         {
  86.                 while(1); /* 参数异常,死机等待看门狗复位 */
  87.         }

  88.         __disable_irq();                          /* 关中断 */

  89.         s_tTmr[_id].Count = 0;                                /* 实时计数器初值 */
  90.         s_tTmr[_id].Flag = 0;                                /* 定时时间到标志 */
  91.         s_tTmr[_id].Mode = TMR_MODE_STOP;        /* 自动工作模式 */

  92.         __enable_irq();                                  /* 开中断 */
  93. }

  94. /*
  95. *********************************************************************************************************
  96. *        函 数 名: bsp_stimer_check
  97. *        功能说明: 检测定时器是否超时
  98. *        形    参:          _id     : 定时器ID,值域【0,TMR_COUNT-1】。用户必须自行维护定时器ID,以避免定时器ID冲突。
  99. *                                _period : 定时周期,单位1ms
  100. *        返 回 值: 返回 0 表示定时未到, 1表示定时到
  101. *********************************************************************************************************
  102. */
  103. u8 bsp_stimer_check(u8 _id)
  104. {
  105.         if (_id >= TMR_COUNT)
  106.         {
  107.                 return 0;
  108.         }

  109.         if (s_tTmr[_id].Flag == 1)
  110.         {
  111.                 s_tTmr[_id].Flag = 0;                return 1;
  112.         }
  113.         else
  114.         {
  115.                 return 0;
  116.         }
  117. }
好的,到此各个模块已经准备好了,在main函数中调用这几个模块就可以显示出想要的结果。
  1. int main(void)
  2. {
  3.   bsp_stimer_init();
  4.   bsp_adc_sample();
  5.   bsp_ledc_config();
  6.   bsp_ledc_display(8888);

  7.   HT32F_DVB_LEDInit(HT_LED1);

  8.   bsp_stimer_start(TMR_REFRESH_DISPLAY, 1000, TMR_MODE_AUTO);
  9.   bsp_stimer_start(TMR_ADC_SAMPLE, 50, TMR_MODE_AUTO);

  10.   while (1)
  11.   {
  12.     if(bsp_stimer_check(TMR_ADC_SAMPLE))
  13.     {
  14.       bsp_adc_chache();
  15.     }

  16.     if(bsp_stimer_check(TMR_REFRESH_DISPLAY))
  17.     {
  18.       u16 adc_val;
  19.       adc_val = get_adc_value();
  20.       bsp_ledc_display(adc_val);

  21.       HT32F_DVB_LEDToggle(HT_LED1);
  22.     }
  23.   }
  24. }
左右旋转Potentiometer电位器,在数码管上就会显示出当前ADC转换值。





eltonchang2001 发表于 2022-9-26 10:57 | 显示全部楼层
楼主排针焊错方向,改用飞线,累了。
beacherblack 发表于 2022-10-1 16:56 | 显示全部楼层
PDMA的控制器?                 
typeof 发表于 2022-10-1 17:09 | 显示全部楼层
这个学一学,dma的配置不容易呢
usysm 发表于 2022-10-1 17:30 | 显示全部楼层
可以实现多少路ADC的采集              
aspoke 发表于 2022-10-1 18:13 | 显示全部楼层
PDMA和DMA有什么区别呢         
 楼主| lgnstar 发表于 2022-10-3 09:36 | 显示全部楼层
本帖最后由 lgnstar 于 2022-10-3 09:47 编辑
usysm 发表于 2022-10-1 17:30
可以实现多少路ADC的采集

手册上有提到:     单片机内建一个带参考电压发生器 (V REF ) 的12-bit 多通道 A/D 转换器,总共有 14 个复用通
道,包括10 个可供外部模拟信号输入的外部通道和 4 个内部通道。
    A/D 转换器支持14 个多路复用通道,转换结果依组转换次序存放到对应数据寄存器中。一
个转换组可以安排一个转换序列,此序列长度可为1 到 8 个通道。
   我理解使用dma一次最多可以转换8路adc。
caigang13 发表于 2022-10-3 11:49 来自手机 | 显示全部楼层
看看楼主的经验
Henryko 发表于 2022-10-4 19:51 | 显示全部楼层
dma的配置很麻烦吧
cashrwood 发表于 2023-1-5 15:59 | 显示全部楼层
PDMA和DMA有什么直接区别呢
benjaminka 发表于 2023-1-5 16:07 | 显示全部楼层
这个是官网的例程吗?              
pl202 发表于 2023-1-6 15:00 | 显示全部楼层
支持多少路的ADC采样?              
minzisc 发表于 2023-1-6 16:21 | 显示全部楼层
不同通道之间的ADC是否存在干扰呢
pixhw 发表于 2023-1-6 21:07 | 显示全部楼层
pdma是什么模式呢              
saservice 发表于 2023-1-6 22:08 | 显示全部楼层
是否有总线可以调用呢              
bartonalfred 发表于 2023-1-9 16:17 | 显示全部楼层
这个板子非常的漂亮了。              
deliahouse887 发表于 2023-1-10 20:59 | 显示全部楼层
怎么配置多通道的ADC和DMA?
cashrwood 发表于 2023-3-2 11:03 | 显示全部楼层
PDMA是什么?              
modesty3jonah 发表于 2023-3-2 11:32 | 显示全部楼层
adc和dma怎么在中断中采集?
iyoum 发表于 2023-3-2 11:49 | 显示全部楼层
dma支持多大的数据存储              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

17

帖子

1

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