From 6be658595221216bf46470a7b779090ee5bfeab3 Mon Sep 17 00:00:00 2001 From: Winford Date: Tue, 10 Sep 2024 14:56:21 -0700 Subject: [PATCH] Replace uf2 creation code with upstream uf2tool Replace `atomvm_uf2create_provider` uf2 creation code with upstream standalone `uf2tool` from https://github.com/pguyot/uf2tool. Signed-off-by: Winford --- CHANGELOG.md | 1 + README.md | 45 +++++++++----- rebar.config | 5 +- src/atomvm_pico_flash_provider.erl | 6 +- src/atomvm_uf2create_provider.erl | 94 +++++++++--------------------- 5 files changed, 67 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f938386..5b2d23b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Using the `-s init` option is still supported but deprecated. Use the `--application` (or `-a`) option to generate OTP applications using AtomVM. +- Replace `atomvm_uf2create_provider` uf2 creation code with [upstream `uf2tool`](https://github.com/pguyot/uf2tool) ## [0.7.3] (2023.11.25) diff --git a/README.md b/README.md index a0bd5d5..139dd39 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ file for this task. Use `packbeam` as the key for any properties defined for th | Key | Type | Description | |-----|------|-------------| | `force` | `boolean()` | Always force a rebuild of the AVM file, even if up to date | -| `prune` | `boolean()` | Prune unecessary BEAM files from generated AVM | +| `prune` | `boolean()` | Prune unnecessary BEAM files from generated AVM | | `start` | `atom()` | The start module | | `remove_lines` | `boolean()` | Remove line number information from generated AVM files. | | `list` | `boolean()` | List the AVM file contents when generating AVM files. | @@ -205,7 +205,7 @@ For example, a module that implements the OTP `application` behavior might look (assume `myapp_sup` is also a part of your OTP application). -And the application configuration file (e.g., `myapp.app.src`) should include the application mdoule (`myapp_app`) under it's `mod` entry: +And the application configuration file (e.g., `myapp.app.src`) should include the application module (`myapp_app`) under it's `mod` entry: { application, myapp, [ @@ -297,7 +297,7 @@ The following table enumerates the properties that may be defined in your projec | Key | Type | Description | |-----|------|-------------| | `esptool` | `string()` | Path to the `esptool.py` tool, if not already in user's `PATH` | -| `chip` | `string()` | ESP32 chipt type | +| `chip` | `string()` | ESP32 chip type | | `port` | `string()` | Device port on which the ESP32 can be located | | `baud` | `integer()` | Device BAUD rate | | `offset` | `string()` | Offset into which to write AtomVM application | @@ -343,7 +343,7 @@ You may use the `stm32_flash` task to flash the generated AtomVM packbeam applic -s, --stflash Path to st-flash -o, --offset Offset (default 0x8080000) -The `stm32_flash` will use the `st-flash` tool from the open source (bsd-3 liscensed) [stlink](https://github.com/stlink-org/stlink) suite of stm32 utilites to flash the STM32 device. This tool is available on [github](https://github.com/stlink-org/stlink), and in many package managers. +The `stm32_flash` will use the `st-flash` tool from the open source (bsd-3 licensed) [stlink](https://github.com/stlink-org/stlink) suite of stm32 utilities to flash the STM32 device. This tool is available on [github](https://github.com/stlink-org/stlink), and in many package managers. By default, the `stm32_flash` task will assume the `st-flash` command is available on the user's executable path. Alternatively, you may specify the full path to the `st-flash` command via the `-s` (or `--stflash`) option @@ -452,11 +452,13 @@ Example: Alternatively, the following environment variables may be used to control the above settings: -* `ATOMVM_REBAR3_PLUGIN_PICO_MOUNT_PATH` -* `ATOMVM_REBAR3_PLUGIN_PICO_RESET_DEV` +* `ATOMVM_REBAR3_PLUGIN_PICO_MOUNT_PATH` | `ATOMVM_PICO_MOUNT_PATH` +* `ATOMVM_REBAR3_PLUGIN_PICO_RESET_DEV` | `ATOMVM_PICO_RESET_DEV` Any setting specified on the command line take precedence over entries in `rebar.config`, which in turn take precedence over environment variable settings, which in turn take precedence over the default values specified above. +> Note the setting `ATOMVM_REBAR3_PLUGIN_PICO_MOUNT_PATH` and `ATOMVM_REBAR3_PLUGIN_PICO_RESET_PATH` take precedence, but `ATOMVM_PICO_MOUNT_PATH` and `ATOMVM_PICO_RESET_DEV` are also honoured as a fallback, so that the same environment setting can be shared with the [ExAtomVM](https://github.com/atomvm/exatomvm) `mix` plugin. + The `pico_flash` task depends on the `uf2create` task (which in turn depends on the `packbeam` task), so the so the application will be packed and re-formatted if any changes have been made to dependencies. ### The `uf2create` task @@ -467,27 +469,44 @@ The `uf2create` task is used to generated an uf2 binary suitable for running on Use this plugin to create Raspberry Pico uf2 files from an AtomVM packbeam file. - Usage: rebar3 atomvm uf2create [-o ] [-s ] [-i ] + Usage: rebar3 atomvm uf2create [-f ] [-o ] + [-s ] [-i ] - -o, --output Output path/name - -s, --start Start address for the uf2 binary (default 0x10180000) - -i, --input Input avm file to convert to uf2 + -f, --family_id Flavor of uf2 file to create (default rp2040) + -o, --output Output path/name + -s, --start Start address for the uf2 binary (default 0x10180000) + -i, --input Input avm file to convert to uf2 It should not be necessary to use this tool before using `pico_flash`, unless you have built a custom VM that requires changing the start address of the uf2 binary. If the application has not been compiled, or packed with packbeam, these steps will be run first using the default settings for `packbeam`. +The following table enumerates the valid `family_id` options: + +| Key | Description | +|-------------|-------------| +| `rp2040` | Original Raspberry Pi Pico and Pico-W | +| `rp2035` | Raspberry Pi Pico 2 | +| `data` | Raspberry Pi Pico 2 | +| `universal` | Universal format for both `rp2040` and `rp2035` | + +> Note the convenience of universal uf2 binaries comes with the expense of being twice the size, as both versions are included in the universal uf2. + The following table enumerates the properties that may be defined in your project's `rebar.config` file for this task. Use `uf2create` as the key for any properties defined for this task. | Key | Type | Description | |-----|------|-------------| | `start` | `string()` | Start address for the uf2 binary | +| `family_id` | `string()` | The family\_id or flavor of uf2 to build | Example: - {atomvm_rebar3_plugin, [{uf2create, [{start, "0x10180000"}]}]}. + {atomvm_rebar3_plugin, [{uf2create, [{app_id, "0x10180000"},{family_id,universal}]}]}. Alternatively, the following environment variables may be used to control the above settings: -* `ATOMVM_REBAR3_PLUGIN_UF2CREATE_START` +* `ATOMVM_REBAR3_PLUGIN_UF2CREATE_START` | `ATOMVM_PICO_APP_START` +* `ATOMVM_REBAR3_PLUGIN_UF2_FAMILY` | `ATOMVM_PICO_UF2_FAMILY` + +> Note the settings `ATOMVM_REBAR3_PLUGIN_UF2CREATE_START` and `ATOMVM_REBAR3_PLUGIN_UF2_FAMILY` take precedence, but `ATOMVM_PICO_APP_START` and`ATOMVM_PICO_UF2_FAMILY` will also be used, if set, so that the same environment setting can be shared with the [ExAtomVM](https://github.com/atomvm/exatomvm) `mix` plugin. Any setting specified on the command line take precedence over entries in `rebar.config`, which in turn take precedence over environment variable settings, which in turn take precedence over the default values specified above. @@ -495,7 +514,7 @@ The `uf2create` task depends on the `packbeam` task, so the packbeam file will g ### The `version` task -use the `version` task to print the current verison of the [`atomvm_rebar3_plugin`](https://atomvm.github.io/atomvm_rebar3_plugin) to the console. +use the `version` task to print the current version of the [`atomvm_rebar3_plugin`](https://atomvm.github.io/atomvm_rebar3_plugin) to the console. shell$ rebar3 atomvm version 0.7.3 diff --git a/rebar.config b/rebar.config index 0564215..661f766 100644 --- a/rebar.config +++ b/rebar.config @@ -19,7 +19,10 @@ %% {erl_opts, [debug_info]}. -{deps, [{atomvm_packbeam, "0.7.2"}]}. +{deps, [ + {atomvm_packbeam, "0.7.2"}, + {uf2tool, {git, "https://github.com/pguyot/uf2tool.git", {tag, "v1.1.0"}}} +]}. {ex_doc, [ {source_url, <<"https://github.com/atomvm/atomvm_rebar3_plugin">>}, diff --git a/src/atomvm_pico_flash_provider.erl b/src/atomvm_pico_flash_provider.erl index 766cc96..c79b7bf 100644 --- a/src/atomvm_pico_flash_provider.erl +++ b/src/atomvm_pico_flash_provider.erl @@ -132,7 +132,8 @@ get_reset_base() -> "/dev/cu.usbmodem14*"; _Other -> "" - end. + end, + os:getenv("ATOMVM_PICO_RESET_DEV", Base). %% @private get_default_mount() -> @@ -144,7 +145,8 @@ get_default_mount() -> "/Volumes/RPI-RP2"; _Other -> "" - end. + end, + os:getenv("ATOMVM_PICO_MOUNT_PATH", Default). %% @private wait_for_mount(Mount, Count) when Count < 30 -> diff --git a/src/atomvm_uf2create_provider.erl b/src/atomvm_uf2create_provider.erl index fe0ba5c..242965e 100644 --- a/src/atomvm_uf2create_provider.erl +++ b/src/atomvm_uf2create_provider.erl @@ -1,10 +1,7 @@ % % This file is part of AtomVM. % -% Copyright 2022 Paul Guyot -% -% Adapted for atomvm_rebar3_plugin: -% Copyright 2023 Winford (UncleGrumpy) +% Copyright 2023-24 Winford (UncleGrumpy) % % Licensed under the Apache License, Version 2.0 (the "License"); % you may not use this file except in compliance with the License. @@ -32,13 +29,15 @@ -define(PROVIDER, uf2create). -define(DEPS, [packbeam]). -define(OPTS, [ + {family_id, $f, "family_id", string, "Flavor of uf2 file to create (default rp2040)"}, {output, $o, "output", string, "Output path/name"}, {start, $s, "start", string, "Start address for the uf2 binary (default 0x10180000)"}, {input, $i, "input", string, "Input avm file to convert to uf2"} ]). -define(DEFAULT_OPTS, #{ - start => "0x10180000" + start => os:getenv("ATOMVM_PICO_APP_START", "0x10180000"), + family_id => os:getenv("ATOMVM_PICO_UF2_FAMILY", rp2040) }). %% @@ -75,11 +74,11 @@ do(State) -> rebar_api:debug("Effective opts for ~p: ~p", [?PROVIDER, Opts]), OutFile = get_out_file(State), TargetAVM = get_avm_file(State), - ok = do_uf2create( - maps:get(output, Opts, OutFile), - parse_addr(maps:get(start, Opts)), - maps:get(input, Opts, TargetAVM) - ), + Output = maps:get(output, Opts, OutFile), + StartAddrStr = parse_addr(maps:get(start, Opts)), + Image = maps:get(input, Opts, TargetAVM), + Uf2Flavor = validate_flavor(maps:get(family_id, Opts, maps:get(family_id, ?DEFAULT_OPTS))), + ok = uf2tool:uf2create(Output, Uf2Flavor, StartAddrStr, Image), {ok, State} catch C:E:S -> @@ -115,6 +114,10 @@ env_opts() -> start => os:getenv( "ATOMVM_REBAR3_PLUGIN_UF2CREATE_START", maps:get(start, ?DEFAULT_OPTS) + ), + family_id => os:getenv( + "ATOMVM_REBAR3_PLUGIN_UF2_FAMILY", + maps:get(family_id, ?DEFAULT_OPTS) ) }. @@ -142,62 +145,17 @@ parse_addr("16#" ++ AddrHex) -> parse_addr(AddrDec) -> list_to_integer(AddrDec). -%%% UF2 defines --define(UF2_MAGIC_START0, 16#0A324655). --define(UF2_MAGIC_START1, 16#9E5D5157). --define(UF2_MAGIC_END, 16#0AB16F30). - --define(UF2_FLAG_FAMILY_ID_PRESENT, 16#00002000). - -%%% Pico defines --define(UF2_PICO_FLAGS, ?UF2_FLAG_FAMILY_ID_PRESENT). --define(UF2_PICO_PAGE_SIZE, 256). --define(UF2_PICO_FAMILY_ID, 16#E48BFF56). - -%%% - -do_uf2create(OutputPath, StartAddr, ImagePath) -> - {ok, ImageBin} = file:read_file(ImagePath), - BlocksCount0 = byte_size(ImageBin) div ?UF2_PICO_PAGE_SIZE, - BlocksCount = - BlocksCount0 + - if - byte_size(ImageBin) rem ?UF2_PICO_PAGE_SIZE =:= 0 -> 0; - true -> 1 - end, - OutputBin = uf2create0(0, BlocksCount, StartAddr, ImageBin, []), - ok = file:write_file(OutputPath, OutputBin). - %% @private -uf2create0(_BlockIndex, _BlocksCount, _BaseAddr, <<>>, Acc) -> - lists:reverse(Acc); -uf2create0(BlockIndex, BlocksCount, BaseAddr, ImageBin, Acc) -> - {PageBin, Tail} = - if - byte_size(ImageBin) >= ?UF2_PICO_PAGE_SIZE -> - split_binary(ImageBin, ?UF2_PICO_PAGE_SIZE); - true -> - {ImageBin, <<>>} - end, - PaddedData = pad_binary(PageBin, 476), - Block = [ - << - ?UF2_MAGIC_START0:32/little, - ?UF2_MAGIC_START1:32/little, - ?UF2_PICO_FLAGS:32/little, - BaseAddr:32/little, - ?UF2_PICO_PAGE_SIZE:32/little, - BlockIndex:32/little, - BlocksCount:32/little, - ?UF2_PICO_FAMILY_ID:32/little - >>, - PaddedData, - <> - ], - uf2create0(BlockIndex + 1, BlocksCount, BaseAddr + ?UF2_PICO_PAGE_SIZE, Tail, [Block | Acc]). - -%% @private -pad_binary(Bin, Len) -> - PadCount = Len - byte_size(Bin), - Pad = binary:copy(<<0>>, PadCount), - [Bin, Pad]. +validate_flavor(Flavor) -> + case Flavor of + rp2040 -> + rp2040; + rp2035 -> + data; + data -> + data; + universal -> + universal; + Family -> + rebar_api:error("An error occurred in the ~p task. Invalid family_id ~p~n", [?PROVIDER, Family]) + end.