Page 1 of 1

Calling mp_hal_delay_ms() from a native module, what am I doing wrong?

Posted: Tue Jun 02, 2020 7:57 pm
by JohnLittle
Hello,

I tried to make this module as simple as possible to try and understand how to use mp_hal_delay_ms() in a native module. It's just a wrapper called mydelay.

So I have these two files (based on the factorial example). mydelay.c and Makefile as follows:

Code: Select all

// Include the header file to get access to the MicroPython API
//#include "py/mphal.h"
#include "py/dynruntime.h"

// This is the function which will be called from Python, as delay_ms(x)
STATIC mp_obj_t delay_ms(mp_obj_t x_obj) {
    // Extract the integer from the MicroPython input object
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_printf(&mp_plat_print,"delaying for " INT_FMT " ms...\n",x);
    //mp_hal_delay_ms(x);
	return mp_const_none;
}

// This is the function which will be called from Python, as delay_ms(x)
STATIC mp_obj_t delay_us(mp_obj_t x_obj) {
    // Extract the integer from the MicroPython input object
    mp_int_t x = mp_obj_get_int(x_obj);
    mp_printf(&mp_plat_print,"delaying for " INT_FMT " us...\n",x);
    //mp_hal_delay_us(x);
	return mp_const_none;
}

// Define a Python reference to the function above
STATIC MP_DEFINE_CONST_FUN_OBJ_1(delay_ms_obj, delay_ms);
STATIC MP_DEFINE_CONST_FUN_OBJ_1(delay_us_obj, delay_us);

// This is the entry point and is called when the module is imported
mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) {
    // This must be first, it sets up the globals dict and other things
    MP_DYNRUNTIME_INIT_ENTRY

    // Make the function available in the module's namespace
    mp_store_global(MP_QSTR_delay_ms, MP_OBJ_FROM_PTR(&delay_ms_obj));
    mp_store_global(MP_QSTR_delay_us, MP_OBJ_FROM_PTR(&delay_us_obj));

    // This must be last, it restores the globals dict
    MP_DYNRUNTIME_INIT_EXIT
}
Makefile is

Code: Select all

# Location of top-level MicroPython directory
MPY_DIR = ../..

# Name of module
MOD = mydelay

# Source files (.c or .py)
SRC = mydelay.c

# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin)
ARCH = armv7m

# Include to get the rules for compiling and linking the module
include $(MPY_DIR)/py/dynruntime.mk
Compilation looks like:

Code: Select all

lj@mint:~/projects/micropython-1.12/examples/mydelay$ make
GEN build/mydelay.config.h
CC mydelay.c
LINK build/mydelay.o
arch:         EM_ARM
text size:    248
bss size:     0
GOT entries:  2
GEN mydelay.mpy
lj@mint:~/projects/micropython-1.12/examples/mydelay$
Output is from MicroPython looks like:

Code: Select all

MicroPython v1.12 on 2020-05-30; MCUDEV STM32F407VE with STM32F407VE
Type "help()" for more information.
>>> import mydelay
>>> mydelay.delay_ms(150)
delaying for 150 ms...
>>> mydelay.delay_us(200)
delaying for 200 us...
>>>
If I try to uncomment the #include "mphal.h" or mp_hal_delay_ms or mp_hal_delay_us, I get the following error:

Code: Select all

lj@mint:~/projects/micropython-1.12/examples/mydelay$ make
GEN build/mydelay.config.h
CC mydelay.c
In file included from mydelay.c:2:0:
../../py/mphal.h:34:10: fatal error: mphalport.h: No such file or directory
 #include <mphalport.h>
          ^~~~~~~~~~~~~
compilation terminated.
../../py/dynruntime.mk:128: recipe for target 'build/mydelay.o' failed
make: *** [build/mydelay.o] Error 1
lj@mint:~/projects/micropython-1.12/examples/mydelay$
And this is where I'm stuck. Any help welcome :-)

Cheers,
John

Re: Calling mp_hal_delay_ms() from a native module, what am I doing wrong?

Posted: Wed Jun 10, 2020 6:09 am
by jimmo
JohnLittle wrote:
Tue Jun 02, 2020 7:57 pm
If I try to uncomment the #include "mphal.h" or mp_hal_delay_ms or mp_hal_delay_us, I get the following error:
For the most part, the only functionality available to a dynamic module (https://docs.micropython.org/en/latest/ ... atmod.html) is what's in dynruntime.h.

Anything else either needs to be completely provided by your module and statically linked into it, or accessible via the interfaces in dynruntime.h.

The problem is that the dynamic loader doesn't have a way to look up arbitrary symbols like you'd expect on Linux or whatever. At the moment there's only the table defined in dynruntime.h.

It might be worth considering adding the mp_hal_* functions to this table though (similarly, mp_hal_pin_* would be quite useful).

See https://github.com/micropython/micropython/pull/5711 for some ESP32-specific discussion around exposing IDF functionality to native modules.