- #include "at32f403a_407_wk_config.h"
- #include "wk_system.h"
- //#include "timecalculate.h" /*(DWT测量法)*/
- uint16_t adc_value[2] = {0}; //用于存放外部信号的adc数组
- uint16_t dma_trans_complete_flag = 0; //dma转换完成标志
- //uint16_t start = 0, stop = 0; /*(DWT测量法)*/
- /*(调试器跟踪法)——基本配置*/
- /*
- void disable_swo_debug_config(void)
- {
- crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
- gpio_pin_remap_config(SWJTAG_GMUX_010, TRUE);
- // DEBUGMCU->ctrl_bit.trace_ioen = FALSE;
- DEBUGMCU->ctrl_bit.trace_ioen = TRUE;
- }
- */
- int main(void)
- {
- wk_system_clock_config();
- wk_periph_clock_config();
- //disable_swo_debug_config();/*(调试器跟踪法)——使能swo功能*/
- wk_nvic_config();
- wk_timebase_init();
- wk_dma1_channel1_init();
- wk_dma_channel_config(DMA1_CHANNEL1,
- (uint32_t)&ADC1->odt,
- DMA1_CHANNEL1_MEMORY_BASE_ADDR,
- DMA1_CHANNEL1_BUFFER_SIZE);
- dma_channel_enable(DMA1_CHANNEL1, TRUE);
- wk_adc1_init();
- wk_gpio_config(); /*GPIO翻转法*/
- adc_ordinary_software_trigger_enable(ADC1, TRUE);
- //start = ARM_CM_DWT_CYCCNT; /*(DWT测量法)*/
- //gpio_bits_set(GPIOA, GPIO_PINS_4); /*(GPIO翻转法)*/
- while(dma_trans_complete_flag == 0); //等待DMA传输完成
-
- while(1)
- {
-
- }
- }
at32f403a_407_wk_config.c
- #include "at32f403a_407_wk_config.h"
- void wk_system_clock_config(void)
- {
- crm_reset();
- crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);
- while(crm_flag_get(CRM_LICK_STABLE_FLAG) != SET)
- {
- }
- crm_clock_source_enable(CRM_CLOCK_SOURCE_HICK, TRUE);
- while(crm_flag_get(CRM_HICK_STABLE_FLAG) != SET)
- {
- }
- crm_pll_config(CRM_PLL_SOURCE_HICK, CRM_PLL_MULT_60, CRM_PLL_OUTPUT_RANGE_GT72MHZ);
- crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);
- while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
- {
- }
- crm_ahb_div_set(CRM_AHB_DIV_1);
- crm_apb2_div_set(CRM_APB2_DIV_2);
- crm_apb1_div_set(CRM_APB1_DIV_2);
- crm_auto_step_mode_enable(TRUE);
- crm_sysclk_switch(CRM_SCLK_PLL);
- while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
- {
- }
- crm_auto_step_mode_enable(FALSE);
- system_core_clock_update();
- }
- void wk_periph_clock_config(void)
- {
- crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
- crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
- crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
- crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
- crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
- }
- void wk_nvic_config(void)
- {
- nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
- NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 15, 0));
- nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
- }
- void wk_gpio_config(void)
- {
- gpio_init_type gpio_init_struct;
- gpio_default_para_init(&gpio_init_struct);
- gpio_bits_reset(GPIOA, GPIO_PINS_4);
- gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
- gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
- gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
- gpio_init_struct.gpio_pins = GPIO_PINS_4;
- gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
- gpio_init(GPIOA, &gpio_init_struct);
- }
- void wk_adc1_init(void)
- {
- gpio_init_type gpio_init_struct;
- adc_base_config_type adc_base_struct;
- gpio_default_para_init(&gpio_init_struct);
- gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG;
- gpio_init_struct.gpio_pins = GPIO_PINS_0;
- gpio_init(GPIOA, &gpio_init_struct);
- gpio_init_struct.gpio_mode = GPIO_MODE_ANALOG;
- gpio_init_struct.gpio_pins = GPIO_PINS_1;
- gpio_init(GPIOA, &gpio_init_struct);
- crm_adc_clock_div_set(CRM_ADC_DIV_6);
- adc_combine_mode_select(ADC_INDEPENDENT_MODE);
- adc_base_default_para_init(&adc_base_struct);
- adc_base_struct.sequence_mode = TRUE;
- adc_base_struct.repeat_mode = FALSE;
- adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
- adc_base_struct.ordinary_channel_length = 2;
- adc_base_config(ADC1, &adc_base_struct);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_239_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_239_5);
- adc_ordinary_conversion_trigger_set(ADC1, ADC12_ORDINARY_TRIG_SOFTWARE, TRUE);
- adc_ordinary_part_mode_enable(ADC1, FALSE);
- adc_dma_mode_enable(ADC1, TRUE);
- adc_enable(ADC1, TRUE);
- adc_calibration_init(ADC1);
- while(adc_calibration_init_status_get(ADC1));
- adc_calibration_start(ADC1);
- while(adc_calibration_status_get(ADC1));
- }
- void wk_dma1_channel1_init(void)
- {
- dma_init_type dma_init_struct;
- dma_reset(DMA1_CHANNEL1);
- dma_default_para_init(&dma_init_struct);
- dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
- dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
- dma_init_struct.memory_inc_enable = TRUE;
- dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
- dma_init_struct.peripheral_inc_enable = FALSE;
- dma_init_struct.priority = DMA_PRIORITY_LOW;
- dma_init_struct.loop_mode_enable = FALSE;
- dma_init(DMA1_CHANNEL1, &dma_init_struct);
- dma_flexible_config(DMA1, FLEX_CHANNEL1, DMA_FLEXIBLE_ADC1);
- dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
- }
- void wk_dma_channel_config(dma_channel_type* dmax_channely, uint32_t peripheral_base_addr, uint32_t memory_base_addr, uint16_t buffer_size)
- {
- dmax_channely->dtcnt = buffer_size;
- dmax_channely->paddr = peripheral_base_addr;
- dmax_channely->maddr = memory_base_addr;
- }
at32f403a_407_wk_config.h
- #ifndef __AT32F403A_407_WK_CONFIG_H
- #define __AT32F403A_407_WK_CONFIG_H
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "at32f403a_407.h"
- #define DMA1_CHANNEL1_BUFFER_SIZE 2 //DMA传输数据个数
- #define DMA1_CHANNEL1_MEMORY_BASE_ADDR (uint32_t)adc_value //DMA传输目标地址
- void wk_system_clock_config(void);
- void wk_periph_clock_config(void);
- void wk_nvic_config(void);
- void wk_gpio_config(void);
- void wk_adc1_init(void);
- void wk_dma1_channel1_init(void);
- void wk_dma_channel_config(dma_channel_type* dmax_channely, uint32_t peripheral_base_addr, uint32_t memory_base_addr, uint16_t buffer_size);
- #ifdef __cplusplus
- }
- #endif
- #endif
-
at32f403a_407_int.c
- #include "at32f403a_407_int.h"
- #include "wk_system.h"
- //#include "timecalculate.h" /*(DWT测量法)*/
- extern uint16_t dma_trans_complete_flag;
- //extern uint16_t stop; /*(DWT测量法)*/
- void SysTick_Handler(void)
- {
- wk_timebase_handler();
- }
- void DMA1_Channel1_IRQHandler(void)
- {
- //stop = ARM_CM_DWT_CYCCNT; /*(DWT测量法)*/
- //gpio_bits_reset(GPIOA, GPIO_PINS_4); /*(GPIO翻转法)*/
- if(dma_interrupt_flag_get(DMA1_FDT1_FLAG) != RESET)
- {
- dma_flag_clear(DMA1_FDT1_FLAG);
- dma_trans_complete_flag = 1;
- }
- }
-
四、测试方法
不同测试方法的main.c和at32f403a_407_int.c略有不同,其他基本一致。
1.GPIO翻转法
介绍
GPIO在ADC转换前为低电平,转换开始时为高电平,转换结束后为低电平。
代码
main.c
- #include "at32f403a_407_wk_config.h"
- #include "wk_system.h"
- uint16_t adc_value[2] = {0}; //用于存放外部信号的adc数组
- uint16_t dma_trans_complete_flag = 0; //dma转换完成标志
- int main(void)
- {
- wk_system_clock_config();
- wk_periph_clock_config();
- wk_nvic_config();
- wk_timebase_init();
- wk_dma1_channel1_init();
- wk_dma_channel_config(DMA1_CHANNEL1,
- (uint32_t)&ADC1->odt,
- DMA1_CHANNEL1_MEMORY_BASE_ADDR,
- DMA1_CHANNEL1_BUFFER_SIZE);
- dma_channel_enable(DMA1_CHANNEL1, TRUE);
- wk_adc1_init();
- wk_gpio_config(); /*GPIO翻转法——默认PA4为低电平*/
- adc_ordinary_software_trigger_enable(ADC1, TRUE);
- gpio_bits_set(GPIOA, GPIO_PINS_4); /*(GPIO翻转法)——ADC开始转换后PA4设为高电平*/
- while(dma_trans_complete_flag == 0); //等待DMA传输完成
- while(1)
- {
- }
- }
at32f403a_407_int.c
- #include "at32f403a_407_int.h"
- #include "wk_system.h"
- extern uint16_t dma_trans_complete_flag;
- void SysTick_Handler(void)
- {
- wk_timebase_handler();
- }
- void DMA1_Channel1_IRQHandler(void)
- {
- gpio_bits_reset(GPIOA, GPIO_PINS_4); /*(GPIO翻转法)——ADC转换结束后PA4设为低电平*/
- if(dma_interrupt_flag_get(DMA1_FDT1_FLAG) != RESET)
- {
- dma_flag_clear(DMA1_FDT1_FLAG);
- dma_trans_complete_flag = 1;
- }
- }
-
结果
①理论时间
单个通道:(采样+转换)时间= (采样时间+12.5)个ADCCLK周期;
两个通道:T_calculate = (239.5+12.5) ÷ 20M × 2 = 25.2us
②实测时间
逻辑分析仪测量得ADC转换(两个通道)时间T_test = 25.75us。
2.调试器跟踪法(AT-Link)
介绍
使用AT-link进入调试,测量两个断点之间的时间差。代码
main.c
- #include "at32f403a_407_wk_config.h"
- #include "wk_system.h"
- uint16_t adc_value[2] = {0}; //用于存放外部信号的adc数组
- uint16_t dma_trans_complete_flag = 0; //dma转换完成标志
- /*(调试器跟踪法)——基本配置*/
- void disable_swo_debug_config(void)
- {
- crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
- gpio_pin_remap_config(SWJTAG_GMUX_010, TRUE);
- //DEBUGMCU->ctrl_bit.trace_ioen = FALSE;
- DEBUGMCU->ctrl_bit.trace_ioen = TRUE;
- }
- int main(void)
- {
- wk_system_clock_config();
- wk_periph_clock_config();
- disable_swo_debug_config();/*(调试器跟踪法)——使能swo功能*/
- wk_nvic_config();
- wk_timebase_init();
- wk_dma1_channel1_init();
- wk_dma_channel_config(DMA1_CHANNEL1,
- (uint32_t)&ADC1->odt,
- DMA1_CHANNEL1_MEMORY_BASE_ADDR,
- DMA1_CHANNEL1_BUFFER_SIZE);
- dma_channel_enable(DMA1_CHANNEL1, TRUE);
- wk_adc1_init();
- adc_ordinary_software_trigger_enable(ADC1, TRUE);
- while(dma_trans_complete_flag == 0); //等待DMA传输完成
-
- while(1)
- {
-
- }
- }
at32f403a_407_int.c
- #include "at32f403a_407_int.h"
- #include "wk_system.h"
- extern uint16_t dma_trans_complete_flag;
- void SysTick_Handler(void)
- {
- wk_timebase_handler();
- }
- void DMA1_Channel1_IRQHandler(void)
- {
- if(dma_interrupt_flag_get(DMA1_FDT1_FLAG) != RESET)
- {
- dma_flag_clear(DMA1_FDT1_FLAG);
- dma_trans_complete_flag = 1;
- }
- }
步骤
①设置调试器
②启用变量跟踪;
③进入DUBUG模式,先设置断点(如下图),再全速运行代码;
④右击右下角的运行时间t1,将其复位为0;
⑤在中断中设置下一个断点,再全速运行;
结果
①理论时间
单个通道:(采样+转换)时间= (采样时间+12.5)个ADCCLK周期;
两个通道:T_calculate = (239.5+12.5) ÷ 20M × 2 = 25.2us
②实测时间
观察右下角t1得ADC转换(两个通道)时间T_test = 25.7us。
3.DWT测量法
介绍
添加DWT测量的C文件和H文件,在DEBUG下观察计数差值,利用差值计算得ADC转换时间。
步骤
①将“cpu_sysclk_time_calculate”文件夹(详见附件)移植至工程文件下;
②新建Group(Calculate)并添加现有文件进来;
③选择步骤①路径下“cpu_sysclk_time_calculate”的c文件;
④添加文件路径;
⑤添加步骤①路径下的“cpu_sysclk_time_calculate”文件夹;
代码
main.c
- #include "at32f403a_407_wk_config.h"
- #include "wk_system.h"
- #include "timecalculate.h" /*(DWT测量法)——包含相关头文件*/
- uint16_t adc_value[2] = {0}; //用于存放外部信号的adc数组
- uint16_t dma_trans_complete_flag = 0; //dma转换完成标志
- uint16_t start = 0, stop = 0; /*(DWT测量法)——计数的起始点和终止点*/
- int main(void)
- {
- wk_system_clock_config();
- wk_periph_clock_config();
- wk_nvic_config();
- wk_timebase_init();
- wk_dma1_channel1_init();
- wk_dma_channel_config(DMA1_CHANNEL1,
- (uint32_t)&ADC1->odt,
- DMA1_CHANNEL1_MEMORY_BASE_ADDR,
- DMA1_CHANNEL1_BUFFER_SIZE);
- dma_channel_enable(DMA1_CHANNEL1, TRUE);
- wk_adc1_init();
- adc_ordinary_software_trigger_enable(ADC1, TRUE);
- start = ARM_CM_DWT_CYCCNT; /*(DWT测量法)——记录起始计数值*/
- while(dma_trans_complete_flag == 0); //等待DMA传输完成
- while(1)
- {
- }
- }
timecalculate.c
- #include "timecalculate.h"
- #include "at32f403a_407_wk_config.h"
- void start_Math(void)
- {
- if (ARM_CM_DWT_CTRL != 0) { // See if DWT is available
- ARM_CM_DEMCR |= 1 << 24; // Set bit 24
- ARM_CM_DWT_CYCCNT = 0;
- ARM_CM_DWT_CTRL |= 1 << 0; // Set bit 0
- }
- }
timecalculate.h
- #ifndef __TIMECALCULATE_H
- #define __TIMECALCULATE_H
- #define ARM_CM_DEMCR (*(uint32_t *)0xE000EDFC)
- #define ARM_CM_DWT_CTRL (*(uint32_t *)0xE0001000)
- #define ARM_CM_DWT_CYCCNT (*(uint32_t *)0xE0001004)
- void start_Math(void);
- #endif
at32f403a_407_int.c
- #include "at32f403a_407_int.h"
- #include "wk_system.h"
- #include "timecalculate.h" /*(DWT测量法)——包含相关头文件*/
- extern uint16_t dma_trans_complete_flag;
- extern uint16_t stop; /*(DWT测量法)——声明外部变量*/
- void SysTick_Handler(void)
- {
- wk_timebase_handler();
- }
- void DMA1_Channel1_IRQHandler(void)
- {
- stop = ARM_CM_DWT_CYCCNT; /*(DWT测量法)——记录终止点的计数值*/
- if(dma_interrupt_flag_get(DMA1_FDT1_FLAG) != RESET)
- {
- dma_flag_clear(DMA1_FDT1_FLAG);
- dma_trans_complete_flag = 1;
- }
- }
-
结果
①理论时间
单个通道:(采样+转换)时间= (采样时间+12.5)个ADCCLK周期;
两个通道:T_calculate = (239.5+12.5) ÷ 20M × 2 = 25.2us
②实测时间
在DEBUG模式下,观察起始计数值和终止计数值,根据二者的差值(指令数)计算得ADC转换(两个通道)时间T_test = (stop - start) ×指令周期= (18578 - 12436) ÷240M = 25.59us。
五、总结
| 优点 | 缺点 |
GPIO翻转法 | 操作简单,通用性强 | 精度受限于GPIO切换速度 |
调试器跟踪法 | 无其他代码的干预 | 需特定的硬件支持 |
DWT测量法 | 无需外部测量工具 | 配置过程相对复杂 |
三种方法都可测量代码片段的运行时间(比如ADC转换时间、定时器的中断频率等),可根据不同场景灵活使用。
由于作者水平有限,文中如有错误之处,恳请读者批评指正。
参考资料:
《RM_AT32F403A_407_CH_V2.06》的19模拟数字转换(ADC)https://www.arterytek.com/file/download/1995
雅特力AT32F423开启FPU跟不开启FPU性能差异(使用DWT测量)https://blog.csdn.net/l18817813618/article/details/140275305