To Pi or not to Pi? That is a DuePi

We know Raspberry Pi is mini computer that developers mostly code using Python. We will explore intermixing the use of DUELink modules, analog/PWM inputs and Qwiic with RPI.

To easily connect DUELink modules, you can use LinkPi. It works with any RPI, even RPI Zero!

But we will use the DuePi istead, which brings many onboard features, including a display and buzzer.

The is a special kind of DUELink adapter because it can also serve as a microcomputer! You can use the USB connector to program the board itself to run standalone (including Arduino), or control it from a computer! This computer can be a full PC or a RPI!

Go ahead and connect DuePi to a computer (or RPI) using USB. To access DuePi via USB from any computer, including RPI, we only need to scan for an appropriate DUELink virtual serial port and connect to it.

availablePort = DUELinkController.GetConnectionPort()
duelink = DUELinkController(availablePort)

We can now issue commands to draw on the display.


duelink.Graphics.Clear(0)
duelink.Graphics.Text('DUELink', 1, 0, 0)
duelink.Graphics.Show()

Those graphics functions are part of the standard library. If you are curious, these functions will end up calling the ExecuteCommand function internally.

duelink.Engine.ExecuteCommand('Clear(0)')
duelink.Engine.ExecuteCommand('Text("DUELink", 1, 0, 0)')
duelink.Engine.ExecuteCommand('Show()')

We will use ExecuteCommand going forward to show what is happening internally. Ok now we want to switch to using the RPI headers instead of using USB.

All you need to switch from USB to headers (which uses UART), is a single line of code, thanks to DUELink.

duelink = DUELinkController("/dev/ttyAMA0")

Try the same code and you should see the same results on the screen. One great benefit of what we did earlier is that you can use a PC to write code that uses DUELink, and then move the entire code AND circuit setup to RPI and it will simply just work!

DuePi has a terminal block for wiring circuits without needing to do any soldering. Those are the first 8 pins in the DUELink system, which include Analog input and PWM alternate functions. See the Engine Pins page for pin details.

In this project we will use a light sensor and soil moisture analog sensors.

Reading analog is simply done using ARead() command. Assuming a sensor is connected to pin 1 then we will need duelink.Engine.ExecuteCommand('Aread(1)'). This returns the raw analog value of a pin. You you can also use VRead() to read the voltage on a pin.

while True:
    voltage = duelink.Engine.ExecuteCommand("VRead(1)")
    duelink.Engine.ExecuteCommand('Clear(0)')
    duelink.Engine.ExecuteCommand(f'Text("{voltage:.2f}v", 1, 0, 0)')
    duelink.Engine.ExecuteCommand('Show()')

Beyond that, it is easy to extend the setup with a DUELink module, such as a slider.

Everything works like before, but the slider is now device 2. Remember DuePi as address 1. To save on bus traffic, here is a piece of code that you may need to include in all of your projects. This function will keep track of currently selected device and only ExecuteCommand if necessary.


def SelectDevice(address):
    global deviceAddress
    if deviceAddress != address:
        # Save bus traffic, only update selection when the address changes
        deviceAddress = address
        duelink.Engine.ExecuteCommand(f"sel({deviceAddress})")

The slider position is returned using Slide()function. We will use the slider position to place a circle on the screen. Move the slider and the circle will move.

while True:
    SelectDevice(2)
    slider = duelink.Engine.ExecuteCommand("Slide()")
    SelectDevice(1)
    duelink.Engine.ExecuteCommand('Clear(0)')
    duelink.Engine.ExecuteCommand(f'Circle(1, {slider:.0f}, 30, 5)')
    duelink.Engine.ExecuteCommand('Show()')

It is amazing what a few lines of code can do in DUELink but we still want to share more! We will connect a Qwiic I2C module to the mix, a Qwiic LED strip from Sparkfun. The connection is easy as Qwiic use the same connector and pinout.

For software, we need to know what that specific Qwiic module I2C commands to send. But first, we switch the Downlink socket to I2C mode using duelink.Engine.ExecuteCommand("dlmode(5,0)"). We can now use I2C on the downlink socket to send the Qwiic LED specific commands using dli2cwr(). The LED expects 0x71 followed by the led index and then 3 bytes for RGB color.

Note how we are selecting device 2. While technically the Qwiic LED is the third circuit, it is not a DUELink circuit and does not have a DUELink address! We are accessing it through the module it is connected to, which is the slider on address 2 in this case.

def SetLed(led, red, green, blue):

    if led <= 0 or led > 10:
        return

    red = red & 0xFF
    green = green & 0xFF
    blue = blue & 0xFF

    SelectDevice(2)
    duelink.Engine.ExecuteCommand(f"dli2cwr(0x23,[0x71,{led},{red},{green},{blue}],0)")

The entire project code listing is available here, in Python and .NET C#!

2 Likes