Firmware Development

Hi all,

If you I sent you a prototype OV7725 OpenMV Cam or you’d just like to have firmware on the bleeding edge of development please see the OpenMV Cam wiki - Home · openmv/openmv Wiki · GitHub. OV2640 OpenMV Cam owners should get themselves setup for firmware development too. This way you can get fixes quickly. Otherwise you’ll have to wait for releases.


Going over to the wiki to see if there were any helpful tips, I came across this section from Create new page · openmv/openmv Wiki · GitHub

Okay, I lied, there’s no Mac development environment. Instead you can install Ubuntu on a virtual machine running on your mac machine:

Given that I have been compiling MicroPython firmware for the pyboard on my Mac for two years now, you had me worried that OpenMV had somehow dramatically diverged from MicroPython.

Happily, I found that it is possible to build the OpenMV firmware and load it using pydfu on OSX just as I have been doing with MicroPython. It takes a bit of tinkering with dependencies to set it up - I needed to install libusb and pyusb and run pydfu specifically using python3 - but it all worked. I can even get the IDE to run, though I will allow that it isn’t as stable on my Mac as it is on Ubuntu. (I suspect that this is something to do with the USB configuration, but OS X doesn’t have /etc/udev so I will need to dig a bit to find the equivalent.)

Unfortunately I won’t have a chance to fill in the details right away, but I just wanted to provide encouragement that OpenMV development on OS X is in fact possible.


I’m telling people to avoid it just because we can’t support that right now. Both me and Ibrahim are doing everything in Linux. So, this is the easiest way to have everyone working.

I get an error message following the instruction
sudo apt-get install python2.7 python-dev python-pi

am I missing a repository or is python-pi supposed to be python-pip?

Fair enough, that is probably wise. It does take some tinkering to get all the dependencies in place, and I appreciate that you don’t want to support that right now; also, my experience is that the IDE is currently more stable on Ubuntu than OS X.

I’ll be busy for the next two weeks or so, but then I would like to dig in to making the IDE more stable and also turn my notes into a proper installation guide for OS X.


I think it needs to be ‘python-pip’; you will use pip to install numpy, pyserial, pyusb, and Pillow.


Hi, just another small typo in instructions…

sudo apt-get install gcc-arm-none-eabi ← -none-, not -non-

Mr. Helper

I just received the OpenMV with the new sensor, and I compiled and flashed the latest firmware. Unfortunately, now the board comes up with a “failed to initialize sensor” error. I wonder if I need to specify some options to the make command to tell it about the new sensor?

No it should detect it automatically. Try the attached firmware, let me know if it still doesn’t work. (609 KB)

That one works, thank you. Any idea why the one I compiled myself doesn’t?

The new sensor really has much nicer colors! However, I tried to run the color blob detection example, and it fails with “None type is not iterable” – seems like the “find_blobs” functions returns None instead of an empty list? I guess I will report a proper bug for that.

Not sure it’s probably the selftests, I disable it for development:

    if (0 && first_soft_reset && f_res == FR_OK) {

This is a development image it might have some issues.

Since you’re on the bleeding edge of development I recommend looking at this file:

That’s basically the API. Doesn’t take that long to figure out what’s going on.

Stuff may be broken and then fixed, and then broken again. Study the API a little bit to see what’s working.

Right now, all the binary stuff should be good. Try that out in the mean time, also, the face detection stuff works too.

The face detector, eye detection, iris detection has improved a lot and works on bigger frames now (up to QVGA).Also made lots of improvements to keypoints, they’re easier to use and more robust now.

I’m trying to delve into my own custom function in imlib.c then wrapped in py_image.c I’m following other functions as an example, however the compile chokes on a generated file qstrdefs.generated.h which does not have an entry for my new function. I read up a bit and the process for micropython is to run this script:

My question - is there a different way or does your toolchain involve running this script?



Add the function name here: micropython/qstrdefsport.h at 1f126da49c3c5be59350121ebd6a8bdf84306ff7 · iabdalkader/micropython · GitHub

Then put the dictionary entry here:

And make sure to define the function object that’s put in to the dictionary here:

And… then create a new function in the py_image.c file with the correct header type and do what you want in it.

The compile is pretty much automatic. However, our build system is… not good at detecting dependency changes. SO, rebuild whenever you edit the qstrdesport file.

Also, how you define the header of functions that are being called in the py_image file is very import. Look at one of our functions for the particular header style that you’d like and copy what we did. Otherwise you’ll get crashes. MP just jumps to these functions using a function pointer. So, you have to make sure it jumps using the correct ABI. In particular, what bit me once was that for less than 3 arguments it will call the function in a slightly faster way than it will call the function with 4 or more arguments.

E.g. Notice the different between the headers of the set_pixel and get_pixel function. The difference between 3 and 4 arguments.

Many thanks. If it is useful, here is the process from end to end using a clone of image.difference to image.sean_contour (please excuse the name which doesn’t really make sense…

  1. create a record in /src/micropython/stmhal/qstrdefsport.h which looks like this:
  1. create a prototype in /src/omv/img/imlib.h which looks like this:
void imlib_sean_contours(image_t *img, const char *file, image_t *other);
  1. create a function in /src/omv/img/imlib.c which looks like this (which is actually just difference() cloned:
void imlib_sean_contours(image_t *img, const char *file, image_t *other) 
    if (IM_IS_GS(img)) {
        uint8_t *pixels = img->pixels;
        if (file) {

        } else {
            uint8_t *other_pixels = other->pixels;
            for (int i=0, j=img->w*img->h; i<j; i++) {
                pixels[i] = abs(pixels[i] - other_pixels[i]);
    } else {
        uint16_t *pixels = (uint16_t *) img->pixels;
        if (file) {

        } else {
            uint16_t *other_pixels = (uint16_t *) img->pixels;
            for (int i=0, j=img->w*img->h; i<j; i++) {
                const int pixel = pixels[i], other_pixel = other_pixels[i];
                const int r = abs(IM_R565(pixel) - IM_R565(other_pixel));
                const int g = abs(IM_G565(pixel) - IM_G565(other_pixel));
                const int b = abs(IM_B565(pixel) - IM_B565(other_pixel));
                pixels[i] = IM_RGB565(r, g, b);
  1. in /src/omv/py/py_image.c

Around line 400, add a line which looks like this (a clone of the python wrapper for difference()):

static mp_obj_t py_image_sean_contours(mp_obj_t img_obj, mp_obj_t other_obj)
    image_t *arg_img = py_image_cobj(img_obj);
            "Operation not supported on JPEG");

    if (MP_OBJ_IS_STR(other_obj)) {
        imlib_sean_contours(arg_img, mp_obj_str_get_str(other_obj), NULL);
    } else {
        image_t *arg_other = py_image_cobj(other_obj);
        PY_ASSERT_TRUE_MSG(IM_EQUAL(arg_img, arg_other),
                "Invalid Argument: img_0_geometry != img_1_geometry");
        imlib_sean_contours(arg_img, NULL, arg_other);
    return mp_const_none;
  1. in py_image.c around line 1226 add a line which looks like this:
STATIC MP_DEFINE_CONST_FUN_OBJ_2(py_image_sean_contours_obj, py_image_sean_contours);
  1. in py_image.c in the dictionary map set starting with
static const mp_map_elem_t locals_dict_table[] = {   ....

add a line like this:

{MP_OBJ_NEW_QSTR(MP_QSTR_sean_contours),          (mp_obj_t)&py_image_sean_contours_obj},
  1. rebuild - this generates an entry for sean_contour in
    /src/build/micropython/genhdr/qstrdefs.generated.h and
    … /qstrdefs.preprocessed.h
    then assuming a successful build…

  2. now upload using IDE
    firmware updated, I can use image.sean_contour()