This post was last edited by tinnu on 2020-10-8 13:57
Testing the ADC speed requires the support of a timer, so you must first understand the timer function.
1. Timer clock
The timer clock goes through: AHB - APB - timer
We use TIMER1
What’s interesting is that the maximum speed of the CK_APB1 bus can only reach 50M, but the clock coming out of CK_APB1 can reach 200M. This is because there is a frequency multiplication function in the middle.
1-CK_APB1 clock
For more information about this clock, see: UART
USART uses PCLK1 clock, and the current CK_APB1 clock is the highest 50M
2-TIMER CLOCK
TIMER1 uses the clock after CK_APB1 multiplication. For the multiplication coefficient, please refer to the RCU_CFG1 register:
is 0 in reset state, which means 2 times the frequency. Here, 2 times the frequency is 100M.
(II) Settings
Routine matching code:
timer_parameter_struct timer_initpara;
timer_initpara.prescaler = 9999;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 9999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1,&timer_initpara);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">
There is a prescaler and comparator. Under a 100M clock, the time for one update is (9999+1)*(9999+1)=100M, which is exactly 1S.
Enable interrupts:
timer_interrupt_enable(TIMER1, TIMER_INT_UP);
nvic_irq_enable(TIMER1_IRQn, 2U, 0U);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">
Enable the timer:
timer_enable(TIMER1);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">
In fact, after running, you will find that the external interrupt cannot be triggered. This is because the clock of TIMER1 needs to be enabled additionally:
rcu_periph_clock_enable(RCU_TIMER1);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">
(III) Interrupt service function and code for testing ADC speed
ADC needs to disable interrupts and operate in the main loop, because after enabling the continuous read and write function of ADC, the conversion speed of ADC is amazing, and the interrupt speed cannot keep up with the read and write speed. Even one more line of code in the main loop will seriously affect the accuracy of the test. This is why ADC recommends using DMA to read and write, but DMA is not convenient for testing speed, so polling is still used.
1- Enable ADC continuous conversion function
adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">
2- Enable once during initialization
adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
") rgba(220, 220, 220, 0.5); top: -15px; left: 0px; display: block;">
3- No redundant operations can be performed in the main loop
if (adc_interrupt_flag_get(ADC0, ADC_INT_FLAG_EOC) == SET)
{
adc_regular_data_read(ADC0);
adc_counter++;
adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC);
}
4-Timer interrupt service function
void TIMER1_IRQHandler(void)
{
char t_char[30] = "";
gd_eval_led_toggle(LED1);
sprintf(t_char, "ADC for one second:%d\r\n", adc_counter);
PRINTF_UART0(t_char);
adc_counter = 0;
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
}
(IV) Effect
When the sampling rate is ADC_SAMPLETIME_112
ADC for one second:403225
ADC for one second:402292
ADC for one second:402292
ADC for one second:402291
ADC for one second:402291
ADC for one second:402291
ADC for one second:402292
ADC for one second:402292
A speed of 400K per second.
When the sampling rate is ADC_SAMPLETIME_15
ADC for one second:1010101
ADC for one second:1007662
ADC for one second:1007662
ADC for one second:1007661
ADC for one second:1007661
It's already 1M.
However, it must be noted that the increase in the adoption rate has not kept pace with the increase in the conversion rate, which may still cause the problem of polling time consumption. After all, at a conversion rate of 1M, there are actually only 200 machine clocks each time.
(V) ADC execution is also put into interrupt
Then I tried to put the ADC execution operation into the ADC interrupt, and set the timer interrupt to a higher priority:
nvic_irq_enable(TIMER1_IRQn, 1U, 0U);
When the sampling rate is ADC_SAMPLETIME_112:
ADC for one second:403225
ADC for one second:402292
ADC for one second:402292
It is exactly the same as when polling. It seems that interrupts will not become a bottleneck for conversion at a low speed of 400k.
When the sampling rate is ADC_SAMPLETIME_15
ADC for one second:925925
ADC for one second:923779
ADC for one second:923778
At this time, it is obviously smaller than polling.
|