Skip to main content
jgalea
Associate III
March 2, 2009
Question

Setting 7 ADCs through DMA and TIM1

  • March 2, 2009
  • 5 replies
  • 849 views
Posted on March 02, 2009 at 07:36

Setting 7 ADCs through DMA and TIM1

    This topic has been closed for replies.

    5 replies

    jgalea
    jgaleaAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 13:01

    Hello Everyone. Had a problem to make DMA interrupt to work. I would like to thank M3allem for his/her help and a colleague of mine, Mr George Saliba. I'm sharing my code which is working.

    #define ADC1_DR_Address ((u32)ADC1_BASE + 0x4C)

    #define ADC_nbrElement 7 //no of channels to be used

    u16 ADC_result[ADC_nbrElement];

    void NVIC_Configuration(void)

    {

    NVIC_InitTypeDef NVIC_InitStructure;

    NVIC_DeInit(); /*Deinitializes the NVIC*/

    NVIC_SCBDeInit();

    NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //was 2

    //Enables DMA channel interrupt when transfer is completed

    /* Enable the DMAChannel1 Interrupt */

    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQChannel;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQChannel;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    }

    void Init_ADC(void) //ADC with DMA set up

    { //RM0008 pg 135, low density have DMA1 with 7 channels

    ADC_InitTypeDef ADC_InitStructure;

    DMA_InitTypeDef DMA_InitStructure;

    DMA_DeInit(DMA1_Channel1);//pg 125

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)ADC1_DR_Address;

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_result; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

    DMA_InitStructure.DMA_BufferSize = ADC_nbrElement;

    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_Circular;

    DMA_InitStructure.DMA_Priority = DMA_Priority_High;

    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

    DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    DMA_Cmd(DMA1_Channel1, ENABLE);

    /* Enable DMA1 Channel1 complete transfer interrupt */

    DMA_ITConfig(DMA1_Channel1, DMA1_IT_HT1 , ENABLE);

    ADC_DeInit(ADC1); //resets ADC1

    //ADC1 Configuration pg 59----

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;

    ADC_InitStructure.ADC_ScanConvMode = ENABLE;

    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;

    ADC_InitStructure.ADC_NbrOfChannel = ADC_nbrElement;

    ADC_Init(ADC1, &ADC_InitStructure);

    //regular ADC channel configuration

    //ADC ,channel, rank, sample time

    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1 , ADC_SampleTime_1Cycles5 );//VL1

    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2 , ADC_SampleTime_1Cycles5 );//VL2

    ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3 , ADC_SampleTime_1Cycles5 );//VT1

    ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4 , ADC_SampleTime_1Cycles5 );//VT2

    ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5 , ADC_SampleTime_1Cycles5 );//VT3

    ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6 , ADC_SampleTime_1Cycles5 );//L3 ref

    ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7 , ADC_SampleTime_1Cycles5 );//Shunt

    ADC_DMACmd(ADC1, ENABLE); //enable ADC1 DMA

    ADC_Cmd(ADC1, ENABLE); //enable ADC

    //Resets the selected ADC calibration registers.

    ADC_ResetCalibration(ADC1);

    while(ADC_GetResetCalibrationStatus(ADC1));

    //start ADC1 calibration

    ADC_StartCalibration(ADC1);

    while(ADC_GetCalibrationStatus(ADC1));

    }

    void InitClk (void) //pg 262

    { RCC_DeInit(); //resets RCC clock configuration to reset state.

    /* Enable HSE */ //External High Speed oscillator

    RCC_HSEConfig(RCC_HSE_ON);

    /* Wait till HSE is ready */

    HSEStartUpStatus = RCC_WaitForHSEStartUp();

    //if succesful

    if(HSEStartUpStatus == SUCCESS)

    { //checked configured well

    RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB clock = SYSCLK

    //AHB is Advanced High-performance Bus, bus protocol.

    /*Flash 2 wait state */

    FLASH_SetLatency(FLASH_Latency_2);

    /* Enable Prefetch Buffer */

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    //PLLCLK = 8MHz / 2 = 4MHz * 9 = 36 MHz

    //sets internal clock

    RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);

    //sets buses depending on internal clock limit is 36MHz, RM0008 pg 34

    /* PCLK2 = HCLK */ //hspeed bus 36MHz

    RCC_PCLK2Config(RCC_HCLK_Div1);

    /* PCLK1 = HCLK *///lspeed bus 36Mhz limit is 36MHz

    RCC_PCLK1Config(RCC_HCLK_Div1);

    /*ADCCLK = PCLK2/6 */

    //ADC clock not exceed 14MHz. mine is 9MHz

    RCC_ADCCLKConfig(RCC_PCLK2_Div4);

    /* Enable PLL */

    RCC_PLLCmd(ENABLE);

    /*Wait till PLL is ready */

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

    {};

    /* Select PLL as system clock source */

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */

    while(RCC_GetSYSCLKSource() != 0x08)

    {};

    }

    //RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SRAM, ENABLE);

    /* Enable DMA clock */ //DMA2 available on high density devices only

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    /* ADC1 & 2 Periph clock enable */

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_TIM1 |

    RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |

    RCC_APB2Periph_GPIOC, ENABLE);

    /* TIM2 clock enable */

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);

    }

    void Timer1_Setup(void)

    { //page 334

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;

    TIM_TimeBaseInitStruct.TIM_Period = 60; //60usec

    TIM_TimeBaseInitStruct.TIM_Prescaler = 36; //1us resolution

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);

    TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//clears TIM's interrupt pending bits

    TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);//Update interrupt source

    // Enable timer counting

    TIM_Cmd(TIM1, ENABLE);

    }

    void DMA1_Channel1_IRQHandler(void)

    {

    if (DMA_GetITStatus(DMA1_IT_HT1)==SET)

    { DMA_ClearFlag(DMA1_FLAG_HT1);

    DMA_ClearITPendingBit(DMA1_IT_HT1);

    L1v_value = ADC_result[0]&0xFFFF;

    L2v_value = ADC_result[1]&0xFFFF;

    T1v_value = ADC_result[2]&0xFFFF;

    T2v_value = ADC_result[3]&0xFFFF;

    T3v_value = ADC_result[4]&0xFFFF;

    L3_ref = ADC_result[5]&0xFFFF;

    Shunt_value = ADC_result[6]&0xFFFF;

    SUPPLY_LED_ON;

    }

    }

    void TIM1_UP_IRQHandler(void)

    { //checks if interrupt occured

    if (TIM_GetITStatus(TIM1,TIM_IT_Update) == SET)

    { TIM_ClearITPendingBit(TIM1, TIM_IT_Update);

    //Start by software the ADC1 Conversion

    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

    }

    }

    bissong
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 13:01

    Hello, I read that you had problem to make it work. It is my case and even your example does not work. My problem is that no DMA interrupt happens. I've got my TIM1 interrupt which works but not the DMA one. Do you have any hint ?

    Otherwise, your comments say that the DMA interrupt happens when the tranfer is complete, but your flag (HT) concerns the Half Transfer, is that normal ?

    I don't know what to do, it's been two days that I struggle to make a DMA interrupt.

    Thanks in advance

    [ This message was edited by: bissong on 24-02-2009 16:08 ]

    bissong
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 13:01

    I think the order of your functions calls is the key to my problem, can you share it ? I did not find the right combination but I've seen that the debug differs with it.

    In fact I think I tried everything, each time I launch the ADC conversion nothing happens anymore. I first get one timer interrupt as requested, thus it launches the ADC conversion and then I don't even have timer interrupt after that. When I comment the ADC_SoftwareStartConvCmd(ADC1, ENABLE) command, I have my timer interrupt every 60µs. It is quite weird that it doesnt work for me...

    [ This message was edited by: bissong on 26-02-2009 15:10 ]

    jgalea
    jgaleaAuthor
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 13:01

    Hello. This is the code im using for it to work. Im transferring half words as the ADC is 16-bit. It took me some time as well to work. This is how Im using it. Johann

    bissong
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 13:01

    I've found out what my problem was. In fact, I always put the same IRQ prototype as you did. But if I put ''void DMAChanneL1_IRQHandler(void)'' instead of ''DMA1_Channel1_IRQHandler'', it works perfectly. Thanks for your advices.