带有DMA的stm32f4 adc eoc标志

时间:2018-09-10 05:27:58

标签: stm32 stm32f4discovery stm32f4

我正在使用stm32f4。目前,我正在使用带有已触发DMA和TIMER的ADC读取芯片的温度。 DMA被设置为具有双缓冲的循环缓冲区。每次都设置TIMER TRGO来触发更新事件。

它似乎工作正常,但是由于某种原因,当我在ADC初始化代码中启用DMA时,从未设置ADC_SR_EOC,因此它从未执行if((ADC1->SR & ADC_SR_EOC) == ADC_SR_EOC)内的代码块

是否有一种方法可以使ADC_IRQHandler中的ADC EOC与DMA配置一起工作?

最终目标只是切换和LED指示灯,以检查是否有需要设置TIMER + ADC模块的计时。 (也许将来我可能想在ADC处理程序中添加更多代码以执行)

void ADC_IRQHandler(void){                                                      


  if((ADC1->SR & ADC_SR_EOC) == ADC_SR_EOC){                                    

    GPIOD->ODR ^=ORANGE_LED;                                                        

    ADC1->SR &= ~(ADC_SR_EOC);                                                   

  }                                                                                                                                                                  
}   

如果我将GPIOD->ODR ^=ORANGE_LED;移到if语句之外,那么它将点亮黑板上的ORANGE_LED

这是所有三个初始化函数和DMA处理程序

void DMA2_Stream4_IRQHandler(void)                                              
{                                                                               
  /* transmission complete interrupt */                                         
  if (DMA2->HISR & DMA_HISR_TCIF4)                                              
  {                                                                             
    GPIOD->ODR ^=GREEN_LED;                                                    
    DMA2->HIFCR |= (DMA_HIFCR_CTCIF4);  // acknowledge interrupt                

    uint16_t *p;                                                                
    if ((DMA2_Stream4->CR & DMA_SxCR_CT) == 0)  // current target buffer 0 (read buffer 1)
      p = (uint16_t*) &sample_buffer0[0];                                       
    else                                        // current target buffer 1 (read buffer 0)
      p = (uint16_t*) &sample_buffer1[0];                                       


    temp_value = p[0];                                                          
    counter = 1;                                                                
  }                                                                             

  if (DMA2->HISR & DMA_HISR_TEIF4)                                              
  {                                                                             
    GPIOD->ODR ^=(RED_LED);                                                    
    DMA2->HIFCR |= (DMA_HIFCR_CTEIF4);  // acknowledge interrupt                

  }                                                                             

}    





void ADCx_Init(ADC_TypeDef * ADCx){

  // Enable ADCx
  if(ADCx == ADC1) RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
  else if(ADCx == ADC2) RCC->APB2ENR |= RCC_APB2ENR_ADC2EN;
  else RCC->APB2ENR |= RCC_APB2ENR_ADC3EN;


  /*
   * ADC Mode Selection
   *
   * Note:
   *  00000 : Independent Mode, ADC operate independently
   */
  ADC123_COMMON->CCR &= ~(ADC_CCR_MULTI);


  /*
   * Set and cleared by software to select the frequency of the clock
   *  to the ADC. The clock is common for all the ADCs.
   *
   * Note:
   *  00: PCLK2 divided by 2
   *  01: PCLK2 divided by 4
   *  10: PCLK2 divided by 6
   *  11: PCLK2 divided by 8
  */
  ADC123_COMMON->CCR &= ~(ADC_CCR_ADCPRE);  // Clear
  ADC123_COMMON->CCR |= (ADC_CCR_ADCPRE_0); // DIV2


  // Disable DMA for Dual/Triple modes
  ADC123_COMMON->CCR &= ~(ADC_CCR_DMA);

  //Configurable delay between conversions in Dual/Triple interleaved mode
  ADC123_COMMON->CCR &= ~(ADC_CCR_DELAY);

  // Resolution ot 12-bits
  ADCx->CR1 &= ~(ADC_CR1_RES);

  // Disable Scan Mode for this example
  ADCx->CR1 &= ~(ADC_CR1_SCAN);

  // Disable Continuos Mode
  ADCx->CR2 &= ~(ADC_CR2_CONT);

  // External Trigger on rising edge
  ADCx->CR2 &= ~(ADC_CR2_EXTEN);
  ADCx->CR2 |= ADC_CR2_EXTEN_0;

  // Timer 3 TRGO to drive ADC conversion
  ADCx->CR2 &= ~ADC_CR2_EXTSEL;
  ADCx->CR2 |= ADC_CR2_EXTSEL_3;

  // Data Alignment Right
  ADCx->CR2 &= ~(ADC_CR2_ALIGN);

  // Number of Conversions 
  ADCx->SQR1 &= ~(ADC_SQR1_L); // 1 conversion


  // Enable Temperature/Vref
  ADC123_COMMON->CCR |=ADC_CCR_TSVREFE;


  /* Configure Channel For Temp Sensor */
  ADCx->SQR3 &= ~(ADC_SQR3_SQ1);
  // Channel 16 for temp sensor on stm32f4 disc
  ADCx->SQR3 |= ADC_SQR3_SQ1_4;
  // Sample Time is 15 cycles (3+12)
  ADCx->SMPR1 &= ~(ADC_SMPR1_SMP16);




  // This call enables the end-of-conversion flag after each channel,
  // which triggers the end-of-conversion interrupt every time this flag is set.
  //ADCx->CR2 &= ~(ADC_CR2_EOCS);
  ADCx->CR2 |= (ADC_CR2_EOCS);

  // Enable Regular channel Interrupt
  ADCx->CR1 |= ADC_CR1_EOCIE;

  // For Double-Circular mode for DMA
  // you can continue to generate requests
  ADCx->CR2 |= ADC_CR2_DDS;

  // Enable DMA mode for ADC
  ADCx->CR2 |= ADC_CR2_DMA;


  // Set ADCx priority to 1
  NVIC_SetPriority(ADC_IRQn,1);

  // Enable ADCx interrupt
  NVIC_EnableIRQ(ADC_IRQn);


  // Turn on the ADC
  ADCx->CR2 |= ADC_CR2_ADON;

}

void timer_init(void){

  // Enable Timer 3 clock
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;

  // Disable Timer 3
  TIM3->CR1 &= ~TIM_CR1_CEN;

  // Counting Direction: 0 = up-counting, 1 = down-counting
  TIM3->CR1 &=~(TIM_CR1_DIR);

  // Clock Division - same as input clock
  TIM3->CR1 &=~(TIM_CR1_CKD);

  //Clock Prescaler

  TIM3->PSC =420; //Timer clock should be 42MHz/420 = 2 kHz

  // Auto Reload: up-counting (0-> ARR), down-counting (ARR -> 0)

  TIM3->ARR = 49;

  // Master Mode Selection
  // Use Update Event as the trigger output (TRGO)
  TIM3->CR2 &= ~(TIM_CR2_MMS);
  TIM3->CR2 |= (TIM_CR2_MMS_1);

  // Enable Timer 3 after all of the initialization
  TIM3->CR1 |= TIM_CR1_CEN;

}

void DMAx_Init(DMA_Stream_TypeDef * DMAx, ADC_TypeDef * ADCx){

  // Enable DMA Clock
  RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;

  // Disable DMA2 so that we can configure it
  DMAx->CR &= ~(DMA_SxCR_EN);

  // Initialize the Channel Member
  // ADC on stream 4 channel 0 of DMA2
  DMAx->CR &= ~(DMA_SxCR_CHSEL);

  // Initialize number of transactions to perform,
  // transaction can be thought of number of sources you need to transfer
  // data from. this is decremented after each transfer.
  DMAx->NDTR &= ~(DMA_SxNDT);
  DMAx->NDTR |= (DMA_SxNDT_0); //3
  //DMAx->NDTR |= (DMA_SxNDT_0|DMA_SxNDT_1); //3

  // Direction, Periphery to Memory
  DMAx->CR &= ~(DMA_SxCR_DIR);

  // No Fifo mode. Direct mode
  DMAx->FCR &= ~(DMA_SxFCR_DMDIS);

  // Fifo Threshold, since using direct mode, just set this to default value
  // Not used in Direct mode
  DMAx->FCR &= ~(DMA_SxFCR_FTH);
  DMAx->FCR |= ~(DMA_SxFCR_FTH_0);

  // Memory Burst Mode
  // In direct mode, these bits are forced to 0x0
  // by hardware as soon as bit EN= '1'.
  DMAx->CR &= ~(DMA_SxCR_MBURST);

  // Periphery Burst Mode
  // In direct mode, these bits are forced to 0x0
  // by hardware as soon as bit EN= '1'.
  DMAx->CR &= ~(DMA_SxCR_PBURST);

  // Circular Buffer
  DMAx->CR |= (DMA_SxCR_CIRC);

  // Use Double buffering
  DMAx->CR |= (DMA_SxCR_DBM);

  // Set the Priority
  DMAx->CR |= (DMA_SxCR_PL); // Highest

  /* Periphery Source configuration */
  DMAx->PAR = (uint32_t)&ADCx->DR; // Source of the Data to grab
  DMAx->CR &= ~(DMA_SxCR_PSIZE);
  DMAx->CR |= (DMA_SxCR_PSIZE_0);
  // Keep the pointer incremenent constant
  DMAx->CR &= ~(DMA_SxCR_PINC);

  /* Memory Destination Configuration */
  DMAx->M0AR =(uint32_t) &sample_buffer0;
  DMAx->M1AR =(uint32_t) &sample_buffer1;
  // In direct mode, MSIZE is forced by hardware to the
  // same value as PSIZE as soon as bit EN= '1'.
  DMAx->CR &= ~(DMA_SxCR_MSIZE);
  DMAx->CR |= (DMA_SxCR_MSIZE_0);
  // Increment the pointer
  DMAx->CR |= (DMA_SxCR_MINC);

  // Set the DMA as the flow controller
  DMAx->CR &= ~(DMA_SxCR_PFCTRL);

  // Enable the DMA transfer complete interrupt
  DMAx->CR |= DMA_SxCR_TCIE;
  DMAx->CR |= DMA_SxCR_TEIE;

  // Set DMAx priority to 1
  NVIC_SetPriority(DMA2_Stream4_IRQn,1);

  // Enable DMAx interrupt
  NVIC_EnableIRQ(DMA2_Stream4_IRQn);

  // Enable the DMA
  DMAx->CR  |= DMA_SxCR_EN;



}

main()中:

  while(1){                                                                     

    while(counter == 0); // Wait till conversion is done, 
                         // DMA_Handler will set counter = 1 after transfer.                        
    counter = 0;                                                                


    LCD_print(&rgb_lcd, "TEMP: %4d", temp_value);                               

    LCD_home(&rgb_lcd);                                                         


  }   

1 个答案:

答案 0 :(得分:1)

我自己在STM32F1上使用扫描转换时遇到了类似的问题,我怀疑这是因为根据参考手册,EOC位“是 通过软件清除或通过读取ADC_DR 清除,” ,我相信DMA实际上是在隐式地做。

我最终将行为基于DMA传输完成中断,但是听起来这可能不是您的用例的有用选择。