[已解决]求教, stm32f303启动ADC的DMA传输时有几十ms的延迟

2019-12-10 18:11发布

本帖最后由 tomzbj 于 2019-10-16 15:59 编辑

程序如下, ADC和DMA配置部分略, 大概流程是先设置dc->config里的num_samples, 然后调用ADCDMA_StartTransmission, 启动DMA.
在DMA2_Channel1_IRQHandler里判断是全满还是半满中断, 然后调用 ADCDMA_IRQHandler来把DMA缓冲区内容交替保存到外部spi sram.

现在的问题是发现每次会丢最前面的几个数据, 刚好前几个数据还比较重要.
用gt.t1 / t2 / t3记录DWT->CYCCNT发现, 从t2到t3一直是准确的500ms没有问题, 但从t1到t2最少是503ms, 多的时候达到588ms. 不知道这几十ms的时间耗在哪里了?



  1. typedef struct { unsigned long t1, t2, t3; } tt_t;
  2. tt_t gt;

  3. void ADCDMA_StartTransmission(void)
  4. {
  5.     extern tt_t gt;
  6.     gt.t1 = DWT->CYCCNT;               // 记录起始时间

  7.     DMA_Cmd(DMA2_Channel1, DISABLE);
  8.     DMA2_Channel1->CMAR = (unsigned long)g.adc_buffer;
  9.     DMA2_Channel1->CNDTR = MAX_SAMPLES;
  10.     DMA_Cmd(DMA2_Channel1, ENABLE);
  11.     ADC_DMACmd(ADC2, ENABLE);
  12. }

  13. void ADCDMA_StopTransmission(void)
  14. {
  15.     ADC_DMACmd(ADC2, DISABLE);
  16.     printf("Data acquisition done! ");
  17. }

  18. void ADCDMA_IRQHandler(int dma_type)
  19. {
  20.     DataConfig_t* pdc = DC_Get();
  21.     int size;
  22.     static unsigned long spisram_addr = 0;
  23.     unsigned short* buf;

  24.     buf = g.adc_buffer;
  25.     if(dma_type == DMA_IT_TC)
  26.         buf = &g.adc_buffer[MAX_SAMPLES / 2];

  27.     size = MAX_SAMPLES / 2;
  28.     if(pdc->config.num_samples < size)
  29.         size = pdc->config.num_samples;
  30.     extern tt_t gt;
  31.     if(spisram_addr == 0) {
  32.         gt.t2 = DWT->CYCCNT;          // 记录第一次进中断时间
  33.     }
  34.     else if(spisram_addr == size * sizeof(g.adc_buffer[0])) {
  35.         gt.t3 = DWT->CYCCNT;       // 记录第二次进中断时间
  36.     }

  37.     SPISRAM_FastWrite(spisram_addr, size * sizeof(g.adc_buffer[0]), buf);

  38.     putchar('.');    fflush(stdout);

  39.     pdc->config.num_samples -= size;
  40.     spisram_addr += size * sizeof(g.adc_buffer[0]);
  41.     if(pdc->config.num_samples <= 0) {
  42.         ADCDMA_StopTransmission();
  43.         spisram_addr = 0;
  44.     }
  45. }

  46. void DMA2_Channel1_IRQHandler(void)
  47. {
  48.     if(DMA_GetITStatus(DMA2_IT_TC1) != RESET) {
  49.         ADCDMA_IRQHandler(DMA_IT_TC);
  50.         DMA_ClearITPendingBit(DMA2_IT_TC1);
  51.     }
  52.     if(DMA_GetITStatus(DMA2_IT_HT1) != RESET) {
  53.         ADCDMA_IRQHandler(DMA_IT_HT);
  54.         DMA_ClearITPendingBit(DMA2_IT_HT1);
  55.     }
  56. }
复制代码

--------------------------已解决----------------
改为不用ADC_DMACmd, 只用DMA_Cmd(DMA2_Channel1, DISABLE)和DMA_Cmd(DMA2_Channel1, ENABLE)来控制启动和停止DMA传输, 可以了.
看来ADC_DMACmd之后确实会延迟一小段时间再启动传输.
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。