2025-05-23 7:51 AM - last edited on 2025-05-23 8:58 AM by Andrew Neil
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?
2025-05-23 7:58 AM
The most obvious would be to sum/average over fewer samples, or use the longer sample/hold to negate the need.
2025-05-23 8:11 AM
thanks, but 128 is minimum, otherwise the noise too high
2025-05-23 8:17 AM
Convert with DMA in background. Perform averaging on demand when you send out sample.
2025-05-23 8:22 AM
2025-05-23 5:53 PM
got it.
2025-05-23 5:54 PM
Good idea, I will try it
2025-05-24 1:56 AM
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) */
}
2025-05-24 6:47 AM
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.