cancel
Showing results for 
Search instead for 
Did you mean: 

Setting 7 ADCs through DMA and TIM1

jgalea
Associate II
Posted on March 02, 2009 at 07:36

Setting 7 ADCs through DMA and TIM1

5 REPLIES 5
jgalea
Associate II
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
Associate II
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 ]

jgalea
Associate II
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
Associate II
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 ]

bissong
Associate II
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.