Trying to read an ADC with Cython on an RPi 2 b+ v

2019-06-09 09:04发布

问题:

I'd like to read differential voltage values from an MCP3304 (5v VDD, 3.3v Vref, main channel = 7, diff channel = 6) connected to an RPi 2 b+ as close as possible to the MCP3304's max sample rate of 100ksps. Preferably, I'd get > 1 sample per 100µs (> 10 ksps).

A kind user recently suggested I try porting my code to C for some speed gains. I'm VERY new to C, so thought I'd give Cython a shot, but can't seem to figure out how to tap into the C-based speed gains.

My guess is that I need to write a .pyx file that includes a more-raw means of accessing the ADC's bits/bytes via SPI than the python package I'm currently using (the python-wrapped gpiozero package). 1) Does this seem correct, and, if so, might someone 2) please help me understand how to manipulate bits/bytes appropriately for the MCP3304 in a way that will produce speed gains from Cython? I've seen C tutorials for the MCP3008, but am having trouble adapting this code to fit the timing laid out in the MCP3304's spec sheet; though I might be able to adapt a Cython-specific MCP3008 (or other ADC) tutorial to fit the MCP3304.

Here's a little .pyx loop I wrote to test how fast I'm reading voltage values. (Timing how long it takes to read 25,000 samples). It's ~ 9% faster than running it straight in Python.

# Load packages
import time
from gpiozero import MCP3304


# create a class to ping PD every ms for 1 minute
def pd_ping():
    cdef char *FILENAME = "testfile.txt"
    cdef double v
    # cdef int adc_channel_pd = 7
    cdef size_t i

    # send message to user re: expected timing
    print "Runing for ", 25000 , "iterations. Fingers crossed!"

    print time.clock()

    s = []
    for i in range(25000):
        v = MCP3304(channel = 7, diff = True).value *  3.3
        # concatenate
        s.append( str(v) )

    print "donezo" , time.clock()

    # write to file
    out = '\n'.join(s)
    f = open(FILENAME, "w")
    f.write(out)

回答1:

There is probably no need to create an MCP3304 object for each iteration. Also conversion from float to string can be delayed.

s = []
mcp = MCP3304(channel = 7, diff = True)
for i in range(25000):
    v = mcp.value *  3.3
    s.append(v)

out = '\n'.join('{:.2f}'.format(v) for v in s) + '\n'

If that multiplication by 3.3 is not strictly necessary at that point, it could be done later.