Let’s get real into making the first micropython module for RTL8722 port
MicroPython modules can be developed using C or C++.
However, C is the preferred language as the MicroPython kernal is entired developed in C, with a hint of Python.
Difference between C module and MicroPython module
Developing module for MicroPython is vastly different from developing for C program.
When a new C module is created, using this new module can be as easy as including the header file and call the function names provided in the header file. However, MicroPython module, though written in C, can not be directly called by MicroPython by using function’s name. There are steps to be done before your MicroPython module can be recognized and called by MicroPython.
Steps to add new MicroPython module
1.Write your module in C
2.Include it in your makefile for compilation
3.Declare it as MicroPython module through mpconfigport.h
Step 1. Writting your module in C
Let’s create a sample module calle factorial . This module will perform factorial mathmetical computation with given input and return the result. The code is as follows,
// Include the header file to get access to the MicroPython API
#include "py/dynruntime.h"
// Helper function to compute factorial
STATIC mp_int_t factorial_helper(mp_int_t x) {
if (x == 0) {
return 1;
}
return x * factorial_helper(x - 1);
}
// This is the function which will be called from Python, as factorial(x)
STATIC mp_obj_t factorial(mp_obj_t x_obj) {
// Extract the integer from the MicroPython input object
mp_int_t x = mp_obj_get_int(x_obj);
// Calculate the factorial
mp_int_t result = factorial_helper(x);
// Convert the result to a MicroPython integer object and return it
return mp_obj_new_int(result);
}
// Define a Python reference to the function above
STATIC MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial);
// This is the entry point and is called when the module is imported
STATIC const mp_map_elem_t factorial_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_factorial) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_factorial), MP_OBJ_FROM_PTR(&factorial_obj) },
};
STATIC MP_DEFINE_CONST_DICT(factorial_module_globals, factorial_module_globals_table);
const mp_obj_module_t mp_module_factorial = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&factorial_module_globals,
};
Note that STATIC mp_obj_t factorial(mp_obj_t x_obj)
is the function that will be called by MicroPython, and apparently, this function has to be of mp_obj_t type which is a void* defined in MicroPython’s obj.h , and result has to be return to MicroPython through mp_obj_new_int(result)
api.
This is so because of how Python is written, anything in Python is an object, thus, functions exposed to MicroPython has to be mp_obj_t
type and the return value also has to be an obj thus using mp_obj_new_int( )
to return it. In this case, return value is an integer, thus using mp_obj_new_int( )
, if your return type is of other type, then you will have to return it using corresponding API declared in obj.h file.
Also note that factorial_helper does not has to be of mp_obj_t type
and dose not has to return using obj.h‘s API because this function is only used internally by other functions and will not be exposed to MicroPython and users.
There are more details to how we can write modules to cater any use cases, but due to the length of this article, those will not be discussed here and will be discussed in future articles.
Step 2. Include it in your makefile for compilation
Now with the module done, open amebad.mk and add this module’s name under UPY_C list, for example,
…
UPY_C += lib/timeutils/timeutils.c
UPY_C += lib//utils/sys_stdio_mphal.c
UPY_C += lib/netutils/netutils.c
UPY_C += factorial.c
…
This is to make sure that this C file wil be compiled and linked into final firmware
Step 3. Declare it as MicroPython module through mpconfigport.h
Last but not the least, we need to declare it in mpconfigport.h file so that users can import the new module and use the API provided inside.
Open mpconfigport.h and add this line above #define MICROPY_PORT_BUILTIN_MODULES \
,
extern const struct _mp_obj_module_t mp_module_factorial;
And then add this line under #define MICROPY_PORT_BUILTIN_MODULES \
,
{ MP_OBJ_NEW_QSTR(MP_QSTR_factorial), MP_OBJ_FROM_PTR(&mp_module_factorial) },
Congratulations
Now you have successfully added your first MicroPython module, now just use make command mentioned in my previous post, and make upload to upload to your RTL8722, then import factorial, you can use it anyway you like!
Happy coding and stay tuned for more article