From 49630ab7c8560b42350260c08e2dc306fcb22dc1 Mon Sep 17 00:00:00 2001 From: Winford Date: Fri, 10 Nov 2023 13:02:04 -0800 Subject: [PATCH 1/2] Cleanup STM32 cmake config options Moves several auto discovered tool paths and configuration options to the `ADVANCED` category, usefull in UI tools like `ccmake` and IDEs that provide GUI configuration for `cmake` options. This cleans up the default menu to only show configuration options for configuring AtomVM itself, while leaving fine tuned toolchain options availabe inder the "Advanced" menus. Signed-off-by: Winford --- src/platforms/stm32/CMakeLists.txt | 1 + src/platforms/stm32/cmake/arm-toolchain.cmake | 2 ++ src/platforms/stm32/cmake/libopencm3.cmake | 1 + 3 files changed, 4 insertions(+) diff --git a/src/platforms/stm32/CMakeLists.txt b/src/platforms/stm32/CMakeLists.txt index 22674bc06..18cab98a4 100644 --- a/src/platforms/stm32/CMakeLists.txt +++ b/src/platforms/stm32/CMakeLists.txt @@ -79,6 +79,7 @@ if (NOT CMAKE_TOOLCHAIN_FILE) message(FATAL_ERROR "Cross compiling only. Please use -DCMAKE_TOOLCHAIN_FILE=cmake/arm-toolchain.cmake or use\ your own toolchain file") endif () +mark_as_advanced(CMAKE_TOOLCHAIN_FILE) if ((NOT ${CMAKE_C_COMPILER_ID} STREQUAL "GNU") OR (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") OR diff --git a/src/platforms/stm32/cmake/arm-toolchain.cmake b/src/platforms/stm32/cmake/arm-toolchain.cmake index 456816bdf..23ab2d4de 100644 --- a/src/platforms/stm32/cmake/arm-toolchain.cmake +++ b/src/platforms/stm32/cmake/arm-toolchain.cmake @@ -28,6 +28,8 @@ find_program(ARM_CXX arm-none-eabi-g++) find_program(ARM_OBJCOPY arm-none-eabi-objcopy) find_program(ARM_SIZE arm-none-eabi-size) +mark_as_advanced(ARM_CC ARM_CXX ARM_OBJCOPY ARM_SIZE) + SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) set(CMAKE_C_COMPILER ${ARM_CC}) set(CMAKE_CXX_COMPILER ${ARM_CXX}) diff --git a/src/platforms/stm32/cmake/libopencm3.cmake b/src/platforms/stm32/cmake/libopencm3.cmake index 609cf81de..3f3c7eeab 100644 --- a/src/platforms/stm32/cmake/libopencm3.cmake +++ b/src/platforms/stm32/cmake/libopencm3.cmake @@ -53,6 +53,7 @@ find_program(PYTHON python) if (NOT PYTHON) message(FATAL_ERROR "python is required to generate the linker script, please install it.") endif () +mark_as_advanced(PYTHON) set(GENLINK_SCRIPT "${LIBOPENCM3_DIR}/scripts/genlink.py") set(DEVICES_DATA "${LIBOPENCM3_DIR}/ld/devices.data") From aa749ec39acd64fdb1395a182cf9880edd945733 Mon Sep 17 00:00:00 2001 From: Winford Date: Fri, 3 Nov 2023 21:27:42 -0700 Subject: [PATCH 2/2] Configure STM32 system clock speed and flash size Configures main system clock and flash size based on the target device. The console uart may be configured by using the `-DAVM_CFG_CONSOLE=` option, or for Nucleo devices the on board TTL->USB-COM can be configured with the `-DBOARD=nucleo` cmake option. Previously these values were hard coded in the C sources and needed to be changed manually if a device other than the default target was used. Closes #454 Signed-off-by: Winford --- .github/workflows/stm32-build.yaml | 4 + CHANGELOG.md | 3 + doc/release-notes.md.in | 1 + doc/src/atomvm-tooling.md | 6 + doc/src/build-instructions.md | 32 +- doc/src/getting-started-guide.md | 8 +- src/platforms/stm32/CMakeLists.txt | 3 + .../stm32/cmake/atomvm_dev_config.cmake | 73 ++++ src/platforms/stm32/cmake/compile-flags.cmake | 4 + src/platforms/stm32/cmake/libopencm3.cmake | 3 +- src/platforms/stm32/src/lib/CMakeLists.txt | 1 + src/platforms/stm32/src/lib/avm_devcfg.h | 111 +++++ src/platforms/stm32/src/main.c | 37 +- .../stm32/tools/atomvm_stm32_config_query.erl | 391 ++++++++++++++++++ src/platforms/stm32/tools/device_config.hrl | 81 ++++ 15 files changed, 730 insertions(+), 28 deletions(-) create mode 100644 src/platforms/stm32/cmake/atomvm_dev_config.cmake create mode 100644 src/platforms/stm32/src/lib/avm_devcfg.h create mode 100755 src/platforms/stm32/tools/atomvm_stm32_config_query.erl create mode 100644 src/platforms/stm32/tools/device_config.hrl diff --git a/.github/workflows/stm32-build.yaml b/.github/workflows/stm32-build.yaml index a9f605bae..e74a98cc2 100644 --- a/.github/workflows/stm32-build.yaml +++ b/.github/workflows/stm32-build.yaml @@ -36,6 +36,10 @@ jobs: /home/runner/libopencm3 key: ${{ runner.os }}-build-deps + - uses: erlef/setup-beam@v1 + with: + otp-version: "26" + - name: Install arm-embedded toolchain if: ${{ steps.builddeps-cache.outputs.cache-hit != 'true' }} working-directory: /home/runner diff --git a/CHANGELOG.md b/CHANGELOG.md index 848de3d9b..b8bba0693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a bug that would leave the STM32 trapped in a loop on hard faults, rather than aborting - Fixed a bug that would make the VM to loop and failing to process selected fds on Linux - Fixed classes of exceptions in estdlib. +- Fixed STM32 code that was hard coded to the default target device, now configured based on the `cmake -DDEVICE=` parameter ### Changed @@ -30,6 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added support for `net:getaddrinfo/1,2` - Added minimal support for the OTP `ssl` interface. - Added support for `crypto:one_time/4,5` on Unix and Pico as well as for `crypto:hash/2` on Pico +- Added ability to configure STM32 Nucleo boards onboard UART->USB-COM using the `-DBOARD=nucleo` cmake option +- Added STM32 cmake option `-DAVM_CFG_CONSOLE=` to select a different uart peripheral for the system console ## [0.6.0-alpha.1] - 2023-10-09 diff --git a/doc/release-notes.md.in b/doc/release-notes.md.in index 13a3dc2a1..dddbd3213 100644 --- a/doc/release-notes.md.in +++ b/doc/release-notes.md.in @@ -75,6 +75,7 @@ AtomVM has been tested on the following development boards: |------------------------------|----------------| | [Nucleo-F429ZI](https://www.st.com/en/evaluation-tools/nucleo-f429zi.html) | ✅ | | [STM32F4Discovery](https://www.st.com/en/evaluation-tools/stm32f4discovery.html) | ✅ | +| [BlackPill V2.0](https://stm32-base.org/boards/STM32F411CEU6-WeAct-Black-Pill-V2.0) | ✅ | Due to the proliferation of boards for the [STMicroelectronics](https://www.st.com) [STM32](https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html) platform, AtomVM does not currently support pre-build binaries for STM32. In order to deploy AtomVM to the STM32 platform, you will need to build AtomVM for STM32 from source. See the [Build Instructions](build-instructions.md) for information about how to build AtomVM from source code. diff --git a/doc/src/atomvm-tooling.md b/doc/src/atomvm-tooling.md index 127c6033a..f1c7795cb 100644 --- a/doc/src/atomvm-tooling.md +++ b/doc/src/atomvm-tooling.md @@ -140,6 +140,12 @@ You may now flash your application to your STM32 device: ... ===> st-flash --reset write /path/to/atomvm_examples/erlang/hello_world/_build/default/lib/hello_world.avm 0x8080000 +For devices with only 512KB of flash the application address is different and must be specified: + + shell$ rebar3 atomvm stm32_flash -o 0x8060000 + ... + ===> st-flash --reset write /path/to/atomvm_examples/erlang/hello_world/_build/default/lib/hello_world.avm 0x8060000 + See the [`atomvm_rebar3_plugin`](https://atomvm.github.io/atomvm_rebar3_plugin) page for more detailed instructions about how to use the `stm32_flash` target. You can now use a serial console program such as [minicom](https://en.wikipedia.org/wiki/Minicom) or [screen](https://en.wikipedia.org/wiki/GNU_Screen) to view console output from a device. diff --git a/doc/src/build-instructions.md b/doc/src/build-instructions.md index c6e9671db..0d1a55580 100644 --- a/doc/src/build-instructions.md +++ b/doc/src/build-instructions.md @@ -505,11 +505,11 @@ The following software is required to build AtomVM for the STM32 platform: * `cmake` * `make` * `git` +* `python` +* Erlang/OTP `escript` > Note. AtomVM tests this build on the latest Ubuntu github runner. - - ### Setup libopencm3 Before building for the first time you need to have a compiled clone of the libopencm3 libraries, from inside the AtomVM/src/platforms/stm32 directory: @@ -530,12 +530,30 @@ Before building for the first time you need to have a compiled clone of the libo ### Changing device The default build is based on the STM32F4Discovery board chip (`stm32f407vgt6`). If you want to target a different -chip, pass the `-DDEVICE` flag when invoking cmake. For example, to use the STM32F429Discovery, pass -`-DDEVICE=stm32f429zit6` +chip, pass the `-DDEVICE` flag when invoking cmake. For example, to use the BlackPill V2.0, pass `-DDEVICE=STM32F411CEU6`. At this time any `STM32F4` or `STM32F7` device with 512KB or more of on package flash should work with AtomVM. If an unsupported device is passed with the `DEVICE` parameter the configuration will fail. For devices with either 512KB or 768KB of flash the available application flash space will be limited to 128KB. Devices with only 512KB of flash may also suffer from slightly reduced performance because the compiler must optimize for size rather than performance. + +>Important Note: for devices with only 512KB of flash the application address is different and must be adjusted when flashing your application with st-flash, or using the recommended `atomvm_rebar3_plugin`. The application address for these devices is `0x8060000`. + +### Configuring the Console + +The default build for any `DEVICE` will use `USART2` and output will be on `PA2`. This default will work well for most `Discovery` and generic boards that do not have an on-board TTL to USB-COM support (including the `STM32F411CEU6` A.K.A. `BlackPill V2.0`). For `Nucleo` boards that do have on board UART to USB-COM support you may pass the `cmake` parameter `-DBOARD=nucleo` to have the correct USART and TX pins configured automatically. The `Nucleo-144` series use `USART3` and `PD8`, while the supported `Nucleo-64` boards use `USART2`, but passing the `BOARD` parameter along with `DEVICE` will configure the correct `USART` for your model. If any other boards are discovered to have on board USB UART support pull requests, or opening issues with the details, are more than welcome. + +Example to configure a `NUCLEO-F429ZI`: + + $ cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/arm-toolchain.cmake -DDEVICE=stm32f429zit6 -DBOARD=nucleo -If you are building for a different target board the `CLOCK_FREQUENCY` definition in main.c will need to be changed to match the clock frequency (in hertz) of your cpu. +The AtomVM system console `USART` may also be configured to a specific uart peripheral. Pass one of the parameters from the chart below with the `cmake` option `-DAVM_CFG_CONSOLE=CONSOLE_#`, using the desired console parameter in place of `CONSOLE_#`. Not all UARTs are available on every supported board, but most will have several options that are not already used by other on board peripherals. Consult your data sheets for your device to select an appropriate console. -The rcc_clock_setup_XXX_XXX will also need to be changed to match your particular chip-set. Consult [ST's documentation](https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html) for appropriate settings. +| Parameter | USART | TX Pin | AtomVM Default | Nucleo-144 | Nucleo-64 | +|-----------|-------|--------|----------------|------------|-----------| +| `CONSOLE_1` | `USART1` | `PA9` | | | | +| `CONSOLE_2` | `USART2` | `PA2` | ✅ | | ✅ | +| `CONSOLE_3` | `USART3` | `PD8` | | ✅ | | +| `CONSOLE_4` | `UART4` | `PC10` | | | | +| `CONSOLE_5` | `UART5` | `PC12` | | | | +| `CONSOLE_6` | `USART6` | `PC6` | | | | +| `CONSOLE_7` | `UART7` | `PF7` | | | | +| `CONSOLE_8` | `UART8` | `PJ8` | | | | ### Configure logging with `cmake` The default maximum log level is `LOG_INFO`. To change the maximum level displayed pass `-DAVM_LOG_LEVEL_MAX="{level}"` to `cmake`, with one of `LOG_ERROR`, `LOG_WARN`, `LOG_INFO`, or `LOG_DEBUG` (listed from least to most verbose). Log messages can be completely disabled by using `-DAVM_LOG_DISABLE=on`. @@ -558,7 +576,7 @@ By default, stdout and stderr are printed on USART2. On the STM32F4Discovery boa using a TTL-USB with the TX pin connected to board's pin PA2 (USART2 RX). Baudrate is 115200 and serial transmission is 8N1 with no flow control. -> If building for a different target USART and gpio pins may need to be adjusted in `main.c`. +> If building for a different target USART may be configure as explained above in [Configuring the Console](#configuring-the-console). ### Configuring for "deployment" After your application has been tested (_and debugged_) and is ready to put into active use you may want to tune the build of AtomVM. For instance disabling logging with `-DAVM_LOG_DISABLE=on` as a `cmake` configuration option may result in slightly better performance. This will have no affect on the console output of your application, just disable low level log messages from the AtomVM system. You may also want to enabling automatic reboot in the case that your application ever exits with a return other than `ok`. This can be enabled with the `cmake` option `-DAVM_CONFIG_REBOOT_ON_NOT_OK=on`. diff --git a/doc/src/getting-started-guide.md b/doc/src/getting-started-guide.md index 070594f91..aacfc9993 100644 --- a/doc/src/getting-started-guide.md +++ b/doc/src/getting-started-guide.md @@ -161,7 +161,7 @@ For information about how to flash your application to your ESP32, see the [Atom ## Getting Started on the STM32 platform -AtomVM can run on a wide variety of STM32 chip-sets available from [STMicroelectronics](https://www.st.com). The support is not nearly as mature as for the ESP32 platform, but work is ongoing, and pull requests are always welcome. At this time AtomVM will work on any board with a minimum of around 128k ram and 512k (1M recommended) flash. Simple applications and tests have been successfully run on a stm32f411ceu6 (A.K.A. Black Pill V2). These minimum requirements may need to be raised as platform support matures. +AtomVM can run on a wide variety of STM32 chip-sets available from [STMicroelectronics](https://www.st.com). The support is not nearly as mature as for the ESP32 platform, but work is ongoing, and pull requests are always welcome. At this time AtomVM will work on any board with a minimum of around 128KB ram and 512KB (1M recommended) flash. Simple applications and tests have been successfully run on a stm32f411ceu6 (A.K.A. Black Pill V2). These minimum requirements may need to be raised as platform support matures. ### Requirements @@ -196,15 +196,17 @@ To flash your image, use the following command: Congratulations! You have now flashed the AtomVM VM image onto your STM32 device! -> Note. AtomVM expects to find the AVM at the address 0x808000. On a STM32 Discovery board this means that the 1MB of flash will be split in 512KB available for the program and 512KB available for the packed AVM. If for any reason you want to modify this, you can change `AVM_ADDRESS` and `AVM_FLASH_MAX_SIZE` defines in `main.c`. +> Note. AtomVM expects to find the AVM at the address 0x8080000. On a STM32 Discovery board this means that the 1MB of flash will be split in 512KB available for the program and 512KB available for the packed AVM. For devices with only 512KB of flash the application address is 0x8060000, leaving 128KB of application flash available. #### Printing By default, stdout and stderr are printed on USART2. On the STM32F4Discovery board, you can see them using a TTL-USB with the TX pin connected to board's pin PA2 (USART2 RX). Baudrate is 115200 and serial transmission is 8N1 with no flow control. +For Nucleo boards the on board USB-COM to USART may be used by configuring your build with a BOARD parameter, see the [STM32 Build Instructions](./build-instructions.md#building-for-stm32) for [Configuring the Console](./build-instructions.md#configuring-the-console). + ### Deploying an AtomVM application -An AtomVM application is a collection of BEAM files, which have been compiled using the Erlang or Elixir compiler. These BEAM files are assembled into an AtomVM "packbeam" (`.avm`) file, which in turn is flashed to the `main` data partition on the STM32 flash module, starting at address `0x210000`. +An AtomVM application is a collection of BEAM files, which have been compiled using the Erlang or Elixir compiler. These BEAM files are assembled into an AtomVM "packbeam" (`.avm`) file, which in turn is flashed to the `main` data partition on the STM32 flash module, starting at address `0x8080000`, for boards with 512KB of flash the address is `0x8060000`. When the AtomVM virtual machine starts, it will search for the first module that contains an exported `start/0` function in this partition, and it will begin execution of the BEAM bytecode at that function. diff --git a/src/platforms/stm32/CMakeLists.txt b/src/platforms/stm32/CMakeLists.txt index 18cab98a4..a874240be 100644 --- a/src/platforms/stm32/CMakeLists.txt +++ b/src/platforms/stm32/CMakeLists.txt @@ -94,6 +94,9 @@ if (NOT DEVICE) set(DEVICE stm32f407vgt6) endif () +# Include auto-device configuration +include(cmake/atomvm_dev_config.cmake) + # Include libopencm3 include(cmake/libopencm3.cmake) diff --git a/src/platforms/stm32/cmake/atomvm_dev_config.cmake b/src/platforms/stm32/cmake/atomvm_dev_config.cmake new file mode 100644 index 000000000..3dad744cb --- /dev/null +++ b/src/platforms/stm32/cmake/atomvm_dev_config.cmake @@ -0,0 +1,73 @@ +# +# This file is part of AtomVM. +# +# Copyright 2023 Winford +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +# + +# Generate config information for device. +if (NOT DEVICE) + message(FATAL_ERROR "No DEVICE specified for device config generator") +endif () + +find_program(ESCRIPT escript) +if (NOT ESCRIPT) + message(FATAL_ERROR "Erlang/OTP 'escript' not found in PATH. Check your Erlang/OTP installation.") +endif () +mark_as_advanced(ESCRIPT) + +set(DEVCONFIG_SCRIPT "${CMAKE_SOURCE_DIR}/tools/atomvm_stm32_config_query.erl") +execute_process( + COMMAND "${ESCRIPT}" "${DEVCONFIG_SCRIPT}" "${DEVICE}" "clock" + OUTPUT_VARIABLE DEVCONFIG_CLOCK_HZ +) +add_compile_definitions(${DEVCONFIG_CLOCK_HZ}) +execute_process( + COMMAND "${ESCRIPT}" "${DEVCONFIG_SCRIPT}" "${DEVICE}" "rom" + OUTPUT_VARIABLE DEVCONFIG_FLASH_SIZE +) +add_compile_definitions(${DEVCONFIG_FLASH_SIZE}) +## also needs to be set for correct optomization flags to be used. +set(CMAKE_FLASH_SIZE "${DEVCONFIG_FLASH_SIZE}") + +if (AVM_CFG_CONSOLE) + set(AVM_CFG_CONSOLE ${AVM_CFG_CONSOLE} CACHE STRING "AtomVM system console uart") + set_property(CACHE AVM_CFG_CONSOLE PROPERTY STRINGS CONSOLE_1 CONSOLE_2 CONSOLE_3 CONSOLE_4 CONSOLE_5 CONSOLE_6 CONSOLE_7 CONSOLE_8) + add_compile_definitions(${AVM_CFG_CONSOLE}) +elseif (BOARD) + execute_process( + COMMAND "${ESCRIPT}" "${DEVCONFIG_SCRIPT}" "${DEVICE}" "${BOARD}_com" + OUTPUT_VARIABLE DEVCONFIG_CONSOLE + ) + add_compile_definitions(${DEVCONFIG_CONSOLE}) + set(AVM_CFG_CONSOLE ${DEVCONFIG_CONSOLE} CACHE STRING "AtomVM system console uart") + set(BOARD ${BOARD} CACHE STRING "Board variant configuration") + set_property(CACHE AVM_CFG_CONSOLE PROPERTY STRINGS CONSOLE_1 CONSOLE_2 CONSOLE_3 CONSOLE_4 CONSOLE_5 CONSOLE_6 CONSOLE_7 CONSOLE_8) +else() + add_compile_definitions(CONSOLE_2) + set(AVM_CFG_CONSOLE CONSOLE_2 CACHE STRING "AtomVM system console uart") + set_property(CACHE AVM_CFG_CONSOLE PROPERTY STRINGS CONSOLE_1 CONSOLE_2 CONSOLE_3 CONSOLE_4 CONSOLE_5 CONSOLE_6 CONSOLE_7 CONSOLE_8) +endif() + +message("----------------------------------------") +message(STATUS "Device : ${DEVICE}") +if (BOARD) +message(STATUS "Board : ${BOARD}") +endif() +message("--------Device Configuration Info-------") +message(STATUS "Clock Hz : ${DEVCONFIG_CLOCK_HZ}") +message(STATUS "Flash Size : ${DEVCONFIG_FLASH_SIZE}") +message(STATUS "Console : ${AVM_CFG_CONSOLE}") diff --git a/src/platforms/stm32/cmake/compile-flags.cmake b/src/platforms/stm32/cmake/compile-flags.cmake index 16320dd00..9669bfabd 100644 --- a/src/platforms/stm32/cmake/compile-flags.cmake +++ b/src/platforms/stm32/cmake/compile-flags.cmake @@ -40,7 +40,11 @@ set(CXX_WARN_FLAGS "${COMMON_WARN_FLAGS} -Wctor-dtor-privacy -Wnoexcept -Wold-st -Wsign-promo -Wstrict-null-sentinel -Wuseless-cast -Wzero-as-null-pointer-constant") # Use C and C++ compiler optimizatons for size and speed. +if (${CMAKE_FLASH_SIZE} STREQUAL "ROM_512K") +set(OPTIMIZE_FLAG "-Os") +else() set(OPTIMIZE_FLAG "-O2") +endif() # Pass them back to the CMake variable set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_WARN_FLAGS} ${OPTIMIZE_FLAG}") diff --git a/src/platforms/stm32/cmake/libopencm3.cmake b/src/platforms/stm32/cmake/libopencm3.cmake index 3f3c7eeab..562841714 100644 --- a/src/platforms/stm32/cmake/libopencm3.cmake +++ b/src/platforms/stm32/cmake/libopencm3.cmake @@ -81,8 +81,7 @@ execute_process( COMMAND "${PYTHON}" "${GENLINK_SCRIPT}" "${DEVICES_DATA}" "${DEVICE}" "DEFS" OUTPUT_VARIABLE GENLINK_DEFS ) -message("----------------------------------------") -message(STATUS "Device : ${DEVICE}") + message("-----------Device Linker Info-----------") message(STATUS "Family : ${GENLINK_FAMILY}") message(STATUS "Sub-family : ${GENLINK_SUBFAMILY}") diff --git a/src/platforms/stm32/src/lib/CMakeLists.txt b/src/platforms/stm32/src/lib/CMakeLists.txt index b0155b577..27730209d 100644 --- a/src/platforms/stm32/src/lib/CMakeLists.txt +++ b/src/platforms/stm32/src/lib/CMakeLists.txt @@ -22,6 +22,7 @@ cmake_minimum_required (VERSION 3.13) project (libAtomVMPlatformSTM32) set(HEADER_FILES + avm_devcfg.h avm_log.h gpio_driver.h stm_sys.h diff --git a/src/platforms/stm32/src/lib/avm_devcfg.h b/src/platforms/stm32/src/lib/avm_devcfg.h new file mode 100644 index 000000000..8271d9109 --- /dev/null +++ b/src/platforms/stm32/src/lib/avm_devcfg.h @@ -0,0 +1,111 @@ +/* This file is part of AtomVM. + * + * Copyright 2023 Winford (Uncle Grumpy) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later + */ + +#ifndef _AVM_DEVCFG_H_ +#define _AVM_DEVCFG_H_ + +#include +#include +#include + +#if (defined(STM32F4) || defined(STM32F7)) +#define FLASH_START_ADDRESS (0x08000000U) +#endif + +#if defined(ROM_512K) +#define CFG_FLASH_END (FLASH_START_ADDRESS + 0x80000U) +#define AVM_APP_ADDRESS (FLASH_START_ADDRESS + 0x60000U) +#elif defined(ROM_768K) +#define CFG_FLASH_END (FLASH_START_ADDRESS + 0xC0000U) +#elif defined(ROM_1024K) +#define CFG_FLASH_END (FLASH_START_ADDRESS + 0x100000U) +#elif defined(ROM_1536K) +#define CFG_FLASH_END (FLASH_START_ADDRESS + 0x180000U) +#elif defined(ROM_2048K) +#define CFG_FLASH_END (FLASH_START_ADDRESS + 0x200000U) +#elif defined(ROM_4096K) +#define CFG_FLASH_END (FLASH_START_ADDRESS + 0x400000U) +#endif + +#ifndef AVM_APP_ADDRESS +#define AVM_APP_ADDRESS (FLASH_START_ADDRESS + 0x80000U) +#endif + +#if defined(MHZ_84) +#define AVM_CLOCK_HZ (84000000U) +#define AVM_CLOCK_CONFIGURATION (&rcc_hse_25mhz_3v3[(RCC_CLOCK_3V3_84MHZ)]) +#elif defined(MHZ_100) +#define AVM_CLOCK_HZ (100000000U) +#define AVM_CLOCK_CONFIGURATION (&rcc_hse_25mhz_3v3[(RCC_CLOCK_3V3_84MHZ)]) +#elif defined(MHZ_168) +#define AVM_CLOCK_HZ (168000000U) +#define AVM_CLOCK_CONFIGURATION (&rcc_hse_8mhz_3v3[(RCC_CLOCK_3V3_168MHZ)]) +#elif defined(MHZ_180) +#define AVM_CLOCK_HZ (180000000U) +#define AVM_CLOCK_CONFIGURATION (&rcc_hse_8mhz_3v3[(RCC_CLOCK_3V3_180MHZ)]) +#elif defined(MHZ_216) +#define AVM_CLOCK_HZ (216000000U) +#define AVM_CLOCK_CONFIGURATION (&rcc_hse_8mhz_3v3[(RCC_CLOCK_3V3_216MHZ)]) +#endif + +#if defined(CONSOLE_1) +#define AVM_CONSOLE (USART1) +#define AVM_CONSOLE_TX (GPIO9) +#define AVM_CONSOLE_GPIO (GPIOA) +#define AVM_CONSOLE_RCC (RCC_USART1) +#elif defined(CONSOLE_2) +#define AVM_CONSOLE (USART2) +#define AVM_CONSOLE_TX (GPIO2) +#define AVM_CONSOLE_GPIO (GPIOA) +#define AVM_CONSOLE_RCC (RCC_USART2) +#elif defined(CONSOLE_3) +#define AVM_CONSOLE (USART3) +#define AVM_CONSOLE_TX (GPIO8) +#define AVM_CONSOLE_GPIO (GPIOD) +#define AVM_CONSOLE_RCC (RCC_USART3) +#elif defined(CONSOLE_4) +#define AVM_CONSOLE (UART4) +#define AVM_CONSOLE_TX (GPIO10) +#define AVM_CONSOLE_GPIO (GPIOC) +#define AVM_CONSOLE_RCC (RCC_UART4) +#elif defined(CONSOLE_5) +#define AVM_CONSOLE (UART5) +#define AVM_CONSOLE_TX (GPIO12) +#define AVM_CONSOLE_GPIO (GPIOC) +#define AVM_CONSOLE_RCC (RCC_UART5) +#ifdef LIBOPENCM3_USART_COMMON_F24_H +#elif defined(CONSOLE_6) +#define AVM_CONSOLE (USART6) +#define AVM_CONSOLE_TX (GPIO6) +#define AVM_CONSOLE_GPIO (GPIOC) +#define AVM_CONSOLE_RCC (RCC_USART6) +#elif defined(CONSOLE_7) +#define AVM_CONSOLE (UART7) +#define AVM_CONSOLE_TX (GPIO7) +#define AVM_CONSOLE_GPIO (GPIOF) +#define AVM_CONSOLE_RCC (RCC_UART7) +#elif defined(CONSOLE_8) +#define AVM_CONSOLE (UART8) +#define AVM_CONSOLE_TX (GPIO8) +#define AVM_CONSOLE_GPIO (GPIOJ) +#define AVM_CONSOLE_RCC (RCC_UART8) +#endif /* LIBOPENCM3_USART_COMMON_F24_H */ +#endif + +#endif /* _AVM_DEVCFG_H_ */ diff --git a/src/platforms/stm32/src/main.c b/src/platforms/stm32/src/main.c index afc54a887..eb8917b22 100644 --- a/src/platforms/stm32/src/main.c +++ b/src/platforms/stm32/src/main.c @@ -39,13 +39,17 @@ #include #include +#include "lib/avm_devcfg.h" #include "lib/avm_log.h" #include "lib/stm_sys.h" -#define USART_CONSOLE USART2 -#define AVM_ADDRESS (0x8080000) -#define AVM_FLASH_MAX_SIZE (0x80000) -#define CLOCK_FREQUENCY (168000000) +#define USART_CONSOLE (AVM_CONSOLE) +#define USART_TX (AVM_CONSOLE_TX) +#define USART_GPIO (AVM_CONSOLE_GPIO) +#define USART_RCC (AVM_CONSOLE_RCC) +#define AVM_ADDRESS (AVM_APP_ADDRESS) +#define AVM_FLASH_END (CFG_FLASH_END) +#define CLOCK_FREQUENCY (AVM_CLOCK_HZ) #define TAG "AtomVM" @@ -70,21 +74,21 @@ int _kill(pid_t pid, int sig); static void clock_setup() { - // Use external clock, set divider for 168 MHz clock frequency - rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]); + // Setup external clock, set divider for device clock frequency + rcc_clock_setup_pll(AVM_CLOCK_CONFIGURATION); } static void usart_setup(GlobalContext *glb) { - // Enable clock for USART2 - rcc_periph_clock_enable(RCC_USART2); + // Enable clock for USART + rcc_periph_clock_enable(USART_RCC); - // Setup GPIO pins for USART2 transmit - gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2); - sys_lock_pin(glb, GPIOA, GPIO2); + // Setup GPIO pins for USART transmit + gpio_mode_setup(USART_GPIO, GPIO_MODE_AF, GPIO_PUPD_NONE, USART_TX); + sys_lock_pin(glb, USART_GPIO, USART_TX); - // Setup USART2 TX pin as alternate function - gpio_set_af(GPIOA, GPIO_AF7, GPIO2); + // Setup USART TX pin as alternate function + gpio_set_af(USART_GPIO, GPIO_AF7, USART_TX); usart_set_baudrate(USART_CONSOLE, 115200); usart_set_databits(USART_CONSOLE, 8); @@ -103,7 +107,7 @@ static void systick_setup() { // ((clock rate / 1000) - 1) to get 1ms interrupt rate systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); - systick_set_reload((CLOCK_FREQUENCY / 1000) - 1); + systick_set_reload((CLOCK_FREQUENCY / 1000U) - 1U); systick_clear(); systick_counter_enable(); systick_interrupt_enable(); @@ -172,13 +176,13 @@ int main() AVM_LOGD(TAG, "Using usart mapped at register 0x%x for stdout/stderr.", USART_CONSOLE); const void *flashed_avm = (void *) AVM_ADDRESS; - uint32_t size = AVM_FLASH_MAX_SIZE; + uint32_t size = (AVM_FLASH_END - AVM_ADDRESS); uint32_t startup_beam_size; const void *startup_beam; const char *startup_module_name; - AVM_LOGD(TAG, "Maximum application size: %lu", size); + AVM_LOGD(TAG, "Maximum application size: %lu KiB", (size / 1024)); port_driver_init_all(glb); nif_collection_init_all(glb); @@ -188,6 +192,7 @@ int main() AVM_ABORT(); } AVM_LOGI(TAG, "Booting file mapped at: %p, size: %lu", flashed_avm, startup_beam_size); + AVM_LOGD(TAG, "Free application flash space: %lu KiB", ((size - startup_beam_size) / 1024)); struct ConstAVMPack *avmpack_data = malloc(sizeof(struct ConstAVMPack)); if (IS_NULL_PTR(avmpack_data)) { diff --git a/src/platforms/stm32/tools/atomvm_stm32_config_query.erl b/src/platforms/stm32/tools/atomvm_stm32_config_query.erl new file mode 100755 index 000000000..0f308a495 --- /dev/null +++ b/src/platforms/stm32/tools/atomvm_stm32_config_query.erl @@ -0,0 +1,391 @@ +%!/usr/bin/env escript +% +% This file is part of AtomVM. +% +% Copyright 2023 Winford +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +-module(atomvm_stm32_config_query). + +-include("device_config.hrl"). + +%% API exports +-export([main/1]). + +%%==================================================================== +%% API functions +%%==================================================================== + +%% escript Entry point +main(Args) -> + case length(Args) of + 2 -> + ok; + _ -> + error() + end, + [Device | Parameter] = Args, + Config = get_dev_config(Device), + case Parameter of + ["nucleo_com"] -> + io:put_chars(get_nucleo_com(Device)); + _ -> + Key = get_param_key(Parameter), + io:put_chars(maps:get(Key, Config, "")) + end, + erlang:halt(0). + +%%==================================================================== +%% Internal functions +%%==================================================================== + +error() -> + io:format("~n Usage: ~s ~n", [?MODULE_STRING]), + io:format("~n Where is one of: clock | rom | ram | ccm~n"), + erlang:halt(255). + +get_dev_config(Device) -> + Core = string:left(Device, 7), + Lookup = string:slice(Device, 7), + case Core of + "stm32f4" -> + Config = get_f4dev_config(Lookup), + case Config of + unsupported -> + io:format("Error! Unsupported device ~s.~n", [Device]), + erlang:halt(255); + _ -> + Config + end; + "stm32f7" -> + Config = get_f7dev_config(Lookup), + case Config of + unsupported -> + io:format("Error! Unsupported device ~s.~n", [Device]), + erlang:halt(255); + _ -> + Config + end; + _ -> + io:format("Error! Unsupported device ~s.~n", [Device]), + erlang:halt(255) + end. + +get_f4dev_config(Lookup) -> + Line = string:slice(Lookup, 0, 2), + Flash = string:slice(Lookup, 3, 1), + case Line of + "01" -> + case Flash of + "e" -> + ?STM32F401_E; + _ -> + unsupported + end; + "05" -> + case Flash of + "e" -> + ?STM32F4_01_57_E; + "g" -> + ?STM32F4_01_57_G; + _ -> + unsupported + end; + "07" -> + case Flash of + "e" -> + ?STM32F4_01_57_E; + "g" -> + ?STM32F4_01_57_G; + _ -> + unsupported + end; + "11" -> + case Flash of + "e" -> + ?STM32F411_E; + _ -> + unsupported + end; + "12" -> + case Flash of + "e" -> + ?STM32F412_E; + "g" -> + ?STM32F412_G; + _ -> + unsupported + end; + "13" -> + case Flash of + "g" -> + ?STM32F4_12_3_G; + "h" -> + ?STM32F4_12_3_H; + _ -> + unsupported + end; + "15" -> + case Flash of + "e" -> + ?STM32F4_01_57_E; + "g" -> + ?STM32F4_01_57_G; + _ -> + unsupported + end; + "17" -> + case Flash of + "e" -> + ?STM32F4_01_57_E; + "g" -> + ?STM32F4_01_57_G; + _ -> + unsupported + end; + "23" -> + case Flash of + "g" -> + ?STM32F4_12_3_G; + "h" -> + ?STM32F4_12_3_H; + _ -> + unsupported + end; + "27" -> + case Flash of + "e" -> + ?STM32F4_23_79_E; + "g" -> + ?STM32F4_23_79_G; + "i" -> + ?STM32F4_23_79_I; + _ -> + unsupported + end; + "29" -> + case Flash of + "e" -> + ?STM32F4_23_79_E; + "g" -> + ?STM32F4_23_79_G; + "i" -> + ?STM32F4_23_79_I; + _ -> + unsupported + end; + "37" -> + case Flash of + "e" -> + ?STM32F4_23_79_E; + "g" -> + ?STM32F4_23_79_G; + "i" -> + ?STM32F4_23_79_I; + _ -> + unsupported + end; + "39" -> + case Flash of + "e" -> + ?STM32F4_23_79_E; + "g" -> + ?STM32F4_23_79_G; + "i" -> + ?STM32F4_23_79_I; + _ -> + unsupported + end; + "46" -> + case Flash of + "e" -> + ?STM32F446_E; + _ -> + unsupported + end; + "69" -> + case Flash of + "e" -> + ?STM32F4_67_9_E; + "g" -> + ?STM32F4_67_9_G; + "i" -> + ?STM32F4_67_9_I; + _ -> + unsupported + end; + "79" -> + case Flash of + "e" -> + ?STM32F4_67_9_E; + "g" -> + ?STM32F4_67_9_G; + "i" -> + ?STM32F4_67_9_I; + _ -> + unsupported + end; + _ -> + unsupported + end. + +get_f7dev_config(Lookup) -> + Line = string:slice(Lookup, 0, 2), + Flash = string:slice(Lookup, 3, 1), + case Line of + "22" -> + case Flash of + "e" -> + ?STM32F7_23_23_E; + _ -> + unsupported + end; + "23" -> + case Flash of + "e" -> + ?STM32F7_23_23_E; + _ -> + unsupported + end; + "32" -> + case Flash of + "e" -> + ?STM32F7_23_23_E; + _ -> + unsupported + end; + "33" -> + case Flash of + "e" -> + ?STM32F7_23_23_E; + _ -> + unsupported + end; + "45" -> + case Flash of + "e" -> + ?STM32F745_E; + "g" -> + ?STM32F745_G; + _ -> + unsupported + end; + "46" -> + case Flash of + "e" -> + ?STM32F7_45_6_E; + "g" -> + ?STM32F7_45_6_G; + _ -> + unsupported + end; + "56" -> + case Flash of + "e" -> + ?STM32F7_45_6_E; + "g" -> + ?STM32F7_45_6_G; + _ -> + unsupported + end; + "65" -> + case Flash of + "g" -> + ?STM32F765_G; + "i" -> + ?STM32F765_I; + _ -> + unsupported + end; + "67" -> + case Flash of + "g" -> + ?STM32F7_67_7_G; + "i" -> + ?STM32F7_67_7_I; + _ -> + unsupported + end; + "68" -> + case Flash of + "i" -> + ?STM32F7_67_89_I; + _ -> + unsupported + end; + "69" -> + case Flash of + "g" -> + ?STM32F769_G; + "i" -> + ?STM32F7_67_89_I; + _ -> + unsupported + end; + "77" -> + case Flash of + "g" -> + ?STM32F7_67_7_G; + "i" -> + ?STM32F7_67_7_I; + _ -> + unsupported + end; + "78" -> + case Flash of + "i" -> + ?STM32F7_67_89_I; + _ -> + unsupported + end; + "79" -> + case Flash of + "i" -> + ?STM32F7_67_89_I; + _ -> + unsupported + end; + _ -> + unsupported + end. + +get_nucleo_com(Device) -> + PinVariant = string:slice(Device, 9, 1), + case PinVariant of + "r" -> + "CONSOLE_2"; + "z" -> + "CONSOLE_3"; + _ -> + io:format("Error: ~p is not a valid Nucleo device.~n", [Device]), + erlang:halt(255) + end. + +get_param_key(Parameter) -> + case Parameter of + ["rom"] -> + rom; + ["ram"] -> + ram; + ["ccm"] -> + ccm; + ["clock"] -> + clock; + _ -> + io:format("Error: ~p is not a valid configuration parameter.~n", [Parameter]), + erlang:halt(255) + end. diff --git a/src/platforms/stm32/tools/device_config.hrl b/src/platforms/stm32/tools/device_config.hrl new file mode 100644 index 000000000..1e3a311d0 --- /dev/null +++ b/src/platforms/stm32/tools/device_config.hrl @@ -0,0 +1,81 @@ +% +% This file is part of AtomVM. +% +% Copyright 2023 Winford +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +%% STM32F4 Family configurations +-define(STM32F401_E, #{rom => "ROM_512K", ram => "RAM_64K", clock => "MHZ_84"}). +-define(STM32F4_01_57_E, #{ + rom => "ROM_512K", ram => "RAM_128K", ccm => "CCM_64K", clock => "MHZ_168" +}). +-define(STM32F4_01_57_G, #{ + rom => "ROM_1024K", ram => "RAM_128K", ccm => "CCM_64K", clock => "MHZ_168" +}). +-define(STM32F411_E, #{rom => "ROM_512K", ram => "RAM_128K", clock => "MHZ_100"}). +-define(STM32F412_E, #{rom => "ROM_512K", ram => "RAM_256K", clock => "MHZ_100"}). +-define(STM32F412_G, #{rom => "ROM_1024K", ram => "RAM_256K", clock => "MHZ_100"}). +-define(STM32F4_12_3_G, #{ + rom => "ROM_1024K", ram => "RAM_256K", ccm => "CCM_64K", clock => "MHZ_100" +}). +-define(STM32F4_12_3_H, #{ + rom => "ROM_1536K", ram => "RAM_256K", ccm => "CCM_64K", clock => "MHZ_100" +}). +-define(STM32F4_23_79_E, #{ + rom => "ROM_512K", ram => "RAM_192K", ccm => "CCM_64K", clock => "MHZ_180" +}). +-define(STM32F4_23_79_G, #{ + rom => "ROM_1024K", ram => "RAM_192K", ccm => "CCM_64K", clock => "MHZ_180" +}). +-define(STM32F4_23_79_I, #{ + rom => "ROM_2048K", ram => "RAM_192K", ccm => "CCM_64K", clock => "MHZ_180" +}). +-define(STM32F446_E, #{rom => "ROM_512K", ram => "RAM_128K", clock => "MHZ_180"}). +-define(STM32F4_67_9_E, #{ + rom => "ROM_512K", ram => "RAM_320K", ccm => "CCM_64K", clock => "MHZ_180" +}). +-define(STM32F4_67_9_G, #{ + rom => "ROM_1024K", ram => "RAM_320K", ccm => "CCM_64K", clock => "MHZ_180" +}). +-define(STM32F4_67_9_I, #{ + rom => "ROM_2048K", ram => "RAM_320K", ccm => "CCM_64K", clock => "MHZ_180" +}). + +%% STM32F7 Family configurations +-define(STM32F7_23_23_E, #{ + rom => "ROM_512K", ram => "RAM_192K", ccm => "CCM_64K", clock => "MHZ_216" +}). +-define(STM32F745_E, #{rom => "ROM_512K", ram => "RAM_256K", ccm => "CCM_64K", clock => "MHZ_216"}). +-define(STM32F745_G, #{rom => "ROM_1024K", ram => "RAM_256K", ccm => "CCM_64K", clock => "MHZ_216"}). +-define(STM32F765_G, #{rom => "ROM_1024K", ram => "RAM_384K", ccm => "CCM_128K", clock => "MHZ_216"}). +-define(STM32F765_I, #{rom => "ROM_2048K", ram => "RAM_384K", ccm => "CCM_128K", clock => "MHZ_216"}). +-define(STM32F7_45_6_E, #{ + rom => "ROM_512K", ram => "RAM_256K", ccm => "CCM_64K", clock => "MHZ_216" +}). +-define(STM32F7_45_6_G, #{ + rom => "ROM_1024K", ram => "RAM_256K", ccm => "CCM_64K", clock => "MHZ_216" +}). +-define(STM32F7_67_7_G, #{ + rom => "ROM_1024K", ram => "RAM_384K", ccm => "CCM_128K", clock => "MHZ_216" +}). +-define(STM32F7_67_7_I, #{ + rom => "ROM_2048K", ram => "RAM_384K", ccm => "CCM_128K", clock => "MHZ_216" +}). +-define(STM32F769_G, #{rom => "ROM_1024K", ram => "RAM_384K", ccm => "CCM_128K", clock => "MHZ_216"}). +-define(STM32F7_67_89_I, #{ + rom => "ROM_2048K", ram => "RAM_384K", ccm => "CCM_128K", clock => "MHZ_216" +}).