2009-03-01 10:36 PM
Setting 7 ADCs through DMA and TIM1
2011-05-17 04:01 AM
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); } }2011-05-17 04:01 AM
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 ]2011-05-17 04:01 AM
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
2011-05-17 04:01 AM
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 ]2011-05-17 04:01 AM
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.