This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ADC config with DMA and Timer

Hi,

I want to program STM32F103 in which define an array that is completed with ADC value. I need to trigger the ADC with timer and also use DMA. It means that when the array complete, the DMA_IRQ Handler send this array by USART channel. I wrote this code but it doesn't work.

I would be appreciate if you help me to correct this program.

#include "stm32f10x.h"

#define ADC1_DR_Address    ((uint32_t)0x4001244C)
uint16_t array [32];
DMA_InitTypeDef DMA_InitStructure;

int main(void)
{

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

   NVIC_InitTypeDef sara3;
  sara3.NVIC_IRQChannel = DMA1_Channel1_IRQn;
  sara3.NVIC_IRQChannelPreemptionPriority = 0;
  sara3.NVIC_IRQChannelSubPriority = 0;
  sara3.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&sara3);

  TIM_TimeBaseInitTypeDef Tim_TimeBaseStructure;
  TIM_TimeBaseStructInit(&Tim_TimeBaseStructure);
  Tim_TimeBaseStructure.TIM_Period = 9000;
  Tim_TimeBaseStructure.TIM_Prescaler = 0x0;
  Tim_TimeBaseStructure.TIM_ClockDivision = 0x0;
  Tim_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &Tim_TimeBaseStructure);
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

 TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

  /*
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0x7F;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
  TIM_OC1Init(TIM2, &TIM_OCInitStructure);
  */


  ADC_InitTypeDef ADC_InitStructure;
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);

  //ADC_SoftwareStartConvCmd(ADC1,ENABLE);







  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)array;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 32;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    USART_InitTypeDef USART_InitStructure;
  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USART1, &USART_InitStructure);
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
  USART_ClearFlag(USART1,USART_FLAG_TC);


  DMA_ITConfig (DMA1_Channel1, DMA_IT_TC,ENABLE);
  DMA_Cmd(DMA1_Channel1, ENABLE);


  ADC_Cmd(ADC1, ENABLE);
  ADC_DMACmd(ADC1, ENABLE);
  USART_Cmd(USART1, ENABLE);
  TIM_Cmd(TIM2, ENABLE);


  ADC_ResetCalibration(ADC1);
  while(ADC_GetResetCalibrationStatus(ADC1));
  ADC_StartCalibration(ADC1);
  while(ADC_GetCalibrationStatus(ADC1));



   while (1);

}



void DMA1_Channel1_IRQHandler(void)
{

  uint8_t i = 0;
  if( DMA_GetITStatus(DMA1_FLAG_TC1) )
  {
        for(i = 0;i < 32 ; i++){

      USART_SendData(USART1, (uint8_t) array[i]);
      while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}

      USART_SendData(USART1, (uint8_t) array[i]>> 8);
      while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
      }


  DMA_DeInit(DMA1_Channel1);
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)array;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_BufferSize = 32;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);



  ADC_DMACmd(ADC1, ENABLE);
DMA_Cmd(DMA1_Channel1, ENABLE);

    DMA_ClearITPendingBit(DMA1_IT_TC1);
    DMA_ClearITPendingBit(DMA1_IT_GL1);
  }
}

Parents
  • You don't want it continuous if the timer is supposed to be triggering it.

    You select Channel 2 of the timer as the source, but then configure it to interrupt on the Update, rather than do anything to configure Channel 2

    The DMA initialization and interrupt clearing in the IRQ doesn't look right, and surely the memory address should increment.

    You enable a TIM2 interrupt, but don't configure the NVIC, or have a handler.

    You use C++ syntax, w atch the name mangling doesn't break your interrupts.

Reply
  • You don't want it continuous if the timer is supposed to be triggering it.

    You select Channel 2 of the timer as the source, but then configure it to interrupt on the Update, rather than do anything to configure Channel 2

    The DMA initialization and interrupt clearing in the IRQ doesn't look right, and surely the memory address should increment.

    You enable a TIM2 interrupt, but don't configure the NVIC, or have a handler.

    You use C++ syntax, w atch the name mangling doesn't break your interrupts.

Children
  • I could'nt find any in tne posted sourcecode that show's C++ Code. It's native C language that
    fill's the init structures of stdLibrary functions to initialize the DMA and other hardware.

    Well, the topic sounds like a problem with the dma usage. I remember that there is a problem
    realated to the DMA usage with the STM32F1xx family. The usage of one DMA should be ok, but
    more than one results in an unexpected state. There is an errata available who describe the details
    around the dma issue.
    I had successfully used the DMA transfer mode to readout the ADC1 on STM32F103VC and STM32F407VG.

    Good luck to solve the problems and don't foget to report the final results or the solution.

    Juppeck


  • I add some init code that uses the STM32F407 and this show's the setup of 4 ADC1 channels handled by DMA transfer.

    #define Num_used_ADC_Channels   5                                                       // how many ADC channels should be handled?                                             // Wieviel ADC-Kanäle sollen ausgelesen werden? !!!
    #define Num_Of_Used_Buffers     Num_used_ADC_Channels                                   // how many memory should be used by DMA ?
    
    volatile uint16_t ADCBuffer[Num_Of_Used_Buffers + 2] = { 0x00AA,0,0,0,0,0,0x00BB };             // DMA-Buffer - 5 words
    enum __ADC_CHAN_BUFF_ORDER__ { CH0 = 1, CH1 = 2, VBAT = 3, TEMP = 4, VREF = 5  };       // Weleche Reihenfolge sollen die ADC Kanöäle gelesen werden?
    
    
    void Init_ADC ( void ) {
    
        // ############## ADC ##########################################################################################################
        // ---------- Configure PB0 and PB1 (ADC Channel1 and ADC Channel2 ) as analog input ------------------
        //
        // GPIOB function block clock enable
    
        RCC_APB2PeriphClockCmd ( RCC_APB2Periph_ADC1,  ENABLE );    // clock to ADC1
        RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOB, ENABLE );    // clock to PortB
    
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0 | GPIO_Pin_1;     // Init AIN0 / AIN1
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                // alternative mode "Analog in"
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init ( GPIOB, &GPIO_InitStructure );                                                                       // Init GPIO-PORTA as Analog input
    
    
    
        // DMA2 Stream0 configuration ------------------------------------------------------------------------------------------------
        //
        // Enable DMA2 clock
    
        RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_DMA2, ENABLE );
        DMA_DeInit ( DMA2_Stream0 );
    
        DMA_InitStructure.DMA_Channel               = DMA_Channel_0;
        DMA_InitStructure.DMA_PeripheralBaseAddr    = (uint32_t) ADC1_DR_Address;           // source
        DMA_InitStructure.DMA_Memory0BaseAddr       = (uint32_t) &ADCBuffer[1];         // destination - start to copy by dma at the second element of the array
        DMA_InitStructure.DMA_DIR                   = DMA_DIR_PeripheralToMemory;           // Transfertype
        DMA_InitStructure.DMA_BufferSize            = Num_used_ADC_Channels;                // Num of ADC register that should transfered
        DMA_InitStructure.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;            // Register address is static - no increment.
        DMA_InitStructure.DMA_MemoryInc             = DMA_MemoryInc_Enable;                 // auto increment the memory at each transfer
        DMA_InitStructure.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_HalfWord;      // transfer size of source register
        DMA_InitStructure.DMA_MemoryDataSize        = DMA_MemoryDataSize_HalfWord;          // transfer size of destinantion (array)
        DMA_InitStructure.DMA_Mode                  = DMA_Mode_Circular;                    // at the end of dma transfer cycle, starts again.
        DMA_InitStructure.DMA_Priority              = DMA_Priority_Low;                     // system load depended - i decide me to low priority.
        DMA_InitStructure.DMA_FIFOMode              = DMA_FIFOMode_Disable;                 //
        DMA_InitStructure.DMA_FIFOThreshold         = DMA_FIFOThreshold_HalfFull;           //
        DMA_InitStructure.DMA_MemoryBurst           = DMA_MemoryBurst_Single;               //
        DMA_InitStructure.DMA_PeripheralBurst       = DMA_PeripheralBurst_Single;           //
    
        DMA_Init ( DMA2_Stream0, &DMA_InitStructure );
        DMA_Cmd  ( DMA2_Stream0, ENABLE );
    
    
        // ------------------ ADC1 configuration -------------------------------------------------------
        //
    
        ADC_DeInit();
    
        ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_Independent;
        ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div8;
        ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_Disabled;
        ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
    
        ADC_CommonInit(&ADC_CommonInitStructure);
    
        // ########################### ADC1 Init #########################################
    
        ADC_InitStructure.ADC_Resolution             = RESOLUTION;                                                                                  //  Auflösung definiert in ADC1.h
        ADC_InitStructure.ADC_ScanConvMode           = ENABLE;
        ADC_InitStructure.ADC_ContinuousConvMode     = ENABLE;                                                                                                      // dauerhaft lesen und wandeln
        ADC_InitStructure.ADC_ExternalTrigConvEdge   = ADC_ExternalTrigConvEdge_None;               //
        ADC_InitStructure.ADC_ExternalTrigConv       = 0;                                                                                                   // ohne Trigger
        ADC_InitStructure.ADC_DataAlign              = ADC_DataAlign_Right;                         // Conversions are 12 bit - put them in the lower 12 bits of the result
        ADC_InitStructure.ADC_NbrOfConversion        = Num_used_ADC_Channels;                       // num of adc-channels
    
        ADC_Init (ADC1, &ADC_InitStructure);
        ADC_DMACmd ( ADC1, ENABLE );              // Enable ADC1 DMA
    
    
    
        // ######### ADC1 regular conversation mode  configuration ####################################
        //                         ADC ,  CHANNEL,           DMA MemoryOrder,    SampleTime
        //
    
        ADC_RegularChannelConfig(ADC1, ADC_Channel_8, CH0, ADC_SampleTime_15Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_9, CH1, ADC_SampleTime_15Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_Vbat, VBAT, ADC_SampleTime_15Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_TempSensor, TEMP, ADC_SampleTime_15Cycles);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, VREF, ADC_SampleTime_15Cycles);
    
    
        ADC_VBATCmd ( ENABLE );                                                                                                                     // Enable VBAT at channel 18
        ADC_TempSensorVrefintCmd ( ENABLE );                                                                // Enable TempSensor and Vrefint at channels 16 and 17
    
        ADC_DMARequestAfterLastTransferCmd ( ADC1, ENABLE );  // Enable DMA request after last transfer (Single-ADC mode)
        ADC_Cmd ( ADC1, ENABLE );                                                                                                     // Enable ADC1
    
        ADC_SoftwareStartConv ( ADC1 );                                                                                             // Start ADC1 Software Conversion
    
      return;
    }
    
    

    take care of the volatile declared array variable

    Juppeck

  • Congratulation on digging up a two month old thread, and then missing all the nuances of the problem. There's a least a dozen problems with the original code, and your solution is to post an example for a different processor which doesn't really address any of the core issues. Nor does it do what the OP wanted on your chosen target.

    Sure I could have wasted a bunch of my time correcting and fixing this, but I'd learn nothing, and the OP would miss a learning moment that you can't just cut and paste a bunch of random code together without any thought, or bothering to read the reference manuals.

  • HEY.

    i wanna to read the timer value and put it onto the adc. it must use dma channels 3 or 5. how can i do it? code gotta be working by two days. plz post examples

  • The world haven't figured out yet how to put the timer value onto the ADC. But if you instead feed it to the DAC, you get a nice sawtooth output.

  • Quit wasting time trolling on the internets and get busy then.

  • I guess that nobody want to do the work for you, so you must solve them instead.

  • Where is the DMA channel declaration?

    like:
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;

    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)array; <--- this don't works.
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&array;<-- This works - see my example

    DMA_InitStructure.DMA_BufferSize = 32; 32 half-word are used as Buffer?
    ADC_InitStructure.ADC_NbrOfChannel = 1; and just one CHannel should be aquire????

    ADC_InitStructure.ADC_NbrOfChannel = 1; one channel needs just
    DMA_InitStructure.DMA_BufferSize = 1; one memory sized of a half-word buffer

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; <-- not required to fill - you do P2M

    // This should used to trigger the conversation by the timer.
    //
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //
    ADC_InitStructure.ADC_ExternalTrigConv = 0;

    I don't had looked your code longer because the structure is mystic.