ADC使用DMA,利用ADC的中断也无法跟踪DMA的行为

[复制链接]
1196|2
 楼主| eagle1983 发表于 2019-12-9 16:15 | 显示全部楼层 |阅读模式
想看一下DMA是怎么传输数据的。于是想利用ADC转换完成中断去跟踪DMA的行为。今天倒腾了一天,看来不行。记录一下调试过程:

启用规则组将八路ADC配置为扫描+连续模式。转换结束后使用DMA传输数据。
疑点:
1.        DMA什么时候读取数据?
手册里这么说:
The ADC generates a DMA request at the end of conversion of a regular channel. When this request is received, the DMA will transfer the converted data from the ADC_RDATA register to the destination which is specified by the user
由于ADC模块只有一个转换结果寄存器:ADC_RDATA。所以可以肯定必须在切换通道之后,在下一个通道的转换结束之前,把上次转换的结果读出来。所以无论规则组定义的通道是几个,每个通道转换完成后DMA必须立刻读取ADC的转换数据。
2.        是否可以通过ADC转换完成中断来看DMA的行为?
手册中不是说ADC转换完成后会请求DMA把数据拿走嘛!那就可以开启ADC转换完成中断,把断点设置在中断里就可以看到DMA的行为了。结果是这样的:
进入中断后,在Keil里看ADC的状态寄存器ADC_SATA只有STRC(Start flag of regular channel group)被置位(很可能这个位是0,原因后面说明),而DMA也早就把ADC_RDATA中的数据拿走了。我想是因为DMA在内核进入中断所需的时间(12个时钟周期)内已经访问过ADC_SATA了,EOC也早已被清零了(这个结论在下面第四小节验证)。但为何还能进入中断,是以为这个中断被挂起了现在才响应。(在Keil里查看SCB-ICSR寄存器可知0x1C这个向量号被挂起,正好是ADC的中断向量号)
3.        既然不能通过ADC的中断跟踪DMA的行为,那是否可以用查询ADC转换完成的方法去看呢?
情况也上述第二小节相同
4.        既然是DMA提前访问了ADC_SATA,那么可以关掉DMA,验证第二小节的结论。
关掉DMA,打开ADC中断会立刻进入中断。若在中断中不访问ADC_SATA,也不清除中断标志,则程序一直在中断服务代码中,导致其他代码无法执行。如果在中断代码中读取ADC_SATA或者清除ADC_STAT寄存器(虽然看到ADC_STAT寄存器的那些位没有变化),则不会出现程序一直在中断服务代码中的情况。所以可以验证上述第二小节的结论是正确的。同时,在第二小节中看到的STRC标志也不一定是1,也许在ADC转换完成后被清掉了。
 楼主| eagle1983 发表于 2019-12-9 16:18 | 显示全部楼层
本帖最后由 eagle1983 于 2019-12-9 16:19 编辑

贴上代码:
  1. void ADC_Init(void)
  2. {        
  3.         rcu_periph_clock_enable(RCU_ADC);
  4.         rcu_periph_clock_enable(RCU_GPIOA);
  5.         rcu_periph_clock_enable(RCU_GPIOC);
  6.         rcu_adc_clock_config(RCU_ADCCK_APB2_DIV8);        // 10MHz
  7.         
  8.         gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
  9.         gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
  10.         gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
  11.         gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_3);
  12.         gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_5);
  13.         gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0);
  14.         gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
  15.         gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
  16.         gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_3);
  17.         
  18.         // 规则排序可以改变每个通道采回来的值,对应DMA数组的下标
  19.         adc_channel_length_config(ADC_REGULAR_CHANNEL, 9);          // 规则组
  20.         
  21.         adc_regular_channel_config(0, ADC_CHANNEL_10, ADC_SAMPLETIME_239POINT5);        // 通道10: PC0
  22.         adc_regular_channel_config(1, ADC_CHANNEL_11, ADC_SAMPLETIME_239POINT5);        // 通道11: PC1
  23.         adc_regular_channel_config(2, ADC_CHANNEL_12, ADC_SAMPLETIME_239POINT5);        // 通道12: PC2
  24.         adc_regular_channel_config(3, ADC_CHANNEL_13, ADC_SAMPLETIME_239POINT5);        // 通道13: PC3 3.3v
  25.         adc_regular_channel_config(4, ADC_CHANNEL_0,  ADC_SAMPLETIME_239POINT5);        // 通道00: PA0
  26.         adc_regular_channel_config(5, ADC_CHANNEL_1,  ADC_SAMPLETIME_239POINT5);        // 通道01: PA1
  27.         adc_regular_channel_config(6, ADC_CHANNEL_2,  ADC_SAMPLETIME_239POINT5);        // 通道02: PA2
  28.         adc_regular_channel_config(7, ADC_CHANNEL_3,  ADC_SAMPLETIME_239POINT5);        // 通道04: PA3
  29.         adc_regular_channel_config(8, ADC_CHANNEL_5,  ADC_SAMPLETIME_239POINT5);        // 通道05: PA5 3.3V

  30.         //12位ADC的转换时间为(239.5+12.5)/10 = 25.2us added by eagle
  31.         adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);        // 规则组触发使能
  32.         adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
  33.         adc_data_alignment_config(ADC_DATAALIGN_RIGHT);         // 数据右对齐
  34.         
  35.         adc_enable();
  36.         //delay_1ms(1);        
  37.         adc_calibration_enable();
  38.         
  39.         adc_special_function_config(ADC_SCAN_MODE, ENABLE);                // 扫描模式使能
  40.         adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);    // 连续转换模式使能
  41.         adc_dma_mode_enable();                                                               // DMA请求
  42.         
  43.         ADC_DMAInit();
  44.         dma_channel_enable(DMA_CH0);

  45.         adc_interrupt_flag_clear(ADC_INT_FLAG_EOC);        
  46.                
  47.         nvic_priority_group_set(NVIC_PRIGROUP);
  48.         nvic_irq_enable(ADC_CMP_IRQn, PRI_ADC);
  49.         
  50.         adc_interrupt_enable(ADC_INT_EOC);        // added by eagle

  51.         adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
  52.         
  53. }

  54. void ADC_DMAInit(void)
  55. {
  56.         dma_parameter_struct  dma_init_struct;
  57.         
  58.         
  59.         rcu_periph_clock_enable(RCU_DMA);
  60.         
  61.         dma_deinit(DMA_CH0);
  62.         dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;        // 外设到内存
  63.         dma_init_struct.memory_addr  = (uint32)Adc_HwValue;                // 内存地址
  64.         dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;        // 内存地址增量
  65.         dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;                // 内存地址长度
  66.         dma_init_struct.number       = FILTER_SAMPLES*ADC_CHN_SIZE;        // 传输数据总长度
  67.         dma_init_struct.periph_addr  = (uint32)&ADC_RDATA;                        // 外设地址
  68.         dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;        // 外设地址增量
  69.         dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;        // 外设地址长度
  70.         dma_init_struct.priority     = DMA_PRIORITY_MEDIUM;                        // 优先级
  71.         dma_init(DMA_CH0, &dma_init_struct);
  72.         
  73.         dma_circulation_enable(DMA_CH0);
  74.         dma_memory_to_memory_disable(DMA_CH0);
  75. }
CharryW 发表于 2019-12-18 11:36 | 显示全部楼层
中断请求在EOC置位时就已经产生了,即使很快被DMA访问清除,但请求已经产生了中断会执行的,不过猜测即使在ADC中不做任何操作不清除标志位,ADC中断也只会产生一次。  至于DMA的行为一定不是靠EOC发出搬运请求的,因为EOC只在ADC一组通道转换完置位,而DMA需要在每个通道转换完时搬走RDATA的数据,使用的应该是ADC的内部信号。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

4

主题

9

帖子

0

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