Increasing SPI Speed for SPI ADC

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
User avatar
Dugite
Posts: 21
Joined: Thu Jan 18, 2018 1:29 pm

Increasing SPI Speed for SPI ADC

Post by Dugite » Wed Aug 19, 2020 2:02 pm

Hello,

I have a data logger using MicroPython 1.12 with a design based on the Pyboard 1.1.

I have an external SPI ADC which is a LTC1857 as shown in the datasheet below where the SPI bus speed is set to 5Mbps. There are also other SPI devices on the same bus but this should not be relevant to the problem below.

LTC1857 data sheet:
https://www.analog.com/media/en/technic ... 5789fb.pdf

The problem I am facing is that I need to read the SPI ADC at least 1kHz or more (plan to use a 500Hz or higher RC filter to prevent aliasing), but from my measurements, with the existing SPI "send_recv" method, to send 16-bit it is taking abound 45us as shown below:

Code: Select all

    
def sendReceive(self, sendBytes, receiveBytes, timeout):
        self._setupSpiPortMain(1)
        timeStart = pyb.micros()
        self._spiBus.send_recv(sendBytes,
                               receiveBytes,
                               timeout=timeout)
        timeEnd = pyb.micros()
        print("sendReceive")
        print(timeEnd - timeStart)
        print(sendBytes)
serial data.JPG
serial data.JPG (25.38 KiB) Viewed 1807 times
This 45us is just to send/receive 16 bits which at 5Mbps is 3.2us + overhead. If I am to sample 8 channels, the minimum time is going to be 8 x 45us = 360us + overhead and average results. This means I might be lucky to get 1kHz (1ms) but this seems to be pushing it and 2kHz (500us) is not possible.

I tried sending more bytes at once which improved the results but this will not work with the SPI ADC as I need to wait for the busy pin before reading the sample.

Code: Select all

    def sendReceive(self, sendBytes, receiveBytes, timeout):
        self._setupSpiPortMain(1)
        sendBytes = bytearray([0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                               0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
        receiveBytes = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
        timeStart = pyb.micros()
        self._spiBus.send_recv(sendBytes,
                               receiveBytes,
                               timeout=timeout)
        timeEnd = pyb.micros()
        print("sendReceive")
        print(timeEnd - timeStart)
        print(sendBytes)
serial data more bytes.JPG
serial data more bytes.JPG (58.28 KiB) Viewed 1797 times
This 85us to send/receive 16 bytes which is 128 bits, which at 5Mbps is 25.6us which is much better but I do not think is possible if I need to wait for the busy bit to be able to read each ADC channel.

I would just like to know what is the best way to approach getting the SPI ADC reading happening faster given I need to call "send_recv" to read each channel waiting for the busy pin in between reads? I know there is assembly, but I will need to read up on that and ideally would like to approach this with easiest options first down to assembly. Thoughts and comments much appreciated.

doublevee
Posts: 75
Joined: Mon Jul 02, 2018 11:09 pm

Re: Increasing SPI Speed for SPI ADC

Post by doublevee » Sat Aug 22, 2020 6:31 am

Hey Dugite.

Although you haven’t listed your code in detail, the 100KHz performance is related to a single channel read. When you divide this max figure by 8 and allow for mux commands etc the figure of approx 10KHz should be feasible (sampling all channels) if I have understood the datasheet correctly.

How are you sampling the _BUSY output from the ADD?

Have you tried simply waiting a fixed period of time (5us) to cover conversion time per channel rather than checking _BUSY? This may give you slightly better results and would also provide more even sampling data in the case of connecting into a microcontroller?

Post Reply