linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* fast spi driver development
@ 2022-07-03 13:05 Patricio Moreno
  2022-07-04 18:00 ` Andy Shevchenko
  0 siblings, 1 reply; 3+ messages in thread
From: Patricio Moreno @ 2022-07-03 13:05 UTC (permalink / raw)
  To: linux-iio

Hello,

I'm writing a driver for the TI ADS127x family of ADCs. The ads127x is a 
24 bit samples, 4/8 channels, ADC, which can be clocked, using SPI, with 
up to 25 MHz. For what I've seen, I've followed a common approach within 
the IIO ADC drivers, but I can't get it to work at high frequencies.

I'm using the triggered buffers interface, with a RDY interrupt pin. The 
problem I have is with timings. When the ADC sends the data ready 
signal, my handler is called approximately 7µs later. This handler then 
calls spi_read to get 24 bytes (8 3 bytes samples) and the kernel takes 
a lot of time to read the SPI bus, actually, to *start* reading.

I would really appreciate some guidance on how to deal with this issue.
I can gladly send the code if someone wish to comment on it, I'm 
planning to free it once it's working anyway.

Below I've copied part of the code, which I think could be useful now.
The first function is passed to devm_request_irq, and the second one to 
iio_triggered_buffer_setup.


irqreturn_t ti_ads1x7x_interrupt(int irq, void *dev_id)
{
         struct iio_dev *indio_dev = dev_id;
         struct ti_ads1x7x_state *st = iio_priv(indio_dev);

         if (iio_buffer_enabled(indio_dev)) {
                 iio_trigger_poll(st->trig);
         } else {
                 complete(&st->completion);
         }

         return IRQ_HANDLED;
};


irqreturn_t ti_ads127x_trigger_handler(int irq, void *p)
{
         struct iio_poll_func *pf = p;
         struct iio_dev *indio_dev = pf->indio_dev;
         struct ti_ads1x7x_state *st = iio_priv(indio_dev);
         int ret;
         int i;
         u8 b[24];

         ret = spi_read(st->spi, b, sizeof b);
         for_each_set_bit(i,
                          indio_dev->active_scan_mask,
                          indio_dev->masklength) {
                 st->data.samples[i] = (b[3 * i] << 16) | (b[3 * i + 1] 
<< 8) | (b[3 * i + 2] << 0);
                 if (ret)
                         goto ads127x_error_notify_done;
         }

         iio_push_to_buffers_with_timestamp(indio_dev,
                                            &st->data,
                                            pf->timestamp);

ads127x_error_notify_done:
         iio_trigger_notify_done(indio_dev->trig);
         return IRQ_HANDLED;
}

Thank you!

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: fast spi driver development
  2022-07-03 13:05 fast spi driver development Patricio Moreno
@ 2022-07-04 18:00 ` Andy Shevchenko
  2022-07-04 19:10   ` Lars-Peter Clausen
  0 siblings, 1 reply; 3+ messages in thread
From: Andy Shevchenko @ 2022-07-04 18:00 UTC (permalink / raw)
  To: Patricio Moreno, Nuno Sá
  Cc: linux-iio, Jonathan Cameron, Lars-Peter Clausen

On Sun, Jul 3, 2022 at 3:09 PM Patricio Moreno <pm.pato@gmail.com> wrote:
>
> Hello,
>
> I'm writing a driver for the TI ADS127x family of ADCs. The ads127x is a
> 24 bit samples, 4/8 channels, ADC, which can be clocked, using SPI, with
> up to 25 MHz. For what I've seen, I've followed a common approach within
> the IIO ADC drivers, but I can't get it to work at high frequencies.
>
> I'm using the triggered buffers interface, with a RDY interrupt pin. The
> problem I have is with timings. When the ADC sends the data ready
> signal, my handler is called approximately 7µs later. This handler then
> calls spi_read to get 24 bytes (8 3 bytes samples) and the kernel takes
> a lot of time to read the SPI bus, actually, to *start* reading.
>
> I would really appreciate some guidance on how to deal with this issue.

+Cc: maintainers and AD guys. I remember there was a discussion about
supporting HiFreq ADCs in IIO and AFAIR there are some issues (and you
probably need to use DMA in cyclic mode or so).

...

>                  st->data.samples[i] = (b[3 * i] << 16) | (b[3 * i + 1]
> << 8) | (b[3 * i + 2] << 0);

JFYI: get_unaligned_be24() is what you need here.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: fast spi driver development
  2022-07-04 18:00 ` Andy Shevchenko
@ 2022-07-04 19:10   ` Lars-Peter Clausen
  0 siblings, 0 replies; 3+ messages in thread
From: Lars-Peter Clausen @ 2022-07-04 19:10 UTC (permalink / raw)
  To: Andy Shevchenko, Patricio Moreno, Nuno Sá
  Cc: linux-iio, Jonathan Cameron

On 7/4/22 20:00, Andy Shevchenko wrote:
> On Sun, Jul 3, 2022 at 3:09 PM Patricio Moreno <pm.pato@gmail.com> wrote:
>> Hello,
>>
>> I'm writing a driver for the TI ADS127x family of ADCs. The ads127x is a
>> 24 bit samples, 4/8 channels, ADC, which can be clocked, using SPI, with
>> up to 25 MHz. For what I've seen, I've followed a common approach within
>> the IIO ADC drivers, but I can't get it to work at high frequencies.
>>
>> I'm using the triggered buffers interface, with a RDY interrupt pin. The
>> problem I have is with timings. When the ADC sends the data ready
>> signal, my handler is called approximately 7µs later. This handler then
>> calls spi_read to get 24 bytes (8 3 bytes samples) and the kernel takes
>> a lot of time to read the SPI bus, actually, to *start* reading.
>>
>> I would really appreciate some guidance on how to deal with this issue.
> +Cc: maintainers and AD guys. I remember there was a discussion about
> supporting HiFreq ADCs in IIO and AFAIR there are some issues (and you
> probably need to use DMA in cyclic mode or so).

A created some slides on this very topic a while ago. See 
https://wiki.analog.com/_media/resources/fpga/peripherals/spi-engine3.pdf

The summary is a general purpose operating system is not well suited to 
this task, mainly, like you noticed, due to the context switch penalty.

In general the solution to this is to batch multiple sample acquisitions 
together to reduce the number of context switches. There are both 
software and hardware based approaches for this.

  * Asymmetric multiprocessing: Dedicate one core to data acquisition 
running a bare metal application. It can control the SPI controller in a 
tight loop and make sure that transactions are scheduled on time. Data 
can be moved to the main OS using a shared memory ring buffer.

  * FIFO in the sensor: Probably the best solution if available. Have a 
FIFO in the sensor with a threshold IRQ and read multiple samples in a 
single SPI transfer when the FIFO is almost full.

  * SPI transfer offloading on the host side: This is what the 
presentation mainly talks about. The host system has a SPI controller IP 
that supports scheduling SPI transfers without software interaction in 
response to a trigger signal, e.g. a timer of external GPIO. The data is 
then pushed to a FIFO or directly to system memory using DMA. The host 
system is notified when a certain amount of samples have been received.

- Lars


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-07-04 19:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-03 13:05 fast spi driver development Patricio Moreno
2022-07-04 18:00 ` Andy Shevchenko
2022-07-04 19:10   ` Lars-Peter Clausen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).