cancel
Showing results for 
Search instead for 
Did you mean: 

How to sample improve ADC speed?

STM32L09
Associate II

My application senario: sample the sensor signal every second, and transmit through UART. 

to save power supply, I select ADC single mode, and used average as filter.

void ConfigureADC(void)
{
ADC1->CFGR1 |= ADC_CFGR1_AUTOFF;
ADC1->CFGR2 = (ADC1->CFGR2 & (~ADC_CFGR2_CKMODE))
| (ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0| ADC_CFGR2_OVSS_2); 
ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; 
ADC1->CR |= ADC_CR_ADEN; 
ADC->CCR |= ADC_CCR_VREFEN|ADC_CCR_TSEN; 
}


unsigned int SignleADC(unsigned long int channel)
{
ADC1->CHSELR = channel; 
ADC1->CR |= ADC_CR_ADSTART;
while ((ADC1->ISR & ADC_ISR_EOC) == 0) 
{
}
ADC1->CR |= ADC_CR_ADSTP;
return ADC1->DR;
}

unsigned int Sensor_Read(void)
{
unsigned int gas[128];
unsigned long int read=0;
for(unsigned char i=0;i<128;i++)
gas[i] = SignleADC(ADC_CHSELR_CHSEL5);
for(unsigned char i=0;i<128;i++)
read += gas[i];

read = read>>7;
return((unsigned int)read);
}

Now the run time for Sensor_Read is about 700ms, it's too long, how can I improve the speed?

 

8 REPLIES 8

The most obvious would be to sum/average over fewer samples, or use the longer sample/hold to negate the need.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

thanks, but 128 is minimum, otherwise the noise too high

Convert with DMA in background. Perform averaging on demand when you send out sample.

If you feel a post has answered your question, please click "Accept as Solution".
mƎALLEm
ST Employee

Hello @STM32L09 ,

In next time please use </> button to paste your code. See this post. I've edited your post.

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

got it.

Good idea, I will try it

Hello, TDK, 

My application needs to sample PA0 16 times every second, PA5 128 times every second, because PA5 signal has large noise.

I read some of the introduction of DMA, I think for my application, I should use ADC continous mode and DMA circular mode.

I am not sure if I can have different ADC sample time? I don't want to sample 128 times for PA0, just to save time and power consumption. From the ST example, I think all seclected ADC channel are at same sampling speed, I don't know how to configure different sampling frequency.

It will be very helpful if you can give me some example code.

ST Example code:

__INLINE void ConfigureADC(void)
{
  /* (1) Select HSI14 by writing 00 in CKMODE (reset value) */  
  /* (2) Select the continuous mode */
  /* (3) Select CHSEL4, CHSEL9 and CHSEL17 */
  /* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */
  /* (5) Enable interrupts on overrrun */
  /* (6) Wake-up the VREFINT (only for VLCD, Temp sensor and VRefInt) */
  //ADC1->CFGR2 &= ~ADC_CFGR2_CKMODE; /* (1) */  
  ADC1->CFGR1 |= ADC_CFGR1_CONT; /* (2)*/
  ADC1->CHSELR = ADC_CHSELR_CHSEL4 | ADC_CHSELR_CHSEL9 \
               | ADC_CHSELR_CHSEL17; /* (3)*/
  ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */
  ADC1->IER = ADC_IER_OVRIE; /* (5) */
  ADC->CCR |= ADC_CCR_VREFEN; /* (6) */

  /* Configure NVIC for ADC */
  /* (1) Enable Interrupt on ADC */
  /* (2) Set priority for ADC */
  NVIC_EnableIRQ(ADC1_COMP_IRQn); /* (1) */
  NVIC_SetPriority(ADC1_COMP_IRQn,0); /* (2) */
}


/**
  * Brief   This function configures the DMA to store the result of an ADC sequence.
  *         The conversion results are stored in N-items array.
  * Param   None
  * Retval  None
  */
__INLINE void ConfigureDMA(void)
{
  /* (1) Enable the peripheral clock on DMA */
  /* (2) Enable DMA transfer on ADC and circular mode */ 
  /* (3) Configure the peripheral data register address */ 
  /* (4) Configure the memory address */
  /* (5) Configure the number of DMA tranfer to be performs on DMA channel 1 */
  /* (6) Configure increment, size, interrupts and circular mode */
  /* (7) Enable DMA Channel 1 */
  RCC->AHBENR |= RCC_AHBENR_DMA1EN; /* (1) */
  ADC1->CFGR1 |= ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG; /* (2) */
  DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); /* (3) */
  DMA1_Channel1->CMAR = (uint32_t)(ADC_array); /* (4) */
  DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNEL; /* (5) */
  DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 \
                      | DMA_CCR_TEIE | DMA_CCR_CIRC; /* (6) */  
  DMA1_Channel1->CCR |= DMA_CCR_EN; /* (7) */
 
  /* Configure NVIC for DMA */
  /* (8) Enable Interrupt on DMA Channel 1  */
  /* (9) Set priority for DMA Channel 1 */
  NVIC_EnableIRQ(DMA1_Channel1_IRQn); /* (8) */
  NVIC_SetPriority(DMA1_Channel1_IRQn,0); /* (9) */
}
STM32L09
Associate II

currently my idea is:

1. Configure ADC and DMA to sample PA0 and PA5 16 times

2. Re-configure ADC and DMA to sample PA5 256-16 times

repeat step 1.