Compile while calling own nifs: error: following modules or functions are not available on AtomVM: * Elixir.MyMod.mynif/1

Hey there! So glad there’s a forum here and really excited about the whole project.

I’m experimenting with adding nifs by compiling my own version of atomvm as documented on build-instructions. I successfully built and flashed (pico in my case). I now want to try if my nifs work as expected.

When implementing my nif, I pretty much copied the way GPIO.ex calls the respective NIFs. So I have an additional Module MyMod in exavmlib/lib in the AtomVM project.

I previously successfully flashed examples like Blinky.ex from atomvm_examples.

So I changed the Blink example to call my MyMod.mynif/1 function. Now with atomvm.pico.flash I get

error: following modules or functions are not available on AtomVM:
* Elixir.MyMod.mynif/1

Maybe I need to learn how to link my custom atomvm build with ExAtomVM? I guess it would also suffice in my case to make ExAtomVM just not throw this problem as an error is might just run on the microcontroller atomvm that has the relevant module?

Any advice or relevant links are appreciated =)

I can also happily go into more detail on what I’m actually trying to achieve but I tried to pin this down to the actual problem I’m dealing with right now.

3 Likes

Just to unstuck you dive into deps/exatomvm/priv/funcs.txt and add Elixir.MyMod.mynif/1 on a line…

I’m not entirely aware of the correct pattern for adding Nifs for pico, but sounds like you are on a good path of getting code to run…

(on esp32 you git clone into esp32/components (for the c code), and add a project as mix dependency - for the elixir code - but the story is a bit more unclear on pico…)

also make sure you have added MyMod to the CMakeLists.txt in exavmlib/lib

1 Like

I don’t think we have as clear of a path for adding nifs to the pico as we do with esp32. At this point I would suggest just adding the nif c sources to the pico src/libs dir, and update the CMakeLists.txt in the same directory accordingly… along with Peter’s advice for updating the functions list for ExAtomVM.

1 Like

Once you get that sorted out, we are indeed interested in hearing what you are working on :wink:

1 Like

Hi, thanks for your answers. Together this got me to getting a nif_error. So I guess linking the nif with the corresponding elixir function doesn’t work yet. I added my Module to libs/exavmlib/lib/CMakeLists.txt right below GPIO. I added the source and header file entries to src/platforms/rp2040/src/lib/CMakeLists.txt as well as some dependencies I need. At the buttom of my source file there is a line calling REGISTER_NIF_COLLLECTION, which I hoped what link my c function nif. If this is not enough info to help me or reveal any mistakes I made a fork here: github

I confirm this is not enough but you are almost there.

The linker will remove every function that are not referenced. You need to prevent this with -u for the function generated by the register nif macro.

See last line of CMakeLists.txt

3 Likes

Jup, this did it :tada:. This brought to a badarg error and by that point it was all debugging the nif I had written.

Once you get that sorted out, we are indeed interested in hearing what you are working on :wink:

I’m trying to add pio functionality. So right now I have a really basic nif that actually makes the led blink via a pio program constructed dynamically from c code :smiling_face:

Thanks for all your help.

2 Likes

Glad to hear you got it working! :tada: I did gather from your code that it looked like a proof of concept for a pio driver. That would be a really cool addition! I would suggest storing the pio application in /priv and use atomvm:read_priv/2 to get the app to pass with the pin to a pio:run/2 function.

1 Like

I think that I still have quite the shallow understanding of the pico sdk. That being said, my understanding was that the .pio files used in the c-examples from pico are something that have to be present at compile time (compile time of AtomVM itself in our case). So if programs are saved in /priv that means I’d have to parse them myself, am I getting that right? The reason I started working on not relying on a .pio file was that I planned to write programs some kind of dsl. I was picturing something like obtaining the same pio program from my piodriver.c::80 in the commit I linked above in elixir via

    my_blink_prog = 
        { pio_set(pio_pins, 1) |> pio_encode_delay(29)
        , pio_set(pio_x, 31)
        , pio_nop() |> pio_encode_delay(29)
        , pio_jmp_x_dec(2)
        , pio_set(pio_pins, 0) |> pio_encode_delay(29)
        , pio_set(pio_x, 31) |> pio_encode_delay(29)
        , pio_nop() |> pio_encode_delay(29)
        , pio_jmp_x_dec(6)
        };

where the functions like pio_set(pio_pins, 1) might just return {:pio_set, :pio_pins, 1} or maybe { instr: {:pivo_set, :pio_pins, 1} } so pio_encode_delay(some_instr, 29) can become

{ instr: {:pivo_set, :pio_pins, 1} 
, delay: 29
}

I would be happy to hear your thoughts on that. By the way should we move this part of the conversation to another thread as my original question has been solved?

Sorry, it has been a while since I worked on the pico platform, and I had not looked very far into how PIO works. I was thinking that where could be a generic pio driver in AtomVM that could be used for user written applications, but after looking into a bit more I realize that the pio applications would have to be written ahead of time and baked into the VM itself. So you couldn’t load the application from /priv. This makes a reusable general pio driver impossible, at least for the foreseeable future. PIO could still be a good candidate for writing other specific use peripheral drivers.

Absolutely, feel free to start a new thread to discuss any other questions or ideas.