1

I am trying to use the Raspberry Pi to read in analog signals at 1MHz and I wanted to know how I would go about doing this. What sort of ADC should I buy, and how many? If not ADC, what do I need to do in order to make this possible?

The background of this question is: I have an ultrasound transducer that is receiving a 1MHz sine wave signal. This would normally say be read by the oscilloscope, but I want the Raspberry PI to be able to read this and be able to analyze the data digitally.

I would definitely want the signal to be as good as possible, so I would actually require possibly greater than 1MHz (due to Nyquist?). I would like to do various forms of computational analysis (spectral, statistics) on the signal after collection of data.

Thank you.

  • I suspect the Pi is not the right device for your project. How many bits per ADC sample do you need? – joan Oct 5 '15 at 20:52
  • probably 8-10 bits. I need to know the signal, so that I could say plot it after data collection, but now it is all done digitally on maybe my laptop. – ajl123 Oct 6 '15 at 1:07
  • Personally I do not believe this is feasible on the Pi. The Pi can handle 20,000 SPI transactions per second. Can you find an ADC which will buffer up 50 readings at a time to return to the Pi in a single transaction? If you can find such an ADC it might be worth investigating further if you have the multi-core Pi2. It simply will not work on any other sort of Pi. You are also treating the input and subsequent processing in isolation. You need to consider the detail of the processing you plan to undertake to see if the Pi can do that one million times per second. – joan Oct 6 '15 at 8:27
  • Why do you say the ADC has to buffer? Why not just capture, analyze, and repeat? – Brian Oct 6 '15 at 21:27
  • @Brian The questioner wanted one million 8-10 bit samples per second. The Pi SPI driver tops out at about 20k transactions per second. If the ADC only delivers one sample per transaction that gives 20 ksps. – joan Feb 23 '16 at 20:32
1

The Pi doesn't have external access to high speed interfaces that would normally be used for something like this. However, for a relatively low speed like 1MHz, you may be able to get away with using the SPI bus:

  • Big assumption: can you use 976.5632 kHz instead of 1MHz? The SPI bus only supports certain frequencies, and that is the closest one. (Note that if, for example, you are reading back 8-bits at a time, you'll run the SPI clock at 8 * 976 =~ 7.8MHz.)
  • Buy a SPI based ADC that supports 1 Msps. For example, search digikey, mouser or other.

The bigger issues are going to be how useful the data received is for analysis. Things like clock jitter, bits of resolution, and probably most importantly the analog front end will strongly effect what you can do with the data. For example, if you have a specific signal you are searching for, then the details of your implementation will very well matter.

But, if you just want to use it to get a rough assessment of the signal, the above will work fine.

  • I added an edit, saying what I want to do with the signal. If collecting the ~1MHz sample in a relatively good manner (doesn't have to be like insanely great, but decent enough to do analysis) is not possible, would you have any suggestions on how to make this hardware I/O possible. – ajl123 Oct 6 '15 at 1:05
  • SPI is the fastest readily available interface on the Pi. It's fast enough for what you are doing, but orders of magnitude slower than a memory interface. It's the other issues that may make things tougher - for example: what is the output of the the transducer? The full range of 0 to 3.3V? If so, great, you can hook it right up to the ADC. If it's small, you'll likely have to amplify it, etc, etc... – Brian Oct 6 '15 at 22:02
  • Say the output is from +7V to -7V, would that be okay? – ajl123 Oct 7 '15 at 3:58
  • The voltage just needs to be between the range that the ADC accepts. I picked 0 and 3.3V above because if your ADC is powered by 3.3V, then hooking it up to the RasPi is simple (if you use a different voltage, then you'll have to use level translators in between the RasPi and the ADC). If the voltage is outside the range the ADC accepts, then the ADC will just report MIN or MAX - not useful. Worse, if the voltage is too far off, you'll fry the ADC. I can give you a rough (poor) idea of you might do this, but its probably better answered by someone else here (or an electronics forum). – Brian Oct 7 '15 at 11:58
1

I have used an MCP3002 ADC to read analogue signals on my Raspberry Pi 2. It was connected to Python through the SPI and it could get up to 1Mhz. I have used an 4067 16-to-1 multiplexer and connected the output to the analogue input pin of the ADC. So, by setting 4 GPIOs on my Raspberry Pi High or Low, I could read 16 analogue devices on my ADC and I have another channel free, just in case that I need it.

Here is the code in python to do so:

#!/usr/bin/python

import time
#import uinput
import RPi.GPIO as GPIO
import spidev # import the SPI driver
from time import sleep
from array import *
import sys

DEBUG = False
vref = 3.3 * 1000 # V-Ref in mV (Vref = VDD for the MCP3002)
resolution = 2**10 # for 10 bits of resolution
calibration = 38 # in mV, to make up for the precision of the components
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
GPIO.setup(15, GPIO.OUT)

# MCP3002 Control bits
#
#   7   6   5   4   3   2   1   0
#   X   1   S   O   M   X   X   X
#
# bit 6 = Start Bit
# S = SGL or \DIFF SGL = 1 = Single Channel, 0 = \DIFF is pseudo differential
# O = ODD or \SIGN
# in Single Ended Mode (SGL = 1)
#   ODD 0 = CH0 = + GND = - (read CH0)
#       1 = CH1 = + GND = - (read CH1)
# in Pseudo Diff Mode (SGL = 0)
#   ODD 0 = CH0 = IN+, CH1 = IN-
#       1 = CH0 = IN-, CH1 = IN+
#
# M = MSBF
# MSBF = 1 = LSB first format
#        0 = MSB first format
# ------------------------------------------------------------------------------


# SPI setup
spi_max_speed = 1000000 # 1 MHz (1.2MHz = max for 2V7 ref/supply)
# reason is that the ADC input cap needs time to get charged to the input     level.
CE = 0 # CE0 | CE1, selection of the SPI device
spi = spidev.SpiDev()
spi.open(0,CE) # Open up the communication to the device
spi.max_speed_hz = spi_max_speed

#
# create a function that sets the configuration parameters and gets the     results
# from the MCP3002
#


def read_mcp3002(channel):
    # see datasheet for more information
    # 8 bit control :
    # X, Strt, SGL|!DIFF, ODD|!SIGN, MSBF, X, X, X
    # 0, 1,    1=SGL,     0 = CH0  , 0   , 0, 0, 0 = 96d
    # 0, 1,    1=SGL,     1 = CH1  , 0   , 0, 0, 0 = 112d
    if channel == 0:
        cmd = 0b01100000
    else:
        cmd = 0b01110000

    if DEBUG : print("cmd = ", cmd)

    spi_data = spi.xfer2([cmd,0]) # send hi_byte, low_byte; receive hi_byte, low_byte

    if DEBUG : print("Raw ADC (hi-byte, low_byte) = {}".format(spi_data))

    # receive data range: 000..3FF (10 bits)
    # MSB first: (set control bit in cmd for LSB first)
    # spidata[0] =  X,  X,  X,  X,  X,  0, B9, B8
    # spidata[1] = B7, B6, B5, B4, B3, B2, B1, B0
    # LSB: mask all but B9 & B8, shift to left and add to the MSB
    adc_data = ((spi_data[0] & 3) << 8) + spi_data[1]
    return adc_data
def main():
        x=0
      while True:
        binary_x="{0:04b}".format(x)
        GPIO.output(15, int(binary_x[0]))
        GPIO.output(13, int(binary_x[1]))
        GPIO.output(11, int(binary_x[2]))
        GPIO.output(7, int(binary_x[3]))
        # average three readings to get a more stable one
        channeldata_1 = read_mcp3002(0) # get CH0 input
        sleep(0.001)
        channeldata_2 = read_mcp3002(0) # get CH0 input
        sleep(0.001)
        channeldata_3 = read_mcp3002(0) # get CH0 input
        channeldata = (channeldata_1+channeldata_2+channeldata_3)/3
        #
        # Voltage = (CHX data * (V-ref [= 3300 mV] * 2 [= 1:2 input divider]) / 1024 [= 10bit resolution]            #
        voltage = int(round(((channeldata * vref * 2) / resolution),0))+ calibration
        print("sensor ",x" voltage: "voltage)
      # if you would like to have some kind of delay.
        #sleep(0.5)
        x=x+1
        if x==16 :
           x=0
if __name__ == '__main__':
    main()
  • 1
    Welcome to the Raspberry Pi part of the Stack Exchange network. Whilst this probably will not be able to meet the OP's requirements (the consensus is that nothing based on the original RPi processor will and it is looking iffy even for the RPi 2B) I think this IS a useful piece of code to have to externally multiplex a single input ADC device with an external CMOS IC. – SlySven Feb 23 '16 at 23:20
1

You'll need a parallel output ADC. As in the other answers, the SPI speed limits your ADC speed - but if you get all the bits from your ADC in one go, you can multiply your speed by 8 to 10. Several setups showed it works, including designs with ADCs such as the CA3306.

In practice, I found that the Raspberry can provide fast enough clock, but copying the ADC values to RAM is the bottleneck, and limits acquisition speed to 11-12 Msps. You can again double this value by having a second adc interleaved on the remaining GPIOs. I'm testing such a design, and even at 11 Msps for a 3.5MHz sensor, it's definitely possible to acquire ultrasound signals.

Raspberry Pi acquisition

0

The Nyquist sampling theorem states you need at least 2 times the highest frequency component of the signal you're going to be sampling. Two megaherz. The higher the sampling frequency, the more accurate the representation.

I would give some attention to high frequency effects in the circuitry. At such high frequencies, the board and components can become reactive. Shielding would also be important.

Low noise instrumentation amplifiers are typically used in such situations.

Some things to think about.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.