Skip to content

Instantly share code, notes, and snippets.

@todbot
Last active August 26, 2022 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save todbot/a8476252e490a4fc59858883c7978ae5 to your computer and use it in GitHub Desktop.
Save todbot/a8476252e490a4fc59858883c7978ae5 to your computer and use it in GitHub Desktop.
Adding new native module to CircuitPython Aug 2022

Intro

"You want to make a native module for CircuitPython" as of 25 Aug 2022.
Short answer: copy what rainbowio does. It does everything the below describes and is known to work well.

What we'll be changing

Let's assume your library is called chicken, with no port-specific functionality, and a single function called bokbok(), that takes an int and returns an int.

Your CircuitPython code to use it would look like:

import chicken
print( chicken.bokbok( 123 ) )

To add a new library, you will need to create the following files:

  • circuitpython/shared-bindings/chicken/__init__.h
  • circuitpython/shared-bindings/chicken/__init__.c
  • circuitpython/shared-module/chicken/__init__.c

And edit the following files:

  • circuitpython/py/circuitpy_mpconfig.mk
  • circuitpython/py/circuitpy_defns.mk

And you'll create a new build variable called CIRCUITPY_CHICKEN that will let you enable your module for your board.

Design API definition

  1. Make directory circuitpython/shared-bindings/chicken This is where you define your library's API to CircuitPython.

  2. Create circuitpython/shared-bindings/chicken/__init__.{c,h} The __init__.h header file will include a forward declaration to the function(s) used in the shared-bindings implementation you'll create later.
    In this case that function is mp_int_t bokbok(mp_int_t);

    The __init__.c will end with MP_REGISTER_MODULE() where you specify a new compile variable CIRCUITPY_CHICKEN. You will use this in your board's config to enable your module.

Create Implementation

  1. Make directory circuitpython/shared-module/chicken This is where your port-agnostic implementation goes. Some libraries only have functionality here, with no need for per-port code.

  2. Put an __init__.c there (if your library has port-agnostic implementation) It will #include 'shared-bindings/chicken/__init__.h' API header you created in step 2.

  3. At this point you're done with your library code. (if your library doesn't need any chip-specific functions)

Update build system

  1. In circuitpython/py/circuitpy_mpconfig.mk add a line to enable your module that looks like:

    CIRCUITPY_CHICKEN ?= 0
    CFLAGS += -DCIRCUITPY_CHICKEN=$(CIRCUITPY_CHICKEN)

    That is, it's disabled by default for all other builds except the one we specify.

  2. In circuitpython/py/circuitpy_defns.mk add an if-clause to add your code to the build:

    ifeq ($(CIRCUITPY_CHICKEN),1)
    SRC_PATTERNS += chicken/%
    endif
    

    Also, add chicken/__init__.c \ to the SRC_SHARED_MODULE_ALL variable.

Enable your library

  1. At this point, do a build to see if everything still compiles as before.

  2. Enable your new library for a board. In circuitpython/ports/<portname>/boards/<boardname>/mpconfigboard.mk add the line: CIRCUITPY_CHICKEN = 1

  3. Do a build, you should see your shared-binding and shared-module code copied into the build directory. And when you install the firmware, you can see it with help("modules").

References:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment