2015-11-13 08:04 AM
I'm developing an application that requires me to quickly and constantly reading 5 ADC channels.
I'm using the STM32F030F4P6. I set it up to do a continuous conversion and told it the 5 ADC channels I need. I have it set to trigger an interrupt at the end of each conversion so I can handle the data.
The problem I am running into is that I can't figure out how to tell which channel's data I am looking at. Since any channel causes the same interrupt, I don't know how to trace it back and tell which one triggered it.
Here's the code I'm using to set up my ADCs
void adc_window_init() {
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
RCC->CR2 |= RCC_CR2_HSI14ON;
ADC_SPIN((RCC->CR2 & RCC_CR2_HSI14RDY) == 0);
ADC1->CR |= ADC_CR_ADCAL; //Enable calibration
ADC_SPIN((ADC1->CR & ADC_CR_ADCAL) != 0);
ADC1->CR |= ADC_CR_ADEN; //Enable ADC
ADC_SPIN((ADC1->ISR & ADC_ISR_ADRDY) == 0);
ADC1->IER |= ADC_IER_EOCIE; //Enable End of conversion interrupt
ADC1->CFGR1 = 0b00000000000000000010000000000000; //12 bit resolution, continuous mode
ADC1->SMPR = 4; // 41.5 Clk cycles for sampling
ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL2 | ADC_CHSELR_CHSEL3 | ADC_CHSELR_CHSEL4 ;
ADC1->CR |= _BV(2); // Start
NVIC->ISER[0] |= _BV(ADC1_COMP_IRQn);
}
?Any help would be appreciated.
#adc-channels-multiple-stm32f02015-11-13 08:10 AM
By looking through the forums, I saw that for many other processors, the only way to do this is to use DMA and have it shove the data directly into an array. I tried setting this up, but its not working for me. I only see junk in two places of my array, and it doesn't seem to update.
Here's my code to set up DMA and the ADC:void adc_window_init() {
//DMA init RCC->AHBENR |= RCC_AHBENR_DMA1EN; ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); DMA1_Channel1->CMAR = (uint32_t)(ADC_array); DMA1_Channel1->CNDTR = 6; DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_TEIE | DMA_CCR_CIRC; DMA1_Channel1->CCR |= DMA_CCR_EN; NVIC_EnableIRQ(DMA1_Channel1_IRQn); NVIC_SetPriority(DMA1_Channel1_IRQn,0); RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; RCC->CR2 |= RCC_CR2_HSI14ON; ADC_SPIN((RCC->CR2 & RCC_CR2_HSI14RDY) == 0); ADC1->CR |= ADC_CR_ADCAL; //Enable calibration ADC_SPIN((ADC1->CR & ADC_CR_ADCAL) != 0); ADC1->CR |= ADC_CR_ADEN; //Enable ADC ADC_SPIN((ADC1->ISR & ADC_ISR_ADRDY) == 0); ADC1->IER |= ADC_IER_EOCIE; //Enable End of conversion interrupt ADC1->CFGR1 = 0b00000000000000000010000000000001; //12 bit resolution, continuous mode //DMA enable ADC1->SMPR = 4; // 41.5 Clk cycles for sampling ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL2 | ADC_CHSELR_CHSEL3 | ADC_CHSELR_CHSEL4 | ADC_CHSELR_CHSEL5 ; ADC1->CR |= _BV(2); // Start NVIC->ISER[0] |= _BV(ADC1_COMP_IRQn);}In my ADC1_COMP_IRQHandler() I am reading ADC1->DR to clear the interrupt. I am not doing anything in the DMA1_Channel1_IRQHandler(), do I need to be?Thanks2015-11-13 09:08 AM
Yes, the STM32 parts expect you to use DMA to do multiple channels, it's too inefficient to EOC after each conversion. If you need an EOC for the completed conversions, you can use the DMA HT and TC interrupts, and the size of the transfer to decimate/manage them.
These are TIM driven, but you can select continuous conversion, and non-triggered quite easily.[DEAD LINK /public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32F0%20ADC-DMA%20touble&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=35]https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32F0%20ADC-DMA%20touble&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=352015-11-13 11:57 AM
Got it working.
I disabled the ADC interrupt and enabled the DMA one. I also had to change my array size from 32 bits to 16 (to match what I told it in the register)Here's the working code:uint16_t ADC_array[6];
****************************************************
RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */ DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */ DMA1_Channel1->CMAR = (uint32_t)(ADC_array); /* (4) */ DMA1_Channel1->CNDTR = 6; /* (5) */ DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC | DMA_CCR_TCIE; /* (6) */ DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */ NVIC_EnableIRQ(DMA1_Channel1_IRQn); /* (1) */ NVIC_SetPriority(DMA1_Channel1_IRQn,0); /* (2) */ RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; RCC->CR2 |= RCC_CR2_HSI14ON; ADC_SPIN((RCC->CR2 & RCC_CR2_HSI14RDY) == 0); ADC1->CR |= ADC_CR_ADCAL; //Enable calibration ADC_SPIN((ADC1->CR & ADC_CR_ADCAL) != 0); ADC1->CR |= ADC_CR_ADEN; //Enable ADC ADC_SPIN((ADC1->ISR & ADC_ISR_ADRDY) == 0); ADC1->CFGR1 = 0b00000000000000000010000000000011; //12 bit resolution, continuous mode //DMA enable ADC1->SMPR = 4; // 41.5 Clk cycles for sampling ADC1->CHSELR = ADC_CHSELR_CHSEL0 | ADC_CHSELR_CHSEL1 | ADC_CHSELR_CHSEL2 | ADC_CHSELR_CHSEL3 | ADC_CHSELR_CHSEL4 | ADC_CHSELR_CHSEL5 ; ADC1->CR |= _BV(2); // Start******************************
void DMA1_Channel1_IRQHandler() { DMA1->IFCR |= DMA_IFCR_CTCIF1; //Clears transfer complete flag //Do stuff with ADC data}