Can the AE3 be powered via the QWIIC connector?

The title says it all - is it okay to feed the 3v3 line via the qwiic connector?

In other words: no other power would be supplied to the camera, I would only connect the data and power lines of the qwiic connector and expect the camera to run (and my script to communicate via the uart1 tx/rx pins)

Best regards

Yes, this works, we need to do some more hardening on the I2CTarget mode driver. But, master mode is generally fine. If you use Target mode… do not deinit during a transfer. This causes unrecoverable hardware lockups on the Alif chip.

OK, so if I understood it correctly:

  1. from the power system perspective there’s no issue?
  2. And if I keep to using serial (rs232-ttl style) communication and not i2c there’s also not going to be a hardware issue?
  3. And shall I use the camera as i2c master and connect an i2c slave sensor, just power everything from the slave side via through the qwiic connector it’s also safe?

Thanks for your answer!

  1. Yep
  2. Yep
  3. Either! It can be a master, it can be a slave, it can power downstream devices, and it can be powered by downstream devices.

Basically, the QWIIC cable is connected to the main 3.3V rail and we inject 3.3V onto that rail using an ideal diode from a USB 5V → 3.3V switching regulator.

And here it is! OpenMV AE3 feeding its data into a LEGO Spike Prime hub :blush:

The adapter is quite big right now, but target PCBs are being manufactured already and shall arrive after Easter.

I do have a ā€˜funny’ though: if I connect this setup to my PC over USB-C, the connection keeps dropping and restarting. It works if I disconnect power from the LEGO hub. Not sure what’s the deal here, but I didn’t get to the bottom of the schematics yet (just printed them big, this is why I was pestering you for the schematics over at Kickstarter… :grin:)

Thanks for the help! Really appreciated!

Just tested with switching the AE3 back and forth between 3.3V externally and also being powered via USB. Works perfectly. When USB is applied there is no load on the 3.3V PSU. When USB is removed the load switches over, and then switches back when USB is applied again.

If your 3.3V rail needs to be charged up though, this can result in a brownout if there’s a lot of big caps the AE3 has to power all of a sudden.

I will investigate it further, I have a suspicion it’s not the AE3 that’s playing tricks but my laptop’s usb. I don’t have issues if I connect via USBA to USBC cable, but it gets unstable if I go USB-C to USB-C, like if the laptop couldn’t decide if it should supply the usb or get supplied by the usb port.

I need to test it properly, but today I ran out of time and will not be able to get back to it for a couple days now - Easter is coming

So, I looked into it a bit more, here’s a summary for those who might land here via a search:

  • If the AE3 is powered by external 3.3V (e.g. via the QWIIC port) AND
  • it is connected to a laptop via USB-C to USB-C through a PD capable USB-C port AND
  • the laptop’s battery isn’t full
  • it MAY trigger the laptop into a loop switching between [I’m being charged via USB-C] ← → [I’m supplying the connected device], leading each time to an reenumeration of the USB bus.
  • This does, obviously, not happen if the connection is done via USB-C to USB-A cable

This condition can (but not always will) get triggered on my Lenovo T14Gen3 Intel laptop. It seems not to be related specifically to the AE3, but rather to the implementation of the USB system on the laptop.

Ah, weird. The AE3 just accepts 5V USB, and we have the two 5.1k pull-downs on the device. This is the correct implementation. It appears the laptop design isn’t quite right.

But, I have a Lenovo too, and all sorts of stuff isn’t quite right also. These laptops are buggy. My camera fails to work randomly along with many other issues.

Yeah, I blame the laptop here too… I posted it just as a warning/info that one should not get startled when observing the behaviour, but just connect to an USB-A and check if it persists.

I have connection problems too: AE3 <> OpenMV IDE.
Running on a Macbook Pro M3 with USB-C.

I have narrowed it down to this:

a main.py that is actively writing to UART(1) or I2CTarget(1) on the qwiic in a tight loop.

As soon as such program is running, USB and the IDE balk, doesn’t matter if it was booted via 3v3 on SPIKE or via USB. The only thing I can do is flash the AE3 again.

My first workaround was to put a 5s sleep before the program, so I could quickly connect after the green light stopped blinking.

My second workaround was to use the switch on the side. Now I have this in my main loop:

from machine import Pin, UART, I2CTarget

sw = Pin("SW", Pin.IN)
while True:    
    if not sw.value():
        break

This stops the loop and the writing and enables the IDE to connect again.

Nonetheless, it would be much more userfriendly if USB always worked, regardless of what UART or I2C is doing.

Hi Aton,

Can you give me a demo program that crashes things for both? The issue is that the driver isn’t polling USB events internally when blocking for data. I can send Damien your code samples so he can fix these bugs. However, you can also avoid the issue by doing non-blocking calls for the UART or I2C too.

Here are the scripts. Both crash the camera and the IDE hard if I connect without pressing the switch and exiting the loop:

UART
```

import time
import math

time.sleep(5)

thresholds = [(0,20,-6,6,-6,6)] #Black

import sensor
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=1000)
sensor.set_auto_gain(False)  # must be turned off for color tracking
sensor.set_auto_whitebal(False)  # must be turned off for color tracking
clock = time.clock()


# Start uart
import machine
import struct

sw = machine.Pin("SW", machine.Pin.IN)
u = machine.UART(1, 115200)

while True:
    clock.tick()
    img = sensor.snapshot()
    blobs = img.find_blobs(
        [thresholds[threshold_index]],
        pixels_threshold=200,
        area_threshold=200,
        merge=True,
    )
    if len(blobs) > 0:
        blob = blobs[-1]
        # These values depend on the blob not being circular - otherwise they will be shaky.
        if blob.elongation() > 0.5:
            img.draw_edges(blob.min_corners(), color=(255, 0, 0))
            img.draw_line(blob.major_axis_line(), color=(0, 255, 0))
            img.draw_line(blob.minor_axis_line(), color=(0, 0, 255))
        # These values are stable all the time.
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        # Note - the blob rotation is unique to 0-180 only.
        img.draw_keypoints(
            [(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20
        )
        u.write("{} {}\n".format(blob.cx(), blob.cy()))
    else:
        u.write("00 00\n")

    print(clock.fps())
    if not sw.value():
        break

I2C target

# This work is licensed under the MIT license.
# Copyright (c) 2013-2023 OpenMV LLC. All rights reserved.
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# Single Color RGB565 Blob Tracking Example
#
# This example shows off single color RGB565 tracking using the OpenMV Cam.


import time
import math
from machine import Pin, I2CTarget, LED

led = LED("LED_BLUE")


sw = Pin("SW", Pin.IN)
print(sw.value())


threshold_index = 0  # 0 for red, 1 for green, 2 for blue

# Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max)
# The below thresholds track in general red/green/blue things. You may wish to tune them...
# thresholds = [
#     (30, 100, 15, 127, 15, 127),  # generic_red_thresholds
#     (30, 100, -64, -8, -32, 32),  # generic_green_thresholds
#     (0, 30, 0, 64, -128, 0),
# ]  # generic_blue_thresholds

thresholds = [(0,20,-6,6,-6,6)] #Black

import sensor
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing([0,sensor.height()//2,sensor.width(),sensor.height()])
sensor.skip_frames(time=1000)
sensor.set_auto_gain(False)  # must be turned off for color tracking
sensor.set_auto_whitebal(False)  # must be turned off for color tracking
clock = time.clock()

# Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are
# returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the
# camera resolution. "merge=True" merges all overlapping blobs in the image.


# Start i2c

import struct

# Initialiseer de buffer met een grootte van exact 4 bytes
buf = bytearray(4)

# Start de I2C Target (Slave) met de gevulde 4-byte buffer
target = I2CTarget(1, addr=42, mem=buf)

n = 0

while True:
    n = (n + 1) % 60
    if n == 0:
        led.on()
    if n == 30:
        led.off()
    clock.tick()
    img = sensor.snapshot()
    blobs = img.find_blobs(
        [thresholds[threshold_index]],
        pixels_threshold=200,
        area_threshold=200,
        merge=True,
    )
    if len(blobs) > 0:
        blob = blobs[-1]
        # These values depend on the blob not being circular - otherwise they will be shaky.
        if blob.elongation() > 0.5:
            img.draw_edges(blob.min_corners(), color=(255, 0, 0))
            img.draw_line(blob.major_axis_line(), color=(0, 255, 0))
            img.draw_line(blob.minor_axis_line(), color=(0, 0, 255))
        # These values are stable all the time.
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        # Note - the blob rotation is unique to 0-180 only.
        img.draw_keypoints(
            [(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20
        )
        struct.pack_into('<hh', buf, 0, blob.cx(), blob.cy())
    else:
        struct.pack_into('<hh', buf, 0, 0, 0)

    print(clock.fps())
    if not sw.value():
        break

Thanks for the post. Will get it debugged.

Okay, so, you need to update to the latest pre-release firmware via Tools->Install the Latest Dev release.

Note that the API has changed significantly for using python objects. We’ve removed a lot of older stuff that wasn’t pythonic and was also costing us valuable flash space.

See: v5.0.0 - OpenMV MicroPython 1.28 documentation

I am still working on the tutorial, but, once complete, I’ll be updating the IDE with things and getting this out the door.

import time
import math

time.sleep(5)

thresholds = [(0,20,-6,6,-6,6)] #Black
threshold_index =0

import sensor
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.VGA)
sensor.skip_frames(time=1000)
sensor.set_auto_gain(False)  # must be turned off for color tracking
sensor.set_auto_whitebal(False)  # must be turned off for color tracking
clock = time.clock()


# Start uart
import machine
import struct

sw = machine.Pin("SW", machine.Pin.IN)
u = machine.UART(1, 115200)

while True:
    clock.tick()
    img = sensor.snapshot()
    blobs = img.find_blobs(
        [thresholds[threshold_index]],
        pixels_threshold=200,
        area_threshold=200,
        merge=True,
    )
    if len(blobs) > 0:
        blob = blobs[-1]
        # These values depend on the blob not being circular - otherwise they will be shaky.
        # if blob.elongation() > 0.5:
        #     img.draw_edges(blob.min_corners(), color=(255, 0, 0))
        #     img.draw_line(blob.major_axis_line(), color=(0, 255, 0))
        #     img.draw_line(blob.minor_axis_line(), color=(0, 0, 255))
        # These values are stable all the time.
        img.draw_rectangle(blob.rect)
        img.draw_cross((blob.cx, blob.cy))
        # Note - the blob rotation is unique to 0-180 only.
        # img.draw_keypoints(
        #     [(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20
        # )
        u.write("{} {}\n".format(blob.cx, blob.cy))
    else:
        u.write("00 00\n")

    print(clock.fps())
    if not sw.value():
        break

This works with V5.0.0 without crashing. I didn’t fix all the calls to the new API, but, everything is documented.

Doesn’t work on my side. Still hangs the camera. Where did I go wrong?

I have OpenMV IDE 4.5.0

When I install latest dev release on AE3 via tools it still says:

OpenMV v4.8.1; MicroPython v1.26.0-77; OpenMV-AE3 with AE302F80F55D5AE
Type ā€œhelp()ā€ for more information.


(Expecting 5.0.0, MicroPython 1.28)

The framerates seem to be lower.

And I had to update the script you shared to this:

import time

import csi
sensor = csi.CSI()
sensor.reset()
sensor.pixformat(csi.RGB565)
sensor.framesize(csi.VGA)
sensor.snapshot(time=1000)
sensor.auto_gain(True)  # must be turned off for color tracking
sensor.auto_whitebal(False)  # must be turned off for color tracking
clock = time.clock()


# Start uart
import machine
import struct
sw = machine.Pin("SW", machine.Pin.IN)
u = machine.UART(1, 115200)

while True:
    clock.tick()
    img = sensor.snapshot()
    blobs = img.find_blobs(
        [(0,20,-6,6,-6,6)], #Black
        pixels_threshold=200,
        area_threshold=200,
        merge=True,
    )
    if len(blobs) > 0:
        blob = blobs[-1]
        img.draw_rectangle(blob.rect())
        img.draw_cross((blob.cx(), blob.cy()))
        u.write(struct.pack( 'hh',blob.cx(), blob.cy() ))
    else:
        u.write(struct.pack('hh',0,0))

    print(clock.fps())
    if not sw.value():
        break

OK. Updated the IDE to 4.8.11 manually. A whopping 5Gb. (I thought is was auto-updated) Then installed the latest dev release.

Now it says:

OpenMV fe74ac2725; MicroPython 0f831e89f0; OpenMV-AE3 with AE302F80F55D5AE
Type "help()" for more information.

But camera still hangs on this (adapted again) main.py. And framerates are in the low 20’s, while on the 4.81. firmware, framerates were in the 60’s!

import time

import csi
sensor = csi.CSI()
sensor.reset()
sensor.pixformat(csi.RGB565)
sensor.framesize(csi.VGA)
sensor.snapshot(time=1000)
sensor.auto_gain(True)  # must be turned off for color tracking
sensor.auto_whitebal(False)  # must be turned off for color tracking
clock = time.clock()


# Start uart
import machine
import struct
sw = machine.Pin("SW", machine.Pin.IN)
u = machine.UART(1, 115200)

while True:
    clock.tick()
    img = sensor.snapshot()
    blobs = img.find_blobs(
        [(0,20,-6,6,-6,6)], #Black
        pixels_threshold=200,
        area_threshold=200,
        merge=True,
    )
    if len(blobs) > 0:
        blob = blobs[-1]
        img.draw_rectangle(blob.rect)
        img.draw_cross((blob.cx, blob.cy))
        u.write(struct.pack( 'hh',blob.cx, blob.cy ))
    else:
        u.write(struct.pack('hh',0,0))

    print(clock.fps())
    if not sw.value():
        break

Yeah, the IDE is big because of the STEdge AI compiler. Ibrahim is working on a new, smaller IDE that’s coming along. The install size on disk is similar, but it downloads the tools after installation.

What OS are you on? I’m not getting a hang running the script. It’s working as expected.

As for the decrease in frame rate, mmm, we changed the memory architecture for allocations. This may be a one-liner to fix. Will check.

sensor.framesize(csi.VGA)

You were using QVGA before. Change it back to that, and you get 60 FPS.