i.MX93 Adc latency issue

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

i.MX93 Adc latency issue

ソリューションへジャンプ
280件の閲覧回数
NZP
Contributor III


Hello experts,

I am working on IMX9352 processors ADC, I am able to read adc using libiio cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw. 

In my project requirement of reading adc is at very fast interval. so, looking at imx93_adc.c driver I found that below function takes much time.

ret = wait_for_completion_interruptible_timeout(&adc->completion, IMX93_ADC_TIMEOUT);

Measuring execution time using below

ktime_t start, end;
s64 delta_time_ns;
start = ktime_get();
ret = wait_for_completion_interruptible_timeout(&adc->completion,IMX93_ADC_TIMEOUT);
end = ktime_get();
delta_time_ns = ktime_to_ns(ktime_sub(end, start));
printk(KERN_INFO "Execution time: %lld ns\n", delta_time_ns);

cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[ 5680.026447] Execution time: 167833 ns
3775
cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[ 5681.053120] Execution time: 183459 ns
3780
cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[ 5681.955820] Execution time: 157406 ns
3774

I found this function takes around average 150 microseconds and more. However, ADC clock is 24MHZ and much faster.

1. So, can anyone please let me know how can I reduce this execution time of reading ADC value?

2. Is there any way to read ADC in real-time as we do in microcontroller with very less latency in user space.

0 件の賞賛
1 解決策
246件の閲覧回数
NZP
Contributor III

Dear LFGP,

Thanks for your suggestion,

I have slightly modified my execution time measurement logic as below, Now storing end = ktime_get(); variable in imx93_adc_isr as below.

 

start = ktime_get();
ret = wait_for_completion_interruptible_timeout(&adc->completion,IMX93_ADC_TIMEOUT);
//end = ktime_get();
delta_time_ns = ktime_to_ns(ktime_sub(end, start));
printk(KERN_INFO "Execution time: start, end, delta  %lld, %lld, %lld ns\n", start, end, delta_time_ns);
static irqreturn_t imx93_adc_isr(int irq, void *dev_id)
{
	struct imx93_adc *adc = dev_id;
	u32 isr, eoc, unexpected;
        end = ktime_get();
	isr = readl(adc->regs + IMX93_ADC_ISR);

	if (FIELD_GET(IMX93_ADC_ISR_EOC_ECH_MASK, isr)) {
		eoc = isr & IMX93_ADC_ISR_EOC_ECH_MASK;
		writel(eoc, adc->regs + IMX93_ADC_ISR);
		complete(&adc->completion);
	}

	unexpected = isr & ~IMX93_ADC_ISR_EOC_ECH_MASK;
	if (unexpected) {
		writel(unexpected, adc->regs + IMX93_ADC_ISR);
		dev_err(adc->dev, "Unexpected interrupt 0x%08x.\n", unexpected);
		return IRQ_NONE;
	}

	return IRQ_HANDLED;
}

 

Below is time delta of conversion start time and interrupt generation.

cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[12122.109633] Execution time: start, end, delta 12122502929521, 12122502953563, 24042 ns
3775
cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[12166.448276] Execution time: start, end, delta 12166842653231, 12166842689690, 36459 ns
3786
cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[12168.208182] Execution time: start, end, delta 12168602600091, 12168602636592, 36501 ns
3779

1. Here my question is that is it possible to minimize this latency? Because ADC interrupt generation takes too long here.

 

元の投稿で解決策を見る

0 件の賞賛
3 返答(返信)
234件の閲覧回数
LFGP
NXP TechSupport
NXP TechSupport

dear @NZP ,

if you only comment the line end = ktime_get();  you can't be sure for the value in ""end"" variable, in other words, from my point of view, it is a garbage value.

On the other hand, the best way to obtain tha ADC value is performing an interrupt due the function 

wait_for_completion_interruptible_timeout

depends of the Linux scheduler ( it is a consult to the kernel and not an interrupt as well), so, there isn't any efective method to reduce the elapsed time.

0 件の賞賛
253件の閲覧回数
LFGP
NXP TechSupport
NXP TechSupport

dear @NZP ,

the values of   "Execution time: ...."   you are seeing it doesn't depend of the ADC sped conversion, they depend of the Linux scheduler ( excerpt: "Completions are built on top of the waitqueue and wakeup infrastructure of the Linux scheduler") . In other words, you need to use/develop a direct interrupt for the ADC. Into the driver you are using there is a function intended to do the interrupt, could please check it.

static irqreturn_t imx93_adc_isr(int irq, void *dev_id)
{
struct imx93_adc *adc = dev_id;
u32 isr, eoc, unexpected;
 
isr = readl(adc->regs + IMX93_ADC_ISR);
 
if (FIELD_GET(IMX93_ADC_ISR_EOC_ECH_MASK, isr)) {
eoc = isr & IMX93_ADC_ISR_EOC_ECH_MASK;
writel(eoc, adc->regs + IMX93_ADC_ISR);
complete(&adc->completion);
}
 
unexpected = isr & ~IMX93_ADC_ISR_EOC_ECH_MASK;
if (unexpected) {
writel(unexpected, adc->regs + IMX93_ADC_ISR);
dev_err(adc->dev, "Unexpected interrupt 0x%08x.\n", unexpected);
return IRQ_NONE;
}
 
return IRQ_HANDLED;
}

 

0 件の賞賛
247件の閲覧回数
NZP
Contributor III

Dear LFGP,

Thanks for your suggestion,

I have slightly modified my execution time measurement logic as below, Now storing end = ktime_get(); variable in imx93_adc_isr as below.

 

start = ktime_get();
ret = wait_for_completion_interruptible_timeout(&adc->completion,IMX93_ADC_TIMEOUT);
//end = ktime_get();
delta_time_ns = ktime_to_ns(ktime_sub(end, start));
printk(KERN_INFO "Execution time: start, end, delta  %lld, %lld, %lld ns\n", start, end, delta_time_ns);
static irqreturn_t imx93_adc_isr(int irq, void *dev_id)
{
	struct imx93_adc *adc = dev_id;
	u32 isr, eoc, unexpected;
        end = ktime_get();
	isr = readl(adc->regs + IMX93_ADC_ISR);

	if (FIELD_GET(IMX93_ADC_ISR_EOC_ECH_MASK, isr)) {
		eoc = isr & IMX93_ADC_ISR_EOC_ECH_MASK;
		writel(eoc, adc->regs + IMX93_ADC_ISR);
		complete(&adc->completion);
	}

	unexpected = isr & ~IMX93_ADC_ISR_EOC_ECH_MASK;
	if (unexpected) {
		writel(unexpected, adc->regs + IMX93_ADC_ISR);
		dev_err(adc->dev, "Unexpected interrupt 0x%08x.\n", unexpected);
		return IRQ_NONE;
	}

	return IRQ_HANDLED;
}

 

Below is time delta of conversion start time and interrupt generation.

cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[12122.109633] Execution time: start, end, delta 12122502929521, 12122502953563, 24042 ns
3775
cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[12166.448276] Execution time: start, end, delta 12166842653231, 12166842689690, 36459 ns
3786
cat /sys/bus/iio/devices/iio\:device0/in_voltage0_raw
[12168.208182] Execution time: start, end, delta 12168602600091, 12168602636592, 36501 ns
3779

1. Here my question is that is it possible to minimize this latency? Because ADC interrupt generation takes too long here.

 

0 件の賞賛