I have been struggling on this over the past few days and its starting to really push my buttons now.
Device: sTM32F405RGTX
Basically I have ADC 1 configured in regular mode Channel 10 and 11, and I am using DMA to get the values from it and pass it onto a global variable.
the ADC is triggered by a timer TIM3_TRGO
The problem I'm facing is on the peripheral viewer, I can see that the ADC is overrunning, i.e OVR register is set high. when i try to debug and run the code, the ADc output is stuck o one value, however when I untick the OVR register in the periph viewer, it (ADC output) updates for a few secs and the OVR goes back high again.
I think it might be something to do with the fact that maybe the DMA isn't somehow configured right. On first run I can see it copies a value into my buffer but then afterwards its just stuck can someone help please?
void Config_ADCtimer_init () //Regular ADC Timer { TIM_TimeBaseInitTypeDef Timer_Struct; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //enabling the clock for Timer 3 Timer_Struct.TIM_Period = 16000-1; //scaled to 1000khz Timer_Struct.TIM_Prescaler = 1000-1; Timer_Struct.TIM_CounterMode = TIM_CounterMode_Up; Timer_Struct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInit(TIM3, &Timer_Struct); //Enabling Timer 3 TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO TIM_Cmd(TIM3,ENABLE); } void Config_RegADC_Init(void) { ADC_InitTypeDef ADC_InitStruct; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //GPIO setups PC3 and PC4 for the raw TEV signals GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, &GPIO_InitStructure); ADC_DeInit(); //Default All ADC settings registers ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; ADC_InitStruct.ADC_NbrOfConversion= 2; ADC_InitStruct.ADC_ScanConvMode= ENABLE; ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO ;//TIM3 trigger output TIM3 is a 16 bit timer.Reg ADC ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_Init(ADC1, &ADC_InitStruct); /* Enable ADC1 DMA */ ADC_DiscModeChannelCountConfig(ADC1, 2); //Discontinuous Mode configuration ADC_DiscModeCmd(ADC1, ENABLE); /*ADC Channel for LP TEV*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_12,1,ADC_SampleTime_56Cycles); //tocheck /*ADC Channel for UTP TEV*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_13,2,ADC_SampleTime_56Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); } void RegADC_DMA_Setup () { DMA_InitTypeDef DMA_InitStruct; NVIC_InitTypeDef NVIC_ADCRegDMA_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_ITConfig (DMA2_Stream4, DMA_IT_TC | DMA_IT_HT, ENABLE); DMA_InitStruct.DMA_Channel = DMA_Channel_0; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS; DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&ADC_DMA_Buffer[0]; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStruct.DMA_BufferSize = DMA_BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream4, &DMA_InitStruct); //adc1 is on dma2 channel 0 stream 4 /***NVIC Setup for the DMA***/ NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannel = DMA2_Stream4_IRQn; //dma 2 stream 4 pertains to ADC1 NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init (&NVIC_ADCRegDMA_InitStruct); DMA_Cmd(DMA2_Stream4, ENABLE); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); /*Enabling the DMA interput for a halfway transfer and end of copy transfer*/ }
Here's my DMA IRQ handler
void DMA2_Stream4_IRQHandler () { extern uint16_t ADC_DMA_Buffer [DMA_BUFFER_SIZE]; extern bool dataALCready; extern uint16_t probeALCdata[PERIOD], plusALCdata[PERIOD]; uint16_t probeChan_A, plusChan_B; //Locator probe and UTP log amped TEV signals respectively static uint16_t count = 0; uint8_t i;
if ( DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF4) != RESET)//if the stream transfer is complete
{ DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF4);
probeChan_A = ADC_DMA_Buffer [0]; //copy DMA contents into globals plusChan_B = ADC_DMA_Buffer [1]; probeTEV [count] = probeChan_A; // Array to store 20ms worth of LP TEV signals plusTEV [count] = plusChan_B; // Array to store 20ms worth of UTP TEV signals count++; if (count == 20) { for ( i = 0; i < count; i++) { probeALCdata [i] = probeTEV [i]; plusALCdata [i] = plusTEV [i]; } count = 0; }
}
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
You'll need to reinitialize the transfer at every TC, perhaps you should use Circular Mode?
What happens when you get a HT interrupt? If you don't service interrupt you enable the processor will keep entering the interrupt handler.
Consider the use of HT/TC to handle half the buffer at each interrupt, and use of circular so that it keeps going.
worked! Thanks very much Clive!
Hi Clive, I was wondering if you could be of further assistance at all.
Below is my set up for a regular ADC conversion for channels 12 and 13. I am using DMA as whon in the previous post to copy the data from the ADC buffer. But I'm having another problem now.
Channel 12 seems to be following channel 13. i.e when I have the analogue input of channel 12 set at around 100 mV and the channel 13 set at say around 600mV, channel 13 reads 600mV okay but the channel 12 reads just short of channel 13's value nothing close to the 100mV value. Any ideas on what I'm doing wrong?
void Config_RegADC_Init(void) { ADC_InitTypeDef ADC_InitStruct; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); //GPIO setups PC3 and PC4 for the raw TEV signals GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, &GPIO_InitStructure); ADC_DeInit(); //Default All ADC settings registers ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; ADC_InitStruct.ADC_NbrOfConversion= 2; ADC_InitStruct.ADC_ScanConvMode= ENABLE; ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO ;//TIM3 trigger output TIM3 is a 16 bit timer.Reg ADC ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_Init(ADC1, &ADC_InitStruct); /* Enable ADC1 DMA */ ADC_DiscModeChannelCountConfig(ADC1, 2); //Discontinuous Mode configuration ADC_DiscModeCmd(ADC1, ENABLE); /*ADC Channel for LP TEV*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_12,1,ADC_SampleTime_112Cycles); //tocheck /*ADC Channel for UTP TEV*/ ADC_RegularChannelConfig(ADC1, ADC_Channel_13,2,ADC_SampleTime_112Cycles); /* Enable DMA request after last transfer (Single-ADC mode) */ ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); }
void RegADC_DMA_Setup () { DMA_InitTypeDef DMA_InitStruct; NVIC_InitTypeDef NVIC_ADCRegDMA_InitStruct; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_ITConfig (DMA2_Stream4, DMA_IT_TC | DMA_IT_HT, ENABLE); DMA_InitStruct.DMA_Channel = DMA_Channel_0; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS; DMA_InitStruct.DMA_Memory0BaseAddr = (uint32_t)&ADC_DMA_Buffer[0]; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStruct.DMA_BufferSize = DMA_BUFFER_SIZE; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream4, &DMA_InitStruct); //adc1 is on dma2 channel 0 stream 4 /***NVIC Setup for the DMA***/ NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannel = DMA2_Stream4_IRQn; //dma 2 stream 4 pertains to ADC1 NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_ADCRegDMA_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_Init (&NVIC_ADCRegDMA_InitStruct); DMA_Cmd(DMA2_Stream4, ENABLE); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); /*Enabling the DMA interput for a halfway transfer and end of copy transfer*/ } void DMA2_Stream4_IRQHandler () { extern uint16_t ADC_DMA_Buffer [DMA_BUFFER_SIZE]; extern bool dataALCready; extern uint16_t probeALCdata[PERIOD], plusALCdata[PERIOD]; //buffers to store 20 ms worth of raw TEv signals uint16_t probeChan_A, plusChan_B; //Locator probe and UTP log raw TEV signals respectively static uint16_t count = 0; uint8_t i; uint16_t probeTEV[PERIOD]; uint16_t plusTEV[PERIOD]; if ( DMA_GetITStatus(DMA2_Stream4, DMA_IT_HTIF4) != RESET)//if the stream transfer is complete { probeChan_A = ADC_DMA_Buffer [0]; //copy DMA contents into globals DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_HTIF4); } if ( DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF4) != RESET)//if the stream transfer is complete { plusChan_B = ADC_DMA_Buffer [1]; probeTEV [count] = probeChan_A; // Array to store 20ms worth of LP TEV signals plusTEV [count] = plusChan_B; // Array to store 20ms worth of UTP TEV signals count++; if (count == 20) { for ( i = 0; i < count; i++) { probeALCdata [i] = probeTEV [i]; plusALCdata [i] = plusTEV [i]; } count = 0; } DMA_ClearITPendingBit(DMA2_Stream4, DMA_IT_TCIF4); } }