microscope-cockpit / cockpit

Cockpit is a microscope graphical user interface. It is a flexible and easy to extend platform aimed at life scientists using bespoke microscopes.
https://microscope-cockpit.org
GNU General Public License v3.0
37 stars 27 forks source link

Digital only executor via a Raspberry Pi Pico #830

Open iandobbie opened 2 years ago

iandobbie commented 2 years ago

In previous emails and now in the microscope/cockpit development meeting on 2022-11-08 it has been suggested that the programable IO components of the Raspberry Pi Pico could be used as a digital only executor with high performance and super cheap.

I have a couple of Pi Picos and I will try to knock up a test to see if this is feasible.

juliomateoslangerak commented 1 year ago

I found this code I worked some 10 months ago https://github.com/juliomateoslangerak/rp2040_executor Use the main.py script with Micropython

prog defines the 'program' to run on the PIO. Then I sequentially load in the state machine the time and digital value into the same register. These should be coming from an array (https://docs.micropython.org/en/latest/library/array.html)

from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

@asm_pio(
         # set_init=PIO.OUT_LOW,
         out_init=(PIO.OUT_LOW,) * 32,
         out_shiftdir=PIO.SHIFT_LEFT,
         fifo_join=PIO.JOIN_TX,
)
def prog():
    wrap_target()
    pull()
    mov(x, osr)
    jmp(not_x, 'end')
    pull()
    out(pins, 32)
    label('loop')
    jmp(x_dec, 'loop')
    wrap()
    label('end')
    mov(pins, null)

sm = StateMachine(1, prog, freq=2000, out_base=Pin(0))

sm.active(1)
for _ in range(3):
    sm.put(1000)
    sm.put(0b00000010000000000000000000000001)  # 1000 0100 0010 0001 1000010000100001
    sm.put(1000)
    sm.put(0b00000000000000000000000000000000)  # 1000 0100 0010 0001 1000010000100001
    sm.put(1000)
    sm.put(0b00000010000000000000000000000001)  # 1000 0100 0010 0001 1000010000100001
    sm.put(1000)
    sm.put(0b00000000000000000000000000000000)  # 1000 0100 0010 0001 1000010000100001
    sm.put(0)
    sm.put(0b00000000000000000000000000000000)  # 1000 0100 0010 0001 1000010000100001
sleep(20)
sm.active(0)

One thought I had was to dedicate one core of the rp2040 for dealing with the serial com and the other for running loading data into the PIO. The main advantage would be to be able to interrupt the acquisitions upon request from the host and to deal with the logic of the program a bit more easily.

juliomateoslangerak commented 1 year ago

Some Analog I2C output breakout boards could be used. I looked for 0-10V cause that is the range of the PI piezo Z-stage

juliomateoslangerak commented 1 year ago

An option to add Ethernet to the pico https://github.com/Wiznet/RP2040-HAT-MicroPython This would leave us with 16 digital lines (GP0-GP15), and the possibility to add analogue output through I2C at GP26-GP27. GP22 and GP28 still free for some added neopixel coolness.

iandobbie commented 1 year ago

I would worry a bit about the first I2C option as the DAC is only 12 bit. If you have a 200 um range piezo (pretty typical) then the maximum resolution is 50 nm which is pretty marginal for decent Z stacks at high NA.

The second option only does 0-5 v, so neither seem ideal, but it seems like a good solution if we can find a sensible board.