1
votes

I'm working on a project for a digital filter, see figure below. I have timer 3 triggering the ADC at 40kHz, the ADC should then make a sample and when its conversion is done it should trigger the DMA. The DMA should then move the converted value from the ADC peripheral memory to a memory address. Timer 3 works fine, however the DMA_IRQHandler code doesn't seem to work. Does anybody know if my configuration of the DMA or the ADC is wrong? My code is depicted below.

Many thanks!

block diagram code

void timer_init (void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    TIM_TimeBaseInitTypeDef timerInitStructure;
    timerInitStructure.TIM_Prescaler = 0;
    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    timerInitStructure.TIM_Period = 1050*2; // Sample frequentie, 40kHz
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    timerInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &timerInitStructure);
    TIM_Cmd(TIM3, ENABLE);

    TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);
}

void timer_interrupt_init (void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  /* Enable the timer global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init (&NVIC_InitStructure);

  //NVIC_SetPriority(TIM3_IRQn, 2);
}

void timer_start (void)
{
  TIM_Cmd (TIM3, ENABLE);
}

void timer_stop (void)
{
  TIM_Cmd (TIM3, DISABLE);
}

void timer_interrupt_enable (void)
{
  /*
   * It is important to clear any pending interrupt flags since the timer
   * has been free-running since we last used it and that will generate
   * interrupts on overflow even though the associated interrupt event has
   * not been enabled.
   */
  TIM_ClearITPendingBit (TIM3, TIM_IT_Update);
  /* put the counter into a known state */
  TIM_SetCounter (TIM3, 0);
  TIM_ITConfig (TIM3, TIM_IT_Update, ENABLE);
}

void timer_interrupt_disable (void)
{
  TIM_ITConfig (TIM3, TIM_IT_Update, DISABLE);
}

void TIM3_IRQHandler (void)
{
  if (TIM_GetITStatus (TIM3, TIM_IT_Update) != RESET)
  {
      //GPIO_ToggleBits(GPIOD, GREEN_PIN); // For checking the timer frequency with a scope
      TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
  }
}

void adc_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); // Enable the clock for the ADC peripheral
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);// Enable the clock for the GPIO peripheral

    // Configure GPIO PC1 to analog mode
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    // Configure the common adc parameters
    ADC_CommonInitTypeDef ADC_CommonInitStruct;
    ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2;
    ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;

    ADC_CommonInit(&ADC_CommonInitStruct);

    // Configure the specific adc parameters
    ADC_InitTypeDef ADC_InitStruct;
    ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b;
    ADC_InitStruct.ADC_DataAlign  = ADC_DataAlign_Right;
    ADC_InitStruct.ADC_ScanConvMode = DISABLE;
    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO; // ADC gets triggered by timer 3
    ADC_InitStruct.ADC_NbrOfConversion = 1; // single conversion

    ADC_Init(ADC2, &ADC_InitStruct);

    ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_3Cycles);

    ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
    ADC_DMACmd(ADC2, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
}

void DMA_Initialize(void)
{
    RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);
    DMA_InitTypeDef DMA_InitStructure;

    /* Initialise DMA */
    DMA_StructInit(&DMA_InitStructure);
    DMA_DeInit(DMA2_Stream3);  //Set DMA registers to default values

    /* config of DMAC */
    DMA_InitStructure.DMA_Channel = DMA_Channel_1; /* This channel is linked to ADC2*/
    DMA_InitStructure.DMA_BufferSize = 1; /* Size in words of the buffer where the adc sample value gets stored */
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; /* direction */
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; /* no FIFO */
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; /* here you van select normal mode or circular buffer */
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* here you can select the priority of the dma stream. */

    /* config of memory */
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC_value; /* target addr */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA_MemoryDataSize_Word /* 16 bit */
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_Init(DMA2_Stream3, &DMA_InitStructure); /* See Table 20 for mapping */
    DMA_Cmd(DMA2_Stream3, ENABLE);
    DMA_ITConfig(DMA2_Stream3,DMA_IT_TC, ENABLE);
}

void DMA2_Stream3_IRQHandler()
{
    if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TCIF3) != RESET)
    {
        DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);
        GPIO_ToggleBits(GPIOD, RED_PIN);
    }
}
1
Use registers. Will be easier and much better0___________
Your graph is wrong: should be Timer -> Trigger -> ADC -> DMA -> interrupt at the end of the transmition0___________

1 Answers

0
votes

It looks like the NVIC configuration for DMA is missing. I guess something like this before DMA_ITConfig(DMA2_Stream3,DMA_IT_TC, ENABLE);

NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA2_Channel1, DMA_IT_TC, ENABLE);

also, call this part before DMA_Cmd(DMA2_Stream3, ENABLE);