AtomVM icon indicating copy to clipboard operation
AtomVM copied to clipboard

Align Peripheral call semantics between platforms.

Open DawDavis opened this issue 1 year ago • 5 comments

This is not my idea - just breaking out an issue from #894

This should have an associated target milestone and individual issues for each peripheral and each platform.

I think the goal is to remove the need for code like this:

start() ->
    platform_gpio_setup(atomvm:platform()),
    loop(pin(), low).

loop(Pin, Level) ->
    io:format("Setting pin ~p ~p~n", [Pin, Level]),
    gpio:digital_write(Pin, Level),
    timer:sleep(1000),
    loop(Pin, toggle(Level)).

toggle(high) ->
    low;
toggle(low) ->
    high.

pin() ->
    case atomvm:platform() of
        esp32 ->
            2;
        pico ->
            ?PIN;
        stm32 ->
            {b, 0};
        Platform ->
            erlang:exit({unsupported_platform, Platform})
    end.

platform_gpio_setup(esp32) ->
    gpio:set_pin_mode(pin(), output);
platform_gpio_setup(stm32) ->
    gpio:set_pin_mode(pin(), output);
platform_gpio_setup(pico) ->
    case ?PIN of
        {wl, 0} ->
            % Pico-W needs no setup for extra "WL" pins
            ok;
        Pin ->
            % Setup for Pico GPIO pins
            gpio:init(Pin),
            gpio:set_pin_mode(Pin, output)
    end;
platform_gpio_setup(Platform) ->
    io:format("Platform ~p is not supported.~n", [Platform]),
    erlang:exit({error, {unsupported_platform, Platform}}).

In favor of something closer to this:

start() ->
    Pin = ?PIN,
    gpio:init(Pin),
    gpio:set_pin_mode(Pin, output),
    loop(Pin, low).

loop(Pin, Level) ->
    io:format("Setting pin ~p ~p~n", [Pin, Level]),
    gpio:digital_write(Pin, Level),
    timer:sleep(1000),
    loop(Pin, toggle(Level)).

toggle(high) ->
    low;
toggle(low) ->
    high.

I specifically included the gpio:init() call - I know STM32 doesn't need it, but it is still important to keep unity between all devices.

This is a VM after all - there should not be a code-visible difference between running on the RP2040 or the STM32.

DawDavis avatar Mar 23 '24 05:03 DawDavis

I absolutely agree, the unique peculiarities of each platform and development environment should be handled internally in the VM, and users should be able to use a consistent set of functions to setup and use devices like GPIO.

We already have fixing the error returns from the GPIO driver to be consistent across platforms planned for a future release, and I believe adding an single setup function that works for all supported platforms should also be added.

There are some unavoidable differences across platforms, like stm32 gpio pins must be a tuple, while other platforms use an atom. I believe a setup function that takes a map would be convenient for users, and the easiest way to handle the setup input internally. The map could be a single pin, or many pins, so that a single function call could be used to configure all of the pins used for a given application. We should still continue to support the lower level configuration functions, so that users have the flexibility to work with the pins using the underlying platform functionality directly when needed.

UncleGrumpy avatar Apr 02 '24 20:04 UncleGrumpy

We can't use gpio:init/1 on any platform except rp2040, so this is an example of something that should (at least optionally) be handled internally by the driver when a pin is configured on the rp2040 platform.

UncleGrumpy avatar Apr 02 '24 20:04 UncleGrumpy

Yeah, after reading the documentation around the RP2040, it looks like just doing the init any time a configuration is set is A-okay. The call is idempotent afaik.

I also think a key idea would be to consider a software layer on non-MCU systems, so that you can run a blackbox test of the code on a linux machine and really test the crap out of production code. I'm really thinking that Erlang on an MCU could offer a really good environment for hobby aerospace stuff. (Model rocketry and drones mostly)

A framework around I2C, SPI, CAN, and UART would also be useful. Because of the non-standard nature of it though, I'm not sure that non-master/primary control needs to be a priority. Unless you're trying to network nodes together?

I guess having a sort of OTP-alike networking layer over UART or I2C would be neat.

DawDavis avatar Apr 05 '24 23:04 DawDavis

I also think a key idea would be to consider a software layer on non-MCU systems, so that you can run a blackbox test of the code on a linux machine and really test the crap out of production code.

This is a great idea, but not a small amount of work. A gpio emulator for the generic_unix port would be fairly straightforward. To do this for I2C or SPI, and have it be truly useful, you would also need to emulate all of the various sensors and output devices you want to test as well. This would be an amazing feature, but something I would not expect until after a 1.0 release. …but if this is something you want to work on I’m sure it would be more than welcome!

Personally I would rather see GPIO, SPI and I2C support for the generic_unix port first. There are plenty of supported devices with these built in and exposed to users (any single board computer), and there are USB breakout boards that can add support for most other systems.

UncleGrumpy avatar Apr 29 '24 22:04 UncleGrumpy

I also think a key idea would be to consider a software layer on non-MCU systems, so that you can run a blackbox test of the code on a linux machine and really test the crap out of production code. I'm really thinking that Erlang on an MCU could offer a really good environment for hobby aerospace stuff. (Model rocketry and drones mostly)

I should have thought of this sooner, you can look at our GitHub workflows esp32-build.yaml does tests on QEMU, and esp32-simtest.yaml uses Wokwi for testing. These should give you enough clues to get set up to run emulated hardware tests on a linux host. We also have a brief section the Build Instructions section of our documentation for setting up and running our esp32 test suite on QEMU.

UncleGrumpy avatar Feb 06 '25 03:02 UncleGrumpy