diff --git a/.devcontainer/All/devcontainer.json b/.devcontainer/All/devcontainer.json index 9d0e0a02a4..12f3c4b4ef 100644 --- a/.devcontainer/All/devcontainer.json +++ b/.devcontainer/All/devcontainer.json @@ -9,9 +9,9 @@ // Bind the Unix socket the Docker daemon listens on by default "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind", // Keep command history - "source=nano-bashhistory,target=/home/vscode/commandhistory,type=volume", + "source=nano-bashhistory,target=/home/vscode/commandhistory,type=volume" // OPTIONAL: Mount .azure folder for seamless az cli auth - // "source=${env:HOME}${env:USERPROFILE}/.azure,target=/home/vscode/.azure,type=bind" + // ,"source=${env:HOME}${env:USERPROFILE}/.azure,target=/home/vscode/.azure,type=bind" ], // Set the *default* container specific settings.json values on container create. "customizations": { diff --git a/.devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP b/.devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP new file mode 100644 index 0000000000..9da239fcb2 --- /dev/null +++ b/.devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP @@ -0,0 +1,5 @@ +# Pre-built image is not yet available for ChibiOS-RP. +# Use Dockerfile.ChibiOS-RP.SRC to build from source. +# Once published, replace this line with the image reference, e.g.: +# FROM ghcr.io/nanoframework/dev-container-chibios-rp:v1.0 +FROM ghcr.io/nanoframework/dev-container-chibios-rp:v1.0 diff --git a/.devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP.SRC b/.devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP.SRC new file mode 100644 index 0000000000..5f04c97bf6 --- /dev/null +++ b/.devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP.SRC @@ -0,0 +1,113 @@ +FROM ubuntu:latest AS downloader +RUN apt-get update \ + && apt-get -y install --no-install-recommends apt-utils \ + && apt-get install -y \ + curl \ + xz-utils \ + unzip \ + wget + +RUN mkdir -p /tmp/dc-downloads /tmp/dc-extracted + +ARG GCC_VERSION=13.3.rel1 +ARG GCC_URI=https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/$GCC_VERSION/binrel/arm-gnu-toolchain-$GCC_VERSION-x86_64-arm-none-eabi.tar.xz +RUN mkdir -p /tmp/dc-downloads /tmp/dc-extracted/gcc \ + && curl -o /tmp/dc-downloads/gcc-arm.tar.xz $GCC_URI \ + && xz -d /tmp/dc-downloads/gcc-arm.tar.xz \ + && tar -xvf /tmp/dc-downloads/gcc-arm.tar -C /tmp/dc-extracted/gcc --strip-components 1 \ + && rm -rf /tmp/dc-extracted/gcc/share/doc/ /tmp/dc-extracted/gcc/share/gcc-arm-none-eabi/samples/ + +ARG CMAKE_VERSION=3.31.6 +ARG CMAKE_SCRIPT=https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-x86_64.sh +RUN wget $CMAKE_SCRIPT \ + -q -O /tmp/dc-downloads/cmake-install.sh \ + && chmod u+x /tmp/dc-downloads/cmake-install.sh \ + && mkdir -p /tmp/dc-extracted/cmake \ + && /tmp/dc-downloads/cmake-install.sh --skip-license --prefix=/tmp/dc-extracted/cmake \ + && rm /tmp/dc-downloads/cmake-install.sh + +FROM ubuntu:latest AS devcontainer + +# Avoid warnings by switching to noninteractive +ENV DEBIAN_FRONTEND=noninteractive + +# You can set up non-root user +# ARG USERNAME=vscode +# ARG USER_UID=1000 +# ARG USER_GID=$USER_UID + +# Configure apt and install packages +RUN apt-get update \ + && apt-get -y install --no-install-recommends apt-utils dialog icu-devtools 2>&1 \ + && apt-get install -y \ + git \ + git-svn \ + subversion \ + clang-format \ + curl \ + ninja-build \ + srecord \ + python3 \ + python3-pip \ + libusb-1.0-0-dev \ + pkg-config \ + build-essential + +# Create needed directories +RUN mkdir -p /usr/local/bin/gcc + +# ============================================================ +# KEY DIFFERENCE from ChibiOS container: +# Clone ChibiOS master/trunk which has RP2040/RP2350 support +# The stable_21.11.x branch does NOT include RP ports. +# ============================================================ +# Try GitHub mirror first (faster), fall back to SVN trunk +RUN git clone --branch master https://github.com/ChibiOS/ChibiOS.git --depth 1 ./sources/ChibiOs \ + || git svn clone http://svn.code.sf.net/p/chibios/code/trunk -rHEAD ./sources/ChibiOs + +# NO STM32 Cube packages — not needed for RP targets + +# Clone dependent repos (mbedtls, fatfs, littlefs, lwIP) +RUN git clone --branch R0.16 https://github.com/abbrev/fatfs.git --depth 1 ./sources/fatfs \ + && git clone --branch v2.11.2 https://github.com/littlefs-project/littlefs --depth 1 ./sources/littlefs \ + && git clone --branch STABLE-2_1_3_RELEASE https://github.com/lwip-tcpip/lwip.git --depth 1 ./sources/lwip \ + && git clone --branch mbedtls-3.6.5 https://github.com/ARMmbed/mbedtls.git --depth 1 ./sources/mbedtls \ + && cd ./sources/mbedtls \ + && git submodule update --init --recursive + +# set gcc location +ARG TMP_GCC_PATH=/usr/local/bin/gcc +ENV ARM_GCC_PATH=$TMP_GCC_PATH/bin + +# Copy from our other container +COPY --from=downloader /tmp/dc-extracted/gcc $TMP_GCC_PATH +COPY --from=downloader /tmp/dc-extracted/cmake /usr/bin/cmake + +ENV PATH=/usr/bin/cmake/bin:${PATH} + +# picotool is NOT included — it requires the Pico SDK (PICO_SDK_PATH) to build. +# Since we use ChibiOS (not the Pico SDK), picotool can be added later if UF2 +# conversion is needed, by also cloning the pico-sdk. +# hex2dfu is NOT included — RP targets use UF2 format, not DFU +# srecord is still useful for bin packaging + +# Install Python dependencies for Kconfig configuration system +RUN pip3 install --no-cache-dir --break-system-packages pyserial "kconfiglib>=14.1.0" + +# Clean up downloaded files +RUN apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +# Install .NET SDK 9.0 and .NET 8.0 runtime (needed by nanoFramework build tooling) +RUN curl -sSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \ + && chmod +x /tmp/dotnet-install.sh \ + && /tmp/dotnet-install.sh --channel 9.0 --install-dir /usr/share/dotnet \ + && /tmp/dotnet-install.sh --channel 8.0 --runtime dotnet --install-dir /usr/share/dotnet \ + && ln -sf /usr/share/dotnet/dotnet /usr/local/bin/dotnet \ + && rm /tmp/dotnet-install.sh + +ENV DOTNET_ROOT=/usr/share/dotnet + +# Switch back to dialog for any ad-hoc use of apt-get +ENV DEBIAN_FRONTEND=dialog diff --git a/.devcontainer/ChibiOS-RP/devcontainer.json b/.devcontainer/ChibiOS-RP/devcontainer.json new file mode 100644 index 0000000000..c5e403b2bd --- /dev/null +++ b/.devcontainer/ChibiOS-RP/devcontainer.json @@ -0,0 +1,50 @@ +{ + "name": "nanoFramework-ChibiOS-RP", + // This container is for developing Raspberry Pi Pico (RP2040/RP2350) targets using ChibiOS. + // It uses Dockerfile.ChibiOS-RP.SRC which builds from source because there is no pre-built image yet. + // Once a pre-built image is published, change "dockerFile" to "Dockerfile.ChibiOS-RP". + "dockerFile": "Dockerfile.ChibiOS-RP.SRC", + "context": ".", + "runArgs": ["--privileged", "--device=/dev/ttyUSB0:/dev/ttyUSB0"], + "mounts": [ + // Bind the Unix socket the Docker daemon listens on by default + "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind", + // Keep command history + "source=nano-bashhistory,target=/home/vscode/commandhistory,type=volume", + // Map /dev for USB device access (debug probes, serial ports) + "source=/dev,target=/dev,type=bind" + // OPTIONAL: Mount .azure folder for seamless az cli auth + // ,"source=${env:HOME}${env:USERPROFILE}/.azure,target=/home/vscode/.azure,type=bind" + ], + // Set the *default* container specific settings.json values on container create. + "customizations": { + "vscode": { + "settings": { + "cmake.preferredGenerators": [ + "Ninja" + ], + "cmake.generator": "Ninja", + "cmake.autoRestartBuild" : true, + "cmake.configureSettings": { + "CMAKE_MAKE_PROGRAM":"/usr/bin/ninja" + }, + "cmake.configureOnOpen": false + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vsliveshare.vsliveshare-pack", + "streetsidesoftware.code-spell-checker", + "twxs.cmake", + "ms-vscode.cmake-tools", + "xaver.clang-format" + ] + } + }, + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + // Use 'postCreateCommand' to run commands after the container is created. + // This is needed to allow cloning repositories + "postCreateCommand": "git config --global safe.directory '*'" + // Uncomment to connect as a non-root user. See https: //aka.ms/vscode-remote/containers/non-root. + // ,"remoteUser": "vscode" +} diff --git a/.devcontainer/README.md b/.devcontainer/README.md index 8fc5daa6a2..fc9f0b25fa 100644 --- a/.devcontainer/README.md +++ b/.devcontainer/README.md @@ -10,6 +10,7 @@ The available pre build images are: * ghcr.io/nanoframework/dev-container-esp32: contains all elements to build a firmware image for any of the ESP32 targets * ghcr.io/nanoframework/dev-container-azure-rtos: contains all elements to build a firmware image for any of the Eclipse ThreadX (used to be Azure RTOS) targets * ghcr.io/nanoframework/dev-container-freertos-nxp: contains all elements to build a firmware image for any of the NXP targets +* ChibiOS-RP: contains all elements to build a firmware image for Raspberry Pi Pico (RP2040/RP2350) ChibiOS targets. Uses ChibiOS master branch which includes RP support. You can choose the dev container needed when opening a remote container in VSCode. The options are: @@ -19,6 +20,7 @@ You can choose the dev container needed when opening a remote container in VSCod * `nanoFramework-ESP32` to use the pre build container with all the elements to build ESP32 targets * `nanoFramework-TI` to use the pre build container with all the elements to build TI SimpleLink targets * `nanoFramework-FreeRTOS-NXP` to use the pre build container with all the elements to build TI SimpleLink targets +* `nanoFramework-ChibiOS-RP` to build from source a container with all the elements to build Raspberry Pi Pico RP2040/RP2350 ChibiOS targets To use the source dockerfile for the respective platform adjust its `devcontainer.json` file and change the `"dockerFile": "Dockerfile."` element for the image you would like to use: @@ -28,6 +30,7 @@ To use the source dockerfile for the respective platform adjust its `devcontaine * `Dockerfile.ESP32.SRC` to build the container image from the source with all the elements to build ESP32 based devices * `Dockerfile.TI.SRC` to build the container image from the source with all the elements to build TI SimpleLink based devices * `Dockerfile.FreeRTOS.NXP.SRC` to build the container image from the source with all the elements to build NXP based devices +* `Dockerfile.ChibiOS-RP.SRC` to build the container image from the source with all the elements to build Raspberry Pi Pico (RP2040/RP2350) ChibiOS targets ## Building and releasing Docker images in a fork diff --git a/.github/workflows/devcontainer-chibios-rp.yaml b/.github/workflows/devcontainer-chibios-rp.yaml new file mode 100644 index 0000000000..2257712607 --- /dev/null +++ b/.github/workflows/devcontainer-chibios-rp.yaml @@ -0,0 +1,64 @@ +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. + +name: Build Dev Container for ChibiOS-RP + +env: + CONTAINER_REPO: ghcr.io + CONTAINER_NAME: dev-container-chibios-rp + CONTAINER_SRC_FILE: .devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP.SRC + +on: + push: + branches: + - main + paths: + - '**Dockerfile.ChibiOS-RP' + + workflow_dispatch: + +jobs: + build: + if: ${{ vars.PUBLISH_DOCKER_IMAGE == 'true' }} + runs-on: ubuntu-latest + permissions: + contents: read + steps: + + - name: Checkout Repository + uses: actions/checkout@v5 + + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@main + with: + # this might remove tools that are actually needed, + # when set to "true" but frees about 6 GB + tool-cache: true + large-packages: false + + - name: Get container version + run: | + $dockerfileContent = Get-Content(".devcontainer/ChibiOS-RP/Dockerfile.ChibiOS-RP") + $dockerfileContent -match '(?<=\:)(?:[v]\d+.\d+)' + $containerVersion = $Matches[0].ToString() + echo "GCR_VERSION=$containerVersion" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append + shell: pwsh + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.CONTAINER_BUILD_TOKEN }} + + - name: Build and Push Docker Image + uses: docker/build-push-action@v6 + with: + file: ${{ env.CONTAINER_SRC_FILE }} + push: true # Will only build if this is not here + tags: | + ${{ env.CONTAINER_REPO }}/${{ github.repository_owner }}/${{ env.CONTAINER_NAME }}:${{ env.GCR_VERSION }} + ${{ env.CONTAINER_REPO }}/${{ github.repository_owner }}/${{ env.CONTAINER_NAME }}:latest diff --git a/.github/workflows/devcontainer-smoketest.yaml b/.github/workflows/devcontainer-smoketest.yaml index 5b62106364..eb3b12b07b 100644 --- a/.github/workflows/devcontainer-smoketest.yaml +++ b/.github/workflows/devcontainer-smoketest.yaml @@ -27,6 +27,7 @@ jobs: # { target: ESP32_H2_THREAD, build-type: Debug, container: ESP32 }, { target: NXP_MIMXRT1060_EVK, build-type: Debug, container: FreeRTOS-NXP }, { target: NXP_MIMXRT1060_EVK, build-type: Debug, container: All }, + { target: RP_PICO_W_RP2040, build-type: Debug, container: ChibiOS-RP }, { target: TI_CC1352R1_LAUNCHXL, build-type: Debug, container: TI, radio-freq: 915 }, { target: TI_CC1352R1_LAUNCHXL, build-type: Debug, container: All, radio-freq: 915 }, { target: TI_CC1352R1_LAUNCHXL, build-type: Debug, container: TI, radio-freq: 868 }, diff --git a/CMake/Modules/CHIBIOS_RP2040_GCC_options.cmake b/CMake/Modules/CHIBIOS_RP2040_GCC_options.cmake new file mode 100644 index 0000000000..699e5f014f --- /dev/null +++ b/CMake/Modules/CHIBIOS_RP2040_GCC_options.cmake @@ -0,0 +1,68 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +################################################################# +# WHEN ADDING A NEW SERIES add the appropriate GCC options below +################################################################# + +# RP2040: ARM Cortex-M0+ (ARMv6-M), no FPU, soft float + +# need to specify this for assembler +set(CMAKE_ASM_FLAGS " -mthumb -mcpu=cortex-m0plus -mfloat-abi=soft -mabi=aapcs -x assembler-with-cpp -DCRT0_VTOR_INIT=TRUE" CACHE INTERNAL "asm compiler flags") + +# need to specify linker flags here +set(CMAKE_EXE_LINKER_FLAGS " -Wl,--gc-sections -Wl,--no-wchar-size-warning -Wl,--print-memory-usage -Wl,--no-warn-rwx-segments -mthumb -mcpu=cortex-m0plus -mfloat-abi=soft -mabi=aapcs -nostartfiles " CACHE INTERNAL "executable linker flags") + + +# TARGET parameter to set the target that's setting them for +# optional EXTRA_COMPILE_OPTIONS with compile options to be added +macro(nf_set_compile_options) + + # parse arguments + cmake_parse_arguments(NFSCO "" "TARGET" "EXTRA_COMPILE_OPTIONS" ${ARGN}) + + if(NOT NFSCO_TARGET OR "${NFSCO_TARGET}" STREQUAL "") + message(FATAL_ERROR "Need to set TARGET argument when calling nf_set_compile_options()") + endif() + + # include any extra options coming from any extra args? + target_compile_options(${NFSCO_TARGET} PUBLIC ${NFSCO_EXTRA_COMPILE_OPTIONS} -mthumb -mcpu=cortex-m0plus -mabi=aapcs -nostdlib -Wall -Wextra -Werror -Wundef -Wshadow -Wimplicit-fallthrough $<$:-Wno-cast-user-defined> -fshort-wchar -fno-builtin -fno-common -mno-long-calls -fno-exceptions -fcheck-new ) + + # RP2040 has no FPU (Cortex-M0+) + # Note: RP2040 is defined by ChibiOS board.h, no need to add it here + target_compile_definitions(${NFSCO_TARGET} PUBLIC -DPLATFORM_ARM -DCORTEX_USE_FPU=FALSE -DUSE_FPU=FALSE) + +endmacro() + + +# TARGET parameter to set the target that's setting them for +# optional EXTRA_LINK_FLAGS with link flags to be added +macro(nf_set_link_options) + + # parse arguments + cmake_parse_arguments(NFSLO "" "TARGET;EXTRA_LINK_FLAGS" "" ${ARGN}) + + if(NOT NFSLO_TARGET OR "${NFSLO_TARGET}" STREQUAL "") + message(FATAL_ERROR "Need to set TARGET argument when calling nf_set_link_options()") + endif() + + # set optimization linker flags for RELEASE and MinSizeRel + if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel") + set_property(TARGET ${NFSLO_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " -Os -flto -fuse-linker-plugin -fstrict-aliasing -fomit-frame-pointer -fno-unroll-loops -frounding-math -fsignaling-nans -ffloat-store -fno-math-errno -ftree-vectorize -fno-default-inline -finline-functions-called-once -fno-defer-pop ") + endif() + + # request specs from newlib nano + set_property(TARGET ${NFSLO_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " --specs=nano.specs ") + + # include libraries in build + nf_include_libraries_in_build(${NFSLO_TARGET}) + + # set extra linker flags + set_property(TARGET ${NFSLO_TARGET} APPEND_STRING PROPERTY LINK_FLAGS " ${NFSLO_EXTRA_LINK_FLAGS} ") + + # set optimization flags + nf_set_optimization_options(${NFSLO_TARGET}) + +endmacro() diff --git a/CMake/Modules/CHIBIOS_RP2040_sources.cmake b/CMake/Modules/CHIBIOS_RP2040_sources.cmake new file mode 100644 index 0000000000..ff9e91fd93 --- /dev/null +++ b/CMake/Modules/CHIBIOS_RP2040_sources.cmake @@ -0,0 +1,40 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +include(FetchContent) +FetchContent_GetProperties(chibios) + +# List of the ChibiOS generic RP2040 startup source files. +# RP2040 uses ARM Cortex-M0+ (ARMv6-M architecture) + +set(CHIBIOS_PORT_SRCS + + # RT port for ARMv6-M + chcore.c + chcoreasm.S +) + +foreach(SRC_FILE ${CHIBIOS_PORT_SRCS}) + + set(CHIBIOS_RP_SRC_FILE SRC_FILE-NOTFOUND) + + find_file(CHIBIOS_RP_SRC_FILE ${SRC_FILE} + PATHS + ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/compilers/GCC + ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M + ${chibios_SOURCE_DIR}/os/hal/ports/common/ARMCMx + + CMAKE_FIND_ROOT_PATH_BOTH + ) + + if (BUILD_VERBOSE) + message("${SRC_FILE} >> ${CHIBIOS_RP_SRC_FILE}") + endif() + + list(APPEND CHIBIOS_SOURCES ${CHIBIOS_RP_SRC_FILE}) + +endforeach() + +list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M) diff --git a/CMake/Modules/FindCYW43_Driver.cmake b/CMake/Modules/FindCYW43_Driver.cmake new file mode 100644 index 0000000000..b66e1ffac1 --- /dev/null +++ b/CMake/Modules/FindCYW43_Driver.cmake @@ -0,0 +1,60 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# CMake module to fetch and locate the georgerobotics/cyw43-driver sources. +# Used for Pico W (and other CYW43-based) WiFi targets on ChibiOS. + +include(FetchContent) +FetchContent_GetProperties(cyw43_driver) + +# CYW43 driver sources (high-level driver + lwIP glue + firmware blobs) +set(CYW43_DRIVER_SRCS + cyw43_ll.c + cyw43_ctrl.c + cyw43_stats.c +) +# Note: cyw43_spi.c is intentionally excluded — our cyw43_bus_pio_spi.c +# provides all SPI protocol functions (half-duplex PIO, not full-duplex). +# Note: cyw43_lwip.c is intentionally excluded — nf_lwipthread_wifi.c provides +# the lwIP integration with nanoFramework-specific network interface management. + +set(CYW43_DRIVER_INCLUDE_DIRS "") +set(CYW43_DRIVER_SOURCES "") + +# Include directories +list(APPEND CYW43_DRIVER_INCLUDE_DIRS ${cyw43_driver_SOURCE_DIR}/src) +list(APPEND CYW43_DRIVER_INCLUDE_DIRS ${cyw43_driver_SOURCE_DIR}/firmware) +list(APPEND CYW43_DRIVER_INCLUDE_DIRS ${cyw43_driver_SOURCE_DIR}) + +# Platform-specific ChibiOS WiFi adapter includes +list(APPEND CYW43_DRIVER_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi/cyw43) +list(APPEND CYW43_DRIVER_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi) + +# Find source files +foreach(SRC_FILE ${CYW43_DRIVER_SRCS}) + + set(CYW43_SRC_FILE SRC_FILE-NOTFOUND) + + find_file(CYW43_SRC_FILE ${SRC_FILE} + PATHS + ${cyw43_driver_SOURCE_DIR}/src + CMAKE_FIND_ROOT_PATH_BOTH + ) + + if(BUILD_VERBOSE) + message("${SRC_FILE} >> ${CYW43_SRC_FILE}") + endif() + + list(APPEND CYW43_DRIVER_SOURCES ${CYW43_SRC_FILE}) + +endforeach() + +# Add the ChibiOS PIO SPI bus driver (our implementation) +list(APPEND CYW43_DRIVER_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi/cyw43/cyw43_bus_pio_spi.c) +list(APPEND CYW43_DRIVER_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi/cyw43/cyw43_arch_chibios.c) + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(CYW43_Driver DEFAULT_MSG CYW43_DRIVER_INCLUDE_DIRS CYW43_DRIVER_SOURCES) diff --git a/CMake/Modules/FindChibiOS.cmake b/CMake/Modules/FindChibiOS.cmake index 2014a60fa7..bed9e55440 100644 --- a/CMake/Modules/FindChibiOS.cmake +++ b/CMake/Modules/FindChibiOS.cmake @@ -10,21 +10,33 @@ FetchContent_GetProperties(chibios) # WHEN ADDING A NEW SERIES, add the respective name to the list below along with the CMake files with GCC options and source files ################################################################################################################################### -# check if the series name is supported +# check if the series name is supported +# Supported series by vendor set(CHIBIOS_STM_SUPPORTED_SERIES "STM32F0xx" "STM32F4xx" "STM32F7xx" "STM32H7xx" "STM32L4xx" CACHE INTERNAL "supported STM series names for ChibiOS") +set(CHIBIOS_RP_SUPPORTED_SERIES "RP2040" "RP2350" CACHE INTERNAL "supported RP series names for ChibiOS") -list(FIND CHIBIOS_STM_SUPPORTED_SERIES ${TARGET_SERIES} TARGET_SERIES_NAME_INDEX) -if(TARGET_SERIES_NAME_INDEX EQUAL -1) - # series is NOT supported by STM - message(FATAL_ERROR "\n\nSorry but the ${TARGET_SERIES} is not supported at this time...\nYou can wait for it to be added, or you might want to contribute by working on a PR for it.\n\n") -else() +# Check STM32 series +list(FIND CHIBIOS_STM_SUPPORTED_SERIES ${TARGET_SERIES} TARGET_STM_INDEX) +# Check RP series +list(FIND CHIBIOS_RP_SUPPORTED_SERIES ${TARGET_SERIES} TARGET_RP_INDEX) + +if(NOT TARGET_STM_INDEX EQUAL -1) # series is supported by ST set(TARGET_VENDOR "ST" CACHE INTERNAL "target vendor is ST") + set(TARGET_VENDOR_FAMILY "STM32" CACHE INTERNAL "target vendor family") +elseif(NOT TARGET_RP_INDEX EQUAL -1) + # series is supported by Raspberry Pi + set(TARGET_VENDOR "RP" CACHE INTERNAL "target vendor is Raspberry Pi") + set(TARGET_VENDOR_FAMILY "RP" CACHE INTERNAL "target vendor family") +else() + message(FATAL_ERROR "\n\nSorry but the ${TARGET_SERIES} is not supported at this time...\nYou can wait for it to be added, or you might want to contribute by working on a PR for it.\n\n") endif() -# store the package name for later use -set(TARGET_STM32_SERIES STM32${TARGET_SERIES_SHORT} CACHE INTERNAL "name for STM32 Cube package") +# store the package name for STM32 targets (only relevant for ST vendor) +if(TARGET_VENDOR STREQUAL "ST") + set(TARGET_STM32_SERIES STM32${TARGET_SERIES_SHORT} CACHE INTERNAL "name for STM32 Cube package") +endif() # including here the CMake files for the source files specific to the target series include(CHIBIOS_${TARGET_SERIES}_sources) @@ -36,6 +48,8 @@ if (BUILD_VERBOSE) endif() # set include directories for ChibiOS + +# common include directories (vendor-agnostic) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/license) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/common/ARMCMx) @@ -43,19 +57,35 @@ list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/include) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/osal/rt-nil) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/oslib/include) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/rt/include) -list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/STM32/${TARGET_SERIES}) -list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv7-M) -list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv7-M/compilers/GCC) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/abstractions/cmsis_os) list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC) -list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/CMSIS/include) -list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/CMSIS/ST/${TARGET_SERIES}) -# -list(APPEND CHIBIOS_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/common/startup/ARMCMx/devices/${TARGET_SERIES}) +# vendor-specific include directories +if(TARGET_VENDOR STREQUAL "ST") + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/STM32/${TARGET_SERIES}) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv7-M) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv7-M/compilers/GCC) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/CMSIS/include) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/CMSIS/ST/${TARGET_SERIES}) + list(APPEND CHIBIOS_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/common/startup/ARMCMx/devices/${TARGET_SERIES}) + list(APPEND CHIBIOS_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/targets/ChibiOS/ST/${TARGET_BOARD}) +elseif(TARGET_VENDOR STREQUAL "RP") + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/EFLv1) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/${TARGET_SERIES}) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/portability/GCC) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARM-common) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARM-common/include) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/compilers/GCC) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/smp/rp2) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/devices/${TARGET_SERIES}) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/ARM/CMSIS/Core/Include) + list(APPEND CHIBIOS_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/RP/${TARGET_SERIES}) +endif() + +# common build output include directories list(APPEND CHIBIOS_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/targets/ChibiOS/${TARGET_BOARD}/nanoBooter) list(APPEND CHIBIOS_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/targets/ChibiOS/${TARGET_BOARD}/nanoCLR) -list(APPEND CHIBIOS_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/targets/ChibiOS/ST/${TARGET_BOARD}) # source files and GCC options according to target vendor and series @@ -83,6 +113,7 @@ set(CHIBIOS_SRCS chmboxes.c chmemcore.c + # chmemheap.c # this file is not used in ChibiOS RT-NIL and ThreadX builds, but it is required for ChibiOS-Contrib builds, so we need to include it in the sources list chmemheaps.c chmempools.c chpipes.c @@ -123,6 +154,11 @@ foreach(SRC_FILE ${CHIBIOS_SRCS}) endforeach() +# chmemchecks.c only exists in ChibiOS master, not in stable_21.11.x +if(EXISTS ${chibios_SOURCE_DIR}/os/oslib/src/chmemchecks.c) + list(APPEND CHIBIOS_SOURCES ${chibios_SOURCE_DIR}/os/oslib/src/chmemchecks.c) +endif() + include(FindPackageHandleStandardArgs) diff --git a/CMake/Modules/FindChibiOS_RP2040_HAL.cmake b/CMake/Modules/FindChibiOS_RP2040_HAL.cmake new file mode 100644 index 0000000000..c035a10450 --- /dev/null +++ b/CMake/Modules/FindChibiOS_RP2040_HAL.cmake @@ -0,0 +1,189 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +include(FetchContent) +FetchContent_GetProperties(chibios) + +# set include directories for ChibiOS HAL (RP2040) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/common/ARMCMx) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/include) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/RP2040) + +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/portability/GCC) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARM-common) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/compilers/GCC) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/smp/rp2) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/devices/RP2040) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/common/ext/ARM/CMSIS/Core/Include) + +# RP2040 LLD (Low Level Driver) include directories +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/EFLv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/ADCv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/DMAv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/GPIOv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/I2Cv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/PIOv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/PWMv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/RTCv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/SPIv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/TIMERv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/UARTv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/USBv1) +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/WDGv1) + +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${CHIBIOS_BOARD_DEFINITIONS_PATH}) + +# append dummy include directory when not using ChibiOS-Contrib +if(NOT CHIBIOS_CONTRIB_REQUIRED) + list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/dummy_includes) +endif() + +# OSHAL sources need to be added for ChibiOS RT-NIL or ThreadX depending on build +if(RTOS_CHIBIOS_CHECK) + set(OSHAL_PATH ${chibios_SOURCE_DIR}/os/hal/osal/rt-nil) +elseif(RTOS_THREADX_CHECK) + set(OSHAL_PATH ${CMAKE_SOURCE_DIR}/targets/ThreadX/ChibiOS/HAL) +else() + message(FATAL_ERROR "RTOS not configured to use ChibiOS HAL") +endif() + +# set include path for OSHAL header +list(APPEND CHIBIOS_HAL_INCLUDE_DIRS ${OSHAL_PATH}) + +# source files for ChibiOS HAL (RP2040) +set(CHIBIOS_HAL_SRCS + + # startup code + crt1.c + vectors.S + crt0_v6m.S + + # RP2040 2nd stage bootloader (required for XIP flash) + bs2_default_padded_checksummed.S + + # RP2040 platform-specific ISR and clock init + hal_lld.c + rp_clocks.c + rp_isr.c + rp_pll.c + rp_xosc.c + + # NVIC driver (common ARMCMx) + nvic.c + + # HAL-OSAL files + hal.c + hal_st.c + + hal_buffers.c + hal_queues.c + hal_flash.c + hal_mmcsd.c + hal_safety.c + + hal_adc.c + hal_can.c + hal_crypto.c + hal_dac.c + hal_efl.c + hal_gpt.c + hal_i2c.c + hal_i2s.c + hal_icu.c + hal_mac.c + hal_mmc_spi.c + hal_pal.c + hal_pwm.c + hal_rtc.c + hal_sdc.c + hal_serial.c + hal_serial_usb.c + hal_sio.c + hal_spi.c + hal_trng.c + hal_uart.c + hal_usb.c + hal_wdg.c + hal_wspi.c + + # RP2040 LLD (Low Level Driver) sources + hal_adc_lld.c + rp_dma.c + hal_pal_lld.c + hal_i2c_lld.c + hal_spi_lld.c + hal_st_lld.c + hal_pwm_lld.c + hal_sio_lld.c + hal_usb_lld.c + hal_wdg_lld.c + hal_efl_lld.c + rp_efl_lld.c + hal_rtc_lld.c + + # OSAL + osal.c + + board.c +) + +foreach(SRC_FILE ${CHIBIOS_HAL_SRCS}) + + set(CHIBIOS_HAL_SRC_FILE SRC_FILE -NOTFOUND) + + find_file(CHIBIOS_HAL_SRC_FILE ${SRC_FILE} + PATHS + + ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/compilers/GCC + ${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/smp/rp2 + ${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC + ${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/devices/RP2040 + + ${chibios_SOURCE_DIR}/os/hal/src + ${chibios_SOURCE_DIR}/os/hal/ports/common/ARMCMx + + # >>> To use nanoFramework overlay, uncomment next line and comment the one after <<< + # ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/ports/RP/LLD/EFLv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/EFLv1 + + ${chibios_SOURCE_DIR}/os/hal/ports/RP/RP2040 + + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/ADCv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/DMAv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/GPIOv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/I2Cv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/PIOv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/PWMv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/RTCv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/SPIv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/TIMERv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/UARTv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/USBv1 + ${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/WDGv1 + + ${OSHAL_PATH} + + ${CHIBIOS_BOARD_DEFINITIONS_PATH} + + CMAKE_FIND_ROOT_PATH_BOTH + ) + + if (BUILD_VERBOSE) + message("${SRC_FILE} >> ${CHIBIOS_HAL_SRC_FILE}") + endif() + + list(APPEND CHIBIOS_HAL_SOURCES ${CHIBIOS_HAL_SRC_FILE}) + +endforeach() + +# Suppress -Wshadow for ChibiOS ADC HAL (variable shadowing in macro expansion) +SET_SOURCE_FILES_PROPERTIES(${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/ADCv1/hal_adc_lld.c PROPERTIES COMPILE_FLAGS -Wno-shadow) + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ChibiOS_RP2040_HAL DEFAULT_MSG CHIBIOS_HAL_INCLUDE_DIRS CHIBIOS_HAL_SOURCES) diff --git a/CMake/Modules/FindChibiOSnfOverlay.cmake b/CMake/Modules/FindChibiOSnfOverlay.cmake index dd583aa398..59a442bb3b 100644 --- a/CMake/Modules/FindChibiOSnfOverlay.cmake +++ b/CMake/Modules/FindChibiOSnfOverlay.cmake @@ -9,18 +9,22 @@ list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_n #################################################################################### # WHEN ADDING A NEW CHIBIOS OVERLAY component add the include directory(ies) below #################################################################################### -# component STM32_FLASH -list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_flash) -# component STM32_CRC -list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_crc) -# component STM32_RNG -list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_rng) -# component STM32_FSMC (Flexible Memory Controller) -list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_fsmc) -# component STM32_ONEWIRE (One Wire driver) -list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_onewire) -# component STM32_QSPI (QSPI driver) -list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_qspi) + +# STM32-specific overlay components +if(TARGET_VENDOR STREQUAL "ST") + # component STM32_FLASH + list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_flash) + # component STM32_CRC + list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_crc) + # component STM32_RNG + list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_rng) + # component STM32_FSMC (Flexible Memory Controller) + list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_fsmc) + # component STM32_ONEWIRE (One Wire driver) + list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_onewire) + # component STM32_QSPI (QSPI driver) + list(APPEND ChibiOSnfOverlay_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/include/stm32_qspi) +endif() ################################################################################################################################## # Add above the required include directory(ies) for a new nanoFramework overlay component that you are adding @@ -41,18 +45,23 @@ list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-ove #################################################################################################### # WHEN ADDING A NEW CHIBIOS OVERLAY component add the source file(s) specific to this series below #################################################################################################### -# component STM32_FLASH -list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_flash/hal_stm32_flash.c) -# component STM32_CRC -list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_crc/hal_stm32_crc.c) -# component STM32_RNG -list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_rng/hal_stm32_rng.c) -# component STM32_FSMC (Flexible Memory Controller) -list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_fsmc/hal_stm32_fsmc.c) -# component STM32_ONEWIRE (One Wire driver) -list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_onewire/hal_stm32_onewire.c) -# component STM32_QSPI (QSPI driver) -list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_qspi/hal_stm32_qspi.c) + +# STM32-specific overlay sources +if(TARGET_VENDOR STREQUAL "ST") + # component STM32_FLASH + list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_flash/hal_stm32_flash.c) + # component STM32_CRC + list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_crc/hal_stm32_crc.c) + # component STM32_RNG + list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_rng/hal_stm32_rng.c) + # component STM32_FSMC (Flexible Memory Controller) + list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_fsmc/hal_stm32_fsmc.c) + # component STM32_ONEWIRE (One Wire driver) + list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_onewire/hal_stm32_onewire.c) + # component STM32_QSPI (QSPI driver) + list(APPEND ChibiOSnfOverlay_SOURCES ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_nf-overlay/os/hal/src/stm32_qspi/hal_stm32_qspi.c) +endif() + ######################################################################################################################### # Add above ALL the source code file(s) required for a new nanoFramework overlay component that you are adding diff --git a/CMake/Modules/FindSystem.Device.Adc.cmake b/CMake/Modules/FindSystem.Device.Adc.cmake index 5f8e53c7ee..5f815d79e4 100644 --- a/CMake/Modules/FindSystem.Device.Adc.cmake +++ b/CMake/Modules/FindSystem.Device.Adc.cmake @@ -12,6 +12,7 @@ list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Core) list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Include) list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/HAL/Include) list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/PAL/Include) +list(APPEND System.Device.Adc_INCLUDE_DIRS ${TARGET_BASE_LOCATION}) list(APPEND System.Device.Adc_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE}) list(APPEND System.Device.Adc_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device.Adc) @@ -31,8 +32,8 @@ foreach(SRC_FILE ${System.Device.Adc_SRCS}) find_file(System.Device.Adc_SRC_FILE ${SRC_FILE} PATHS - ${BASE_PATH_FOR_THIS_MODULE} ${TARGET_BASE_LOCATION} + ${BASE_PATH_FOR_THIS_MODULE} ${CMAKE_SOURCE_DIR}/src/System.Device.Adc CMAKE_FIND_ROOT_PATH_BOTH diff --git a/CMake/Modules/FindSystem.Device.I2c.cmake b/CMake/Modules/FindSystem.Device.I2c.cmake index 6ac123f009..8539427541 100644 --- a/CMake/Modules/FindSystem.Device.I2c.cmake +++ b/CMake/Modules/FindSystem.Device.I2c.cmake @@ -12,6 +12,7 @@ list(APPEND System.Device.I2c_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Core) list(APPEND System.Device.I2c_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Include) list(APPEND System.Device.I2c_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/HAL/Include) list(APPEND System.Device.I2c_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/PAL/Include) +list(APPEND System.Device.I2c_INCLUDE_DIRS ${TARGET_BASE_LOCATION}) list(APPEND System.Device.I2c_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE}) list(APPEND System.Device.I2c_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device.I2c) @@ -30,8 +31,8 @@ foreach(SRC_FILE ${System.Device.I2c_SRCS}) find_file(System.Device.I2c_SRC_FILE ${SRC_FILE} PATHS - ${BASE_PATH_FOR_THIS_MODULE} ${TARGET_BASE_LOCATION} + ${BASE_PATH_FOR_THIS_MODULE} ${CMAKE_SOURCE_DIR}/src/System.Device.I2c CMAKE_FIND_ROOT_PATH_BOTH diff --git a/CMake/Modules/FindSystem.Device.Pwm.cmake b/CMake/Modules/FindSystem.Device.Pwm.cmake index 6b437d7538..a2d7c9bd8c 100644 --- a/CMake/Modules/FindSystem.Device.Pwm.cmake +++ b/CMake/Modules/FindSystem.Device.Pwm.cmake @@ -12,6 +12,7 @@ list(APPEND System.Device.Pwm_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Core) list(APPEND System.Device.Pwm_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Include) list(APPEND System.Device.Pwm_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/HAL/Include) list(APPEND System.Device.Pwm_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/PAL/Include) +list(APPEND System.Device.Pwm_INCLUDE_DIRS ${TARGET_BASE_LOCATION}) list(APPEND System.Device.Pwm_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE}) list(APPEND System.Device.Pwm_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device.Pwm) @@ -30,8 +31,8 @@ foreach(SRC_FILE ${System.Device.Pwm_SRCS}) set(System.Device.Pwm_SRC_FILE SRC_FILE-NOTFOUND) find_file(System.Device.Pwm_SRC_FILE ${SRC_FILE} PATHS - ${BASE_PATH_FOR_THIS_MODULE} ${TARGET_BASE_LOCATION} + ${BASE_PATH_FOR_THIS_MODULE} ${CMAKE_SOURCE_DIR}/src/System.Device.Pwm CMAKE_FIND_ROOT_PATH_BOTH diff --git a/CMake/Modules/FindSystem.Device.Spi.cmake b/CMake/Modules/FindSystem.Device.Spi.cmake index d5d47cd77e..c2f620ff61 100644 --- a/CMake/Modules/FindSystem.Device.Spi.cmake +++ b/CMake/Modules/FindSystem.Device.Spi.cmake @@ -12,6 +12,7 @@ list(APPEND System.Device.Spi_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Core) list(APPEND System.Device.Spi_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/CLR/Include) list(APPEND System.Device.Spi_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/HAL/Include) list(APPEND System.Device.Spi_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/PAL/Include) +list(APPEND System.Device.Spi_INCLUDE_DIRS ${TARGET_BASE_LOCATION}) list(APPEND System.Device.Spi_INCLUDE_DIRS ${BASE_PATH_FOR_THIS_MODULE}) list(APPEND System.Device.Spi_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/System.Device.Spi) @@ -29,8 +30,8 @@ foreach(SRC_FILE ${System.Device.Spi_SRCS}) set(System.Device.Spi_SRC_FILE SRC_FILE-NOTFOUND) find_file(System.Device.Spi_SRC_FILE ${SRC_FILE} PATHS - ${BASE_PATH_FOR_THIS_MODULE} ${TARGET_BASE_LOCATION} + ${BASE_PATH_FOR_THIS_MODULE} ${CMAKE_SOURCE_DIR}/src/System.Device.Spi CMAKE_FIND_ROOT_PATH_BOTH diff --git a/CMake/Modules/FindSystem.Device.Wifi.cmake b/CMake/Modules/FindSystem.Device.Wifi.cmake index 9de343a640..21558b62d2 100644 --- a/CMake/Modules/FindSystem.Device.Wifi.cmake +++ b/CMake/Modules/FindSystem.Device.Wifi.cmake @@ -25,6 +25,7 @@ foreach(SRC_FILE ${System.Device.Wifi_SRCS}) find_file(System.Device.Wifi_SRC_FILE ${SRC_FILE} PATHS + ${CMAKE_SOURCE_DIR}/targets/${RTOS}/_nanoCLR/System.Device.Wifi ${BASE_PATH_FOR_THIS_MODULE} ${CMAKE_SOURCE_DIR}/src/System.Device.Wifi diff --git a/CMake/Modules/FindlwIP.cmake b/CMake/Modules/FindlwIP.cmake index 74372eaf29..f8e59ffc9e 100644 --- a/CMake/Modules/FindlwIP.cmake +++ b/CMake/Modules/FindlwIP.cmake @@ -8,7 +8,6 @@ FetchContent_GetProperties(lwip) # List of the required lwIp include files. list(APPEND lWIP_INCLUDE_DIRS ${lwip_SOURCE_DIR}/src/include/) -list(APPEND lWIP_INCLUDE_DIRS ${lwip_SOURCE_DIR}/src/include/lwip) list(APPEND lWIP_INCLUDE_DIRS ${lwip_SOURCE_DIR}/src/include/netif) list(APPEND lWIP_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src/DeviceInterfaces/Networking.Sntp) @@ -18,6 +17,12 @@ if(RTOS_CHIBIOS_CHECK) list(APPEND lWIP_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_lwIP) list(APPEND lWIP_INCLUDE_DIRS ${chibios_SOURCE_DIR}/os/various) + + # WiFi targets need additional includes + if(TARGET_HAS_WIFI) + list(APPEND lWIP_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi) + list(APPEND lWIP_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi/cyw43) + endif() elseif(RTOS_FREERTOS_CHECK) @@ -91,11 +96,15 @@ set(LWIP_SRCS nf_sockets.c nf_sys_arch.c - # bindings - nf_lwipthread.c - ) +# WiFi targets use a WiFi-specific lwIP thread; Ethernet targets use the standard one +if(TARGET_HAS_WIFI) + list(APPEND LWIP_SRCS nf_lwipthread_wifi.c) +else() + list(APPEND LWIP_SRCS nf_lwipthread.c) +endif() + if(NF_NETWORKING_SNTP) list(APPEND LWIP_SRCS sntp.c) @@ -110,6 +119,11 @@ if(RTOS_CHIBIOS_CHECK) list(APPEND LWIP_PLATFORM_LOCATION ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_lwIP) list(APPEND LWIP_PLATFORM_LOCATION ${chibios_SOURCE_DIR}/os/various) + # WiFi targets also need the _WiFi directory in the search path + if(TARGET_HAS_WIFI) + list(APPEND LWIP_PLATFORM_LOCATION ${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi) + endif() + elseif(RTOS_FREERTOS_CHECK) # platform implementation diff --git a/CMake/Scripts/bin2uf2/Program.cs b/CMake/Scripts/bin2uf2/Program.cs new file mode 100644 index 0000000000..41e9aa34e5 --- /dev/null +++ b/CMake/Scripts/bin2uf2/Program.cs @@ -0,0 +1,149 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// +// Converts binary firmware images to UF2 format for RP2040/RP2350 targets. +// UF2 specification: https://github.com/microsoft/uf2 +// +// Usage: +// Single file: bin2uf2 +// Merge files: bin2uf2 --merge [ ...] +// +// Family IDs: +// RP2040: 0xe48bff56 +// RP2350 (ARM): 0xe48bff59 +// RP2350 (RISC-V): 0xe48bff5a + +using System.Buffers.Binary; + +const uint UF2_MAGIC_START0 = 0x0A324655; // "UF2\n" +const uint UF2_MAGIC_START1 = 0x9E5D5157; +const uint UF2_MAGIC_END = 0x0AB16F30; +const uint UF2_FLAG_FAMILY = 0x00002000; +const int UF2_DATA_SIZE = 256; + +if (args.Length >= 5 && args[0] == "--merge") +{ + // --merge [ ...] + string outputPath = args[1]; + uint familyId = ParseHex(args[2]); + var pairs = args.AsSpan(3); + + if (pairs.Length % 2 != 0) + { + Console.Error.WriteLine("Error: --merge requires pairs of
"); + return 1; + } + + var allBlocks = new List<(uint addr, byte[] data, int len)>(); + + for (int i = 0; i < pairs.Length; i += 2) + { + byte[] bin = File.ReadAllBytes(pairs[i]); + uint baseAddr = ParseHex(pairs[i + 1]); + + // Pad gap between previous segment and this one with 0xFF + if (allBlocks.Count > 0) + { + var last = allBlocks[^1]; + uint nextExpected = last.addr + UF2_DATA_SIZE; + + if (baseAddr > nextExpected) + { + uint gapSize = baseAddr - nextExpected; + byte[] pad = new byte[UF2_DATA_SIZE]; + Array.Fill(pad, (byte)0xFF); + + for (uint off = 0; off < gapSize; off += UF2_DATA_SIZE) + { + allBlocks.Add((nextExpected + off, (byte[])pad.Clone(), UF2_DATA_SIZE)); + } + + Console.WriteLine($" Padded {gapSize} byte gap (0x{nextExpected:X8} -> 0x{baseAddr:X8})"); + } + } + + AddBlocks(allBlocks, bin, baseAddr); + } + + WriteUf2(outputPath, allBlocks, familyId); + Console.WriteLine($"Merged {pairs.Length / 2} binaries -> {outputPath} ({allBlocks.Count} blocks)"); +} +else if (args.Length == 4) +{ + // + string inputPath = args[0]; + uint baseAddr = ParseHex(args[1]); + uint familyId = ParseHex(args[2]); + string outputPath = args[3]; + + byte[] bin = File.ReadAllBytes(inputPath); + var blocks = new List<(uint addr, byte[] data, int len)>(); + AddBlocks(blocks, bin, baseAddr); + WriteUf2(outputPath, blocks, familyId); + Console.WriteLine($"Converted {inputPath} -> {outputPath} ({blocks.Count} blocks)"); +} +else +{ + Console.Error.WriteLine("Usage: bin2uf2 "); + Console.Error.WriteLine(" bin2uf2 --merge [ ...]"); + return 1; +} + +return 0; + +static void AddBlocks(List<(uint addr, byte[] data, int len)> blocks, byte[] bin, uint baseAddr) +{ + int offset = 0; + + while (offset < bin.Length) + { + int chunkLen = Math.Min(UF2_DATA_SIZE, bin.Length - offset); + byte[] chunk = new byte[UF2_DATA_SIZE]; // zero-padded to 256 + Buffer.BlockCopy(bin, offset, chunk, 0, chunkLen); + blocks.Add((baseAddr + (uint)offset, chunk, UF2_DATA_SIZE)); + offset += UF2_DATA_SIZE; + } +} + +static void WriteUf2(string path, List<(uint addr, byte[] data, int len)> blocks, uint familyId) +{ + uint totalBlocks = (uint)blocks.Count; + + using var fs = File.Create(path); + + Span block = stackalloc byte[512]; + + for (int i = 0; i < blocks.Count; i++) + { + var (addr, data, len) = blocks[i]; + + block.Clear(); + + // Header (32 bytes) + BinaryPrimitives.WriteUInt32LittleEndian(block[0..], UF2_MAGIC_START0); + BinaryPrimitives.WriteUInt32LittleEndian(block[4..], UF2_MAGIC_START1); + BinaryPrimitives.WriteUInt32LittleEndian(block[8..], UF2_FLAG_FAMILY); + BinaryPrimitives.WriteUInt32LittleEndian(block[12..], addr); + BinaryPrimitives.WriteUInt32LittleEndian(block[16..], (uint)len); + BinaryPrimitives.WriteUInt32LittleEndian(block[20..], (uint)i); + BinaryPrimitives.WriteUInt32LittleEndian(block[24..], totalBlocks); + BinaryPrimitives.WriteUInt32LittleEndian(block[28..], familyId); + + // Data (256 bytes at offset 32) + data.AsSpan(0, UF2_DATA_SIZE).CopyTo(block[32..]); + + // Footer (4 bytes at offset 508) + BinaryPrimitives.WriteUInt32LittleEndian(block[508..], UF2_MAGIC_END); + + fs.Write(block); + } +} + +static uint ParseHex(string s) +{ + if (s.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + s = s[2..]; + + return uint.Parse(s, System.Globalization.NumberStyles.HexNumber); +} diff --git a/CMake/Scripts/bin2uf2/bin2uf2.csproj b/CMake/Scripts/bin2uf2/bin2uf2.csproj new file mode 100644 index 0000000000..f67f521030 --- /dev/null +++ b/CMake/Scripts/bin2uf2/bin2uf2.csproj @@ -0,0 +1,9 @@ + + + + Exe + net8.0 + enable + + + diff --git a/CMake/binutils.ChibiOS.cmake b/CMake/binutils.ChibiOS.cmake index b9637690db..6f010edb01 100644 --- a/CMake/binutils.ChibiOS.cmake +++ b/CMake/binutils.ChibiOS.cmake @@ -59,6 +59,11 @@ function(nf_set_stm32_target_series) endfunction() +function(nf_set_rp_target_series) + # RP series names are simple (e.g. "RP2040", "RP2350") — use as-is for the short name + set(TARGET_SERIES_SHORT ${TARGET_SERIES} CACHE INTERNAL "RP target series short name") +endfunction() + # Add platform packages specific to ChibiOS # To be called from target CMakeList.txt # optional TARGET argument with target name @@ -81,14 +86,22 @@ macro(nf_add_platform_packages) find_package(CHIBIOS_FATFS REQUIRED QUIET) endif() - # littlefs - if(NF_FEATURE_USE_LITTLEFS_OPTION) - find_package(STM32F7_CubePackage REQUIRED QUIET) - find_package(LITTLEFS REQUIRED QUIET) + # STM32-specific packages (not needed for RP targets) + if(TARGET_VENDOR STREQUAL "ST") + # littlefs + if(NF_FEATURE_USE_LITTLEFS_OPTION) + find_package(STM32F7_CubePackage REQUIRED QUIET) + find_package(LITTLEFS REQUIRED QUIET) + endif() + + if(STM32_CUBE_PACKAGE_REQUIRED) + find_package(${TARGET_STM32_CUBE_PACKAGE}_CubePackage REQUIRED QUIET) + endif() endif() - if(STM32_CUBE_PACKAGE_REQUIRED) - find_package(${TARGET_STM32_CUBE_PACKAGE}_CubePackage REQUIRED QUIET) + # littlefs for non-STM32 targets (e.g. RP2040) + if(NOT TARGET_VENDOR STREQUAL "ST" AND NF_FEATURE_USE_LITTLEFS_OPTION) + find_package(LITTLEFS REQUIRED QUIET) endif() # packages specific for nanoBooter @@ -191,6 +204,13 @@ macro(nf_add_platform_dependencies target) # nF feature: networking if(USE_NETWORKING_OPTION) + # WiFi targets don't use the ChibiOS MAC HAL driver + if(TARGET_HAS_WIFI) + set(NF_NETWORK_EXTRA_DEFS "") + else() + set(NF_NETWORK_EXTRA_DEFS -DHAL_USE_MAC=TRUE) + endif() + nf_add_lib_network( BUILD_TARGET ${target} @@ -206,7 +226,7 @@ macro(nf_add_platform_dependencies target) ${CHIBIOS_FATFS_INCLUDE_DIRS} ${CHIBIOS_CONTRIB_INCLUDE_DIRS} ${${TARGET_STM32_CUBE_PACKAGE}_CubePackage_INCLUDE_DIRS} - EXTRA_COMPILE_DEFINITIONS -DHAL_USE_MAC=TRUE) + EXTRA_COMPILE_DEFINITIONS ${NF_NETWORK_EXTRA_DEFS}) add_dependencies(${target}.elf nano::NF_Network) @@ -293,13 +313,18 @@ macro(nf_add_platform_sources target) ${TARGET_CHIBIOS_COMMON_SOURCES} - ${${TARGET_STM32_CUBE_PACKAGE}_CubePackage_SOURCES} - ${CHIBIOS_HAL_SOURCES} ${CHIBIOS_SOURCES} ${ChibiOSnfOverlay_SOURCES} ) + # STM32 Cube package sources (only for ST vendor) + if(TARGET_VENDOR STREQUAL "ST") + target_sources(${target}.elf PUBLIC + ${${TARGET_STM32_CUBE_PACKAGE}_CubePackage_SOURCES} + ) + endif() + # sources specific to nanoBooter if(${target} STREQUAL ${NANOBOOTER_PROJECT_NAME}) diff --git a/CMake/binutils.common.cmake b/CMake/binutils.common.cmake index c0e0762f1b..e313da212a 100644 --- a/CMake/binutils.common.cmake +++ b/CMake/binutils.common.cmake @@ -241,6 +241,29 @@ macro(nf_add_common_sources) endmacro() +# generates a UF2 image from a binary file for RP2040/RP2350 targets +# uses the bin2uf2 C# tool (requires dotnet SDK) +# NOTE: The RP2040 ROM UF2 bootloader does not flash data after address gaps. +# bin2uf2 --merge automatically pads gaps with 0xFF to produce a continuous image. +function(nf_generate_uf2_package file1 address1 file2 address2 familyid outputfilename) + + add_custom_command( + + TARGET ${NANOCLR_PROJECT_NAME}.elf POST_BUILD + + COMMAND dotnet run --project ${CMAKE_SOURCE_DIR}/CMake/Scripts/bin2uf2 + -- --merge "${outputfilename}" "${familyid}" + "${file1}" "${address1}" + "${file2}" "${address2}" + + COMMENT "Generating combined UF2 image for RP2040/RP2350 (gap-free)" + ) + + # need to add a dependency of NANOCLR to NANOBOOTER because UF2 gen needs bin outputs of both targets + add_dependencies(${NANOCLR_PROJECT_NAME}.elf ${NANOBOOTER_PROJECT_NAME}.elf) + +endfunction() + function(nf_generate_dfu_package file1 address1 file2 address2 outputfilename) add_custom_command( @@ -604,6 +627,7 @@ macro(nf_setup_target_build_common) ${TARGET_BASE_LOCATION}/nanoCLR ${TARGET_BASE_LOCATION} ${CMAKE_BINARY_DIR}/targets/${RTOS}/${TARGET_BOARD} + ${CMAKE_BINARY_DIR}/targets/${RTOS}/${TARGET_VENDOR}/${TARGET_BOARD} ) # need to add extra include directories for MbedTLS @@ -633,7 +657,11 @@ macro(nf_setup_target_build_common) ) # platform implementation of hardware random provider - target_sources(mbedcrypto PRIVATE ${BASE_PATH_FOR_CLASS_LIBRARIES_MODULES}/mbedtls_entropy_hardware_pool.c) + if(EXISTS ${TARGET_BASE_LOCATION}/mbedtls_entropy_hardware_pool.c) + target_sources(mbedcrypto PRIVATE ${TARGET_BASE_LOCATION}/mbedtls_entropy_hardware_pool.c) + else() + target_sources(mbedcrypto PRIVATE ${BASE_PATH_FOR_CLASS_LIBRARIES_MODULES}/mbedtls_entropy_hardware_pool.c) + endif() nf_set_compile_options(TARGET mbedcrypto) nf_set_compile_options(TARGET mbedx509) @@ -847,3 +875,50 @@ function(nf_add_lwip_library) ######################################################################## endfunction() + +# CYW43 driver for WiFi targets (Pico W, etc.) +function(nf_add_cyw43_driver_library) + + # check if CYW43_DRIVER_SOURCE was specified or if it's empty (default is empty) + set(NO_CYW43_SOURCE TRUE) + + if(CYW43_DRIVER_SOURCE) + if(NOT ${CYW43_DRIVER_SOURCE} STREQUAL "") + set(NO_CYW43_SOURCE FALSE) + endif() + endif() + + # set tag for currently supported version + set(CYW43_DRIVER_GIT_TAG "main") + + if(NO_CYW43_SOURCE) + # no CYW43 source specified, download it from its repo + message(STATUS "CYW43 driver from GitHub repo") + + FetchContent_Declare( + cyw43_driver + GIT_REPOSITORY https://github.com/georgerobotics/cyw43-driver.git + GIT_TAG ${CYW43_DRIVER_GIT_TAG} + GIT_SHALLOW TRUE + GIT_CONFIG "core.fileMode=false" + ) + + else() + # CYW43 source was specified + message(STATUS "CYW43 driver (source from: ${CYW43_DRIVER_SOURCE})") + + FetchContent_Declare( + cyw43_driver + SOURCE_DIR ${CYW43_DRIVER_SOURCE} + ) + + endif() + + # Check if population has already been performed + FetchContent_GetProperties(cyw43_driver) + + if(NOT cyw43_driver_POPULATED) + FetchContent_MakeAvailable(cyw43_driver) + endif() + +endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c78476b4d..7c16098a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,8 +552,10 @@ endif() if(USE_NETWORKING_OPTION) - if(RTOS_CHIBIOS_CHECK) + if(RTOS_CHIBIOS_CHECK AND NOT TARGET_HAS_WIFI) set(HAL_USE_MAC_OPTION TRUE CACHE INTERNAL "HAL MAC for USE_NETWORKING_OPTION, ChibiOS only") + else() + set(HAL_USE_MAC_OPTION FALSE CACHE INTERNAL "HAL MAC disabled for WiFi targets") endif() if(NF_SECURITY_MBEDTLS) @@ -642,7 +644,8 @@ endif() ######################################################## # check availability of hex2dfu tool if specified # only required for CHIBIOS and ThreadX -if(DEFINED TOOL_HEX2DFU_PREFIX AND (RTOS_THREADX_CHECK OR RTOS_CHIBIOS_CHECK)) +# hex2dfu is only needed for ChibiOS STM32/ThreadX targets; RP2040 uses UF2 +if(DEFINED TOOL_HEX2DFU_PREFIX AND (RTOS_THREADX_CHECK OR (RTOS_CHIBIOS_CHECK AND NOT TARGET_SERIES STREQUAL "RP2040"))) if(NOT EXISTS ${TOOL_HEX2DFU_PREFIX}/hex2dfu.exe AND NOT EXISTS ${TOOL_HEX2DFU_PREFIX}/hex2dfu) message(STATUS "") message(STATUS "Couldn't find the hex2dfu tool at the specified path: ${TOOL_HEX2DFU_PREFIX}/hex2dfu.exe or ${TOOL_HEX2DFU_PREFIX}/hex2dfu") diff --git a/Kconfig.features b/Kconfig.features index a99b2bba98..0915b59245 100644 --- a/Kconfig.features +++ b/Kconfig.features @@ -53,6 +53,10 @@ config NF_FEATURE_HAS_USB_MSD default n select API_SYSTEM_IO_FILESYSTEM +config TARGET_HAS_WIFI + bool "Target has WiFi hardware" + default n + config NF_FEATURE_WATCHDOG bool "Hardware watchdog" default y diff --git a/azure-pipelines-templates/build-chibios-rp-targets.yml b/azure-pipelines-templates/build-chibios-rp-targets.yml new file mode 100644 index 0000000000..10c5290a22 --- /dev/null +++ b/azure-pipelines-templates/build-chibios-rp-targets.yml @@ -0,0 +1,24 @@ +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. + +parameters: + - name: repoDirectory + type: string + default: $(Build.SourcesDirectory) + +steps: + - template: setup-cmake-user-presets.yml + parameters: + repoDirectory: ${{ parameters.repoDirectory }} + + - task: CMake@1 + displayName: Setup CMake build (RP target) + inputs: + cmakeArgs: "--preset $(CMakePreset) -DCMAKE_BUILD_TYPE=MinSizeRel -DBUILD_VERSION=$(NBGV_VersionMajor).$(NBGV_VersionMinor).$(NBGV_BuildNumber).$(TARGET_BUILD_COUNTER) -DTARGET_NAME=$(TargetPublishName) $(BuildOptions) " + workingDirectory: ${{ parameters.repoDirectory }} + + - task: CMake@1 + displayName: Build with CMake + inputs: + cmakeArgs: "--build --preset $(CMakePreset) --target all --config MinSizeRel" + workingDirectory: ${{ parameters.repoDirectory }} diff --git a/azure-pipelines-templates/pack-publish-artifacts.yml b/azure-pipelines-templates/pack-publish-artifacts.yml index 2fb4d48a23..83befb934d 100644 --- a/azure-pipelines-templates/pack-publish-artifacts.yml +++ b/azure-pipelines-templates/pack-publish-artifacts.yml @@ -16,6 +16,7 @@ steps: *.bin *.hex *.dfu + *.uf2 *.csv TargetFolder: '$(Build.ArtifactStagingDirectory)\$(TargetPublishName)' flattenFolders: true diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e156a04104..f47a582833 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -441,6 +441,67 @@ jobs: - template: azure-pipelines-templates/publish-cloudsmith.yml - template: azure-pipelines-templates/pack-publish-managed-helpers.yml + ###################### + # ChibiOS RP targets + - job: Build_ChibiOS_RP_targets + condition: >- + or( + and( + succeeded('Check_Code_Style'), + ne( dependencies.Check_Build_Options.outputs['BuildOptions.SKIP_BUILD'], true ), + or( + eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_ALL'], true), + eq(dependencies.Check_Build_Options.outputs['TargetsToBuild.BUILD_CHIBIOS'], true) + ) + ), + and( + eq(variables['Build.Reason'], 'Manual'), + or( + eq(variables['BUILD_ALL__'], 'true'), + eq(variables['BUILD_CHIBIOS__'], 'true') + ) + ) + ) + + dependsOn: + - Check_Build_Options + - Check_Code_Style + + pool: + vmImage: "windows-2022" + + strategy: + matrix: + RP_PICO_RP2040: + TargetBoard: RP_PICO_RP2040 + TargetSeries: "RP2040" + BuildOptions: + CMakePreset: RP_PICO_RP2040 + RP_PICO_W_RP2040: + TargetBoard: RP_PICO_W_RP2040 + TargetSeries: "RP2040" + BuildOptions: + CMakePreset: RP_PICO_W_RP2040 + + variables: + DOTNET_NOLOGO: true + # creates a counter and assigns it to the revision variable + REVISION: $[counter('RP_1_0_0_versioncounter', 0)] + HelperPackageVersion: $[counter('HelperPackageVersioncounter', 0)] + TargetPlatform: "rp" + + steps: + - template: azure-pipelines-templates/build-preparations.yml + - template: azure-pipelines-templates/nb-gitversioning.yml + - template: azure-pipelines-templates/download-install-arm-gcc-toolchain.yml + - template: azure-pipelines-templates/install-kconfig-tools.yml + - template: azure-pipelines-templates/validate-kconfig.yml + parameters: + targetPreset: $(CMakePreset) + - template: azure-pipelines-templates/build-chibios-rp-targets.yml + - template: azure-pipelines-templates/pack-publish-artifacts.yml + - template: azure-pipelines-templates/publish-cloudsmith.yml + ################# # ESP32 targets - job: Build_ESP32_targets @@ -1342,6 +1403,7 @@ jobs: - job: Report_Build_Failure dependsOn: - Build_STM32_targets + - Build_ChibiOS_RP_targets - Build_ESP32_targets - Build_NXP_targets - Build_TI_SimpleLink_targets @@ -1354,6 +1416,7 @@ jobs: ne( dependencies.Check_Code_Style.outputs['Check_Code_Style.CODE_STYLE_CHECK_FAILED'], true), or( failed('Build_STM32_targets'), + failed('Build_ChibiOS_RP_targets'), failed('Build_ESP32_targets'), failed('Build_NXP_targets'), failed('Build_TI_SimpleLink_targets'), diff --git a/src/CLR/Debugger/Debugger.cpp b/src/CLR/Debugger/Debugger.cpp index 520cbc2af2..0450050ed9 100644 --- a/src/CLR/Debugger/Debugger.cpp +++ b/src/CLR/Debugger/Debugger.cpp @@ -1037,6 +1037,8 @@ bool CLR_DBG_Debugger::Monitor_EraseMemory(WP_Message *msg) { NATIVE_PROFILE_CLR_DEBUGGER(); + (void)msg; + CLR_DBG_Commands_Monitor_EraseMemory *cmd = (CLR_DBG_Commands_Monitor_EraseMemory *)msg->m_payload; CLR_DBG_Commands_Monitor_EraseMemory_Reply cmdReply; uint32_t errorCode; diff --git a/src/HAL/nanoHAL_SystemEvents.c b/src/HAL/nanoHAL_SystemEvents.c index 91630f1031..ac8f6d903f 100644 --- a/src/HAL/nanoHAL_SystemEvents.c +++ b/src/HAL/nanoHAL_SystemEvents.c @@ -5,7 +5,7 @@ #include #include -#ifdef __CM0_CMSIS_VERSION +#if defined(__CM0_CMSIS_VERSION) || defined(__CM0PLUS_CMSIS_VERSION) #include #endif @@ -30,7 +30,7 @@ __nfweak bool SystemState_QueryNoLock(SYSTEM_STATE_type state) __nfweak void SystemState_Set(SYSTEM_STATE_type state) { -#ifdef __CM0_CMSIS_VERSION +#if defined(__CM0_CMSIS_VERSION) || defined(__CM0PLUS_CMSIS_VERSION) GLOBAL_LOCK(); SystemState_SetNoLock(state); GLOBAL_UNLOCK(); @@ -41,7 +41,7 @@ __nfweak void SystemState_Set(SYSTEM_STATE_type state) __nfweak void SystemState_Clear(SYSTEM_STATE_type state) { -#ifdef __CM0_CMSIS_VERSION +#if defined(__CM0_CMSIS_VERSION) || defined(__CM0PLUS_CMSIS_VERSION) GLOBAL_LOCK(); SystemState_ClearNoLock(state); GLOBAL_UNLOCK(); @@ -52,7 +52,7 @@ __nfweak void SystemState_Clear(SYSTEM_STATE_type state) __nfweak bool SystemState_Query(SYSTEM_STATE_type state) { -#if defined(__CM0_CMSIS_VERSION) +#if defined(__CM0_CMSIS_VERSION) || defined(__CM0PLUS_CMSIS_VERSION) return (SystemStates[state] > 0) ? true : false; #else return (__atomic_load_n(&SystemStates[state], __ATOMIC_RELAXED) > 0) ? true : false; diff --git a/src/PAL/Events/nanoPAL_Events.cpp b/src/PAL/Events/nanoPAL_Events.cpp index 05c0a9c88a..9343827316 100644 --- a/src/PAL/Events/nanoPAL_Events.cpp +++ b/src/PAL/Events/nanoPAL_Events.cpp @@ -28,7 +28,7 @@ __nfweak void Events_Set(uint32_t events) NATIVE_PROFILE_PAL_EVENTS(); // set events atomically -#ifdef __CM0_CMSIS_VERSION +#if defined(__CM0_CMSIS_VERSION) || defined(__CM0PLUS_CMSIS_VERSION) GLOBAL_LOCK(); systemEvents |= events; GLOBAL_UNLOCK(); @@ -48,7 +48,7 @@ __nfweak uint32_t Events_Get(uint32_t eventsOfInterest) // ... clear the requested flags atomically // give the caller notice of just the events they asked for ( and were cleared already ) -#ifdef __CM0_CMSIS_VERSION +#if defined(__CM0_CMSIS_VERSION) || defined(__CM0PLUS_CMSIS_VERSION) // get the requested flags from system events state and... uint32_t returnEvents = (systemEvents & eventsOfInterest); diff --git a/src/PAL/Lwip/lwIP_Sockets.cpp b/src/PAL/Lwip/lwIP_Sockets.cpp index 9e76b61b70..74c3b3f816 100644 --- a/src/PAL/Lwip/lwIP_Sockets.cpp +++ b/src/PAL/Lwip/lwIP_Sockets.cpp @@ -1221,12 +1221,20 @@ HRESULT LWIP_SOCKETS_Driver::LoadAdapterConfiguration( { NATIVE_PROFILE_PAL_NETWORK(); - if (config->StartupAddressMode == AddressMode_DHCP) + struct netif *networkInterface = + netif_find_interface(g_LWIP_SOCKETS_Driver.m_interfaces[interfaceIndex].m_interfaceNumber); + + if (networkInterface != NULL) { - struct netif *networkInterface; + // Always copy the MAC from the live netif — the config block pointer + // may reference read-only flash (e.g. XIP on RP2040) where runtime + // updates via memcpy are silently ignored. + memcpy(config->MacAddress, networkInterface->hwaddr, NETIF_MAX_HWADDR_LEN); + } - if ((networkInterface = - netif_find_interface(g_LWIP_SOCKETS_Driver.m_interfaces[interfaceIndex].m_interfaceNumber))) + if (config->StartupAddressMode == AddressMode_DHCP) + { + if (networkInterface != NULL) { #if LWIP_IPV6 config->IPv4Address = networkInterface->ip_addr.u_addr.ip4.addr; diff --git a/targets/ChibiOS/CMakeLists.txt b/targets/ChibiOS/CMakeLists.txt index 060eae19ae..3b4bb09f9a 100644 --- a/targets/ChibiOS/CMakeLists.txt +++ b/targets/ChibiOS/CMakeLists.txt @@ -7,28 +7,44 @@ include(FetchContent) include(binutils.common) include(binutils.arm-none-eabi) include(binutils.ChibiOS) -include(STM32_CubePackage) -# Set target series -nf_set_stm32_target_series() +# Set target series based on vendor +# TARGET_SERIES is set by the board preset (e.g., "STM32F4xx" or "RP2040") +# Detect vendor from TARGET_SERIES before calling series-specific setup +string(SUBSTRING "${TARGET_SERIES}" 0 3 _TARGET_SERIES_PREFIX) + +if("${_TARGET_SERIES_PREFIX}" STREQUAL "STM") + set(TARGET_VENDOR "ST" CACHE INTERNAL "target vendor is ST") + set(HAL_NF_USE_STM32_CRC_OPTION TRUE CACHE INTERNAL "STM32 CRC hardware available") + include(STM32_CubePackage) + nf_set_stm32_target_series() +elseif("${_TARGET_SERIES_PREFIX}" STREQUAL "RP2") + set(TARGET_VENDOR "RP" CACHE INTERNAL "target vendor is Raspberry Pi") + set(HAL_NF_USE_STM32_CRC_OPTION FALSE CACHE INTERNAL "STM32 CRC hardware not available") + nf_set_rp_target_series() +else() + message(FATAL_ERROR "Unsupported TARGET_SERIES prefix: ${TARGET_SERIES}") +endif() # Define PLATFORM base path set(BASE_PATH_FOR_PLATFORM ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE) ######################################################## -# check availability of hex2dfu tool if specified -if(DEFINED TOOL_HEX2DFU_PREFIX) - if(NOT EXISTS ${TOOL_HEX2DFU_PREFIX}/hex2dfu.exe AND NOT EXISTS ${TOOL_HEX2DFU_PREFIX}/hex2dfu) - message(STATUS "") - message(STATUS "Couldn't find the hex2dfu tool at the specified path: ${TOOL_HEX2DFU_PREFIX}/hex2dfu.exe or ${TOOL_HEX2DFU_PREFIX}/hex2dfu") - message(STATUS "Make sure that the CMake option TOOL_HEX2DFU_PREFIX has the correct path.") - message(STATUS "If you don't have this tool download it from https://github.com/nanoframework/nf-tools/releases") - message(STATUS "") - message(FATAL_ERROR "hex2dfu tool not found") - else() - set(HEX2DFU_TOOL_AVAILABLE TRUE CACHE INTERNAL "hex2dfu tool available") +# check availability of hex2dfu tool if specified (STM32 only — RP targets use UF2 format) +if("${TARGET_VENDOR}" STREQUAL "ST") + if(DEFINED TOOL_HEX2DFU_PREFIX) + if(NOT EXISTS ${TOOL_HEX2DFU_PREFIX}/hex2dfu.exe AND NOT EXISTS ${TOOL_HEX2DFU_PREFIX}/hex2dfu) + message(STATUS "") + message(STATUS "Couldn't find the hex2dfu tool at the specified path: ${TOOL_HEX2DFU_PREFIX}/hex2dfu.exe or ${TOOL_HEX2DFU_PREFIX}/hex2dfu") + message(STATUS "Make sure that the CMake option TOOL_HEX2DFU_PREFIX has the correct path.") + message(STATUS "If you don't have this tool download it from https://github.com/nanoframework/nf-tools/releases") + message(STATUS "") + message(FATAL_ERROR "hex2dfu tool not found") + else() + set(HEX2DFU_TOOL_AVAILABLE TRUE CACHE INTERNAL "hex2dfu tool available") + endif() # hex2dfu tool check endif() -endif() +endif() # TARGET_VENDOR STREQUAL "ST" ######################################################## # check availability of SRecord tool, if specified @@ -79,26 +95,40 @@ if(RTOS_VERSION_EMPTY) set(RTOS_VERSION "stable_21.11.x") endif() -if(NO_CHIBIOS_SOURCE_FOLDER) - # no CHIBIOS source specified, download it from it's repo - message(STATUS "RTOS is: ChibiOS ${RTOS_VERSION} from SVN official repo") +if(NOT NO_CHIBIOS_SOURCE_FOLDER) + # ChibiOS source was specified + message(STATUS "RTOS is: ChibiOS ${RTOS_VERSION} (source from: ${CHIBIOS_SOURCE_FOLDER})") FetchContent_Declare( chibios - SVN_REPOSITORY http://svn.code.sf.net/p/chibios/code/branches/${RTOS_VERSION} - SVN_REVISION -rHEAD + SOURCE_DIR ${CHIBIOS_SOURCE_FOLDER} ) -else() - # ChibiOS source was specified +elseif(CHIBIOS_GIT_REPOSITORY) + # ChibiOS from Git repository (used for RP targets that need master branch) + if(NOT CHIBIOS_GIT_TAG) + set(CHIBIOS_GIT_TAG "master") + endif() + + message(STATUS "RTOS is: ChibiOS ${CHIBIOS_GIT_TAG} from GitHub (${CHIBIOS_GIT_REPOSITORY})") - message(STATUS "RTOS is: ChibiOS ${RTOS_VERSION} (source from: ${CHIBIOS_SOURCE_FOLDER})") FetchContent_Declare( chibios - SOURCE_DIR ${CHIBIOS_SOURCE_FOLDER} + GIT_REPOSITORY ${CHIBIOS_GIT_REPOSITORY} + GIT_TAG ${CHIBIOS_GIT_TAG} + GIT_SHALLOW ON ) +else() + # no CHIBIOS source specified, download it from it's repo + message(STATUS "RTOS is: ChibiOS ${RTOS_VERSION} from SVN official repo") + + FetchContent_Declare( + chibios + SVN_REPOSITORY http://svn.code.sf.net/p/chibios/code/branches/${RTOS_VERSION} + SVN_REVISION -rHEAD + ) endif() @@ -214,6 +244,11 @@ if(USE_NETWORKING_OPTION) nf_add_lwip_library() + # if this is a WiFi target (e.g. Pico W), also fetch the CYW43 driver + if(TARGET_HAS_WIFI) + nf_add_cyw43_driver_library() + endif() + endif() @@ -327,8 +362,9 @@ else() endif() # (default is OFF so STM Cube package is NOT included) +# Only applicable to ST vendor targets option(STM32_CUBE_PACKAGE_REQUIRED "option to include STM Cube pcakge in the build") -if(STM32_CUBE_PACKAGE_REQUIRED) +if(STM32_CUBE_PACKAGE_REQUIRED AND "${TARGET_VENDOR}" STREQUAL "ST") ProcessSTM32CubePackage() endif() diff --git a/targets/ChibiOS/CMakePresets.json b/targets/ChibiOS/CMakePresets.json index fa46b8d28a..a098ad56b0 100644 --- a/targets/ChibiOS/CMakePresets.json +++ b/targets/ChibiOS/CMakePresets.json @@ -4,6 +4,8 @@ "MXCHIP_AZ3166/CMakePresets.json", "ORGPAL_PALTHREE/CMakePresets.json", "ORGPAL_PALX/CMakePresets.json", + "RP_PICO_RP2040/CMakePresets.json", + "RP_PICO_W_RP2040/CMakePresets.json", "ST_NUCLEO64_F091RC/CMakePresets.json", "ST_STM32F429I_DISCOVERY/CMakePresets.json", "ST_STM32F769I_DISCOVERY/CMakePresets.json" diff --git a/targets/ChibiOS/RP_PICO_RP2040/CMakeLists.txt b/targets/ChibiOS/RP_PICO_RP2040/CMakeLists.txt new file mode 100644 index 0000000000..e87dd9dc16 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/CMakeLists.txt @@ -0,0 +1,57 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +include(FetchContent) +FetchContent_GetProperties(chibios) + +include(binutils.common) +include(binutils.ChibiOS) + +# shared RP2040 sources and include directory +set(RP2040_COMMON "${CMAKE_SOURCE_DIR}/targets/ChibiOS/_RP2040") +list(APPEND CMAKE_PREFIX_PATH "${RP2040_COMMON}") +list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${RP2040_COMMON}") +list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${RP2040_COMMON}/common") + +# RP2040 flash driver and common sources from shared directory +list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${RP2040_COMMON}/Target_BlockStorage_RP2040FlashDriver.c") +list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${RP2040_COMMON}/target_stubs.cpp") + +# target include directories +list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") + +nf_setup_target_build( + HAS_NANOBOOTER + + BOOTER_LINKER_FILE + RP2040_booter + + CLR_LINKER_FILE + RP2040_CLR + + CLR_EXTRA_COMPILE_DEFINITIONS + -DRUNTIME_MEMORY_PROFILE__small=1 + -DTARGET_XIP_FLASH_BLOCKS_USB=1 + LFS_CONFIG=lfs_config.h + + BOOTER_EXTRA_LINKMAP_PROPERTIES + ",--library-path=${CMAKE_SOURCE_DIR}/targets/ChibiOS/_common,--library-path=${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC/ld,--defsym=__main_stack_size__=0x400,--defsym=__process_stack_size__=0x400,--defsym=__crt_heap_size__=0x1000" + + CLR_EXTRA_LINKMAP_PROPERTIES + ",--library-path=${CMAKE_SOURCE_DIR}/targets/ChibiOS/_common,--library-path=${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC/ld,--defsym=__main_stack_size__=0x400,--defsym=__process_stack_size__=0x800,--defsym=__crt_heap_size__=0x4000" +) + +#################################################################################################### +## RP2040 UF2 output generation ## +## Addresses must match the linker scripts (RP2040_booter.ld / RP2040_CLR.ld) ## +## RP2040 UF2 family ID: 0xe48bff56 ## +#################################################################################################### + +nf_generate_uf2_package( + ${CMAKE_BINARY_DIR}/${NANOBOOTER_PROJECT_NAME}.bin 0x10000000 + ${CMAKE_BINARY_DIR}/${NANOCLR_PROJECT_NAME}.bin 0x10014000 + 0xe48bff56 + ${CMAKE_BINARY_DIR}/nanoCLR.uf2 +) diff --git a/targets/ChibiOS/RP_PICO_RP2040/CMakePresets.json b/targets/ChibiOS/RP_PICO_RP2040/CMakePresets.json new file mode 100644 index 0000000000..e0165bdbdd --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/CMakePresets.json @@ -0,0 +1,32 @@ +{ + "version": 4, + "include": [ + "../../../CMake/arm-gcc.json", + "../../../config/user-tools-repos.json", + "../../../config/user-prefs.json" + ], + "configurePresets": [ + { + "name": "RP_PICO_RP2040", + "inherits": [ + "arm-gcc-cortex-preset", + "user-tools-repos", + "user-prefs" + ], + "hidden": false, + "cacheVariables": { + "NF_TARGET_DEFCONFIG": "targets/ChibiOS/RP_PICO_RP2040/defconfig", + "CHIBIOS_GIT_REPOSITORY": "https://github.com/ChibiOS/ChibiOS.git", + "CHIBIOS_GIT_TAG": "master" + } + } + ], + "buildPresets": [ + { + "inherits": "base-user", + "name": "RP_PICO_RP2040", + "displayName": "RP_PICO_RP2040", + "configurePreset": "RP_PICO_RP2040" + } + ] +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/README.md b/targets/ChibiOS/RP_PICO_RP2040/README.md new file mode 100644 index 0000000000..4418093ff4 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/README.md @@ -0,0 +1,190 @@ +# Raspberry Pi Pico (RP2040) — nanoFramework Target + +## Overview + +This target supports the **Raspberry Pi Pico** board with the RP2040 microcontroller running ChibiOS/RT. + +- **MCU:** RP2040 — Dual-core ARM Cortex-M0+ @ 125 MHz +- **RAM:** 264 KB SRAM +- **Flash:** 2 MB XIP (execute-in-place) +- **RTOS:** ChibiOS/RT (single-core) + +## Flashing + +The RP2040 uses **UF2 (USB Flashing Format)**. To flash: + +1. Hold the **BOOTSEL** button on the Pico while plugging in USB +2. The Pico appears as a USB mass storage device (`RPI-RP2`) +3. Drag and drop the `nanoCLR.uf2` file onto the drive +4. The Pico reboots automatically and runs nanoFramework + +The `nanoCLR.uf2` file contains both **nanoBooter** and **nanoCLR** combined. + +## Memory Layout + +| Region | Start Address | Size | Description | +|--------|--------------|------|-------------| +| nanoBooter | `0x10000000` | 64 KB | Boot loader | +| Config | `0x10010000` | 32 KB | Configuration block | +| nanoCLR | `0x10018000` | 928 KB | CLR runtime + managed assemblies | +| Deployment | `0x10100000` | 1 MB | Managed application deployment | + +## Pin Mapping + +### GPIO + +All 30 GPIO pins (GP0–GP29) are available. Pin numbers in nanoFramework correspond directly to RP2040 GPIO numbers. + +```csharp +// Example: Blink the on-board LED (GP25 on Pico) +var led = new GpioController(); +var pin = led.OpenPin(25, PinMode.Output); +pin.Write(PinValue.High); +``` + +### SPI Bus Configuration + +| Bus | Function | GPIO | Pico Pin | +|-----|----------|------|----------| +| SPI0 | SCK | GP18 | 24 | +| SPI0 | MOSI | GP19 | 25 | +| SPI0 | MISO | GP16 | 21 | +| SPI1 | SCK | GP10 | 14 | +| SPI1 | MOSI | GP11 | 15 | +| SPI1 | MISO | GP12 | 16 | + +```csharp +// SPI0 example +var settings = new SpiConnectionSettings(0, chipSelectPin); // bus 0 = SPI0 +settings.ClockFrequency = 1_000_000; +var spi = SpiDevice.Create(settings); +``` + +### I2C Bus Configuration + +| Bus | Function | GPIO | Pico Pin | +|-----|----------|------|----------| +| I2C0 | SDA | GP4 | 6 | +| I2C0 | SCL | GP5 | 7 | +| I2C1 | SDA | GP6 | 9 | +| I2C1 | SCL | GP7 | 10 | + +```csharp +// I2C0 example (bus index 0) +var settings = new I2cConnectionSettings(0, 0x48); // bus 0 = I2C0 +var device = I2cDevice.Create(settings); +``` + +> **Note:** I2C buses are 0-indexed on RP2040. Bus 0 = I2C0, Bus 1 = I2C1. + +### PWM + +RP2040 has 8 PWM slices with 2 channels each (A and B). The pin-to-PWM mapping follows a simple formula: + +- **Slice** = GPIO number / 2 +- **Channel** = GPIO number % 2 (0 = A, 1 = B) + +| GPIO | Slice | Channel | GPIO | Slice | Channel | +|------|-------|---------|------|-------|---------| +| GP0 | 0 | A | GP1 | 0 | B | +| GP2 | 1 | A | GP3 | 1 | B | +| GP4 | 2 | A | GP5 | 2 | B | +| GP6 | 3 | A | GP7 | 3 | B | +| GP8 | 4 | A | GP9 | 4 | B | +| GP10 | 5 | A | GP11 | 5 | B | +| GP12 | 6 | A | GP13 | 6 | B | +| GP14 | 7 | A | GP15 | 7 | B | +| GP16 | 0 | A | GP17 | 0 | B | +| GP18 | 1 | A | GP19 | 1 | B | +| GP20 | 2 | A | GP21 | 2 | B | +| GP22 | 3 | A | GP23 | 3 | B | +| GP24 | 4 | A | GP25 | 4 | B | +| GP26 | 5 | A | GP27 | 5 | B | +| GP28 | 6 | A | GP29 | 6 | B | + +```csharp +// PWM on GP25 (on-board LED) — Slice 4, Channel B +var pwm = PwmChannel.CreateUnstarted(4, 25); // timer=4 (slice), pin=25 +pwm.Frequency = 1000; +pwm.DutyCycle = 0.5; +pwm.Start(); +``` + +> **Note:** Two GPIOs sharing the same slice share the same frequency but can have different duty cycles. + +### ADC + +| Channel | GPIO | Pico Pin | Description | +|---------|------|----------|-------------| +| 0 | GP26 | 31 | ADC0 | +| 1 | GP27 | 32 | ADC1 | +| 2 | GP28 | 34 | ADC2 | +| 3 | GP29 | — | ADC3 (VSYS/3 on Pico board) | +| 4 | — | — | Internal temperature sensor | + +```csharp +// Read ADC channel 0 (GP26) +var adc = new AdcController(); +var channel = adc.OpenChannel(0); +int value = channel.ReadValue(); // 0–4095 (12-bit) + +// Read internal temperature sensor (channel 4) +var tempChannel = adc.OpenChannel(4); +int raw = tempChannel.ReadValue(); +// Temperature (°C) ≈ 27 - (raw * 3.3 / 4096 - 0.706) / 0.001721 +``` + +- **Resolution:** 12-bit (0–4095) +- **Reference voltage:** 3.3V (internal) + +## Pico Board Pinout Reference + +``` + ┌──────────────────┐ + GP0 │ 1 40 │ VBUS + GP1 │ 2 39 │ VSYS + GND │ 3 38 │ GND + GP2 │ 4 37 │ 3V3_EN + GP3 │ 5 36 │ 3V3 + GP4 │ 6 ┌─────┐ 35 │ ADC_VREF + GP5 │ 7 │ USB │ 34 │ GP28 (ADC2) + GND │ 8 └─────┘ 33 │ GND + GP6 │ 9 32 │ GP27 (ADC1) + GP7 │10 31 │ GP26 (ADC0) + GP8 │11 30 │ RUN + GP9 │12 29 │ GP22 + GND │13 28 │ GND + GP10 │14 27 │ GP21 + GP11 │15 26 │ GP20 + GP12 │16 25 │ GP19 + GP13 │17 24 │ GP18 + GND │18 23 │ GND + GP14 │19 22 │ GP17 + GP15 │20 21 │ GP16 + └──────────────────┘ + + On-board LED: GP25 +``` + +## Known Limitations + +- **No hardware TRNG:** RP2040 lacks a true random number generator. `USE_RNG` is disabled. +- **No FPU:** Cortex-M0+ has no floating-point unit. Floating-point operations use software emulation. +- **Single GPIO bank:** All 30 pins are in one bank (`IOPORT1`). +- **ADC channel 3 (GP29):** On the standard Pico board, this pin is connected to VSYS/3 (power supply monitoring). It can still be used as a general ADC input on custom boards. +- **SPI/I2C pin flexibility:** The default pin assignments are for the standard Pico board. RP2040 supports flexible pin routing — custom boards may use different GPIO assignments. + +## Build Configuration + +Key CMake preset options (`CMakePresets.json`): + +```json +{ + "API_System.Device.Gpio": "ON", + "API_System.Device.Spi": "ON", + "API_System.Device.I2c": "ON", + "API_System.Device.Pwm": "ON", + "API_System.Device.Adc": "ON", + "USE_RNG": "OFF" +} +``` diff --git a/targets/ChibiOS/RP_PICO_RP2040/common/CMakeLists.txt b/targets/ChibiOS/RP_PICO_RP2040/common/CMakeLists.txt new file mode 100644 index 0000000000..1c5d5c00d0 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/common/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# append common source files (usbcfg.c from shared _RP2040) +list(APPEND COMMON_PROJECT_SOURCES "${CMAKE_SOURCE_DIR}/targets/ChibiOS/_RP2040/common/usbcfg.c") +list(APPEND COMMON_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/Device_BlockStorage$<$,$>:-DEBUG>.c") + +# make var global +set(COMMON_PROJECT_SOURCES ${COMMON_PROJECT_SOURCES} CACHE INTERNAL "make global") diff --git a/targets/ChibiOS/RP_PICO_RP2040/common/Device_BlockStorage-DEBUG.c b/targets/ChibiOS/RP_PICO_RP2040/common/Device_BlockStorage-DEBUG.c new file mode 100644 index 0000000000..d592adc40f --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/common/Device_BlockStorage-DEBUG.c @@ -0,0 +1,81 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include + +// RP2040 Pico flash layout for DEBUG builds (2MB external QSPI flash, 4KB sectors) +// 0x10000000 - 0x1000BFFF : nanoBooter (48KB = 12 sectors) +// 0x1000C000 - 0x10013FFF : Config block (32KB = 8 sectors) +// 0x10014000 - 0x100FBFFF : nanoCLR (928KB = 232 sectors) +// 0x100FC000 - 0x101F7FFF : Deployment (1008KB = 252 sectors) +// 0x101F8000 - 0x101FFFFF : LittleFS (32KB = 8 sectors) + +// 4KB sectors +const BlockRange BlockRange1[] = { + // 0x10000000 nanoBooter (sectors 0-11) + {BlockRange_BLOCKTYPE_BOOTSTRAP, 0, 11}, + + // 0x1000C000 configuration block (sectors 12-19) + {BlockRange_BLOCKTYPE_CONFIG, 12, 19}, + + // 0x10014000 nanoCLR (sectors 20-251) + {BlockRange_BLOCKTYPE_CODE, 20, 251}, + + // 0x10100000 deployment (sectors 252-503) + {BlockRange_BLOCKTYPE_DEPLOYMENT, 252, 503}, + + // 0x101F8000 littlefs (sectors 504-511) + {BlockRange_BLOCKTYPE_FILESYSTEM, 504, 511}}; + +const BlockRegionInfo BlockRegions[] = { + { + (0), // no attributes for this region + 0x10000000, // start address for block region (XIP base) + 512, // total number of blocks in this region (2MB / 4KB) + 0x1000, // total number of bytes per block (4KB) + ARRAYSIZE_CONST_EXPR(BlockRange1), + BlockRange1, + }, +}; + +const DeviceBlockInfo Device_BlockInfo = { + (MediaAttribute_SupportsXIP), // RP2040 flash is XIP (execute in place) + 2, // UINT32 BytesPerSector + ARRAYSIZE_CONST_EXPR(BlockRegions), + (BlockRegionInfo *)BlockRegions, +}; + +MEMORY_MAPPED_NOR_BLOCK_CONFIG Device_BlockStorageConfig = { + { + // BLOCK_CONFIG + { + 0, // GPIO_PIN Pin; + false, // BOOL ActiveState; + }, + + (DeviceBlockInfo *)&Device_BlockInfo, // BlockDeviceinfo + }, + + { + // CPU_MEMORY_CONFIG + 0, // UINT8 CPU_MEMORY_CONFIG::ChipSelect; + true, // UINT8 CPU_MEMORY_CONFIG::ReadOnly; + 0, // UINT32 CPU_MEMORY_CONFIG::WaitStates; + 0, // UINT32 CPU_MEMORY_CONFIG::ReleaseCounts; + 8, // UINT32 CPU_MEMORY_CONFIG::BitWidth; + 0x10000000, // UINT32 CPU_MEMORY_CONFIG::BaseAddress; + 0x00200000, // UINT32 CPU_MEMORY_CONFIG::SizeInBytes; (2MB) + 0, // UINT8 CPU_MEMORY_CONFIG::XREADYEnable + 0, // UINT8 CPU_MEMORY_CONFIG::ByteSignalsForRead + 0, // UINT8 CPU_MEMORY_CONFIG::ExternalBufferEnable + }, + + 0, // UINT32 ChipProtection; + 0, // UINT32 ManufacturerCode; + 0, // UINT32 DeviceCode; +}; + +__attribute__((__used__)) BlockStorageDevice Device_BlockStorage; diff --git a/targets/ChibiOS/RP_PICO_RP2040/common/Device_BlockStorage.c b/targets/ChibiOS/RP_PICO_RP2040/common/Device_BlockStorage.c new file mode 100644 index 0000000000..fb066a3c35 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/common/Device_BlockStorage.c @@ -0,0 +1,81 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include + +// RP2040 Pico flash layout (2MB external QSPI flash, 4KB sectors) +// 0x10000000 - 0x1000BFFF : nanoBooter (48KB = 12 sectors) +// 0x1000C000 - 0x10013FFF : Config block (32KB = 8 sectors) +// 0x10014000 - 0x100FBFFF : nanoCLR (928KB = 232 sectors) +// 0x100FC000 - 0x101F7FFF : Deployment (1008KB = 252 sectors) +// 0x101F8000 - 0x101FFFFF : LittleFS (32KB = 8 sectors) + +// 4KB sectors +const BlockRange BlockRange1[] = { + // 0x10000000 nanoBooter (sectors 0-11) + {BlockRange_BLOCKTYPE_BOOTSTRAP, 0, 11}, + + // 0x1000C000 configuration block (sectors 12-19) + {BlockRange_BLOCKTYPE_CONFIG, 12, 19}, + + // 0x10014000 nanoCLR (sectors 20-251) + {BlockRange_BLOCKTYPE_CODE, 20, 251}, + + // 0x10100000 deployment (sectors 252-503) + {BlockRange_BLOCKTYPE_DEPLOYMENT, 252, 503}, + + // 0x101F8000 littlefs (sectors 504-511) + {BlockRange_BLOCKTYPE_FILESYSTEM, 504, 511}}; + +const BlockRegionInfo BlockRegions[] = { + { + (0), // no attributes for this region + 0x10000000, // start address for block region (XIP base) + 512, // total number of blocks in this region (2MB / 4KB) + 0x1000, // total number of bytes per block (4KB) + ARRAYSIZE_CONST_EXPR(BlockRange1), + BlockRange1, + }, +}; + +const DeviceBlockInfo Device_BlockInfo = { + (MediaAttribute_SupportsXIP), // RP2040 flash is XIP (execute in place) + 2, // UINT32 BytesPerSector + ARRAYSIZE_CONST_EXPR(BlockRegions), + (BlockRegionInfo *)BlockRegions, +}; + +MEMORY_MAPPED_NOR_BLOCK_CONFIG Device_BlockStorageConfig = { + { + // BLOCK_CONFIG + { + 0, // GPIO_PIN Pin; + false, // BOOL ActiveState; + }, + + (DeviceBlockInfo *)&Device_BlockInfo, // BlockDeviceinfo + }, + + { + // CPU_MEMORY_CONFIG + 0, // UINT8 CPU_MEMORY_CONFIG::ChipSelect; + true, // UINT8 CPU_MEMORY_CONFIG::ReadOnly; + 0, // UINT32 CPU_MEMORY_CONFIG::WaitStates; + 0, // UINT32 CPU_MEMORY_CONFIG::ReleaseCounts; + 8, // UINT32 CPU_MEMORY_CONFIG::BitWidth; + 0x10000000, // UINT32 CPU_MEMORY_CONFIG::BaseAddress; + 0x00200000, // UINT32 CPU_MEMORY_CONFIG::SizeInBytes; (2MB) + 0, // UINT8 CPU_MEMORY_CONFIG::XREADYEnable + 0, // UINT8 CPU_MEMORY_CONFIG::ByteSignalsForRead + 0, // UINT8 CPU_MEMORY_CONFIG::ExternalBufferEnable + }, + + 0, // UINT32 ChipProtection; + 0, // UINT32 ManufacturerCode; + 0, // UINT32 DeviceCode; +}; + +__attribute__((__used__)) BlockStorageDevice Device_BlockStorage; diff --git a/targets/ChibiOS/RP_PICO_RP2040/defconfig b/targets/ChibiOS/RP_PICO_RP2040/defconfig new file mode 100644 index 0000000000..463d1b5a74 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/defconfig @@ -0,0 +1,25 @@ +# defconfig for RP_PICO_RP2040 + +CONFIG_API_SYSTEM_DEVICE_ADC=y +CONFIG_API_SYSTEM_DEVICE_GPIO=y +CONFIG_API_SYSTEM_DEVICE_I2C=y +CONFIG_API_SYSTEM_DEVICE_PWM=y +CONFIG_API_SYSTEM_DEVICE_SPI=y +CONFIG_API_NANOFRAMEWORK_RESOURCEMANAGER=y +CONFIG_API_NANOFRAMEWORK_SYSTEM_COLLECTIONS=y +CONFIG_API_NANOFRAMEWORK_SYSTEM_TEXT=y +# CONFIG_CHIBIOS_CONTRIB_REQUIRED is not set +# CONFIG_CHIBIOS_SWO_OUTPUT is not set +# CONFIG_NF_BUILD_RTM is not set +CONFIG_NF_FEATURE_DEBUGGER=y +CONFIG_NF_FEATURE_HAS_ACCESSIBLE_STORAGE=y +CONFIG_NF_FEATURE_HAS_CONFIG_BLOCK=y +CONFIG_NF_FEATURE_LIGHT_MATH=y +CONFIG_NF_FEATURE_RTC=y +CONFIG_NF_FEATURE_USE_LITTLEFS=y +# CONFIG_NF_FEATURE_USE_RNG is not set +# CONFIG_NF_SUPPORT_ANY_BASE_CONVERSION is not set +CONFIG_RTOS_CHIBIOS=y +# CONFIG_STM32_CUBE_PACKAGE_REQUIRED is not set +CONFIG_TARGET_BOARD="RP_PICO_RP2040" +CONFIG_TARGET_SERIES="RP2040" diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/CMakeLists.txt b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/CMakeLists.txt new file mode 100644 index 0000000000..520d67bd04 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# append nanoBooter source files +list(APPEND NANOBOOTER_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c") +# make var global +set(NANOBOOTER_PROJECT_SOURCES ${NANOBOOTER_PROJECT_SOURCES} CACHE INTERNAL "make global") diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/RP2040_booter-DEBUG.ld b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/RP2040_booter-DEBUG.ld new file mode 100644 index 0000000000..3dacff675b --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/RP2040_booter-DEBUG.ld @@ -0,0 +1,89 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoBooter DEBUG memory setup. + * Same layout as release — debug builds just have larger code. + */ +MEMORY +{ + flash0 (rx) : org = 0x10000000, len = 80k /* nanoBooter + config (for __nanoImage_end__) */ + flash1 (rx) : org = 0x10000000, len = 48k /* XIP: nanoBooter */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k + deployment (rx) : org = 0x00000000, len = 0 + ramvt (wx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 256k-48 + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k + ram5 (wx) : org = 0x20041000, len = 4k + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 +} + +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); +REGION_ALIAS("MAIN_STACK_RAM", ram4); +REGION_ALIAS("PROCESS_STACK_RAM", ram4); +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); +REGION_ALIAS("BSS_RAM", ram0); +REGION_ALIAS("HEAP_RAM", ram0); +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > flash1 + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: The Pico second stage bootloader must be 256 bytes in size") +} + +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE rules_code.ld +INCLUDE rules_data.ld +INCLUDE rules_memory.ld +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/RP2040_booter.ld b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/RP2040_booter.ld new file mode 100644 index 0000000000..e6b1b1f917 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/RP2040_booter.ld @@ -0,0 +1,138 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoBooter memory setup. + * nanoBooter occupies the first 48KB of XIP flash. + * + * Flash layout: + * 0x10000000 - 0x1000BFFF : nanoBooter (48KB) + * 0x1000C000 - 0x10013FFF : Config block (32KB) + * 0x10014000 - 0x100FBFFF : nanoCLR (928KB) + * 0x100FC000 - 0x101F7FFF : Deployment (1008KB) + * 0x101F8000 - 0x101FFFFF : littlefs (32KB) + */ +MEMORY +{ + flash0 (rx) : org = 0x10000000, len = 80k /* nanoBooter + config (for __nanoImage_end__) */ + flash1 (rx) : org = 0x10000000, len = 48k /* XIP: nanoBooter */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k /* configuration block */ + deployment (rx) : org = 0x00000000, len = 0 /* not used in booter */ + ramvt (wx) : org = 0x00000000, len = 0 /* no RAM vector table in booter */ + ram0 (wx) : org = 0x20000000, len = 256k-48 /* SRAM0 striped */ + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k /* SRAM4 */ + ram5 (wx) : org = 0x20041000, len = 4k /* SRAM5 */ + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 /* boot clipboard at end of SRAM */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* Core 1 stack regions for SMP.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +/* RAM region to be used for the boot clipboard.*/ +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +/* RP2040 second stage bootloader must be placed at the very start of flash */ +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > flash1 + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: The Pico second stage bootloader must be 256 bytes in size") +} + +/* Stacks rules inclusion.*/ +INCLUDE rules_stacks.ld + +/* Core 1 stacks rules inclusion (SMP).*/ +INCLUDE rules_stacks_c1.ld + +/* Code rules inclusion.*/ +INCLUDE rules_code.ld + +/* Data rules inclusion.*/ +INCLUDE rules_data.ld + +/* Memory rules inclusion.*/ +INCLUDE rules_memory.ld + +/* Boot clipboard rules inclusion.*/ +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/chconf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/chconf.h new file mode 100644 index 0000000000..55177c2513 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/chconf.h @@ -0,0 +1,854 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file rt/templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_8_0_ + +/*===========================================================================*/ +/** + * @name System settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Handling of instances. + * @note If enabled then threads assigned to various instances can + * interact each other using the same synchronization objects. + * If disabled then each OS instance is a separate world, no + * direct interactions are handled by the OS. + */ +#if !defined(CH_CFG_SMP_MODE) +#define CH_CFG_SMP_MODE FALSE +#endif + +/** + * @brief Kernel hardening level. + * @details This option is the level of functional-safety checks enabled + * in the kerkel. The meaning is: + * - 0: No checks, maximum performance. + * - 1: Reasonable checks. + * - 2: All checks. + * . + */ +#if !defined(CH_CFG_HARDENING_LEVEL) +#define CH_CFG_HARDENING_LEVEL 0 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16, 32 or 64 bits. + * @note In tick-less mode this value must match the physical system tick + * timer counter width. + */ +#if !defined(CH_CFG_ST_RESOLUTION) +#define CH_CFG_ST_RESOLUTION 32 +#endif + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + * @note This must be a frequency that is obtainable from the system tick + * timer frequency. + */ +#if !defined(CH_CFG_ST_FREQUENCY) +#define CH_CFG_ST_FREQUENCY 1000000 +#endif + +/** + * @brief Time intervals data size. + * @note Allowed values are 16, 32 or 64 bits. + */ +#if !defined(CH_CFG_INTERVALS_SIZE) +#define CH_CFG_INTERVALS_SIZE 32 +#endif + +/** + * @brief Time types data size. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#define CH_CFG_TIME_TYPES_SIZE 32 +#endif + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#if !defined(CH_CFG_ST_TIMEDELTA) +#define CH_CFG_ST_TIMEDELTA 20 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. + */ +#if !defined(CH_CFG_TIME_QUANTUM) +#define CH_CFG_TIME_QUANTUM 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. + */ +#if !defined(CH_CFG_NO_IDLE_THREAD) +#define CH_CFG_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#define CH_CFG_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TM) +#define CH_CFG_USE_TM FALSE +#endif + +/** + * @brief Time Stamps APIs. + * @details If enabled then the time stamps APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TIMESTAMP) +#define CH_CFG_USE_TIMESTAMP TRUE +#endif + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_REGISTRY) +#define CH_CFG_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_WAITEXIT) +#define CH_CFG_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_SEMAPHORES) +#define CH_CFG_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MUTEXES) +#define CH_CFG_USE_MUTEXES TRUE +#endif + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_CONDVARS) +#define CH_CFG_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_EVENTS) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#if !defined(CH_CFG_USE_EVENTS_TIMEOUT) +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MESSAGES) +#define CH_CFG_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#if !defined(CH_CFG_USE_DYNAMIC) +#define CH_CFG_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name OSLIB options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_MAILBOXES) +#define CH_CFG_USE_MAILBOXES TRUE +#endif + +/** + * @brief Memory checks APIs. + * @details If enabled then the memory checks APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCHECKS) +#define CH_CFG_USE_MEMCHECKS TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCORE) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#if !defined(CH_CFG_MEMCORE_SIZE) +#define CH_CFG_MEMCORE_SIZE 0 +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_CFG_USE_HEAP) +#define CH_CFG_USE_HEAP TRUE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMPOOLS) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Objects FIFOs APIs. + * @details If enabled then the objects FIFOs APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_FIFOS) +#define CH_CFG_USE_OBJ_FIFOS TRUE +#endif + +/** + * @brief Pipes APIs. + * @details If enabled then the pipes APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_PIPES) +#define CH_CFG_USE_PIPES TRUE +#endif + +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + +/** + * @brief Delegate threads APIs. + * @details If enabled then the delegate threads APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_DELEGATES) +#define CH_CFG_USE_DELEGATES TRUE +#endif + +/** + * @brief Jobs Queues APIs. + * @details If enabled then the jobs queues APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_JOBS) +#define CH_CFG_USE_JOBS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Objects factory options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Objects Factory APIs. + * @details If enabled then the objects factory APIs are included in the + * kernel. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_CFG_USE_FACTORY) +#define CH_CFG_USE_FACTORY TRUE +#endif + +/** + * @brief Maximum length for object names. + * @details If the specified length is zero then the name is stored by + * pointer but this could have unintended side effects. + */ +#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#endif + +/** + * @brief Enables the registry of generic objects. + */ +#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#endif + +/** + * @brief Enables factory for generic buffers. + */ +#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#endif + +/** + * @brief Enables factory for semaphores. + */ +#if !defined(CH_CFG_FACTORY_SEMAPHORES) +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#endif + +/** + * @brief Enables factory for mailboxes. + */ +#if !defined(CH_CFG_FACTORY_MAILBOXES) +#define CH_CFG_FACTORY_MAILBOXES TRUE +#endif + +/** + * @brief Enables factory for objects FIFOs. + */ +#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#endif + +/** + * @brief Enables factory for Pipes. + */ +#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the trace buffer is activated. + * + * @note The default is @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_MASK) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p thread_t structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. + */ +#if !defined(CH_DBG_THREADS_PROFILING) +#define CH_DBG_THREADS_PROFILING FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System structure extension. + * @details User fields added to the end of the @p ch_system_t structure. + */ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* Add system custom fields here.*/ + +/** + * @brief System initialization hook. + * @details User initialization code added to the @p chSysInit() function + * just before interrupts are enabled globally. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() do { \ + /* Add system initialization code here.*/ \ +} while (false) + +/** + * @brief OS instance structure extension. + * @details User fields added to the end of the @p os_instance_t structure. + */ +#define CH_CFG_OS_INSTANCE_EXTRA_FIELDS \ + /* Add OS instance custom fields here.*/ + +/** + * @brief OS instance initialization hook. + * + * @param[in] oip pointer to the @p os_instance_t structure + */ +#define CH_CFG_OS_INSTANCE_INIT_HOOK(oip) do { \ + /* Add OS instance initialization code here.*/ \ +} while (false) + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p _thread_init() function. + * + * @note It is invoked from within @p _thread_init() and implicitly from all + * the threads creation APIs. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) do { \ + /* Add threads initialization code here.*/ \ +} while (false) + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) do { \ + /* Add threads finalization code here.*/ \ +} while (false) + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + * + * @param[in] ntp thread being switched in + * @param[in] otp thread being switched out + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) do { \ + /* Context switch code here.*/ \ +} while (false) + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() do { \ + /* IRQ prologue code here.*/ \ +} while (false) + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() do { \ + /* IRQ epilogue code here.*/ \ +} while (false) + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() do { \ + /* Idle-enter code here.*/ \ +} while (false) + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() do { \ + /* Idle-leave code here.*/ \ +} while (false) + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() do { \ + /* Idle loop code here.*/ \ +} while (false) + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() do { \ + /* System tick event code here.*/ \ +} while (false) + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) do { \ + /* System halt code here.*/ \ +} while (false) + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) do { \ + /* Trace code here.*/ \ +} while (false) + +/** + * @brief Runtime Faults Collection Unit hook. + * @details This hook is invoked each time new faults are collected and stored. + */ +#define CH_CFG_RUNTIME_FAULTS_HOOK(mask) do { \ + /* Faults handling code here.*/ \ +} while (false) + +/** + * @brief Safety checks hook. + * @details This hook is invoked when there is a safety violation and the + * system is going to stop. + */ +#define CH_CFG_SAFETY_CHECK_HOOK(l, f) do { \ + /* Safety handling code here.*/ \ + chSysHalt(f); \ +} while (false) + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/halconf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/halconf.h new file mode 100644 index 0000000000..fba5092768 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/halconf.h @@ -0,0 +1,573 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef HALCONF_H +#define HALCONF_H + +#define _CHIBIOS_HAL_CONF_ +#define _CHIBIOS_HAL_CONF_VER_9_1_ + +#include "mcuconf.h" + +/** + * @brief Enables the HAL safety subsystem. + */ +#if !defined(HAL_USE_SAFETY) || defined(__DOXYGEN__) +#define HAL_USE_SAFETY FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC FALSE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the cryptographic subsystem. + */ +#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__) +#define HAL_USE_CRY FALSE +#endif + +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC FALSE +#endif + +/** + * @brief Enables the EFlash subsystem. + */ +#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__) +#define HAL_USE_EFL TRUE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB TRUE +#endif + +/** + * @brief Enables the SIO subsystem. + */ +#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__) +#define HAL_USE_SIO TRUE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the TRNG subsystem. + */ +#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__) +#define HAL_USE_TRNG FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB TRUE +#endif + +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + +/** + * @brief Enables the WSPI subsystem. + */ +#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__) +#define HAL_USE_WSPI FALSE +#endif + +/*===========================================================================*/ +/* PAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__) +#define PAL_USE_CALLBACKS FALSE +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__) +#define PAL_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/** + * @brief Enforces the driver to use direct callbacks rather than OSAL events. + */ +#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__) +#define CAN_ENFORCE_USE_CALLBACKS FALSE +#endif + +/*===========================================================================*/ +/* CRY driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the SW fall-back of the cryptographic driver. + * @details When enabled, this option, activates a fall-back software + * implementation for algorithms not supported by the underlying + * hardware. + * @note Fall-back implementations may not be present for all algorithms. + */ +#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_USE_FALLBACK FALSE +#endif + +/** + * @brief Makes the driver forcibly use the fall-back implementations. + */ +#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_ENFORCE_FALLBACK FALSE +#endif + +/*===========================================================================*/ +/* DAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__) +#define DAC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DAC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Slave mode API enable switch. + * @note The low level driver must support this capability. + */ +#if !defined(I2C_ENABLE_SLAVE_MODE) +#define I2C_ENABLE_SLAVE_MODE FALSE +#endif + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the zero-copy API. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Timeout before assuming a failure while waiting for card idle. + * @note Time is in milliseconds. + */ +#if !defined(MMC_IDLE_TIMEOUT_MS) || defined(__DOXYGEN__) +#define MMC_IDLE_TIMEOUT_MS 1000 +#endif + +/** + * @brief Mutual exclusion on the SPI bus. + */ +#if !defined(MMC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define MMC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/** + * @brief OCR initialization constant for V20 cards. + */ +#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__) +#define SDC_INIT_OCR_V20 0x50FF8000U +#endif + +/** + * @brief OCR initialization constant for non-V20 cards. + */ +#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__) +#define SDC_INIT_OCR 0x80100000U +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 16 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SIO driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SIO_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SIO_DEFAULT_BITRATE 115200 +#endif + +/** + * @brief Support for thread synchronization API. + */ +#if !defined(SIO_USE_SYNCHRONIZATION) || defined(__DOXYGEN__) +#define SIO_USE_SYNCHRONIZATION TRUE +#endif + +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. + * @note The default is 256 bytes for both transmission and receive + * buffers; set to 64 to match every other ChibiOS nanoFramework + * target. This is sufficient for Wire Protocol traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 64 +#endif + +/** + * @brief Serial over USB number of buffers. + * @note The default is 2 buffers; set to 1 to match every other ChibiOS + * nanoFramework target, which is sufficient for Wire Protocol + * traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_NUMBER 1 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Inserts an assertion on function errors before returning. + */ +#if !defined(SPI_USE_ASSERT_ON_ERROR) || defined(__DOXYGEN__) +#define SPI_USE_ASSERT_ON_ERROR TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +/** + * @brief Handling method for SPI CS line. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__) +#define SPI_SELECT_MODE SPI_SELECT_MODE_LINE +#endif + +/*===========================================================================*/ +/* UART driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__) +#define UART_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define UART_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* USB driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* WSPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__) +#define WSPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define WSPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#include "halconf_nf.h" + +#endif /* HALCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/halconf_nf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/halconf_nf.h new file mode 100644 index 0000000000..87d94d8b33 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/halconf_nf.h @@ -0,0 +1,16 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef HALCONF_NF_H +#define HALCONF_NF_H + +// nanoFramework HAL overlay for nanoBooter + +// RP2040 does not have STM32-specific peripherals +#define HAL_NF_USE_STM32_CRC FALSE +#define HAL_NF_USE_STM32_RNG FALSE +#define HAL_NF_USE_STM32_FLASH FALSE + +#endif // HALCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/main.c b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/main.c new file mode 100644 index 0000000000..d950e1b852 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/main.c @@ -0,0 +1,86 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +// need to declare the Receiver thread here +osThreadDef(ReceiverThread, osPriorityHigh, 2048, "ReceiverThread"); + +// Application entry point. +int main(void) +{ + // HAL initialization, this also initializes the configured device drivers + // and performs the board-specific initializations. + halInit(); + + // init boot clipboard + InitBootClipboard(); + + // The kernel is initialized but not started yet, this means that + // main() is executing with absolute priority but interrupts are already enabled. + osKernelInitialize(); + + // check if there is a request to remain on nanoBooter + if (!IsToRemainInBooter()) + { + // check for valid CLR image at address contiguous to nanoBooter + // NOTE: The standard CheckValidCLRImage() opcode check fails on RP2040 due to XIP flash read + // behavior. Use a simple vector table validation instead. + volatile uint32_t *clrVector = (volatile uint32_t *)(uint32_t)&__nanoImage_end__; + uint32_t msp = clrVector[0]; + uint32_t resetHandler = clrVector[1]; + + if (msp != 0xFFFFFFFF && msp != 0x00000000 && + resetHandler > 0x10000000 && resetHandler < 0x10200000) + { + // there seems to be a valid CLR image + // launch nanoCLR + LaunchCLR((uint32_t)&__nanoImage_end__); + } + } + + // Initializes a serial-over-USB CDC driver. + sduObjectInit(&SERIAL_DRIVER); + sduStart(&SERIAL_DRIVER, &serusbcfg); + + // Activates the USB driver and then the USB bus pull-up on D+. + // Note, a delay is inserted in order to not have to disconnect the cable after a reset. + usbDisconnectBus(serusbcfg.usbp); + chThdSleepMilliseconds(100); + usbStart(serusbcfg.usbp, &usbcfg); + usbConnectBus(serusbcfg.usbp); + + // create the receiver thread + osThreadCreate(osThread(ReceiverThread), NULL); + + // start kernel, after this main() will behave like a thread with priority osPriorityNormal + osKernelStart(); + + // initialize block storage list and devices + // in CLR this is called in nanoHAL_Initialize() + // for nanoBooter we have to init it in order to provide the flash map for Monitor_FlashSectorMap command + BlockStorageList_Initialize(); + BlockStorage_AddDevices(); + BlockStorageList_InitializeDevices(); + + // report successful nanoBooter execution + ReportSuccessfullNanoBooter(); + + // Normal main() thread — blink the on-board LED (GP25) + palSetPadMode(IOPORT1, 25U, PAL_MODE_OUTPUT_PUSHPULL); + while (true) + { + palTogglePad(IOPORT1, 25U); + osDelay(500); + } +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/mcuconf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/mcuconf.h new file mode 100644 index 0000000000..868fd0b625 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/mcuconf.h @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 +#define RP_IRQ_RTC_PRIORITY 2 + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USB1 TRUE +#define RP_IRQ_USB0_PRIORITY 2 + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 TRUE +#define RP_SIO_USE_UART1 TRUE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 FALSE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 FALSE + +/* + * PWM driver system settings. + */ +#define RP_PWM_USE_PWM0 FALSE +#define RP_PWM_USE_PWM1 FALSE +#define RP_PWM_USE_PWM2 FALSE +#define RP_PWM_USE_PWM3 FALSE +#define RP_PWM_USE_PWM4 FALSE +#define RP_PWM_USE_PWM5 FALSE +#define RP_PWM_USE_PWM6 FALSE +#define RP_PWM_USE_PWM7 FALSE + +#endif /* MCUCONF_H */ diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/mcuconf_nf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/mcuconf_nf.h new file mode 100644 index 0000000000..fea73e7942 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/mcuconf_nf.h @@ -0,0 +1,12 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef MCUCONF_NF_H +#define MCUCONF_NF_H + +// nanoFramework MCU overlay for nanoBooter +// No additional MCU settings needed for nanoBooter at this stage + +#endif // MCUCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/target_board.h.in b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/target_board.h.in new file mode 100644 index 0000000000..ac85c850b9 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoBooter/target_board.h.in @@ -0,0 +1,18 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +////////////////////////////////////////////////////////////////////////////// +// This file was automatically generated by a tool. // +// Any changes you make here will be overwritten when it's generated again. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef TARGET_BOARD_NANOBOOTER_H +#define TARGET_BOARD_NANOBOOTER_H + +#include + +#define OEMSYSTEMINFOSTRING "nanoBooter running @ @TARGET_NAME@" + +#endif // TARGET_BOARD_NANOBOOTER_H diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/CMakeLists.txt b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/CMakeLists.txt new file mode 100644 index 0000000000..f5fab75926 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# append nanoCLR source files +list(APPEND NANOCLR_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c") +list(APPEND NANOCLR_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/nanoHAL.cpp") + +# make var global +set(NANOCLR_PROJECT_SOURCES ${NANOCLR_PROJECT_SOURCES} CACHE INTERNAL "make global") diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/RP2040_CLR-DEBUG.ld b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/RP2040_CLR-DEBUG.ld new file mode 100644 index 0000000000..02be0083f7 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/RP2040_CLR-DEBUG.ld @@ -0,0 +1,82 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoCLR DEBUG memory setup. + * Same layout as release. + */ +MEMORY +{ + flash0 (rx) : org = 0x10014000, len = 928k /* nanoCLR (also used for __nanoImage_start__) */ + flash1 (rx) : org = 0x10014000, len = 928k + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k + deployment (rx) : org = 0x100FC000, len = 1008k + ramvt (wx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 256k-48 + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k + ram5 (wx) : org = 0x20041000, len = 4k + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 +} + +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); +REGION_ALIAS("MAIN_STACK_RAM", ram4); +REGION_ALIAS("PROCESS_STACK_RAM", ram4); +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); +REGION_ALIAS("BSS_RAM", ram0); +REGION_ALIAS("HEAP_RAM", ram0); +REGION_ALIAS("CLR_MANAGED_HEAP_RAM", ram0); +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 +} + +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE rules_code.ld +INCLUDE rules_data.ld +INCLUDE rules_memory.ld +INCLUDE rules_clr.ld +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/RP2040_CLR.ld b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/RP2040_CLR.ld new file mode 100644 index 0000000000..4a5715589a --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/RP2040_CLR.ld @@ -0,0 +1,126 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoCLR memory setup. + * + * Flash layout: + * 0x10000000 - 0x1000BFFF : nanoBooter (48KB) - not used by CLR + * 0x1000C000 - 0x10013FFF : Config block (32KB) - read-only from CLR + * 0x10014000 - 0x100FBFFF : nanoCLR (928KB) + * 0x100FC000 - 0x101F7FFF : Deployment (1008KB) + * 0x101F8000 - 0x101FFFFF : littlefs (32KB) + * + * When updating the flash1 address below make sure to update the address + * in nf_generate_bin_package if applicable. + */ +MEMORY +{ + flash0 (rx) : org = 0x10014000, len = 928k /* XIP: nanoCLR (also used for __nanoImage_start__) */ + flash1 (rx) : org = 0x10014000, len = 928k /* XIP: nanoCLR */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k /* configuration block */ + deployment (rx) : org = 0x100FC000, len = 1008k /* deployment area */ + ramvt (wx) : org = 0x00000000, len = 0 /* no RAM vector table needed on M0+ */ + ram0 (wx) : org = 0x20000000, len = 256k-48 /* SRAM0 striped */ + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k /* SRAM4 */ + ram5 (wx) : org = 0x20041000, len = 4k /* SRAM5 */ + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 /* boot clipboard at end of SRAM */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* Core 1 stack regions for SMP.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +/* RAM region to be used for the nanoFramework CLR managed heap.*/ +REGION_ALIAS("CLR_MANAGED_HEAP_RAM", ram0); + +/* RAM region to be used for the boot clipboard.*/ +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +/* RP2040 second stage bootloader must be placed at the very start of flash. + For nanoCLR, the boot2 section is empty since nanoBooter owns the flash start. + However, the vector table still needs to be at the start of CLR flash region. */ +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 +} + +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE rules_code.ld +INCLUDE rules_data.ld +INCLUDE rules_memory.ld +INCLUDE rules_clr.ld +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/chconf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/chconf.h new file mode 100644 index 0000000000..55177c2513 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/chconf.h @@ -0,0 +1,854 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file rt/templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_8_0_ + +/*===========================================================================*/ +/** + * @name System settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Handling of instances. + * @note If enabled then threads assigned to various instances can + * interact each other using the same synchronization objects. + * If disabled then each OS instance is a separate world, no + * direct interactions are handled by the OS. + */ +#if !defined(CH_CFG_SMP_MODE) +#define CH_CFG_SMP_MODE FALSE +#endif + +/** + * @brief Kernel hardening level. + * @details This option is the level of functional-safety checks enabled + * in the kerkel. The meaning is: + * - 0: No checks, maximum performance. + * - 1: Reasonable checks. + * - 2: All checks. + * . + */ +#if !defined(CH_CFG_HARDENING_LEVEL) +#define CH_CFG_HARDENING_LEVEL 0 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16, 32 or 64 bits. + * @note In tick-less mode this value must match the physical system tick + * timer counter width. + */ +#if !defined(CH_CFG_ST_RESOLUTION) +#define CH_CFG_ST_RESOLUTION 32 +#endif + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + * @note This must be a frequency that is obtainable from the system tick + * timer frequency. + */ +#if !defined(CH_CFG_ST_FREQUENCY) +#define CH_CFG_ST_FREQUENCY 1000000 +#endif + +/** + * @brief Time intervals data size. + * @note Allowed values are 16, 32 or 64 bits. + */ +#if !defined(CH_CFG_INTERVALS_SIZE) +#define CH_CFG_INTERVALS_SIZE 32 +#endif + +/** + * @brief Time types data size. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#define CH_CFG_TIME_TYPES_SIZE 32 +#endif + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#if !defined(CH_CFG_ST_TIMEDELTA) +#define CH_CFG_ST_TIMEDELTA 20 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. + */ +#if !defined(CH_CFG_TIME_QUANTUM) +#define CH_CFG_TIME_QUANTUM 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. + */ +#if !defined(CH_CFG_NO_IDLE_THREAD) +#define CH_CFG_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#define CH_CFG_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TM) +#define CH_CFG_USE_TM FALSE +#endif + +/** + * @brief Time Stamps APIs. + * @details If enabled then the time stamps APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TIMESTAMP) +#define CH_CFG_USE_TIMESTAMP TRUE +#endif + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_REGISTRY) +#define CH_CFG_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_WAITEXIT) +#define CH_CFG_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_SEMAPHORES) +#define CH_CFG_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MUTEXES) +#define CH_CFG_USE_MUTEXES TRUE +#endif + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_CONDVARS) +#define CH_CFG_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_EVENTS) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#if !defined(CH_CFG_USE_EVENTS_TIMEOUT) +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MESSAGES) +#define CH_CFG_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#if !defined(CH_CFG_USE_DYNAMIC) +#define CH_CFG_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name OSLIB options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_MAILBOXES) +#define CH_CFG_USE_MAILBOXES TRUE +#endif + +/** + * @brief Memory checks APIs. + * @details If enabled then the memory checks APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCHECKS) +#define CH_CFG_USE_MEMCHECKS TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCORE) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#if !defined(CH_CFG_MEMCORE_SIZE) +#define CH_CFG_MEMCORE_SIZE 0 +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_CFG_USE_HEAP) +#define CH_CFG_USE_HEAP TRUE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMPOOLS) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Objects FIFOs APIs. + * @details If enabled then the objects FIFOs APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_FIFOS) +#define CH_CFG_USE_OBJ_FIFOS TRUE +#endif + +/** + * @brief Pipes APIs. + * @details If enabled then the pipes APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_PIPES) +#define CH_CFG_USE_PIPES TRUE +#endif + +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + +/** + * @brief Delegate threads APIs. + * @details If enabled then the delegate threads APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_DELEGATES) +#define CH_CFG_USE_DELEGATES TRUE +#endif + +/** + * @brief Jobs Queues APIs. + * @details If enabled then the jobs queues APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_JOBS) +#define CH_CFG_USE_JOBS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Objects factory options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Objects Factory APIs. + * @details If enabled then the objects factory APIs are included in the + * kernel. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_CFG_USE_FACTORY) +#define CH_CFG_USE_FACTORY TRUE +#endif + +/** + * @brief Maximum length for object names. + * @details If the specified length is zero then the name is stored by + * pointer but this could have unintended side effects. + */ +#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#endif + +/** + * @brief Enables the registry of generic objects. + */ +#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#endif + +/** + * @brief Enables factory for generic buffers. + */ +#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#endif + +/** + * @brief Enables factory for semaphores. + */ +#if !defined(CH_CFG_FACTORY_SEMAPHORES) +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#endif + +/** + * @brief Enables factory for mailboxes. + */ +#if !defined(CH_CFG_FACTORY_MAILBOXES) +#define CH_CFG_FACTORY_MAILBOXES TRUE +#endif + +/** + * @brief Enables factory for objects FIFOs. + */ +#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#endif + +/** + * @brief Enables factory for Pipes. + */ +#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the trace buffer is activated. + * + * @note The default is @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_MASK) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p thread_t structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. + */ +#if !defined(CH_DBG_THREADS_PROFILING) +#define CH_DBG_THREADS_PROFILING FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System structure extension. + * @details User fields added to the end of the @p ch_system_t structure. + */ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* Add system custom fields here.*/ + +/** + * @brief System initialization hook. + * @details User initialization code added to the @p chSysInit() function + * just before interrupts are enabled globally. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() do { \ + /* Add system initialization code here.*/ \ +} while (false) + +/** + * @brief OS instance structure extension. + * @details User fields added to the end of the @p os_instance_t structure. + */ +#define CH_CFG_OS_INSTANCE_EXTRA_FIELDS \ + /* Add OS instance custom fields here.*/ + +/** + * @brief OS instance initialization hook. + * + * @param[in] oip pointer to the @p os_instance_t structure + */ +#define CH_CFG_OS_INSTANCE_INIT_HOOK(oip) do { \ + /* Add OS instance initialization code here.*/ \ +} while (false) + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p _thread_init() function. + * + * @note It is invoked from within @p _thread_init() and implicitly from all + * the threads creation APIs. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) do { \ + /* Add threads initialization code here.*/ \ +} while (false) + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) do { \ + /* Add threads finalization code here.*/ \ +} while (false) + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + * + * @param[in] ntp thread being switched in + * @param[in] otp thread being switched out + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) do { \ + /* Context switch code here.*/ \ +} while (false) + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() do { \ + /* IRQ prologue code here.*/ \ +} while (false) + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() do { \ + /* IRQ epilogue code here.*/ \ +} while (false) + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() do { \ + /* Idle-enter code here.*/ \ +} while (false) + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() do { \ + /* Idle-leave code here.*/ \ +} while (false) + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() do { \ + /* Idle loop code here.*/ \ +} while (false) + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() do { \ + /* System tick event code here.*/ \ +} while (false) + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) do { \ + /* System halt code here.*/ \ +} while (false) + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) do { \ + /* Trace code here.*/ \ +} while (false) + +/** + * @brief Runtime Faults Collection Unit hook. + * @details This hook is invoked each time new faults are collected and stored. + */ +#define CH_CFG_RUNTIME_FAULTS_HOOK(mask) do { \ + /* Faults handling code here.*/ \ +} while (false) + +/** + * @brief Safety checks hook. + * @details This hook is invoked when there is a safety violation and the + * system is going to stop. + */ +#define CH_CFG_SAFETY_CHECK_HOOK(l, f) do { \ + /* Safety handling code here.*/ \ + chSysHalt(f); \ +} while (false) + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/halconf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/halconf.h new file mode 100644 index 0000000000..36be8d1f1d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/halconf.h @@ -0,0 +1,575 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef HALCONF_H +#define HALCONF_H + +#define _CHIBIOS_HAL_CONF_ +#define _CHIBIOS_HAL_CONF_VER_9_1_ + +#include +#include "mcuconf.h" + +/** + * @brief Enables the HAL safety subsystem. + */ +#if !defined(HAL_USE_SAFETY) || defined(__DOXYGEN__) +#define HAL_USE_SAFETY FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC FALSE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the cryptographic subsystem. + */ +#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__) +#define HAL_USE_CRY FALSE +#endif + +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC FALSE +#endif + +/** + * @brief Enables the EFlash subsystem. + */ +#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__) +#define HAL_USE_EFL TRUE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB TRUE +#endif + +/** + * @brief Enables the SIO subsystem. + */ +#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__) +#define HAL_USE_SIO TRUE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the TRNG subsystem. + */ +#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__) +#define HAL_USE_TRNG FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB TRUE +#endif + +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + +/** + * @brief Enables the WSPI subsystem. + */ +#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__) +#define HAL_USE_WSPI FALSE +#endif + +/*===========================================================================*/ +/* PAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__) +#define PAL_USE_CALLBACKS TRUE +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__) +#define PAL_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/** + * @brief Enforces the driver to use direct callbacks rather than OSAL events. + */ +#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__) +#define CAN_ENFORCE_USE_CALLBACKS FALSE +#endif + +/*===========================================================================*/ +/* CRY driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the SW fall-back of the cryptographic driver. + * @details When enabled, this option, activates a fall-back software + * implementation for algorithms not supported by the underlying + * hardware. + * @note Fall-back implementations may not be present for all algorithms. + */ +#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_USE_FALLBACK FALSE +#endif + +/** + * @brief Makes the driver forcibly use the fall-back implementations. + */ +#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_ENFORCE_FALLBACK FALSE +#endif + +/*===========================================================================*/ +/* DAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__) +#define DAC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DAC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Slave mode API enable switch. + * @note The low level driver must support this capability. + */ +#if !defined(I2C_ENABLE_SLAVE_MODE) +#define I2C_ENABLE_SLAVE_MODE FALSE +#endif + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the zero-copy API. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Timeout before assuming a failure while waiting for card idle. + * @note Time is in milliseconds. + */ +#if !defined(MMC_IDLE_TIMEOUT_MS) || defined(__DOXYGEN__) +#define MMC_IDLE_TIMEOUT_MS 1000 +#endif + +/** + * @brief Mutual exclusion on the SPI bus. + */ +#if !defined(MMC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define MMC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/** + * @brief OCR initialization constant for V20 cards. + */ +#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__) +#define SDC_INIT_OCR_V20 0x50FF8000U +#endif + +/** + * @brief OCR initialization constant for non-V20 cards. + */ +#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__) +#define SDC_INIT_OCR 0x80100000U +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 16 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SIO driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SIO_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SIO_DEFAULT_BITRATE 115200 +#endif + +/** + * @brief Support for thread synchronization API. + */ +#if !defined(SIO_USE_SYNCHRONIZATION) || defined(__DOXYGEN__) +#define SIO_USE_SYNCHRONIZATION TRUE +#endif + +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. + * @note The default is 256 bytes for both transmission and receive + * buffers; set to 64 to match every other ChibiOS nanoFramework + * target. This is sufficient for Wire Protocol traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 64 +#endif + +/** + * @brief Serial over USB number of buffers. + + * @note The default is 2 buffers; set to 1 to match every other ChibiOS + * nanoFramework target, which is sufficient for Wire Protocol + * traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_NUMBER 1 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Inserts an assertion on function errors before returning. + */ +#if !defined(SPI_USE_ASSERT_ON_ERROR) || defined(__DOXYGEN__) +#define SPI_USE_ASSERT_ON_ERROR TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +/** + * @brief Handling method for SPI CS line. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__) +#define SPI_SELECT_MODE SPI_SELECT_MODE_LINE +#endif + +/*===========================================================================*/ +/* UART driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__) +#define UART_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define UART_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* USB driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* WSPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__) +#define WSPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define WSPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#include "halconf_nf.h" + +#endif /* HALCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/halconf_nf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/halconf_nf.h new file mode 100644 index 0000000000..1d57e8dd3b --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/halconf_nf.h @@ -0,0 +1,15 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef HALCONF_NF_H +#define HALCONF_NF_H + +// nanoFramework HAL overlay for nanoCLR + +// RP2040 does not have STM32-specific peripherals +#define HAL_NF_USE_STM32_RNG FALSE +#define HAL_NF_USE_STM32_FLASH FALSE + +#endif // HALCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/main.c b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/main.c new file mode 100644 index 0000000000..4d18b47d67 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/main.c @@ -0,0 +1,80 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if (NF_FEATURE_USE_LITTLEFS == TRUE) +extern void hal_lfs_config(void); +extern void hal_lfs_mount(void); +#endif + +// need to declare the Receiver thread here +osThreadDef(ReceiverThread, osPriorityHigh, 2048, "ReceiverThread"); +// declare CLRStartup thread here +osThreadDef(CLRStartupThread, osPriorityNormal, 4096, "CLRStartupThread"); + +// Application entry point. +int main(void) +{ + // HAL initialization, this also initializes the configured device drivers + // and performs the board-specific initializations. + halInit(); + + // init boot clipboard + InitBootClipboard(); + + // The kernel is initialized but not started yet, this means that + // main() is executing with absolute priority but interrupts are already enabled. + osKernelInitialize(); + + // Initializes a serial-over-USB CDC driver. + sduObjectInit(&SERIAL_DRIVER); + sduStart(&SERIAL_DRIVER, &serusbcfg); + + // Activates the USB driver and then the USB bus pull-up on D+. + // Note, a delay is inserted in order to not have to disconnect the cable after a reset. + usbDisconnectBus(serusbcfg.usbp); + chThdSleepMilliseconds(100); + usbStart(serusbcfg.usbp, &usbcfg); + usbConnectBus(serusbcfg.usbp); + +#if (NF_FEATURE_USE_LITTLEFS == TRUE) + hal_lfs_config(); + hal_lfs_mount(); +#endif + + // create the receiver thread + osThreadCreate(osThread(ReceiverThread), NULL); + + // CLR settings to launch CLR thread + CLR_SETTINGS clrSettings; + (void)memset(&clrSettings, 0, sizeof(CLR_SETTINGS)); + + clrSettings.MaxContextSwitches = 50; + clrSettings.WaitForDebugger = false; + clrSettings.EnterDebuggerLoopAfterExit = true; + + // create the CLR Startup thread + osThreadCreate(osThread(CLRStartupThread), &clrSettings); + + // start kernel, after this main() will behave like a thread with priority osPriorityNormal + osKernelStart(); + + while (true) + { + osDelay(100); + } +} diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/mcuconf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/mcuconf.h new file mode 100644 index 0000000000..dab30b3689 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/mcuconf.h @@ -0,0 +1,105 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 +#define RP_IRQ_RTC_PRIORITY 2 + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USB1 TRUE +#define RP_IRQ_USB0_PRIORITY 2 + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 TRUE +#define RP_SIO_USE_UART1 TRUE + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 TRUE +#define RP_SPI_USE_SPI1 TRUE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 TRUE +#define RP_I2C_USE_I2C1 TRUE + +/* + * PWM driver system settings. + */ +#define RP_PWM_USE_PWM0 TRUE +#define RP_PWM_USE_PWM1 TRUE +#define RP_PWM_USE_PWM2 TRUE +#define RP_PWM_USE_PWM3 TRUE +#define RP_PWM_USE_PWM4 TRUE +#define RP_PWM_USE_PWM5 TRUE +#define RP_PWM_USE_PWM6 TRUE +#define RP_PWM_USE_PWM7 TRUE + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 TRUE + +#endif /* MCUCONF_H */ diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/mcuconf_nf.h b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/mcuconf_nf.h new file mode 100644 index 0000000000..3f16409d07 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/mcuconf_nf.h @@ -0,0 +1,12 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef MCUCONF_NF_H +#define MCUCONF_NF_H + +// nanoFramework MCU overlay for nanoCLR +// No additional MCU settings needed at this stage + +#endif // MCUCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/nanoHAL.cpp b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/nanoHAL.cpp new file mode 100644 index 0000000000..e754dd5f80 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/nanoHAL.cpp @@ -0,0 +1,8 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +bool g_fDoNotUninitializeDebuggerPort = false; diff --git a/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/target_board.h.in b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/target_board.h.in new file mode 100644 index 0000000000..53a87fce3d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/nanoCLR/target_board.h.in @@ -0,0 +1,18 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +////////////////////////////////////////////////////////////////////////////// +// This file was automatically generated by a tool. // +// Any changes you make here will be overwritten when it's generated again. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef TARGET_BOARD_NANOCLR_H +#define TARGET_BOARD_NANOCLR_H + +#include + +#define OEMSYSTEMINFOSTRING "nanoCLR running @ @TARGET_NAME@" + +#endif // TARGET_BOARD_NANOCLR_H diff --git a/targets/ChibiOS/RP_PICO_RP2040/sys_dev_adc_native_target.h b/targets/ChibiOS/RP_PICO_RP2040/sys_dev_adc_native_target.h new file mode 100644 index 0000000000..7676195632 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/sys_dev_adc_native_target.h @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/sys_dev_adc_native_target.h" diff --git a/targets/ChibiOS/RP_PICO_RP2040/sys_dev_i2c_native_target.h b/targets/ChibiOS/RP_PICO_RP2040/sys_dev_i2c_native_target.h new file mode 100644 index 0000000000..df769321b5 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/sys_dev_i2c_native_target.h @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/sys_dev_i2c_native_target.h" diff --git a/targets/ChibiOS/RP_PICO_RP2040/sys_dev_spi_native_target.h b/targets/ChibiOS/RP_PICO_RP2040/sys_dev_spi_native_target.h new file mode 100644 index 0000000000..bd2e2c1d69 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/sys_dev_spi_native_target.h @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/sys_dev_spi_native_target.h" diff --git a/targets/ChibiOS/RP_PICO_RP2040/target_BlockStorage.c b/targets/ChibiOS/RP_PICO_RP2040/target_BlockStorage.c new file mode 100644 index 0000000000..d5e54b342d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/target_BlockStorage.c @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/target_BlockStorage.c" diff --git a/targets/ChibiOS/RP_PICO_RP2040/target_common.c b/targets/ChibiOS/RP_PICO_RP2040/target_common.c new file mode 100644 index 0000000000..073eeee722 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/target_common.c @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/target_common.c" diff --git a/targets/ChibiOS/RP_PICO_RP2040/target_common.h.in b/targets/ChibiOS/RP_PICO_RP2040/target_common.h.in new file mode 100644 index 0000000000..d6e78825bc --- /dev/null +++ b/targets/ChibiOS/RP_PICO_RP2040/target_common.h.in @@ -0,0 +1,53 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +////////////////////////////////////////////////////////////////////////////// +// This file was automatically generated by a tool. // +// Any changes you make here will be overwritten when it's generated again. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef TARGET_COMMON_H +#define TARGET_COMMON_H + +///////////////////////////////////////////////////////////////////////////////////////// +// The following addresses and sizes should be filled in according to the SoC data-sheet +// they also must be coherent with what's in the linker file for nanoBooter and nanoCLR + +// RAM base address (RP2040: 264 KB SRAM total, main 256 KB striped bank) +#define RAM1_MEMORY_StartAddress ((uint32_t)0x20000000) +// RAM size (256 KB main SRAM) +#define RAM1_MEMORY_Size ((uint32_t)0x00040000) + +// FLASH base address (RP2040: XIP flash starts at 0x10000000) +#define FLASH1_MEMORY_StartAddress ((uint32_t)0x10000000) +// FLASH size (2 MB on standard Pico board) +#define FLASH1_MEMORY_Size ((uint32_t)0x00200000) + +///////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////// +// set Wire Protocol packet size +// valid sizes are 1024, 512, 256, 128 +// check Monitor_Ping_Source_Flags enum +#define WP_PACKET_SIZE 512U +////////////////////////////////////////////// + +////////////////////////////////////////////// +#define TARGETNAMESTRING "@TARGET_NAME@" +#define PLATFORMNAMESTRING "RP2040" +////////////////////////////////////////////// + +////////////////////////////////////////////// +// RP2040 has 264 KB SRAM — constrained but not as tight as STM32F0 +// set define to signal build system that this target is RAM constrained +#define TARGET_RAM_CONSTRAINED +////////////////////////////////////////////// + +///////////////////////////////////// +// LED blink heartbeat (GP25 is the onboard LED on Pico) +//#define EVENTS_HEART_BEAT palToggleLine(PAL_LINE(GPIO, 25U)) +///////////////////////////////////// + +#endif // TARGET_COMMON_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/CMakeLists.txt b/targets/ChibiOS/RP_PICO_W_RP2040/CMakeLists.txt new file mode 100644 index 0000000000..f398f56e0c --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/CMakeLists.txt @@ -0,0 +1,88 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +include(FetchContent) +FetchContent_GetProperties(chibios) + +include(binutils.common) +include(binutils.ChibiOS) + +# shared RP2040 sources and include directory +set(RP2040_COMMON "${CMAKE_SOURCE_DIR}/targets/ChibiOS/_RP2040") +list(APPEND CMAKE_PREFIX_PATH "${RP2040_COMMON}") +list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${RP2040_COMMON}") +list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${RP2040_COMMON}/common") + +# RP2040 flash driver and common sources from shared directory +list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${RP2040_COMMON}/Target_BlockStorage_RP2040FlashDriver.c") + +# SMP support source (Pico W uses dual-core SMP) +list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${chibios_SOURCE_DIR}/os/common/ports/ARMv6-M/smp/rp2/chcoresmp.c") +list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${RP2040_COMMON}/target_stubs.cpp") + +# RP2040 RNG stub (ROSC-based, replaces STM32 RNG) +list(APPEND TARGET_CHIBIOS_NANOCLR_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_rng.c") + +# target include directories +list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") +list(APPEND TARGET_CHIBIOS_NANOCLR_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi") +list(APPEND TARGET_CHIBIOS_NANOCLR_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/targets/ChibiOS/_WiFi/cyw43") + +# CYW43 driver includes (from FetchContent) +if(USE_NETWORKING_OPTION AND TARGET_HAS_WIFI) + find_package(CYW43_Driver REQUIRED QUIET) + list(APPEND TARGET_CHIBIOS_NANOCLR_INCLUDE_DIRS ${CYW43_DRIVER_INCLUDE_DIRS}) + list(APPEND TARGET_CHIBIOS_NANOCLR_SOURCES ${CYW43_DRIVER_SOURCES}) +endif() + +# PIO LLD sources for CYW43 SPI bus +list(APPEND TARGET_CHIBIOS_NANOCLR_INCLUDE_DIRS "${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/PIOv1") +list(APPEND TARGET_CHIBIOS_NANOCLR_SOURCES "${chibios_SOURCE_DIR}/os/hal/ports/RP/LLD/PIOv1/rp_pio.c") + +nf_setup_target_build( + HAS_NANOBOOTER + + BOOTER_LINKER_FILE + RP2040_booter + + CLR_LINKER_FILE + RP2040_CLR + + CLR_EXTRA_COMPILE_DEFINITIONS + -DRUNTIME_MEMORY_PROFILE__small=1 + -DTARGET_HAS_WIFI=1 + -DRP_PIO_REQUIRED=1 + LFS_CONFIG=lfs_config.h + + BOOTER_EXTRA_LINKMAP_PROPERTIES + ",--library-path=${CMAKE_SOURCE_DIR}/targets/ChibiOS/_common,--library-path=${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC/ld,--defsym=__main_stack_size__=0x400,--defsym=__process_stack_size__=0x400,--defsym=__crt_heap_size__=0x1000" + + CLR_EXTRA_LINKMAP_PROPERTIES + ",--library-path=${CMAKE_SOURCE_DIR}/targets/ChibiOS/_common,--library-path=${chibios_SOURCE_DIR}/os/common/startup/ARMCMx/compilers/GCC/ld,--defsym=__main_stack_size__=0x400,--defsym=__process_stack_size__=0x800,--defsym=__crt_heap_size__=0x14000" +) + +# Relax warnings for external CYW43 driver sources (we cannot modify them) +if(USE_NETWORKING_OPTION AND TARGET_HAS_WIFI) + foreach(CYW43_SRC ${CYW43_DRIVER_SOURCES}) + get_filename_component(CYW43_SRC_NAME ${CYW43_SRC} NAME) + if(CYW43_SRC_NAME MATCHES "^cyw43_") + set_source_files_properties(${CYW43_SRC} PROPERTIES COMPILE_FLAGS + "-Wno-error=shadow -Wno-error=return-type -Wno-error=implicit-function-declaration -Wno-error=type-limits -Wno-error=unused-parameter -Wno-error=missing-prototypes -Wno-error=missing-declarations -Wno-error=old-style-definition -Wno-error=undef") + endif() + endforeach() +endif() + +#################################################################################################### +## RP2040 UF2 output generation ## +## Addresses must match the linker scripts (RP2040_booter.ld / RP2040_CLR.ld) ## +## RP2040 UF2 family ID: 0xe48bff56 ## +#################################################################################################### + +nf_generate_uf2_package( + ${CMAKE_BINARY_DIR}/${NANOBOOTER_PROJECT_NAME}.bin 0x10000000 + ${CMAKE_BINARY_DIR}/${NANOCLR_PROJECT_NAME}.bin 0x10014000 + 0xe48bff56 + ${CMAKE_BINARY_DIR}/nanoCLR.uf2 +) diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/CMakePresets.json b/targets/ChibiOS/RP_PICO_W_RP2040/CMakePresets.json new file mode 100644 index 0000000000..dd4bdedc6b --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/CMakePresets.json @@ -0,0 +1,32 @@ +{ + "version": 4, + "include": [ + "../../../CMake/arm-gcc.json", + "../../../config/user-tools-repos.json", + "../../../config/user-prefs.json" + ], + "configurePresets": [ + { + "name": "RP_PICO_W_RP2040", + "inherits": [ + "arm-gcc-cortex-preset", + "user-tools-repos", + "user-prefs" + ], + "hidden": false, + "cacheVariables": { + "NF_TARGET_DEFCONFIG": "targets/ChibiOS/RP_PICO_W_RP2040/defconfig", + "CHIBIOS_GIT_REPOSITORY": "https://github.com/ChibiOS/ChibiOS.git", + "CHIBIOS_GIT_TAG": "master" + } + } + ], + "buildPresets": [ + { + "inherits": "base-user", + "name": "RP_PICO_W_RP2040", + "displayName": "RP_PICO_W_RP2040", + "configurePreset": "RP_PICO_W_RP2040" + } + ] +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/board.c b/targets/ChibiOS/RP_PICO_W_RP2040/board.c new file mode 100644 index 0000000000..49c1cf9e85 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/board.c @@ -0,0 +1,121 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Early initialization code. + * @details GPIO ports and system clocks are initialized before everything + * else. + */ +void __early_init(void) { + + /* Disable the bootrom watchdog. */ + WATCHDOG->CLR.CTRL = WATCHDOG_CTRL_ENABLE; + +#if RP_NO_INIT == FALSE + /* Reset of all peripherals. + Note, IO_QSPI, PADS_QSPI, PLL_SYS and PLL_USB are not reset because + the system is executing from flash via XIP and needs clock sources to + remain active. PLLs are handled by rp_clock_init() after switching to + safe sources.*/ + rp_peripheral_reset(~(RESETS_ALLREG_IO_QSPI | RESETS_ALLREG_PADS_QSPI | + RESETS_ALLREG_PLL_SYS | RESETS_ALLREG_PLL_USB)); + + rp_clock_init(); +#endif +} + +#if HAL_USE_SDC || defined(__DOXYGEN__) +/** + * @brief SDC card detection. + */ +bool sdc_lld_is_card_inserted(SDCDriver *sdcp) { + + (void)sdcp; + /* CHTODO: Fill the implementation.*/ + return true; +} + +/** + * @brief SDC card write protection detection. + */ +bool sdc_lld_is_write_protected(SDCDriver *sdcp) { + + (void)sdcp; + /* CHTODO: Fill the implementation.*/ + return false; +} +#endif /* HAL_USE_SDC */ + +#if HAL_USE_MMC_SPI || defined(__DOXYGEN__) +/** + * @brief MMC_SPI card detection. + */ +bool mmc_lld_is_card_inserted(MMCDriver *mmcp) { + + (void)mmcp; + /* CHTODO: Fill the implementation.*/ + return true; +} + +/** + * @brief MMC_SPI card write protection detection. + */ +bool mmc_lld_is_write_protected(MMCDriver *mmcp) { + + (void)mmcp; + /* CHTODO: Fill the implementation.*/ + return false; +} +#endif + +/** + * @brief Board-specific initialization code. + * @note You can add your board-specific code here. + */ +void boardInit(void) { + +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/board.h b/targets/ChibiOS/RP_PICO_W_RP2040/board.h new file mode 100644 index 0000000000..f975a38367 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/board.h @@ -0,0 +1,89 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/* + * This file has been automatically generated using ChibiStudio board + * generator plugin. Do not edit manually. + */ + +#ifndef BOARD_H +#define BOARD_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/* + * Setup for Raspberry Pi Pico board. + */ + +/* + * Board identifier. + */ +#define BOARD_RP_PICO_RP2040 +#define BOARD_NAME "Raspberry Pi Pico" + +/* + * Board oscillators-related settings. + */ +#if !defined(RP_XOSCCLK) +#define RP_XOSCCLK 12000000U +#endif + +/* + * MCU type. + */ +#define RP2040 + +/* + * IO pins assignments. + */ + +/* + * IO lines assignments. + */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* BOARD_H */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/common/CMakeLists.txt b/targets/ChibiOS/RP_PICO_W_RP2040/common/CMakeLists.txt new file mode 100644 index 0000000000..9d9231fe84 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/common/CMakeLists.txt @@ -0,0 +1,12 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# append source files required for ChibiOS interface (usbcfg.c from shared _RP2040) +list(APPEND COMMON_PROJECT_SOURCES "${CMAKE_SOURCE_DIR}/targets/ChibiOS/_RP2040/common/usbcfg.c") +list(APPEND COMMON_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/Device_BlockStorage$<$,$>:-DEBUG>.c") +list(APPEND COMMON_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/targetHAL_ConfigurationManager.cpp") + +# make var global +set(COMMON_PROJECT_SOURCES ${COMMON_PROJECT_SOURCES} CACHE INTERNAL "make global") diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/common/Device_BlockStorage-DEBUG.c b/targets/ChibiOS/RP_PICO_W_RP2040/common/Device_BlockStorage-DEBUG.c new file mode 100644 index 0000000000..52167da437 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/common/Device_BlockStorage-DEBUG.c @@ -0,0 +1,83 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include + +// RP2040 Pico W flash layout for DEBUG builds (2MB external QSPI flash, 4KB sectors) +// WiFi variant: nanoCLR expanded for CYW43 firmware blob +// 0x10000000 - 0x1000BFFF : nanoBooter (48KB = 12 sectors) +// 0x1000C000 - 0x10013FFF : Config block (32KB = 8 sectors) +// 0x10014000 - 0x10153FFF : nanoCLR (1280KB = 320 sectors) +// 0x10154000 - 0x101F7FFF : Deployment (656KB = 164 sectors) +// 0x101F8000 - 0x101FFFFF : LittleFS (32KB = 8 sectors) + +// 4KB sectors +const BlockRange BlockRange1[] = { + // 0x10000000 nanoBooter (sectors 0-11) + {BlockRange_BLOCKTYPE_BOOTSTRAP, 0, 11}, + + // 0x1000C000 configuration block (sectors 12-19) + {BlockRange_BLOCKTYPE_CONFIG, 12, 19}, + + // 0x10014000 nanoCLR (sectors 20-339) + {BlockRange_BLOCKTYPE_CODE, 20, 339}, + + // 0x10154000 deployment (sectors 340-503) + {BlockRange_BLOCKTYPE_DEPLOYMENT, 340, 503}, + + // 0x101F8000 littlefs internal storage (sectors 504-511) + {BlockRange_BLOCKTYPE_FILESYSTEM, 504, 511}, +}; + +const BlockRegionInfo BlockRegions[] = { + { + (0), // no attributes for this region + 0x10000000, // start address for block region (XIP base) + 512, // total number of blocks in this region (2MB / 4KB) + 0x1000, // total number of bytes per block (4KB) + ARRAYSIZE_CONST_EXPR(BlockRange1), + BlockRange1, + }, +}; + +const DeviceBlockInfo Device_BlockInfo = { + (MediaAttribute_SupportsXIP), // RP2040 flash is XIP (execute in place) + 2, // UINT32 BytesPerSector + ARRAYSIZE_CONST_EXPR(BlockRegions), + (BlockRegionInfo *)BlockRegions, +}; + +MEMORY_MAPPED_NOR_BLOCK_CONFIG Device_BlockStorageConfig = { + { + // BLOCK_CONFIG + { + 0, // GPIO_PIN Pin; + false, // BOOL ActiveState; + }, + + (DeviceBlockInfo *)&Device_BlockInfo, // BlockDeviceinfo + }, + + { + // CPU_MEMORY_CONFIG + 0, // UINT8 CPU_MEMORY_CONFIG::ChipSelect; + true, // UINT8 CPU_MEMORY_CONFIG::ReadOnly; + 0, // UINT32 CPU_MEMORY_CONFIG::WaitStates; + 0, // UINT32 CPU_MEMORY_CONFIG::ReleaseCounts; + 8, // UINT32 CPU_MEMORY_CONFIG::BitWidth; + 0x10000000, // UINT32 CPU_MEMORY_CONFIG::BaseAddress; + 0x00200000, // UINT32 CPU_MEMORY_CONFIG::SizeInBytes; (2MB) + 0, // UINT8 CPU_MEMORY_CONFIG::XREADYEnable + 0, // UINT8 CPU_MEMORY_CONFIG::ByteSignalsForRead + 0, // UINT8 CPU_MEMORY_CONFIG::ExternalBufferEnable + }, + + 0, // UINT32 ChipProtection; + 0, // UINT32 ManufacturerCode; + 0, // UINT32 DeviceCode; +}; + +__attribute__((__used__)) BlockStorageDevice Device_BlockStorage; diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/common/Device_BlockStorage.c b/targets/ChibiOS/RP_PICO_W_RP2040/common/Device_BlockStorage.c new file mode 100644 index 0000000000..63f16b262a --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/common/Device_BlockStorage.c @@ -0,0 +1,83 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include + +// RP2040 Pico W flash layout (2MB external QSPI flash, 4KB sectors) +// WiFi variant: nanoCLR expanded for CYW43 firmware blob +// 0x10000000 - 0x1000BFFF : nanoBooter (48KB = 12 sectors) +// 0x1000C000 - 0x10013FFF : Config block (32KB = 8 sectors) +// 0x10014000 - 0x10153FFF : nanoCLR (1280KB = 320 sectors) +// 0x10154000 - 0x101F7FFF : Deployment (656KB = 164 sectors) +// 0x101F8000 - 0x101FFFFF : LittleFS (32KB = 8 sectors) + +// 4KB sectors +const BlockRange BlockRange1[] = { + // 0x10000000 nanoBooter (sectors 0-11) + {BlockRange_BLOCKTYPE_BOOTSTRAP, 0, 11}, + + // 0x1000C000 configuration block (sectors 12-19) + {BlockRange_BLOCKTYPE_CONFIG, 12, 19}, + + // 0x10014000 nanoCLR (sectors 20-339) + {BlockRange_BLOCKTYPE_CODE, 20, 339}, + + // 0x10154000 deployment (sectors 340-503) + {BlockRange_BLOCKTYPE_DEPLOYMENT, 340, 503}, + + // 0x101F8000 littlefs internal storage (sectors 504-511) + {BlockRange_BLOCKTYPE_FILESYSTEM, 504, 511}, +}; + +const BlockRegionInfo BlockRegions[] = { + { + (0), // no attributes for this region + 0x10000000, // start address for block region (XIP base) + 512, // total number of blocks in this region (2MB / 4KB) + 0x1000, // total number of bytes per block (4KB) + ARRAYSIZE_CONST_EXPR(BlockRange1), + BlockRange1, + }, +}; + +const DeviceBlockInfo Device_BlockInfo = { + (MediaAttribute_SupportsXIP), // RP2040 flash is XIP (execute in place) + 2, // UINT32 BytesPerSector + ARRAYSIZE_CONST_EXPR(BlockRegions), + (BlockRegionInfo *)BlockRegions, +}; + +MEMORY_MAPPED_NOR_BLOCK_CONFIG Device_BlockStorageConfig = { + { + // BLOCK_CONFIG + { + 0, // GPIO_PIN Pin; + false, // BOOL ActiveState; + }, + + (DeviceBlockInfo *)&Device_BlockInfo, // BlockDeviceinfo + }, + + { + // CPU_MEMORY_CONFIG + 0, // UINT8 CPU_MEMORY_CONFIG::ChipSelect; + true, // UINT8 CPU_MEMORY_CONFIG::ReadOnly; + 0, // UINT32 CPU_MEMORY_CONFIG::WaitStates; + 0, // UINT32 CPU_MEMORY_CONFIG::ReleaseCounts; + 8, // UINT32 CPU_MEMORY_CONFIG::BitWidth; + 0x10000000, // UINT32 CPU_MEMORY_CONFIG::BaseAddress; + 0x00200000, // UINT32 CPU_MEMORY_CONFIG::SizeInBytes; (2MB) + 0, // UINT8 CPU_MEMORY_CONFIG::XREADYEnable + 0, // UINT8 CPU_MEMORY_CONFIG::ByteSignalsForRead + 0, // UINT8 CPU_MEMORY_CONFIG::ExternalBufferEnable + }, + + 0, // UINT32 ChipProtection; + 0, // UINT32 ManufacturerCode; + 0, // UINT32 DeviceCode; +}; + +__attribute__((__used__)) BlockStorageDevice Device_BlockStorage; diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/common/targetHAL_ConfigurationManager.cpp b/targets/ChibiOS/RP_PICO_W_RP2040/common/targetHAL_ConfigurationManager.cpp new file mode 100644 index 0000000000..02c47bd3ee --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/common/targetHAL_ConfigurationManager.cpp @@ -0,0 +1,50 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include +#include + +// Strong implementation replacing ChibiOS 'weak' InitialiseNetworkDefaultConfig. +// Creates a default WiFi (802.11) network configuration for the Pico W. +bool InitialiseNetworkDefaultConfig(HAL_Configuration_NetworkInterface *pconfig, uint32_t configurationIndex) +{ + (void)configurationIndex; + + // zero memory + memset(pconfig, 0, sizeof(HAL_Configuration_NetworkInterface)); + + // make sure the config block marker is set + memcpy(pconfig->Marker, c_MARKER_CONFIGURATION_NETWORK_V1, sizeof(c_MARKER_CONFIGURATION_NETWORK_V1)); + + // WiFi station interface + pconfig->InterfaceType = NetworkInterfaceType_Wireless80211; + pconfig->StartupAddressMode = AddressMode_DHCP; + pconfig->AutomaticDNS = 1; + pconfig->SpecificConfigId = 0; + + // MAC address will be read from the CYW43 chip at runtime; + // leave as zeros here — targetHAL_Network.cpp fills it in from cyw43_wifi_get_mac_addr(). + + return true; +} + +// Strong implementation replacing ChibiOS 'weak' InitialiseWirelessDefaultConfig. +// Creates a default Wireless80211 configuration block for the Pico W. +void InitialiseWirelessDefaultConfig(HAL_Configuration_Wireless80211 *pconfig, uint32_t configurationIndex) +{ + memset(pconfig, 0, sizeof(HAL_Configuration_Wireless80211)); + + // set config block marker + memcpy(pconfig, c_MARKER_CONFIGURATION_WIRELESS80211_V1, sizeof(c_MARKER_CONFIGURATION_WIRELESS80211_V1)); + + pconfig->Id = configurationIndex; + + // Enable auto-connect so managed code can store credentials and reconnect + pconfig->Options = + (Wireless80211Configuration_ConfigurationOptions)(Wireless80211Configuration_ConfigurationOptions_AutoConnect | + Wireless80211Configuration_ConfigurationOptions_Enable); +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/defconfig b/targets/ChibiOS/RP_PICO_W_RP2040/defconfig new file mode 100644 index 0000000000..eed1b73b42 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/defconfig @@ -0,0 +1,30 @@ +# defconfig for RP_PICO_W_RP2040 + +CONFIG_API_SYSTEM_DEVICE_ADC=y +CONFIG_API_SYSTEM_DEVICE_GPIO=y +CONFIG_API_SYSTEM_DEVICE_I2C=y +CONFIG_API_SYSTEM_DEVICE_PWM=y +CONFIG_API_SYSTEM_DEVICE_SPI=y +CONFIG_API_SYSTEM_DEVICE_WIFI=y +CONFIG_API_SYSTEM_IO_FILESYSTEM=y +CONFIG_API_SYSTEM_NET=y +CONFIG_API_NANOFRAMEWORK_RESOURCEMANAGER=y +CONFIG_API_NANOFRAMEWORK_SYSTEM_COLLECTIONS=y +CONFIG_API_NANOFRAMEWORK_SYSTEM_TEXT=y +# CONFIG_CHIBIOS_CONTRIB_REQUIRED is not set +# CONFIG_CHIBIOS_SWO_OUTPUT is not set +# CONFIG_NF_BUILD_RTM is not set +CONFIG_NF_FEATURE_DEBUGGER=y +CONFIG_NF_FEATURE_HAS_ACCESSIBLE_STORAGE=y +CONFIG_NF_FEATURE_HAS_CONFIG_BLOCK=y +CONFIG_NF_FEATURE_LIGHT_MATH=y +CONFIG_NF_FEATURE_RTC=y +CONFIG_NF_FEATURE_USE_LITTLEFS=y +# CONFIG_NF_FEATURE_USE_RNG is not set +CONFIG_NF_SECURITY_MBEDTLS=y +# CONFIG_NF_SUPPORT_ANY_BASE_CONVERSION is not set +CONFIG_RTOS_CHIBIOS=y +# CONFIG_STM32_CUBE_PACKAGE_REQUIRED is not set +CONFIG_TARGET_BOARD="RP_PICO_W_RP2040" +CONFIG_TARGET_HAS_WIFI=y +CONFIG_TARGET_SERIES="RP2040" diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/mbedtls_config.h b/targets/ChibiOS/RP_PICO_W_RP2040/mbedtls_config.h new file mode 100644 index 0000000000..4feb0017a9 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/mbedtls_config.h @@ -0,0 +1,23 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// MbedTLS configuration overrides for Pico W. +// This file is included before the nanoFramework-wide mbedtls config. +// Keep empty to use platform defaults; add overrides as needed. + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +// RP2040 uses ROSC random-bit sampling for entropy (see +// mbedtls_entropy_hardware_pool.c). PLATFORM_HAS_RNG is set in +// target_common.h.in so that MBEDTLS_ENTROPY_HARDWARE_ALT is enabled. + +// Reduce SSL record buffers for RAM-constrained RP2040. +// Default is 16384 each (33 KB total) which exhausts the 64 KB CLR heap. +// 4096 is sufficient for TLS 1.2 with most servers. +#define MBEDTLS_SSL_IN_CONTENT_LEN 6144 +#define MBEDTLS_SSL_OUT_CONTENT_LEN 4096 + +#endif // MBEDTLS_CONFIG_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/mbedtls_entropy_hardware_pool.c b/targets/ChibiOS/RP_PICO_W_RP2040/mbedtls_entropy_hardware_pool.c new file mode 100644 index 0000000000..22a3db0612 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/mbedtls_entropy_hardware_pool.c @@ -0,0 +1,58 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include + +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen); + +// RP2040 ROSC random bit register +#define ROSC_BASE 0x40060000 +#define ROSC_RANDOMBIT (*(volatile uint32_t *)(ROSC_BASE + 0x1C)) + +static uint32_t rp2040_get_random_u32(void) +{ + uint32_t value = 0; + + for (int i = 0; i < 32; i++) + { + value = (value << 1) | (ROSC_RANDOMBIT & 1u); + } + + return value; +} + +// Get len bytes of entropy from the RP2040 ROSC. +int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) +{ + (void)data; + + for (size_t i = 0; i < len; i++) + { + output[i] = (unsigned char)(rp2040_get_random_u32() & 0xFF); + } + + *olen = len; + + return 0; +} + +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, + size_t output_size, + size_t *output_length) +{ + (void)context; + + for (size_t i = 0; i < output_size; i++) + { + output[i] = (uint8_t)(rp2040_get_random_u32() & 0xFF); + } + + *output_length = output_size; + + return PSA_SUCCESS; +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/CMakeLists.txt b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/CMakeLists.txt new file mode 100644 index 0000000000..520d67bd04 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/CMakeLists.txt @@ -0,0 +1,9 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# append nanoBooter source files +list(APPEND NANOBOOTER_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c") +# make var global +set(NANOBOOTER_PROJECT_SOURCES ${NANOBOOTER_PROJECT_SOURCES} CACHE INTERNAL "make global") diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/RP2040_booter-DEBUG.ld b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/RP2040_booter-DEBUG.ld new file mode 100644 index 0000000000..3dacff675b --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/RP2040_booter-DEBUG.ld @@ -0,0 +1,89 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoBooter DEBUG memory setup. + * Same layout as release — debug builds just have larger code. + */ +MEMORY +{ + flash0 (rx) : org = 0x10000000, len = 80k /* nanoBooter + config (for __nanoImage_end__) */ + flash1 (rx) : org = 0x10000000, len = 48k /* XIP: nanoBooter */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k + deployment (rx) : org = 0x00000000, len = 0 + ramvt (wx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 256k-48 + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k + ram5 (wx) : org = 0x20041000, len = 4k + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 +} + +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); +REGION_ALIAS("MAIN_STACK_RAM", ram4); +REGION_ALIAS("PROCESS_STACK_RAM", ram4); +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); +REGION_ALIAS("BSS_RAM", ram0); +REGION_ALIAS("HEAP_RAM", ram0); +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > flash1 + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: The Pico second stage bootloader must be 256 bytes in size") +} + +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE rules_code.ld +INCLUDE rules_data.ld +INCLUDE rules_memory.ld +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/RP2040_booter.ld b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/RP2040_booter.ld new file mode 100644 index 0000000000..8d2938b0a0 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/RP2040_booter.ld @@ -0,0 +1,138 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoBooter memory setup. + * nanoBooter occupies the first 48KB of XIP flash. + * + * Flash layout: + * 0x10000000 - 0x1000BFFF : nanoBooter (48KB) + * 0x1000C000 - 0x10013FFF : Config block (32KB) + * 0x10014000 - 0x10153FFF : nanoCLR (1280KB) + * 0x10154000 - 0x101F7FFF : Deployment (656KB) + * 0x101F8000 - 0x101FFFFF : littlefs (32KB) + */ +MEMORY +{ + flash0 (rx) : org = 0x10000000, len = 80k /* nanoBooter + config (for __nanoImage_end__) */ + flash1 (rx) : org = 0x10000000, len = 48k /* XIP: nanoBooter */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k /* configuration block */ + deployment (rx) : org = 0x00000000, len = 0 /* not used in booter */ + ramvt (wx) : org = 0x00000000, len = 0 /* no RAM vector table in booter */ + ram0 (wx) : org = 0x20000000, len = 256k-48 /* SRAM0 striped */ + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k /* SRAM4 */ + ram5 (wx) : org = 0x20041000, len = 4k /* SRAM5 */ + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 /* boot clipboard at end of SRAM */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* Core 1 stack regions for SMP.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +/* RAM region to be used for the boot clipboard.*/ +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +/* RP2040 second stage bootloader must be placed at the very start of flash */ +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 + + .boot2 : { + __boot2_start__ = .; + KEEP (*(.boot2)) + __boot2_end__ = .; + } > flash1 + + ASSERT(__boot2_end__ - __boot2_start__ <= 256, + "ERROR: The Pico second stage bootloader must be 256 bytes in size") +} + +/* Stacks rules inclusion.*/ +INCLUDE rules_stacks.ld + +/* Core 1 stacks rules inclusion (SMP).*/ +INCLUDE rules_stacks_c1.ld + +/* Code rules inclusion.*/ +INCLUDE rules_code.ld + +/* Data rules inclusion.*/ +INCLUDE rules_data.ld + +/* Memory rules inclusion.*/ +INCLUDE rules_memory.ld + +/* Boot clipboard rules inclusion.*/ +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/chconf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/chconf.h new file mode 100644 index 0000000000..3c61c5914d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/chconf.h @@ -0,0 +1,854 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file rt/templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_8_0_ + +/*===========================================================================*/ +/** + * @name System settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Handling of instances. + * @note If enabled then threads assigned to various instances can + * interact each other using the same synchronization objects. + * If disabled then each OS instance is a separate world, no + * direct interactions are handled by the OS. + */ +#if !defined(CH_CFG_SMP_MODE) +#define CH_CFG_SMP_MODE TRUE +#endif + +/** + * @brief Kernel hardening level. + * @details This option is the level of functional-safety checks enabled + * in the kerkel. The meaning is: + * - 0: No checks, maximum performance. + * - 1: Reasonable checks. + * - 2: All checks. + * . + */ +#if !defined(CH_CFG_HARDENING_LEVEL) +#define CH_CFG_HARDENING_LEVEL 0 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16, 32 or 64 bits. + * @note In tick-less mode this value must match the physical system tick + * timer counter width. + */ +#if !defined(CH_CFG_ST_RESOLUTION) +#define CH_CFG_ST_RESOLUTION 32 +#endif + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + * @note This must be a frequency that is obtainable from the system tick + * timer frequency. + */ +#if !defined(CH_CFG_ST_FREQUENCY) +#define CH_CFG_ST_FREQUENCY 1000000 +#endif + +/** + * @brief Time intervals data size. + * @note Allowed values are 16, 32 or 64 bits. + */ +#if !defined(CH_CFG_INTERVALS_SIZE) +#define CH_CFG_INTERVALS_SIZE 32 +#endif + +/** + * @brief Time types data size. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#define CH_CFG_TIME_TYPES_SIZE 32 +#endif + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#if !defined(CH_CFG_ST_TIMEDELTA) +#define CH_CFG_ST_TIMEDELTA 20 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. + */ +#if !defined(CH_CFG_TIME_QUANTUM) +#define CH_CFG_TIME_QUANTUM 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. + */ +#if !defined(CH_CFG_NO_IDLE_THREAD) +#define CH_CFG_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#define CH_CFG_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TM) +#define CH_CFG_USE_TM TRUE +#endif + +/** + * @brief Time Stamps APIs. + * @details If enabled then the time stamps APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TIMESTAMP) +#define CH_CFG_USE_TIMESTAMP TRUE +#endif + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_REGISTRY) +#define CH_CFG_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_WAITEXIT) +#define CH_CFG_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_SEMAPHORES) +#define CH_CFG_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MUTEXES) +#define CH_CFG_USE_MUTEXES TRUE +#endif + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_CONDVARS) +#define CH_CFG_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_EVENTS) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#if !defined(CH_CFG_USE_EVENTS_TIMEOUT) +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MESSAGES) +#define CH_CFG_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#if !defined(CH_CFG_USE_DYNAMIC) +#define CH_CFG_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name OSLIB options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_MAILBOXES) +#define CH_CFG_USE_MAILBOXES TRUE +#endif + +/** + * @brief Memory checks APIs. + * @details If enabled then the memory checks APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCHECKS) +#define CH_CFG_USE_MEMCHECKS TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCORE) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#if !defined(CH_CFG_MEMCORE_SIZE) +#define CH_CFG_MEMCORE_SIZE 0 +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_CFG_USE_HEAP) +#define CH_CFG_USE_HEAP TRUE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMPOOLS) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Objects FIFOs APIs. + * @details If enabled then the objects FIFOs APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_FIFOS) +#define CH_CFG_USE_OBJ_FIFOS TRUE +#endif + +/** + * @brief Pipes APIs. + * @details If enabled then the pipes APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_PIPES) +#define CH_CFG_USE_PIPES TRUE +#endif + +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + +/** + * @brief Delegate threads APIs. + * @details If enabled then the delegate threads APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_DELEGATES) +#define CH_CFG_USE_DELEGATES TRUE +#endif + +/** + * @brief Jobs Queues APIs. + * @details If enabled then the jobs queues APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_JOBS) +#define CH_CFG_USE_JOBS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Objects factory options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Objects Factory APIs. + * @details If enabled then the objects factory APIs are included in the + * kernel. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_CFG_USE_FACTORY) +#define CH_CFG_USE_FACTORY TRUE +#endif + +/** + * @brief Maximum length for object names. + * @details If the specified length is zero then the name is stored by + * pointer but this could have unintended side effects. + */ +#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#endif + +/** + * @brief Enables the registry of generic objects. + */ +#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#endif + +/** + * @brief Enables factory for generic buffers. + */ +#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#endif + +/** + * @brief Enables factory for semaphores. + */ +#if !defined(CH_CFG_FACTORY_SEMAPHORES) +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#endif + +/** + * @brief Enables factory for mailboxes. + */ +#if !defined(CH_CFG_FACTORY_MAILBOXES) +#define CH_CFG_FACTORY_MAILBOXES TRUE +#endif + +/** + * @brief Enables factory for objects FIFOs. + */ +#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#endif + +/** + * @brief Enables factory for Pipes. + */ +#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the trace buffer is activated. + * + * @note The default is @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_MASK) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p thread_t structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. + */ +#if !defined(CH_DBG_THREADS_PROFILING) +#define CH_DBG_THREADS_PROFILING FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System structure extension. + * @details User fields added to the end of the @p ch_system_t structure. + */ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* Add system custom fields here.*/ + +/** + * @brief System initialization hook. + * @details User initialization code added to the @p chSysInit() function + * just before interrupts are enabled globally. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() do { \ + /* Add system initialization code here.*/ \ +} while (false) + +/** + * @brief OS instance structure extension. + * @details User fields added to the end of the @p os_instance_t structure. + */ +#define CH_CFG_OS_INSTANCE_EXTRA_FIELDS \ + /* Add OS instance custom fields here.*/ + +/** + * @brief OS instance initialization hook. + * + * @param[in] oip pointer to the @p os_instance_t structure + */ +#define CH_CFG_OS_INSTANCE_INIT_HOOK(oip) do { \ + /* Add OS instance initialization code here.*/ \ +} while (false) + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p _thread_init() function. + * + * @note It is invoked from within @p _thread_init() and implicitly from all + * the threads creation APIs. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) do { \ + /* Add threads initialization code here.*/ \ +} while (false) + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) do { \ + /* Add threads finalization code here.*/ \ +} while (false) + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + * + * @param[in] ntp thread being switched in + * @param[in] otp thread being switched out + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) do { \ + /* Context switch code here.*/ \ +} while (false) + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() do { \ + /* IRQ prologue code here.*/ \ +} while (false) + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() do { \ + /* IRQ epilogue code here.*/ \ +} while (false) + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() do { \ + /* Idle-enter code here.*/ \ +} while (false) + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() do { \ + /* Idle-leave code here.*/ \ +} while (false) + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() do { \ + /* Idle loop code here.*/ \ +} while (false) + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() do { \ + /* System tick event code here.*/ \ +} while (false) + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) do { \ + /* System halt code here.*/ \ +} while (false) + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) do { \ + /* Trace code here.*/ \ +} while (false) + +/** + * @brief Runtime Faults Collection Unit hook. + * @details This hook is invoked each time new faults are collected and stored. + */ +#define CH_CFG_RUNTIME_FAULTS_HOOK(mask) do { \ + /* Faults handling code here.*/ \ +} while (false) + +/** + * @brief Safety checks hook. + * @details This hook is invoked when there is a safety violation and the + * system is going to stop. + */ +#define CH_CFG_SAFETY_CHECK_HOOK(l, f) do { \ + /* Safety handling code here.*/ \ + chSysHalt(f); \ +} while (false) + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/halconf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/halconf.h new file mode 100644 index 0000000000..fba5092768 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/halconf.h @@ -0,0 +1,573 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef HALCONF_H +#define HALCONF_H + +#define _CHIBIOS_HAL_CONF_ +#define _CHIBIOS_HAL_CONF_VER_9_1_ + +#include "mcuconf.h" + +/** + * @brief Enables the HAL safety subsystem. + */ +#if !defined(HAL_USE_SAFETY) || defined(__DOXYGEN__) +#define HAL_USE_SAFETY FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC FALSE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the cryptographic subsystem. + */ +#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__) +#define HAL_USE_CRY FALSE +#endif + +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC FALSE +#endif + +/** + * @brief Enables the EFlash subsystem. + */ +#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__) +#define HAL_USE_EFL TRUE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB TRUE +#endif + +/** + * @brief Enables the SIO subsystem. + */ +#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__) +#define HAL_USE_SIO TRUE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the TRNG subsystem. + */ +#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__) +#define HAL_USE_TRNG FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB TRUE +#endif + +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + +/** + * @brief Enables the WSPI subsystem. + */ +#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__) +#define HAL_USE_WSPI FALSE +#endif + +/*===========================================================================*/ +/* PAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__) +#define PAL_USE_CALLBACKS FALSE +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__) +#define PAL_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/** + * @brief Enforces the driver to use direct callbacks rather than OSAL events. + */ +#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__) +#define CAN_ENFORCE_USE_CALLBACKS FALSE +#endif + +/*===========================================================================*/ +/* CRY driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the SW fall-back of the cryptographic driver. + * @details When enabled, this option, activates a fall-back software + * implementation for algorithms not supported by the underlying + * hardware. + * @note Fall-back implementations may not be present for all algorithms. + */ +#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_USE_FALLBACK FALSE +#endif + +/** + * @brief Makes the driver forcibly use the fall-back implementations. + */ +#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_ENFORCE_FALLBACK FALSE +#endif + +/*===========================================================================*/ +/* DAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__) +#define DAC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DAC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Slave mode API enable switch. + * @note The low level driver must support this capability. + */ +#if !defined(I2C_ENABLE_SLAVE_MODE) +#define I2C_ENABLE_SLAVE_MODE FALSE +#endif + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the zero-copy API. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Timeout before assuming a failure while waiting for card idle. + * @note Time is in milliseconds. + */ +#if !defined(MMC_IDLE_TIMEOUT_MS) || defined(__DOXYGEN__) +#define MMC_IDLE_TIMEOUT_MS 1000 +#endif + +/** + * @brief Mutual exclusion on the SPI bus. + */ +#if !defined(MMC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define MMC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/** + * @brief OCR initialization constant for V20 cards. + */ +#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__) +#define SDC_INIT_OCR_V20 0x50FF8000U +#endif + +/** + * @brief OCR initialization constant for non-V20 cards. + */ +#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__) +#define SDC_INIT_OCR 0x80100000U +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 16 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SIO driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SIO_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SIO_DEFAULT_BITRATE 115200 +#endif + +/** + * @brief Support for thread synchronization API. + */ +#if !defined(SIO_USE_SYNCHRONIZATION) || defined(__DOXYGEN__) +#define SIO_USE_SYNCHRONIZATION TRUE +#endif + +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. + * @note The default is 256 bytes for both transmission and receive + * buffers; set to 64 to match every other ChibiOS nanoFramework + * target. This is sufficient for Wire Protocol traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 64 +#endif + +/** + * @brief Serial over USB number of buffers. + * @note The default is 2 buffers; set to 1 to match every other ChibiOS + * nanoFramework target, which is sufficient for Wire Protocol + * traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_NUMBER 1 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Inserts an assertion on function errors before returning. + */ +#if !defined(SPI_USE_ASSERT_ON_ERROR) || defined(__DOXYGEN__) +#define SPI_USE_ASSERT_ON_ERROR TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +/** + * @brief Handling method for SPI CS line. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__) +#define SPI_SELECT_MODE SPI_SELECT_MODE_LINE +#endif + +/*===========================================================================*/ +/* UART driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__) +#define UART_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define UART_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* USB driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* WSPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__) +#define WSPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define WSPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#include "halconf_nf.h" + +#endif /* HALCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/halconf_nf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/halconf_nf.h new file mode 100644 index 0000000000..87d94d8b33 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/halconf_nf.h @@ -0,0 +1,16 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef HALCONF_NF_H +#define HALCONF_NF_H + +// nanoFramework HAL overlay for nanoBooter + +// RP2040 does not have STM32-specific peripherals +#define HAL_NF_USE_STM32_CRC FALSE +#define HAL_NF_USE_STM32_RNG FALSE +#define HAL_NF_USE_STM32_FLASH FALSE + +#endif // HALCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/main.c b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/main.c new file mode 100644 index 0000000000..6f713d5cac --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/main.c @@ -0,0 +1,86 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include + +#include +#include +#include +#include +#include + +// need to declare the Receiver thread here +osThreadDef(ReceiverThread, osPriorityHigh, 2048, "ReceiverThread"); + +// Application entry point. +int main(void) +{ + // HAL initialization, this also initializes the configured device drivers + // and performs the board-specific initializations. + halInit(); + + // init boot clipboard + InitBootClipboard(); + + // The kernel is initialized but not started yet, this means that + // main() is executing with absolute priority but interrupts are already enabled. + osKernelInitialize(); + + // the following IF is not mandatory, it's just providing a way for a user to 'force' + // the board to remain in nanoBooter and not launching nanoCLR + + // check if there is a request to remain on nanoBooter + if (!IsToRemainInBooter()) + { + // check for valid CLR image at address contiguous to nanoBooter + volatile uint32_t *clrVector = (volatile uint32_t *)(uint32_t)&__nanoImage_end__; + uint32_t msp = clrVector[0]; + uint32_t resetHandler = clrVector[1]; + + if (msp != 0xFFFFFFFF && msp != 0x00000000 && + resetHandler > 0x10000000 && resetHandler < 0x10200000) + { + // there seems to be a valid CLR image + // launch nanoCLR + LaunchCLR((uint32_t)&__nanoImage_end__); + } + } + + // Initializes a serial-over-USB CDC driver. + sduObjectInit(&SERIAL_DRIVER); + sduStart(&SERIAL_DRIVER, &serusbcfg); + + // Activates the USB driver and then the USB bus pull-up on D+. + // Note, a delay is inserted in order to not have to disconnect the cable after a reset. + usbDisconnectBus(serusbcfg.usbp); + chThdSleepMilliseconds(100); + usbStart(serusbcfg.usbp, &usbcfg); + usbConnectBus(serusbcfg.usbp); + + // create the receiver thread + osThreadCreate(osThread(ReceiverThread), NULL); + + // start kernel, after this main() will behave like a thread with priority osPriorityNormal + osKernelStart(); + + // initialize block storage list and devices + // in CLR this is called in nanoHAL_Initialize() + // for nanoBooter we have to init it in order to provide the flash map for Monitor_FlashSectorMap command + BlockStorageList_Initialize(); + BlockStorage_AddDevices(); + BlockStorageList_InitializeDevices(); + + // report successful nanoBooter execution + ReportSuccessfullNanoBooter(); + + // Normal main() thread + // NOTE: On Pico W, GP25 is the CYW43 WiFi SPI CS — do NOT toggle it as LED. + while (true) + { + osDelay(500); + } +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/mcuconf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/mcuconf.h new file mode 100644 index 0000000000..27aa61772d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/mcuconf.h @@ -0,0 +1,100 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 +#define RP_IRQ_RTC_PRIORITY 2 + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 TRUE +#define RP_SIO_USE_UART1 TRUE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USB1 TRUE +#define RP_IRQ_USB0_PRIORITY 2 + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 FALSE +#define RP_SPI_USE_SPI1 FALSE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 FALSE +#define RP_I2C_USE_I2C1 FALSE + +/* + * PWM driver system settings. + */ +#define RP_PWM_USE_PWM0 FALSE +#define RP_PWM_USE_PWM1 FALSE +#define RP_PWM_USE_PWM2 FALSE +#define RP_PWM_USE_PWM3 FALSE +#define RP_PWM_USE_PWM4 FALSE +#define RP_PWM_USE_PWM5 FALSE +#define RP_PWM_USE_PWM6 FALSE +#define RP_PWM_USE_PWM7 FALSE + +#endif /* MCUCONF_H */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/mcuconf_nf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/mcuconf_nf.h new file mode 100644 index 0000000000..fea73e7942 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/mcuconf_nf.h @@ -0,0 +1,12 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef MCUCONF_NF_H +#define MCUCONF_NF_H + +// nanoFramework MCU overlay for nanoBooter +// No additional MCU settings needed for nanoBooter at this stage + +#endif // MCUCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/target_board.h.in b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/target_board.h.in new file mode 100644 index 0000000000..ac85c850b9 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoBooter/target_board.h.in @@ -0,0 +1,18 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +////////////////////////////////////////////////////////////////////////////// +// This file was automatically generated by a tool. // +// Any changes you make here will be overwritten when it's generated again. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef TARGET_BOARD_NANOBOOTER_H +#define TARGET_BOARD_NANOBOOTER_H + +#include + +#define OEMSYSTEMINFOSTRING "nanoBooter running @ @TARGET_NAME@" + +#endif // TARGET_BOARD_NANOBOOTER_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/CMakeLists.txt b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/CMakeLists.txt new file mode 100644 index 0000000000..f5fab75926 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/CMakeLists.txt @@ -0,0 +1,11 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + +# append nanoCLR source files +list(APPEND NANOCLR_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.c") +list(APPEND NANOCLR_PROJECT_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/nanoHAL.cpp") + +# make var global +set(NANOCLR_PROJECT_SOURCES ${NANOCLR_PROJECT_SOURCES} CACHE INTERNAL "make global") diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/RP2040_CLR-DEBUG.ld b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/RP2040_CLR-DEBUG.ld new file mode 100644 index 0000000000..158baaab1c --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/RP2040_CLR-DEBUG.ld @@ -0,0 +1,82 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoCLR DEBUG memory setup. + * Same layout as release. + */ +MEMORY +{ + flash0 (rx) : org = 0x10014000, len = 1280k /* XIP: nanoCLR (also defines __nanoImage_start__) */ + flash1 (rx) : org = 0x10014000, len = 1280k + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k + deployment (rx) : org = 0x10154000, len = 656k + ramvt (wx) : org = 0x00000000, len = 0 + ram0 (wx) : org = 0x20000000, len = 256k-48 + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k + ram5 (wx) : org = 0x20041000, len = 4k + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 +} + +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); +REGION_ALIAS("MAIN_STACK_RAM", ram4); +REGION_ALIAS("PROCESS_STACK_RAM", ram4); +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); +REGION_ALIAS("BSS_RAM", ram0); +REGION_ALIAS("HEAP_RAM", ram0); +REGION_ALIAS("CLR_MANAGED_HEAP_RAM", ram0); +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 +} + +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE rules_code.ld +INCLUDE rules_data.ld +INCLUDE rules_memory.ld +INCLUDE rules_clr.ld +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/RP2040_CLR.ld b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/RP2040_CLR.ld new file mode 100644 index 0000000000..960c314308 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/RP2040_CLR.ld @@ -0,0 +1,126 @@ +/* +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2026 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// +*/ + +/* The RP2040 requires 256-byte vector table alignment to run from flash. */ +__vectors_align__ = 256; + +/* + * RP2040 nanoCLR memory setup. + * + * Flash layout (WiFi variant — needs more code space for CYW43 firmware blob): + * 0x10000000 - 0x1000BFFF : nanoBooter (48KB) - not used by CLR + * 0x1000C000 - 0x10013FFF : Config block (32KB) - read-only from CLR + * 0x10014000 - 0x10153FFF : nanoCLR (1280KB) + * 0x10154000 - 0x101F7FFF : Deployment (656KB) + * 0x101F8000 - 0x101FFFFF : littlefs (32KB) + * + * When updating the flash1 address below make sure to update the address + * in nf_generate_bin_package if applicable. + */ +MEMORY +{ + flash0 (rx) : org = 0x10014000, len = 1280k /* XIP: nanoCLR (also defines __nanoImage_start__) */ + flash1 (rx) : org = 0x10014000, len = 1280k /* XIP: nanoCLR */ + flash2 (rx) : org = 0x00000000, len = 0 + flash3 (rx) : org = 0x00000000, len = 0 + flash4 (rx) : org = 0x00000000, len = 0 + flash5 (rx) : org = 0x00000000, len = 0 + flash6 (rx) : org = 0x00000000, len = 0 + flash7 (rx) : org = 0x00000000, len = 0 + config (rw) : org = 0x1000C000, len = 32k /* configuration block */ + deployment (rx) : org = 0x10154000, len = 656k /* deployment area */ + ramvt (wx) : org = 0x00000000, len = 0 /* no RAM vector table needed on M0+ */ + ram0 (wx) : org = 0x20000000, len = 256k-48 /* SRAM0 striped */ + ram1 (wx) : org = 0x00000000, len = 0 + ram2 (wx) : org = 0x00000000, len = 0 + ram3 (wx) : org = 0x00000000, len = 0 + ram4 (wx) : org = 0x20040000, len = 4k /* SRAM4 */ + ram5 (wx) : org = 0x20041000, len = 4k /* SRAM5 */ + ram6 (wx) : org = 0x00000000, len = 0 + ram7 (wx) : org = 0x00000000, len = 0 + bootclpbrd : org = 0x2003FFD0, len = 48 /* boot clipboard at end of SRAM */ +} + +/* For each data/text section two region are defined, a virtual region + and a load region (_LMA suffix).*/ + +/* Flash region to be used for exception vectors.*/ +REGION_ALIAS("VECTORS_FLASH", flash1); +REGION_ALIAS("VECTORS_FLASH_LMA", flash1); + +/* Flash region to be used for constructors and destructors.*/ +REGION_ALIAS("XTORS_FLASH", flash1); +REGION_ALIAS("XTORS_FLASH_LMA", flash1); + +/* Flash region to be used for code text.*/ +REGION_ALIAS("TEXT_FLASH", flash1); +REGION_ALIAS("TEXT_FLASH_LMA", flash1); + +/* Flash region to be used for read only data.*/ +REGION_ALIAS("RODATA_FLASH", flash1); +REGION_ALIAS("RODATA_FLASH_LMA", flash1); + +/* Flash region to be used for various.*/ +REGION_ALIAS("VARIOUS_FLASH", flash1); +REGION_ALIAS("VARIOUS_FLASH_LMA", flash1); + +/* Flash region to be used for RAM(n) initialization data.*/ +REGION_ALIAS("RAM_INIT_FLASH_LMA", flash1); + +/* RAM region to be used for Main stack. This stack accommodates the processing + of all exceptions and interrupts.*/ +REGION_ALIAS("MAIN_STACK_RAM", ram4); + +/* RAM region to be used for the process stack. This is the stack used by + the main() function.*/ +REGION_ALIAS("PROCESS_STACK_RAM", ram4); + +/* Core 1 stack regions for SMP.*/ +REGION_ALIAS("C1_MAIN_STACK_RAM", ram5); +REGION_ALIAS("C1_PROCESS_STACK_RAM", ram5); + +/* RAM region to be used for data segment.*/ +REGION_ALIAS("DATA_RAM", ram0); +REGION_ALIAS("DATA_RAM_LMA", flash1); + +/* RAM region to be used for BSS segment.*/ +REGION_ALIAS("BSS_RAM", ram0); + +/* RAM region to be used for the default heap.*/ +REGION_ALIAS("HEAP_RAM", ram0); + +/* RAM region to be used for the nanoFramework CLR managed heap.*/ +REGION_ALIAS("CLR_MANAGED_HEAP_RAM", ram0); + +/* RAM region to be used for the boot clipboard.*/ +REGION_ALIAS("SECTION_FOR_BOOTCLIPBOARD", bootclpbrd); + +/* RP2040 second stage bootloader must be placed at the very start of flash. + For nanoCLR, the boot2 section is empty since nanoBooter owns the flash start. + However, the vector table still needs to be at the start of CLR flash region. */ +SECTIONS +{ + .flash_begin : { + __flash_binary_start = .; + } > flash1 +} + +INCLUDE rules_stacks.ld +INCLUDE rules_stacks_c1.ld +INCLUDE rules_code.ld +INCLUDE rules_data.ld +INCLUDE rules_memory.ld +INCLUDE rules_clr.ld +INCLUDE rules_bootclipboard.ld + +SECTIONS +{ + .flash_end : { + __flash_binary_end = .; + } > flash1 +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/chconf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/chconf.h new file mode 100644 index 0000000000..3c61c5914d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/chconf.h @@ -0,0 +1,854 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file rt/templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H +#define CHCONF_H + +#define _CHIBIOS_RT_CONF_ +#define _CHIBIOS_RT_CONF_VER_8_0_ + +/*===========================================================================*/ +/** + * @name System settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Handling of instances. + * @note If enabled then threads assigned to various instances can + * interact each other using the same synchronization objects. + * If disabled then each OS instance is a separate world, no + * direct interactions are handled by the OS. + */ +#if !defined(CH_CFG_SMP_MODE) +#define CH_CFG_SMP_MODE TRUE +#endif + +/** + * @brief Kernel hardening level. + * @details This option is the level of functional-safety checks enabled + * in the kerkel. The meaning is: + * - 0: No checks, maximum performance. + * - 1: Reasonable checks. + * - 2: All checks. + * . + */ +#if !defined(CH_CFG_HARDENING_LEVEL) +#define CH_CFG_HARDENING_LEVEL 0 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16, 32 or 64 bits. + * @note In tick-less mode this value must match the physical system tick + * timer counter width. + */ +#if !defined(CH_CFG_ST_RESOLUTION) +#define CH_CFG_ST_RESOLUTION 32 +#endif + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + * @note This must be a frequency that is obtainable from the system tick + * timer frequency. + */ +#if !defined(CH_CFG_ST_FREQUENCY) +#define CH_CFG_ST_FREQUENCY 1000000 +#endif + +/** + * @brief Time intervals data size. + * @note Allowed values are 16, 32 or 64 bits. + */ +#if !defined(CH_CFG_INTERVALS_SIZE) +#define CH_CFG_INTERVALS_SIZE 32 +#endif + +/** + * @brief Time types data size. + * @note Allowed values are 16 or 32 bits. + */ +#if !defined(CH_CFG_TIME_TYPES_SIZE) +#define CH_CFG_TIME_TYPES_SIZE 32 +#endif + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#if !defined(CH_CFG_ST_TIMEDELTA) +#define CH_CFG_ST_TIMEDELTA 20 +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + * @note The round robin preemption is not supported in tickless mode and + * must be set to zero in that case. + */ +#if !defined(CH_CFG_TIME_QUANTUM) +#define CH_CFG_TIME_QUANTUM 0 +#endif + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread. The application @p main() + * function becomes the idle thread and must implement an + * infinite loop. + */ +#if !defined(CH_CFG_NO_IDLE_THREAD) +#define CH_CFG_NO_IDLE_THREAD FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_OPTIMIZE_SPEED) +#define CH_CFG_OPTIMIZE_SPEED TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TM) +#define CH_CFG_USE_TM TRUE +#endif + +/** + * @brief Time Stamps APIs. + * @details If enabled then the time stamps APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_TIMESTAMP) +#define CH_CFG_USE_TIMESTAMP TRUE +#endif + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_REGISTRY) +#define CH_CFG_USE_REGISTRY TRUE +#endif + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_WAITEXIT) +#define CH_CFG_USE_WAITEXIT TRUE +#endif + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_SEMAPHORES) +#define CH_CFG_USE_SEMAPHORES TRUE +#endif + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_SEMAPHORES_PRIORITY) +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE +#endif + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MUTEXES) +#define CH_CFG_USE_MUTEXES TRUE +#endif + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_MUTEXES_RECURSIVE) +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE +#endif + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#if !defined(CH_CFG_USE_CONDVARS) +#define CH_CFG_USE_CONDVARS TRUE +#endif + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#if !defined(CH_CFG_USE_CONDVARS_TIMEOUT) +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE +#endif + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_EVENTS) +#define CH_CFG_USE_EVENTS TRUE +#endif + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#if !defined(CH_CFG_USE_EVENTS_TIMEOUT) +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE +#endif + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MESSAGES) +#define CH_CFG_USE_MESSAGES TRUE +#endif + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special + * requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#if !defined(CH_CFG_USE_MESSAGES_PRIORITY) +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE +#endif + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#if !defined(CH_CFG_USE_DYNAMIC) +#define CH_CFG_USE_DYNAMIC TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name OSLIB options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#if !defined(CH_CFG_USE_MAILBOXES) +#define CH_CFG_USE_MAILBOXES TRUE +#endif + +/** + * @brief Memory checks APIs. + * @details If enabled then the memory checks APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCHECKS) +#define CH_CFG_USE_MEMCHECKS TRUE +#endif + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMCORE) +#define CH_CFG_USE_MEMCORE TRUE +#endif + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#if !defined(CH_CFG_MEMCORE_SIZE) +#define CH_CFG_MEMCORE_SIZE 0 +#endif + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#if !defined(CH_CFG_USE_HEAP) +#define CH_CFG_USE_HEAP TRUE +#endif + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_MEMPOOLS) +#define CH_CFG_USE_MEMPOOLS TRUE +#endif + +/** + * @brief Objects FIFOs APIs. + * @details If enabled then the objects FIFOs APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_FIFOS) +#define CH_CFG_USE_OBJ_FIFOS TRUE +#endif + +/** + * @brief Pipes APIs. + * @details If enabled then the pipes APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_PIPES) +#define CH_CFG_USE_PIPES TRUE +#endif + +/** + * @brief Objects Caches APIs. + * @details If enabled then the objects caches APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_OBJ_CACHES) +#define CH_CFG_USE_OBJ_CACHES TRUE +#endif + +/** + * @brief Delegate threads APIs. + * @details If enabled then the delegate threads APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_DELEGATES) +#define CH_CFG_USE_DELEGATES TRUE +#endif + +/** + * @brief Jobs Queues APIs. + * @details If enabled then the jobs queues APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(CH_CFG_USE_JOBS) +#define CH_CFG_USE_JOBS TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Objects factory options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Objects Factory APIs. + * @details If enabled then the objects factory APIs are included in the + * kernel. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_CFG_USE_FACTORY) +#define CH_CFG_USE_FACTORY TRUE +#endif + +/** + * @brief Maximum length for object names. + * @details If the specified length is zero then the name is stored by + * pointer but this could have unintended side effects. + */ +#if !defined(CH_CFG_FACTORY_MAX_NAMES_LENGTH) +#define CH_CFG_FACTORY_MAX_NAMES_LENGTH 8 +#endif + +/** + * @brief Enables the registry of generic objects. + */ +#if !defined(CH_CFG_FACTORY_OBJECTS_REGISTRY) +#define CH_CFG_FACTORY_OBJECTS_REGISTRY TRUE +#endif + +/** + * @brief Enables factory for generic buffers. + */ +#if !defined(CH_CFG_FACTORY_GENERIC_BUFFERS) +#define CH_CFG_FACTORY_GENERIC_BUFFERS TRUE +#endif + +/** + * @brief Enables factory for semaphores. + */ +#if !defined(CH_CFG_FACTORY_SEMAPHORES) +#define CH_CFG_FACTORY_SEMAPHORES TRUE +#endif + +/** + * @brief Enables factory for mailboxes. + */ +#if !defined(CH_CFG_FACTORY_MAILBOXES) +#define CH_CFG_FACTORY_MAILBOXES TRUE +#endif + +/** + * @brief Enables factory for objects FIFOs. + */ +#if !defined(CH_CFG_FACTORY_OBJ_FIFOS) +#define CH_CFG_FACTORY_OBJ_FIFOS TRUE +#endif + +/** + * @brief Enables factory for Pipes. + */ +#if !defined(CH_CFG_FACTORY_PIPES) || defined(__DOXYGEN__) +#define CH_CFG_FACTORY_PIPES TRUE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_STATISTICS) +#define CH_DBG_STATISTICS FALSE +#endif + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_SYSTEM_STATE_CHECK) +#define CH_DBG_SYSTEM_STATE_CHECK FALSE +#endif + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_CHECKS) +#define CH_DBG_ENABLE_CHECKS FALSE +#endif + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_ENABLE_ASSERTS) +#define CH_DBG_ENABLE_ASSERTS FALSE +#endif + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the trace buffer is activated. + * + * @note The default is @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_MASK) +#define CH_DBG_TRACE_MASK CH_DBG_TRACE_MASK_DISABLED +#endif + +/** + * @brief Trace buffer entries. + * @note The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is + * different from @p CH_DBG_TRACE_MASK_DISABLED. + */ +#if !defined(CH_DBG_TRACE_BUFFER_SIZE) +#define CH_DBG_TRACE_BUFFER_SIZE 128 +#endif + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) +#define CH_DBG_ENABLE_STACK_CHECK FALSE +#endif + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#if !defined(CH_DBG_FILL_THREADS) +#define CH_DBG_FILL_THREADS FALSE +#endif + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p thread_t structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p FALSE. + * @note This debug option is not currently compatible with the + * tickless mode. + */ +#if !defined(CH_DBG_THREADS_PROFILING) +#define CH_DBG_THREADS_PROFILING FALSE +#endif + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System structure extension. + * @details User fields added to the end of the @p ch_system_t structure. + */ +#define CH_CFG_SYSTEM_EXTRA_FIELDS \ + /* Add system custom fields here.*/ + +/** + * @brief System initialization hook. + * @details User initialization code added to the @p chSysInit() function + * just before interrupts are enabled globally. + */ +#define CH_CFG_SYSTEM_INIT_HOOK() do { \ + /* Add system initialization code here.*/ \ +} while (false) + +/** + * @brief OS instance structure extension. + * @details User fields added to the end of the @p os_instance_t structure. + */ +#define CH_CFG_OS_INSTANCE_EXTRA_FIELDS \ + /* Add OS instance custom fields here.*/ + +/** + * @brief OS instance initialization hook. + * + * @param[in] oip pointer to the @p os_instance_t structure + */ +#define CH_CFG_OS_INSTANCE_INIT_HOOK(oip) do { \ + /* Add OS instance initialization code here.*/ \ +} while (false) + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p _thread_init() function. + * + * @note It is invoked from within @p _thread_init() and implicitly from all + * the threads creation APIs. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) do { \ + /* Add threads initialization code here.*/ \ +} while (false) + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + * + * @param[in] tp pointer to the @p thread_t structure + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) do { \ + /* Add threads finalization code here.*/ \ +} while (false) + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + * + * @param[in] ntp thread being switched in + * @param[in] otp thread being switched out + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) do { \ + /* Context switch code here.*/ \ +} while (false) + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() do { \ + /* IRQ prologue code here.*/ \ +} while (false) + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() do { \ + /* IRQ epilogue code here.*/ \ +} while (false) + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() do { \ + /* Idle-enter code here.*/ \ +} while (false) + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() do { \ + /* Idle-leave code here.*/ \ +} while (false) + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() do { \ + /* Idle loop code here.*/ \ +} while (false) + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() do { \ + /* System tick event code here.*/ \ +} while (false) + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) do { \ + /* System halt code here.*/ \ +} while (false) + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) do { \ + /* Trace code here.*/ \ +} while (false) + +/** + * @brief Runtime Faults Collection Unit hook. + * @details This hook is invoked each time new faults are collected and stored. + */ +#define CH_CFG_RUNTIME_FAULTS_HOOK(mask) do { \ + /* Faults handling code here.*/ \ +} while (false) + +/** + * @brief Safety checks hook. + * @details This hook is invoked when there is a safety violation and the + * system is going to stop. + */ +#define CH_CFG_SAFETY_CHECK_HOOK(l, f) do { \ + /* Safety handling code here.*/ \ + chSysHalt(f); \ +} while (false) + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#endif /* CHCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/halconf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/halconf.h new file mode 100644 index 0000000000..f0568bff0b --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/halconf.h @@ -0,0 +1,574 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef HALCONF_H +#define HALCONF_H + +#define _CHIBIOS_HAL_CONF_ +#define _CHIBIOS_HAL_CONF_VER_9_1_ + +#include +#include "mcuconf.h" + +/** + * @brief Enables the HAL safety subsystem. + */ +#if !defined(HAL_USE_SAFETY) || defined(__DOXYGEN__) +#define HAL_USE_SAFETY FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC FALSE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the cryptographic subsystem. + */ +#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__) +#define HAL_USE_CRY FALSE +#endif + +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC FALSE +#endif + +/** + * @brief Enables the EFlash subsystem. + */ +#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__) +#define HAL_USE_EFL TRUE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB TRUE +#endif + +/** + * @brief Enables the SIO subsystem. + */ +#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__) +#define HAL_USE_SIO TRUE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the TRNG subsystem. + */ +#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__) +#define HAL_USE_TRNG FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB TRUE +#endif + +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + +/** + * @brief Enables the WSPI subsystem. + */ +#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__) +#define HAL_USE_WSPI FALSE +#endif + +/*===========================================================================*/ +/* PAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__) +#define PAL_USE_CALLBACKS TRUE +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__) +#define PAL_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/** + * @brief Enforces the driver to use direct callbacks rather than OSAL events. + */ +#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__) +#define CAN_ENFORCE_USE_CALLBACKS FALSE +#endif + +/*===========================================================================*/ +/* CRY driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the SW fall-back of the cryptographic driver. + * @details When enabled, this option, activates a fall-back software + * implementation for algorithms not supported by the underlying + * hardware. + * @note Fall-back implementations may not be present for all algorithms. + */ +#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_USE_FALLBACK FALSE +#endif + +/** + * @brief Makes the driver forcibly use the fall-back implementations. + */ +#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__) +#define HAL_CRY_ENFORCE_FALLBACK FALSE +#endif + +/*===========================================================================*/ +/* DAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__) +#define DAC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DAC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Slave mode API enable switch. + * @note The low level driver must support this capability. + */ +#if !defined(I2C_ENABLE_SLAVE_MODE) +#define I2C_ENABLE_SLAVE_MODE FALSE +#endif + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the zero-copy API. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Timeout before assuming a failure while waiting for card idle. + * @note Time is in milliseconds. + */ +#if !defined(MMC_IDLE_TIMEOUT_MS) || defined(__DOXYGEN__) +#define MMC_IDLE_TIMEOUT_MS 1000 +#endif + +/** + * @brief Mutual exclusion on the SPI bus. + */ +#if !defined(MMC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define MMC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/** + * @brief OCR initialization constant for V20 cards. + */ +#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__) +#define SDC_INIT_OCR_V20 0x50FF8000U +#endif + +/** + * @brief OCR initialization constant for non-V20 cards. + */ +#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__) +#define SDC_INIT_OCR 0x80100000U +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 38400 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 16 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SIO driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SIO_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SIO_DEFAULT_BITRATE 115200 +#endif + +/** + * @brief Support for thread synchronization API. + */ +#if !defined(SIO_USE_SYNCHRONIZATION) || defined(__DOXYGEN__) +#define SIO_USE_SYNCHRONIZATION TRUE +#endif + +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. +* @note The default is 256 bytes for both transmission and receive + * buffers; set to 64 to match every other ChibiOS nanoFramework + * target. This is sufficient for Wire Protocol traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 64 +#endif + +/** + * @brief Serial over USB number of buffers. + * @note The default is 2 buffers; set to 1 to match every other ChibiOS + * nanoFramework target, which is sufficient for Wire Protocol + * traffic. + */ +#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_NUMBER 1 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT TRUE +#endif + +/** + * @brief Inserts an assertion on function errors before returning. + */ +#if !defined(SPI_USE_ASSERT_ON_ERROR) || defined(__DOXYGEN__) +#define SPI_USE_ASSERT_ON_ERROR TRUE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +/** + * @brief Handling method for SPI CS line. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__) +#define SPI_SELECT_MODE SPI_SELECT_MODE_LINE +#endif + +/*===========================================================================*/ +/* UART driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__) +#define UART_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define UART_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* USB driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__) +#define USB_USE_WAIT FALSE +#endif + +/*===========================================================================*/ +/* WSPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__) +#define WSPI_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define WSPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +#include "halconf_nf.h" + +#endif /* HALCONF_H */ + +/** @} */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/halconf_nf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/halconf_nf.h new file mode 100644 index 0000000000..1d57e8dd3b --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/halconf_nf.h @@ -0,0 +1,15 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef HALCONF_NF_H +#define HALCONF_NF_H + +// nanoFramework HAL overlay for nanoCLR + +// RP2040 does not have STM32-specific peripherals +#define HAL_NF_USE_STM32_RNG FALSE +#define HAL_NF_USE_STM32_FLASH FALSE + +#endif // HALCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/main.c b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/main.c new file mode 100644 index 0000000000..99e593d257 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/main.c @@ -0,0 +1,72 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +// need to declare the Receiver thread here +osThreadDef(ReceiverThread, osPriorityHigh, 2048, "ReceiverThread"); +// declare CLRStartup thread here +// 8192 bytes: software TLS on Cortex-M0+ (no hardware crypto) needs ~4KB +// for mbedTLS bignum operations, on top of the CLR interpreter stack. +osThreadDef(CLRStartupThread, osPriorityNormal, 8192, "CLRStartupThread"); + +// Application entry point. +int main(void) +{ + // HAL initialization, this also initializes the configured device drivers + // and performs the board-specific initializations. + halInit(); + + // init boot clipboard + InitBootClipboard(); + + // The kernel is initialized but not started yet, this means that + // main() is executing with absolute priority but interrupts are already enabled. + osKernelInitialize(); + + // Initializes a serial-over-USB CDC driver. + sduObjectInit(&SERIAL_DRIVER); + sduStart(&SERIAL_DRIVER, &serusbcfg); + + // Activates the USB driver and then the USB bus pull-up on D+. + // Note, a delay is inserted in order to not have to disconnect the cable after a reset. + usbDisconnectBus(serusbcfg.usbp); + chThdSleepMilliseconds(100); + usbStart(serusbcfg.usbp, &usbcfg); + usbConnectBus(serusbcfg.usbp); + + // create the receiver thread + osThreadCreate(osThread(ReceiverThread), NULL); + + // CLR settings to launch CLR thread + CLR_SETTINGS clrSettings; + (void)memset(&clrSettings, 0, sizeof(CLR_SETTINGS)); + + clrSettings.MaxContextSwitches = 50; + clrSettings.WaitForDebugger = false; + clrSettings.EnterDebuggerLoopAfterExit = true; + + // create the CLR Startup thread + osThreadCreate(osThread(CLRStartupThread), &clrSettings); + + // start kernel, after this main() will behave like a thread with priority osPriorityNormal + osKernelStart(); + + while (true) + { + osDelay(100); + } +} diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/mcuconf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/mcuconf.h new file mode 100644 index 0000000000..ed2679df0a --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/mcuconf.h @@ -0,0 +1,108 @@ +/* + ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio. + + 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. +*/ + +#ifndef MCUCONF_H +#define MCUCONF_H + +/* + * RP2040_MCUCONF drivers configuration. + * Raspberry Pi Pico W variant — requires PIO for CYW43439 WiFi. + * + * IRQ priorities: + * 3...0 Lowest...Highest. + * + * DMA priorities: + * 0...1 Lowest...Highest. + */ + +#define RP2040_MCUCONF + +/* + * HAL driver system settings. + */ +#define RP_NO_INIT FALSE +#define RP_CORE1_START FALSE +#define RP_CORE1_VECTORS_TABLE _vectors +#define RP_CORE1_ENTRY_POINT _crt0_c1_entry +#define RP_CORE1_STACK_END __c1_main_stack_end__ + +/* + * IRQ system settings. + */ +#define RP_IRQ_SYSTICK_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM0_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM1_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM2_PRIORITY 2 +#define RP_IRQ_TIMER0_ALARM3_PRIORITY 2 +#define RP_IRQ_UART0_PRIORITY 3 +#define RP_IRQ_UART1_PRIORITY 3 +#define RP_IRQ_SPI0_PRIORITY 2 +#define RP_IRQ_SPI1_PRIORITY 2 +#define RP_IRQ_I2C0_PRIORITY 2 +#define RP_IRQ_I2C1_PRIORITY 2 +#define RP_IRQ_RTC_PRIORITY 2 +#define RP_IRQ_PIO0_0_PRIORITY 1 +#define RP_IRQ_PIO0_1_PRIORITY 1 + +/* + * SIO driver system settings. + */ +#define RP_SIO_USE_UART0 TRUE +#define RP_SIO_USE_UART1 TRUE + +/* + * USB driver system settings. + */ +#define RP_USB_USE_USB1 TRUE +#define RP_IRQ_USB0_PRIORITY 2 + +/* + * SPI driver system settings. + */ +#define RP_SPI_USE_SPI0 TRUE +#define RP_SPI_USE_SPI1 TRUE +#define RP_SPI_SPI0_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_RX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI1_TX_DMA_CHANNEL RP_DMA_CHANNEL_ID_ANY +#define RP_SPI_SPI0_DMA_PRIORITY 1 +#define RP_SPI_SPI1_DMA_PRIORITY 1 +#define RP_SPI_DMA_ERROR_HOOK(spip) + +/* + * I2C driver system settings. + */ +#define RP_I2C_USE_I2C0 TRUE +#define RP_I2C_USE_I2C1 TRUE + +/* + * PWM driver system settings. + */ +#define RP_PWM_USE_PWM0 TRUE +#define RP_PWM_USE_PWM1 TRUE +#define RP_PWM_USE_PWM2 TRUE +#define RP_PWM_USE_PWM3 TRUE +#define RP_PWM_USE_PWM4 TRUE +#define RP_PWM_USE_PWM5 TRUE +#define RP_PWM_USE_PWM6 TRUE +#define RP_PWM_USE_PWM7 TRUE + +/* + * ADC driver system settings. + */ +#define RP_ADC_USE_ADC1 TRUE + +#endif /* MCUCONF_H */ diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/mcuconf_nf.h b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/mcuconf_nf.h new file mode 100644 index 0000000000..3f16409d07 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/mcuconf_nf.h @@ -0,0 +1,12 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef MCUCONF_NF_H +#define MCUCONF_NF_H + +// nanoFramework MCU overlay for nanoCLR +// No additional MCU settings needed at this stage + +#endif // MCUCONF_NF_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/nanoHAL.cpp b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/nanoHAL.cpp new file mode 100644 index 0000000000..e754dd5f80 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/nanoHAL.cpp @@ -0,0 +1,8 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +bool g_fDoNotUninitializeDebuggerPort = false; diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/target_board.h.in b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/target_board.h.in new file mode 100644 index 0000000000..53a87fce3d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/nanoCLR/target_board.h.in @@ -0,0 +1,18 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +////////////////////////////////////////////////////////////////////////////// +// This file was automatically generated by a tool. // +// Any changes you make here will be overwritten when it's generated again. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef TARGET_BOARD_NANOCLR_H +#define TARGET_BOARD_NANOCLR_H + +#include + +#define OEMSYSTEMINFOSTRING "nanoCLR running @ @TARGET_NAME@" + +#endif // TARGET_BOARD_NANOCLR_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_adc_native_target.h b/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_adc_native_target.h new file mode 100644 index 0000000000..7676195632 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_adc_native_target.h @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/sys_dev_adc_native_target.h" diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_i2c_native_target.h b/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_i2c_native_target.h new file mode 100644 index 0000000000..df769321b5 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_i2c_native_target.h @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/sys_dev_i2c_native_target.h" diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_spi_native_target.h b/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_spi_native_target.h new file mode 100644 index 0000000000..bd2e2c1d69 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/sys_dev_spi_native_target.h @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/sys_dev_spi_native_target.h" diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/target_BlockStorage.c b/targets/ChibiOS/RP_PICO_W_RP2040/target_BlockStorage.c new file mode 100644 index 0000000000..d5e54b342d --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/target_BlockStorage.c @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/target_BlockStorage.c" diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/target_common.c b/targets/ChibiOS/RP_PICO_W_RP2040/target_common.c new file mode 100644 index 0000000000..073eeee722 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/target_common.c @@ -0,0 +1,7 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// Shared RP2040 implementation +#include "../_RP2040/target_common.c" diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/target_common.h.in b/targets/ChibiOS/RP_PICO_W_RP2040/target_common.h.in new file mode 100644 index 0000000000..f13a1acff8 --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/target_common.h.in @@ -0,0 +1,72 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +////////////////////////////////////////////////////////////////////////////// +// This file was automatically generated by a tool. // +// Any changes you make here will be overwritten when it's generated again. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef TARGET_COMMON_H +#define TARGET_COMMON_H + +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// +// The following addresses and sizes should be filled in according to the SoC data-sheet +// they also must be coherent with what's in the linker file for nanoBooter and nanoCLR + +// RAM base address (RP2040: 264 KB SRAM total, main 256 KB striped bank) +#define RAM1_MEMORY_StartAddress ((uint32_t)0x20000000) +// RAM size (256 KB main SRAM) +#define RAM1_MEMORY_Size ((uint32_t)0x00040000) + +// FLASH base address (RP2040: XIP flash starts at 0x10000000) +#define FLASH1_MEMORY_StartAddress ((uint32_t)0x10000000) +// FLASH size (2 MB on standard Pico board) +#define FLASH1_MEMORY_Size ((uint32_t)0x00200000) + +///////////////////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////// +// set Wire Protocol packet size +// valid sizes are 1024, 512, 256, 128 +// check Monitor_Ping_Source_Flags enum +#define WP_PACKET_SIZE 512U +////////////////////////////////////////////// + +////////////////////////////////////////////// +#define TARGETNAMESTRING "@TARGET_NAME@" +#define PLATFORMNAMESTRING "RP2040" +////////////////////////////////////////////// + +////////////////////////////////////////////// +// RP2040 has 264 KB SRAM — constrained but not as tight as STM32F0 +// set define to signal build system that this target is RAM constrained +#define TARGET_RAM_CONSTRAINED +////////////////////////////////////////////// + +///////////////////////////////////// +// RP2040 has an ROSC-based entropy source (not a true TRNG, but sufficient +// for mbedTLS seeding). This enables MBEDTLS_ENTROPY_HARDWARE_ALT so that +// mbedtls_hardware_poll() in mbedtls_entropy_hardware_pool.c is called. +#define PLATFORM_HAS_RNG TRUE +///////////////////////////////////// + +///////////////////////////////////// +// Reduce mbedTLS SSL record buffers for RAM-constrained RP2040. +// Default is 16384 each (33 KB total) which exhausts the CLR heap. +// Input needs 6144 to handle typical server certificate chains. +// Output can stay smaller (client sends are small). +#define MBEDTLS_SSL_IN_CONTENT_LEN 6144 +#define MBEDTLS_SSL_OUT_CONTENT_LEN 4096 +///////////////////////////////////// + +///////////////////////////////////// +// LED blink heartbeat (GP25 is the onboard LED on Pico) +//#define EVENTS_HEART_BEAT palToggleLine(PAL_LINE(GPIO, 25U)) +///////////////////////////////////// + +#endif // TARGET_COMMON_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/target_lwip_sntp_opts.h b/targets/ChibiOS/RP_PICO_W_RP2040/target_lwip_sntp_opts.h new file mode 100644 index 0000000000..86039e007c --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/target_lwip_sntp_opts.h @@ -0,0 +1,9 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// RP2040 has no RTC so time is bogus until SNTP syncs. +// Send the first NTP request immediately (no startup delay). +#undef SNTP_STARTUP_DELAY +#define SNTP_STARTUP_DELAY 0 diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/target_lwipopts.h b/targets/ChibiOS/RP_PICO_W_RP2040/target_lwipopts.h new file mode 100644 index 0000000000..d66b3149dd --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/target_lwipopts.h @@ -0,0 +1,45 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// WiFi-specific lwIP option overrides for Pico W. +// These are included before the platform-wide lwipopts.h via target_board.h. +// The CYW43 WiFi chip does NOT have hardware checksum offload, so we need +// software checksums enabled (the platform lwipopts.h disables them for STM32 Ethernet). + +#ifndef TARGET_LWIPOPTS_H +#define TARGET_LWIPOPTS_H + +// Override checksum settings — WiFi requires software checksums +// (The platform default disables checksums assuming hardware offload) +#define CHECKSUM_GEN_IP 1 +#define CHECKSUM_GEN_UDP 1 +#define CHECKSUM_GEN_TCP 1 +#define CHECKSUM_GEN_ICMP 1 +#define CHECKSUM_CHECK_IP 1 +#define CHECKSUM_CHECK_UDP 1 +#define CHECKSUM_CHECK_TCP 1 +#define CHECKSUM_CHECK_ICMP 1 + +// Match Pico SDK: skip gratuitous ARP probe during DHCP — the CYW43 data +// path is not yet proven to deliver responses fast enough, so the ARP check +// would time out and stall DHCP. +#define DHCP_DOES_ARP_CHECK 0 +#define LWIP_DHCP_DOES_ACD_CHECK 0 + +// Increase lwIP thread stack for WiFi operations +#undef LWIP_THREAD_STACK_SIZE +#define LWIP_THREAD_STACK_SIZE 2048 + +// Increase tcpip thread stack — netconn/socket calls execute here, +// and TLS record processing via mbedtls needs significant headroom on Cortex-M0+. +#define TCPIP_THREAD_STACKSIZE 4096 + +// WiFi interface name +#undef LWIP_IFNAME0 +#undef LWIP_IFNAME1 +#define LWIP_IFNAME0 'w' +#define LWIP_IFNAME1 'l' + +#endif // TARGET_LWIPOPTS_H diff --git a/targets/ChibiOS/RP_PICO_W_RP2040/target_rng.c b/targets/ChibiOS/RP_PICO_W_RP2040/target_rng.c new file mode 100644 index 0000000000..92d022ffdb --- /dev/null +++ b/targets/ChibiOS/RP_PICO_W_RP2040/target_rng.c @@ -0,0 +1,33 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// RP2040 RNG stub — provides rngStart()/rngStop()/rngGenerateRandomNumber() +// using the Ring Oscillator (ROSC) random bit register. + +#include +#include + +#define ROSC_BASE 0x40060000 +#define ROSC_RANDOMBIT (*(volatile uint32_t *)(ROSC_BASE + 0x1C)) + +void rngStart(void) +{ + // ROSC is always running on RP2040 +} + +void rngStop(void) +{ + // Nothing to do +} + +uint32_t rngGenerateRandomNumber(void) +{ + uint32_t value = 0; + for (int i = 0; i < 32; i++) + { + value = (value << 1) | (ROSC_RANDOMBIT & 1u); + } + return value; +} diff --git a/targets/ChibiOS/_RP2040/Target_BlockStorage_RP2040FlashDriver.c b/targets/ChibiOS/_RP2040/Target_BlockStorage_RP2040FlashDriver.c new file mode 100644 index 0000000000..3f61525ac9 --- /dev/null +++ b/targets/ChibiOS/_RP2040/Target_BlockStorage_RP2040FlashDriver.c @@ -0,0 +1,159 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include + +// RP2040 XIP flash base address +#define RP2040_XIP_BASE 0x10000000U + +// RP2040 flash sector size (4KB) +#define RP2040_FLASH_SECTOR_SIZE 4096U + +// Reference to ChibiOS EFL driver instance +extern EFlashDriver EFLD1; + +bool RP2040FlashDriver_InitializeDevice(void *context) +{ + (void)context; + + // Start the EFL driver + eflStart(&EFLD1, NULL); + + return true; +} + +bool RP2040FlashDriver_UninitializeDevice(void *context) +{ + (void)context; + + eflStop(&EFLD1); + + return true; +} + +DeviceBlockInfo *RP2040FlashDriver_GetDeviceInfo(void *context) +{ + MEMORY_MAPPED_NOR_BLOCK_CONFIG *config = context; + + return config->BlockConfig.BlockDeviceInformation; +} + +bool RP2040FlashDriver_Read(void *context, ByteAddress startAddress, unsigned int numBytes, unsigned char *buffer) +{ + (void)context; + + // RP2040 flash is XIP memory-mapped, so we can read directly + memcpy(buffer, (const void *)startAddress, numBytes); + + return true; +} + +bool RP2040FlashDriver_Write( + void *context, + ByteAddress startAddress, + unsigned int numBytes, + unsigned char *buffer, + bool readModifyWrite) +{ + (void)context; + (void)readModifyWrite; + + // Convert absolute address to flash offset for EFL driver + flash_offset_t offset = (flash_offset_t)(startAddress - RP2040_XIP_BASE); + + flash_error_t err = flashProgram(&EFLD1, offset, numBytes, buffer); + + return (err == FLASH_NO_ERROR); +} + +bool RP2040FlashDriver_IsBlockErased(void *context, ByteAddress blockAddress, unsigned int length) +{ + (void)context; + + // Check if all bytes are 0xFF (erased state) + unsigned char *p = (unsigned char *)blockAddress; + + for (unsigned int i = 0; i < length; i++) + { + if (*p++ != 0xFF) + { + return false; + } + } + + return true; +} + +bool RP2040FlashDriver_EraseBlock(void *context, ByteAddress address) +{ + (void)context; + + // Convert absolute address to flash offset + flash_offset_t offset = (flash_offset_t)(address - RP2040_XIP_BASE); + + // Calculate sector number + flash_sector_t sector = (flash_sector_t)(offset / RP2040_FLASH_SECTOR_SIZE); + + flash_error_t err = flashStartEraseSector(&EFLD1, sector); + if (err != FLASH_NO_ERROR) + { + return false; + } + + // Wait for erase to complete + uint32_t wait_time = 0; + do + { + err = flashQueryErase(&EFLD1, &wait_time); + if (err == FLASH_ERROR_ERASE) + { + return false; + } + if (wait_time > 0) + { + chThdSleepMilliseconds(wait_time); + } + } while (err == FLASH_BUSY_ERASING); + + return (err == FLASH_NO_ERROR); +} + +// nanoBooter flash access functions (called from WireProtocol_MonitorCommands) +int nf_TargetFlashWrite(uint32_t startAddress, uint32_t length, const uint8_t *buffer) +{ + flash_offset_t offset = (flash_offset_t)(startAddress - RP2040_XIP_BASE); + flash_error_t err = flashProgram(&EFLD1, offset, length, buffer); + return (err == FLASH_NO_ERROR) ? 1 : 0; +} + +int nf_TargetFlashErase(uint32_t address) +{ + flash_offset_t offset = (flash_offset_t)(address - RP2040_XIP_BASE); + flash_sector_t sector = (flash_sector_t)(offset / RP2040_FLASH_SECTOR_SIZE); + + flash_error_t err = flashStartEraseSector(&EFLD1, sector); + if (err != FLASH_NO_ERROR) + { + return 0; + } + + uint32_t wait_time = 0; + do + { + err = flashQueryErase(&EFLD1, &wait_time); + if (err == FLASH_ERROR_ERASE) + { + return 0; + } + if (wait_time > 0) + { + chThdSleepMilliseconds(wait_time); + } + } while (err == FLASH_BUSY_ERASING); + + return (err == FLASH_NO_ERROR) ? 1 : 0; +} diff --git a/targets/ChibiOS/_RP2040/Target_BlockStorage_RP2040FlashDriver.h b/targets/ChibiOS/_RP2040/Target_BlockStorage_RP2040FlashDriver.h new file mode 100644 index 0000000000..52b8ab3cc6 --- /dev/null +++ b/targets/ChibiOS/_RP2040/Target_BlockStorage_RP2040FlashDriver.h @@ -0,0 +1,35 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef TARGET_RP2040FLASH_DRIVER_H +#define TARGET_RP2040FLASH_DRIVER_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + bool RP2040FlashDriver_InitializeDevice(void *); + bool RP2040FlashDriver_UninitializeDevice(void *); + DeviceBlockInfo *RP2040FlashDriver_GetDeviceInfo(void *); + bool RP2040FlashDriver_Read(void *, ByteAddress startAddress, unsigned int numBytes, unsigned char *buffer); + bool RP2040FlashDriver_Write( + void *, + ByteAddress startAddress, + unsigned int numBytes, + unsigned char *buffer, + bool readModifyWrite); + bool RP2040FlashDriver_IsBlockErased(void *, ByteAddress blockAddress, unsigned int length); + bool RP2040FlashDriver_EraseBlock(void *, ByteAddress address); + +#ifdef __cplusplus +} +#endif + +#endif // TARGET_RP2040FLASH_DRIVER_H diff --git a/targets/ChibiOS/_RP2040/common/serialcfg.h b/targets/ChibiOS/_RP2040/common/serialcfg.h new file mode 100644 index 0000000000..04e7b57dd9 --- /dev/null +++ b/targets/ChibiOS/_RP2040/common/serialcfg.h @@ -0,0 +1,14 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef SERIALCFG_H +#define SERIALCFG_H + +// define which serial driver the Wire Protocol will be using +// RP2040 uses SIO driver for UART (ChibiOS SIO = Serial I/O) +// UART0 is on GP0 (TX) and GP1 (RX) on the Pico board +#define SERIAL_DRIVER SIOD0 + +#endif // SERIALCFG_H diff --git a/targets/ChibiOS/_RP2040/common/usbcfg.c b/targets/ChibiOS/_RP2040/common/usbcfg.c new file mode 100644 index 0000000000..d88c5a840d --- /dev/null +++ b/targets/ChibiOS/_RP2040/common/usbcfg.c @@ -0,0 +1,386 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2015 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include "hal.h" + +/* Virtual serial port over USB.*/ +SerialUSBDriver SDU1; + +/* + * Endpoints to be used for USBD1. + */ +#define USBD1_DATA_REQUEST_EP 1 +#define USBD1_DATA_AVAILABLE_EP 1 +#define USBD1_INTERRUPT_REQUEST_EP 2 + +//////////////////////////////////////////////// +// vendor +#define USB_STRING_VENDOR L"nanoFramework" +//////////////////////////////////////////////// + +// structure for USB Vendor with Unicode string +typedef struct usb_string_vendor +{ + uint8_t bLength; + uint8_t bDescriptorType; + wchar_t bPropertyData[sizeof(USB_STRING_VENDOR)/sizeof(wchar_t) - 1]; + +}usb_string_vendor; + + +///////////////////////////////////////////////////////////////////////// +// device description +#define USB_STRING_DEVICE_DESCRIPTION L"nanoFramework Virtual COM Port" +///////////////////////////////////////////////////////////////////////// + +// structure for USB device descriptor with Unicode string +typedef struct usb_string_device_description +{ + uint8_t bLength; + uint8_t bDescriptorType; + wchar_t bPropertyData[sizeof(USB_STRING_DEVICE_DESCRIPTION)/sizeof(wchar_t) - 1]; + +}usb_string_device_description; + + +///////////////////////////////////////////////////////////////////////// +// device serial number +#define USB_STRING_SERIAL_NUMBER L"NANO_RP2040_00000" +///////////////////////////////////////////////////////////////////////// + +// structure for USB serial number descriptor with Unicode string +typedef struct usb_string_serial_number +{ + uint8_t bLength; + uint8_t bDescriptorType; + wchar_t bPropertyData[sizeof(USB_STRING_SERIAL_NUMBER)/sizeof(wchar_t) - 1]; + +}usb_string_serial_number; + + +/* + * USB Device Descriptor. + */ +static const uint8_t vcom_device_descriptor_data[18] = { + USB_DESC_DEVICE (0x0200, /* bcdUSB (2.0). */ + 0x02, /* bDeviceClass (CDC). */ + 0x00, /* bDeviceSubClass. */ + 0x00, /* bDeviceProtocol. */ + 0x40, /* bMaxPacketSize. */ + 0x1209, /* idVendor (pid.codes test VID). */ + 0xDB40, /* idProduct. */ + 0x0200, /* bcdDevice. */ + 1, /* iManufacturer. */ + 2, /* iProduct. */ + 3, /* iSerialNumber. */ + 1) /* bNumConfigurations. */ +}; + +/* + * Device Descriptor wrapper. + */ +static const USBDescriptor vcom_device_descriptor = { + sizeof vcom_device_descriptor_data, + vcom_device_descriptor_data +}; + +/* Configuration Descriptor tree for a CDC.*/ +static const uint8_t vcom_configuration_descriptor_data[67] = { + /* Configuration Descriptor.*/ + USB_DESC_CONFIGURATION(67, /* wTotalLength. */ + 0x02, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0x80, /* bmAttributes (bus powered). */ + 50), /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x01, /* bNumEndpoints. */ + 0x02, /* bInterfaceClass (Communications + Interface Class, CDC section + 4.2). */ + 0x02, /* bInterfaceSubClass (Abstract + Control Model, CDC section 4.3). */ + 0x01, /* bInterfaceProtocol (AT commands, + CDC section 4.4). */ + 0), /* iInterface. */ + /* Header Functional Descriptor (CDC section 5.2.3).*/ + USB_DESC_BYTE (5), /* bLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header + Functional Descriptor. */ + USB_DESC_BCD (0x0110), /* bcdCDC. */ + /* Call Management Functional Descriptor. */ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ + USB_DESC_BYTE (0x01), /* bDataInterface. */ + /* ACM Functional Descriptor.*/ + USB_DESC_BYTE (4), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract + Control Management Descriptor). */ + USB_DESC_BYTE (0x02), /* bmCapabilities. */ + /* Union Functional Descriptor.*/ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bMasterInterface (Communication + Class Interface). */ + USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class + Interface). */ + /* Endpoint 2 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_INTERRUPT_REQUEST_EP|0x80, + 0x03, /* bmAttributes (Interrupt). */ + 0x0008, /* wMaxPacketSize. */ + 0xFF), /* bInterval. */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x0A, /* bInterfaceClass (Data Class + Interface, CDC section 4.5). */ + 0x00, /* bInterfaceSubClass (CDC section + 4.6). */ + 0x00, /* bInterfaceProtocol (CDC section + 4.7). */ + 0x00), /* iInterface. */ + /* Endpoint 3 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00), /* bInterval. */ + /* Endpoint 1 Descriptor.*/ + USB_DESC_ENDPOINT (USBD1_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00) /* bInterval. */ +}; + +/* + * Configuration Descriptor wrapper. + */ +static const USBDescriptor vcom_configuration_descriptor = { + sizeof vcom_configuration_descriptor_data, + vcom_configuration_descriptor_data +}; + +/* + * U.S. English language identifier. + */ +static const uint8_t vcom_string0[] = { + USB_DESC_BYTE(4), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ +}; + + +// Vendor string +static const usb_string_vendor usb_vendor = { + sizeof(usb_vendor), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), + USB_STRING_VENDOR +}; + + +// Device Description string +static const usb_string_device_description usb_device_description = { + sizeof(usb_device_description), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), + USB_STRING_DEVICE_DESCRIPTION +}; + + +// Serial Number string. +static usb_string_serial_number usb_serial_number = { + sizeof(usb_serial_number), + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), + USB_STRING_SERIAL_NUMBER +}; + + +/* + * Strings wrappers array. + */ +static const USBDescriptor vcom_strings[] = { + {sizeof vcom_string0, vcom_string0}, + {sizeof usb_vendor, (uint8_t*)(&usb_vendor)}, + {sizeof usb_device_description, (uint8_t*)(&usb_device_description)}, + {sizeof usb_serial_number, (uint8_t*)(&usb_serial_number)}, +}; + +/* + * Handles the GET_DESCRIPTOR callback. All required descriptors must be + * handled here. + */ +static const USBDescriptor *get_descriptor(USBDriver *usbp, + uint8_t dtype, + uint8_t dindex, + uint16_t lang) { + + (void)usbp; + (void)lang; + + switch (dtype) { + case USB_DESCRIPTOR_DEVICE: + return &vcom_device_descriptor; + case USB_DESCRIPTOR_CONFIGURATION: + return &vcom_configuration_descriptor; + case USB_DESCRIPTOR_STRING: + if (dindex < 4) + { + return &vcom_strings[dindex]; + } + } + return NULL; +} + +/** + * @brief IN EP1 state. + */ +static USBInEndpointState ep1instate; + +/** + * @brief OUT EP1 state. + */ +static USBOutEndpointState ep1outstate; + +/** + * @brief EP1 initialization structure (both IN and OUT). + */ +static const USBEndpointConfig ep1config = { + USB_EP_MODE_TYPE_BULK, + NULL, + sduDataTransmitted, + sduDataReceived, + 0x0040, + 0x0040, + &ep1instate, + &ep1outstate +}; + +/** + * @brief IN EP2 state. + */ +static USBInEndpointState ep2instate; + +/** + * @brief EP2 initialization structure (IN only). + */ +static const USBEndpointConfig ep2config = { + USB_EP_MODE_TYPE_INTR, + NULL, + sduInterruptTransmitted, + NULL, + 0x0010, + 0x0000, + &ep2instate, + NULL +}; + +/* + * Handles the USB driver global events. + */ +static void usb_event(USBDriver *usbp, usbevent_t event) { + extern SerialUSBDriver SDU1; + + switch (event) { + case USB_EVENT_ADDRESS: + return; + case USB_EVENT_CONFIGURED: + chSysLockFromISR(); + + if (usbp->state == USB_ACTIVE) { + /* Enables the endpoints specified into the configuration. + Note, this callback is invoked from an ISR so I-Class functions + must be used.*/ + usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP, &ep1config); + usbInitEndpointI(usbp, USBD1_INTERRUPT_REQUEST_EP, &ep2config); + + /* Resetting the state of the CDC subsystem.*/ + sduConfigureHookI(&SDU1); + } + else if (usbp->state == USB_SELECTED) { + usbDisableEndpointsI(usbp); + } + + chSysUnlockFromISR(); + return; + case USB_EVENT_RESET: + /* Falls into.*/ + case USB_EVENT_UNCONFIGURED: + /* Falls into.*/ + case USB_EVENT_SUSPEND: + chSysLockFromISR(); + + /* Disconnection event on suspend.*/ + sduSuspendHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_WAKEUP: + chSysLockFromISR(); + + /* Connection event on wakeup.*/ + sduWakeupHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_STALLED: + return; + } + return; +} + +/* + * Handling messages not implemented in the default handler nor in the + * SerialUSB handler. + */ +static bool requests_hook(USBDriver *usbp) { + + if (((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE) && + (usbp->setup[1] == USB_REQ_SET_INTERFACE)) { + usbSetupTransfer(usbp, NULL, 0, NULL); + return true; + } + return sduRequestsHook(usbp); +} + +/* + * Handles the USB driver global events. + */ +static void sof_handler(USBDriver *usbp) { + + (void)usbp; + + osalSysLockFromISR(); + sduSOFHookI(&SDU1); + osalSysUnlockFromISR(); +} + +/* + * USB driver configuration. + */ +const USBConfig usbcfg = { + usb_event, + get_descriptor, + requests_hook, + sof_handler +}; + +/* + * Serial over USB driver configuration. + */ +const SerialUSBConfig serusbcfg = { + &USBD1, + USBD1_DATA_REQUEST_EP, + USBD1_DATA_AVAILABLE_EP, + USBD1_INTERRUPT_REQUEST_EP +}; diff --git a/targets/ChibiOS/_RP2040/common/usbcfg.h b/targets/ChibiOS/_RP2040/common/usbcfg.h new file mode 100644 index 0000000000..b8c7c4b0e0 --- /dev/null +++ b/targets/ChibiOS/_RP2040/common/usbcfg.h @@ -0,0 +1,17 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2006..2015 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#ifndef USBCFG_H +#define USBCFG_H + +// define which serial driver the Wire Protocol will be using +#define SERIAL_DRIVER SDU1 + +extern const USBConfig usbcfg; +extern SerialUSBConfig serusbcfg; +extern SerialUSBDriver SDU1; + +#endif // USBCFG_H diff --git a/targets/ChibiOS/_RP2040/cpu_spi.cpp b/targets/ChibiOS/_RP2040/cpu_spi.cpp new file mode 100644 index 0000000000..7b60a2e907 --- /dev/null +++ b/targets/ChibiOS/_RP2040/cpu_spi.cpp @@ -0,0 +1,463 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include +#include +#include +#include + +#include + +///////////////////////////////////////////////////// +// SPI PAL structs for RP2040 (2 buses: SPI0, SPI1) +///////////////////////////////////////////////////// +#if RP_SPI_USE_SPI0 +NF_PAL_SPI SPI0_PAL; +#endif +#if RP_SPI_USE_SPI1 +NF_PAL_SPI SPI1_PAL; +#endif + +// RP2040 peripheral clock is always 125 MHz (from peri_clk) +#define RP_SPI_PERI_CLK 125000000 + +// Tidy up after completing transfer +static void CompleteTransfer(NF_PAL_SPI *palSpi) +{ + spiUnselect(palSpi->Driver); + spiReleaseBus(palSpi->Driver); +} + +// Callback used when an async operation completes +static void SpiCallback(SPIDriver *spip) +{ + (void)spip; + + NATIVE_INTERRUPT_START + + NF_PAL_SPI *palSpi = NULL; + +#if RP_SPI_USE_SPI0 + if (spip == &SPID0) + { + palSpi = &SPI0_PAL; + } +#endif +#if RP_SPI_USE_SPI1 + if (spip == &SPID1) + { + palSpi = &SPI1_PAL; + } +#endif + + if (palSpi == NULL) + { + NATIVE_INTERRUPT_END + return; + } + + if (palSpi->SequentialTxRx) + { + palSpi->SequentialTxRx = false; + spiStartReceive(palSpi->Driver, palSpi->ReadSize, palSpi->ReadBuffer); + } + else + { + CompleteTransfer(palSpi); + + if (palSpi->ChipSelect >= 0) + { + CPU_GPIO_TogglePinState(palSpi->ChipSelect); + } + + if (palSpi->Callback) + { + palSpi->Callback(palSpi->BusIndex); + } + } + + NATIVE_INTERRUPT_END +}; + +// Compute RP2040 SPI baud rate registers (SSPCPSR and SSPCR0.SCR) +// RP2040 SPI (PL022): freq = peri_clk / (CPSDVSR * (1 + SCR)) +// CPSDVSR must be even, 2-254; SCR is 0-255 +static void ComputeBaudRate(int32_t requestedFrequency, int32_t &actualFrequency, uint32_t &sspcpsr, uint32_t &sspcr0) +{ + if (requestedFrequency <= 0) + { + // Default to max frequency (62.5 MHz) + requestedFrequency = RP_SPI_PERI_CLK / 2; + } + + // Find best CPSDVSR and SCR combination + uint32_t bestCpsdvsr = 2; + uint32_t bestScr = 0; + int32_t bestFreq = RP_SPI_PERI_CLK / 2; + + for (uint32_t cpsdvsr = 2; cpsdvsr <= 254; cpsdvsr += 2) + { + uint32_t scr = (RP_SPI_PERI_CLK / (cpsdvsr * requestedFrequency)) - 1; + if (scr > 255) + scr = 255; + + int32_t freq = RP_SPI_PERI_CLK / (cpsdvsr * (1 + scr)); + + if (freq <= requestedFrequency && freq > bestFreq) + { + bestFreq = freq; + bestCpsdvsr = cpsdvsr; + bestScr = scr; + } + else if (bestFreq > requestedFrequency && freq <= requestedFrequency) + { + bestFreq = freq; + bestCpsdvsr = cpsdvsr; + bestScr = scr; + } + + if (freq <= requestedFrequency) + break; + } + + actualFrequency = bestFreq; + sspcpsr = bestCpsdvsr; + sspcr0 = (bestScr << 8); // SCR is bits [15:8] of SSPCR0 +} + +// Return the NF_PAL structure for busIndex (0-based) +NF_PAL_SPI *GetNfPalfromBusIndex(uint8_t busIndex) +{ + switch (busIndex) + { +#if RP_SPI_USE_SPI0 + case 0: + return &SPI0_PAL; +#endif +#if RP_SPI_USE_SPI1 + case 1: + return &SPI1_PAL; +#endif + default: + return NULL; + } +} + +// Build low-level SPI configuration for RP2040 PL022 +void GetSPIConfig(SPI_DEVICE_CONFIGURATION &config, SPI_WRITE_READ_SETTINGS &wrc, SPIConfig *llConfig) +{ + int32_t actualFrequency; + uint32_t sspcpsr, sspcr0; + + ComputeBaudRate(config.Clock_RateHz, actualFrequency, sspcpsr, sspcr0); + + // SSPCR0: SCR field (from baud rate), data size bits, SPI mode + // Data Size Select (DSS): bits [3:0], value = datasize - 1 + if (wrc.Bits16ReadWrite) + { + sspcr0 |= (16 - 1); // 16-bit frames + } + else + { + sspcr0 |= (8 - 1); // 8-bit frames + } + + // SPI mode: SPO (bit 6) = CPOL, SPH (bit 7) = CPHA + switch (config.Spi_Mode) + { + case SpiMode_Mode1: + sspcr0 |= (1 << 7); // CPHA=1 + break; + case SpiMode_Mode2: + sspcr0 |= (1 << 6); // CPOL=1 + break; + case SpiMode_Mode3: + sspcr0 |= (1 << 6) | (1 << 7); // CPOL=1, CPHA=1 + break; + default: // Mode0 + break; + } + + llConfig->SSPCR0 = sspcr0; + llConfig->SSPCPSR = sspcpsr; + llConfig->end_cb = SpiCallback; +} + +// Performs a read/write operation on 8-bit or 16-bit word data. +HRESULT CPU_SPI_nWrite_nRead( + uint32_t deviceHandle, + SPI_DEVICE_CONFIGURATION &sdev, + SPI_WRITE_READ_SETTINGS &wrc, + uint8_t *writeBuffer, + int32_t writeSize, + uint8_t *readBuffer, + int32_t readSize) +{ + NANOCLR_HEADER(); + { + NF_PAL_SPI *palSpi = (NF_PAL_SPI *)deviceHandle; + bool sync = (wrc.callback == 0); + + palSpi->BufferIs16bits = wrc.Bits16ReadWrite; + palSpi->Callback = wrc.callback; + + if (writeBuffer != NULL) + { + palSpi->WriteSize = writeSize; + palSpi->WriteBuffer = writeBuffer; + } + + if (readBuffer != NULL) + { + palSpi->ReadSize = readSize; + palSpi->ReadBuffer = readBuffer; + } + + palSpi->BusIndex = sdev.Spi_Bus; + + GetSPIConfig(sdev, wrc, &palSpi->Configuration); + + if (sync) + { + palSpi->Configuration.end_cb = NULL; + } + + spiAcquireBus(palSpi->Driver); + spiStart(palSpi->Driver, &palSpi->Configuration); + spiSelect(palSpi->Driver); + + palSpi->ChipSelect = wrc.DeviceChipSelect; + if (wrc.DeviceChipSelect >= 0) + { + CPU_GPIO_SetPinState(wrc.DeviceChipSelect, (GpioPinValue)wrc.ChipSelectActiveState); + } + + if (sync) + { + if (palSpi->WriteSize != 0 && palSpi->ReadSize != 0) + { + if (wrc.fullDuplex) + { + spiExchange( + palSpi->Driver, + palSpi->WriteSize > palSpi->ReadSize ? palSpi->WriteSize : palSpi->ReadSize, + palSpi->WriteBuffer, + palSpi->ReadBuffer); + } + else + { + spiSend(palSpi->Driver, palSpi->WriteSize, palSpi->WriteBuffer); + spiReceive(palSpi->Driver, palSpi->ReadSize, palSpi->ReadBuffer); + } + } + else + { + if (palSpi->ReadSize != 0) + { + spiReceive(palSpi->Driver, palSpi->ReadSize, palSpi->ReadBuffer); + } + else + { + spiSend(palSpi->Driver, palSpi->WriteSize, palSpi->WriteBuffer); + } + } + + CompleteTransfer(palSpi); + + if (wrc.DeviceChipSelect >= 0) + { + CPU_GPIO_SetPinState(wrc.DeviceChipSelect, (GpioPinValue)!wrc.ChipSelectActiveState); + } + } + else + { + if (wrc.DeviceChipSelect >= 0) + { + CPU_GPIO_SetPinState(wrc.DeviceChipSelect, (GpioPinValue)wrc.ChipSelectActiveState); + } + + if (palSpi->WriteSize != 0 && palSpi->ReadSize != 0) + { + if (wrc.fullDuplex) + { + palSpi->SequentialTxRx = false; + spiStartExchange( + palSpi->Driver, + palSpi->WriteSize > palSpi->ReadSize ? palSpi->WriteSize : palSpi->ReadSize, + palSpi->WriteBuffer, + palSpi->ReadBuffer); + } + else + { + palSpi->SequentialTxRx = true; + spiStartSend(palSpi->Driver, palSpi->WriteSize, palSpi->WriteBuffer); + } + } + else + { + palSpi->SequentialTxRx = false; + + if (palSpi->ReadSize != 0) + { + spiStartReceive(palSpi->Driver, palSpi->ReadSize, palSpi->ReadBuffer); + } + else + { + spiStartSend(palSpi->Driver, palSpi->WriteSize, palSpi->WriteBuffer); + } + } + + NANOCLR_SET_AND_LEAVE(CLR_E_BUSY); + } + } + + NANOCLR_NOCLEANUP(); +} + +SPI_OP_STATUS CPU_SPI_OP_Status(uint8_t busIndex, uint32_t deviceHandle) +{ + (void)busIndex; + + NF_PAL_SPI *palSpi = (NF_PAL_SPI *)deviceHandle; + + switch (palSpi->Driver->state) + { + default: + case SPI_UNINIT: + case SPI_STOP: + case SPI_READY: + return SPI_OP_READY; + case SPI_ACTIVE: + return SPI_OP_RUNNING; + case SPI_COMPLETE: + return SPI_OP_COMPLETE; + } +} + +bool CPU_SPI_Initialize(uint8_t busIndex, const SPI_DEVICE_CONFIGURATION &spiDeviceConfig) +{ + switch (busIndex) + { +#if RP_SPI_USE_SPI0 + case 0: + if (SPI0_PAL.Driver == NULL) + { + ConfigPins_SPI0(spiDeviceConfig); + SPI0_PAL.Driver = &SPID0; + SPI0_PAL.ChipSelect = spiDeviceConfig.DeviceChipSelect; + } + break; +#endif +#if RP_SPI_USE_SPI1 + case 1: + if (SPI1_PAL.Driver == NULL) + { + ConfigPins_SPI1(spiDeviceConfig); + SPI1_PAL.Driver = &SPID1; + SPI1_PAL.ChipSelect = spiDeviceConfig.DeviceChipSelect; + } + break; +#endif + default: + return false; + } + + return true; +} + +bool CPU_SPI_Uninitialize(uint8_t busIndex) +{ + switch (busIndex) + { +#if RP_SPI_USE_SPI0 + case 0: + spiStop(&SPID0); + SPI0_PAL.Driver = NULL; + spiReleaseBus(&SPID0); + break; +#endif +#if RP_SPI_USE_SPI1 + case 1: + spiStop(&SPID1); + SPI1_PAL.Driver = NULL; + spiReleaseBus(&SPID1); + break; +#endif + default: + return false; + } + + return true; +} + +uint32_t CPU_SPI_PortsMap() +{ + uint32_t map = 0; + +#if RP_SPI_USE_SPI0 + map |= 0x01; +#endif +#if RP_SPI_USE_SPI1 + map |= 0x02; +#endif + + return map; +} + +HRESULT CPU_SPI_Add_Device(const SPI_DEVICE_CONFIGURATION &spiDeviceConfig, uint32_t &handle) +{ + if (spiDeviceConfig.BusConfiguration == SpiBusConfiguration_Simplex) + { + return CLR_E_NOT_SUPPORTED; + } + + handle = (uint32_t)GetNfPalfromBusIndex(spiDeviceConfig.Spi_Bus); + + return S_OK; +} + +void CPU_SPI_GetPins(uint32_t busIndex, GPIO_PIN &clk, GPIO_PIN &miso, GPIO_PIN &mosi) +{ + (void)busIndex; + + clk = (GPIO_PIN)-1; + miso = (GPIO_PIN)-1; + mosi = (GPIO_PIN)-1; +} + +HRESULT CPU_SPI_MinClockFrequency(uint32_t spiBus, int32_t *frequency) +{ + if (spiBus >= NUM_SPI_BUSES) + { + return CLR_E_INVALID_PARAMETER; + } + + // RP2040: min freq = 125MHz / (254 * 256) ≈ 1923 Hz + *frequency = RP_SPI_PERI_CLK / (254 * 256); + + return S_OK; +} + +HRESULT CPU_SPI_MaxClockFrequency(uint32_t spiBus, int32_t *frequency) +{ + if (spiBus >= NUM_SPI_BUSES) + { + return CLR_E_INVALID_PARAMETER; + } + + // RP2040: max freq = 125MHz / 2 = 62.5 MHz + *frequency = RP_SPI_PERI_CLK / 2; + + return S_OK; +} + +uint32_t CPU_SPI_ChipSelectLineCount(uint32_t busIndex) +{ + (void)busIndex; + + return MAX_SPI_DEVICES; +} diff --git a/targets/ChibiOS/_RP2040/lfs_config.h b/targets/ChibiOS/_RP2040/lfs_config.h new file mode 100644 index 0000000000..e54692d07d --- /dev/null +++ b/targets/ChibiOS/_RP2040/lfs_config.h @@ -0,0 +1,241 @@ +/* + * lfs utility functions + * + * Copyright (c) 2022, The littlefs authors. + * Copyright (c) 2017, Arm Limited. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef LFS_CONFIG_H +#define LFS_CONFIG_H + +// System includes +#include +#include +#include +#include + +extern void *platform_malloc(size_t size); +extern void platform_free(void *ptr); + +// configuration for this target +#define LFS_NO_ASSERT +#define LFS_NO_DEBUG +#define LFS_MALLOC platform_malloc +#define LFS_FREE platform_free +#define LFS_THREADSAFE + +#ifndef LFS_NO_MALLOC +#include +#endif +#ifndef LFS_NO_ASSERT +#include +#endif +#if !defined(LFS_NO_DEBUG) || !defined(LFS_NO_WARN) || !defined(LFS_NO_ERROR) || defined(LFS_YES_TRACE) +#include +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +// Logging functions +#ifndef LFS_TRACE +#ifdef LFS_YES_TRACE +#define LFS_TRACE_(fmt, ...) printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") +#else +#define LFS_TRACE(...) +#endif +#endif + +#ifndef LFS_DEBUG +#ifndef LFS_NO_DEBUG +#define LFS_DEBUG_(fmt, ...) printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") +#else +#define LFS_DEBUG(...) +#endif +#endif + +#ifndef LFS_WARN +#ifndef LFS_NO_WARN +#define LFS_WARN_(fmt, ...) printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") +#else +#define LFS_WARN(...) +#endif +#endif + +#ifndef LFS_ERROR +#ifndef LFS_NO_ERROR +#define LFS_ERROR_(fmt, ...) printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) +#define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") +#else +#define LFS_ERROR(...) +#endif +#endif + +// Runtime assertions +#ifndef LFS_ASSERT +#ifndef LFS_NO_ASSERT +#define LFS_ASSERT(test) assert(test) +#else +#define LFS_ASSERT(test) +#endif +#endif + + // Min/max functions for unsigned 32-bit numbers + static inline uint32_t lfs_max(uint32_t a, uint32_t b) + { + return (a > b) ? a : b; + } + + static inline uint32_t lfs_min(uint32_t a, uint32_t b) + { + return (a < b) ? a : b; + } + + // Align to nearest multiple of a size + static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) + { + return a - (a % alignment); + } + + static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) + { + return lfs_aligndown(a + alignment - 1, alignment); + } + + // Find the smallest power of 2 greater than or equal to a + static inline uint32_t lfs_npw2(uint32_t a) + { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return 32 - __builtin_clz(a - 1); +#else + uint32_t r = 0; + uint32_t s; + a -= 1; + s = (a > 0xffff) << 4; + a >>= s; + r |= s; + s = (a > 0xff) << 3; + a >>= s; + r |= s; + s = (a > 0xf) << 2; + a >>= s; + r |= s; + s = (a > 0x3) << 1; + a >>= s; + r |= s; + return (r | (a >> 1)) + 1; +#endif + } + + // Count the number of trailing binary zeros in a + static inline uint32_t lfs_ctz(uint32_t a) + { +#if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) + return __builtin_ctz(a); +#else + return lfs_npw2((a & -a) + 1) - 1; +#endif + } + + // Count the number of binary ones in a + static inline uint32_t lfs_popc(uint32_t a) + { +#if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) + return __builtin_popcount(a); +#else + a = a - ((a >> 1) & 0x55555555); + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); + return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; +#endif + } + + // Find the sequence comparison of a and b + static inline int lfs_scmp(uint32_t a, uint32_t b) + { + return (int)(unsigned)(a - b); + } + + // Convert between 32-bit little-endian and native order + static inline uint32_t lfs_fromle32(uint32_t a) + { +#if (defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + return a; +#elif !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) + return __builtin_bswap32(a); +#else + return (((uint8_t *)&a)[0] << 0) | (((uint8_t *)&a)[1] << 8) | (((uint8_t *)&a)[2] << 16) | + (((uint8_t *)&a)[3] << 24); +#endif + } + + static inline uint32_t lfs_tole32(uint32_t a) + { + return lfs_fromle32(a); + } + + // Convert between 32-bit big-endian and native order + static inline uint32_t lfs_frombe32(uint32_t a) + { +#if !defined(LFS_NO_INTRINSICS) && \ + ((defined(BYTE_ORDER) && defined(ORDER_LITTLE_ENDIAN) && BYTE_ORDER == ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_LITTLE_ENDIAN) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) + return __builtin_bswap32(a); +#elif (defined(BYTE_ORDER) && defined(ORDER_BIG_ENDIAN) && BYTE_ORDER == ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && defined(__ORDER_BIG_ENDIAN) && __BYTE_ORDER == __ORDER_BIG_ENDIAN) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + return a; +#else + return (((uint8_t *)&a)[0] << 24) | (((uint8_t *)&a)[1] << 16) | (((uint8_t *)&a)[2] << 8) | + (((uint8_t *)&a)[3] << 0); +#endif + } + + static inline uint32_t lfs_tobe32(uint32_t a) + { + return lfs_frombe32(a); + } + +// Calculate CRC-32 with polynomial = 0x04c11db7 +uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); + + // Allocate memory + static inline void *lfs_malloc(size_t size) + { +#if defined(LFS_MALLOC) + return LFS_MALLOC(size); +#elif !defined(LFS_NO_MALLOC) + return malloc(size); +#else + (void)size; + return NULL; +#endif + } + + // Deallocate memory + static inline void lfs_free(void *p) + { +#if defined(LFS_FREE) + LFS_FREE(p); +#elif !defined(LFS_NO_MALLOC) + free(p); +#else + (void)p; +#endif + } + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // LFS_CONFIG_H diff --git a/targets/ChibiOS/_RP2040/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp b/targets/ChibiOS/_RP2040/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp new file mode 100644 index 0000000000..d3f966e061 --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_adc_native_System_Device_Adc_AdcChannel.cpp @@ -0,0 +1,71 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +// Single-element sample buffer for synchronous conversion +static adcsample_t sampleBuffer[1]; + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeReadValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channelNumber; + NF_PAL_ADC_PORT_PIN_CHANNEL adcDefinition; + ADCConversionGroup adcgrpcfg; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + channelNumber = pThis[FIELD___channelNumber].NumericByRef().s4; + + if (channelNumber < 0 || channelNumber >= AdcChannelCount) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + adcDefinition = AdcPortPinConfig[channelNumber]; + + // Setup RP2040 ADC conversion group for single channel read + adcgrpcfg = { + FALSE, // circular + 1, // num_channels + NULL, // end_cb + NULL, // error_cb + adcDefinition.adcChannel, // channel + 0, // rrobin (0 = single channel) + 0, // div (0 = free-running, fastest) + (adcDefinition.adcChannel == ADC_CHANNEL_TEMPSENSOR), // ts_enabled + }; + + // Enable temp sensor if needed + if (adcDefinition.adcChannel == ADC_CHANNEL_TEMPSENSOR) + { + adcRPEnableTS(&ADCD1); + osDelay(1); + } + + // Perform synchronous conversion + adcConvert(&ADCD1, &adcgrpcfg, sampleBuffer, 1); + + // Disable temp sensor if it was enabled + if (adcDefinition.adcChannel == ADC_CHANNEL_TEMPSENSOR) + { + adcRPDisableTS(&ADCD1); + } + + stack.SetResult_I4(sampleBuffer[0]); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcChannel::NativeDisposeChannel___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + NANOCLR_NOCLEANUP_NOLABEL(); +} diff --git a/targets/ChibiOS/_RP2040/sys_dev_adc_native_System_Device_Adc_AdcController.cpp b/targets/ChibiOS/_RP2040/sys_dev_adc_native_System_Device_Adc_AdcController.cpp new file mode 100644 index 0000000000..7a0daed50e --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_adc_native_System_Device_Adc_AdcController.cpp @@ -0,0 +1,100 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeOpenChannel___VOID__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int channel; + NF_PAL_ADC_PORT_PIN_CHANNEL adcDefinition; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + channel = stack.Arg1().NumericByRef().s4; + + if (channel < 0 || channel >= AdcChannelCount) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + adcDefinition = AdcPortPinConfig[channel]; + + // Initialize GPIO for ADC input (not needed for temp sensor) + if (adcDefinition.gpio != 0xFF) + { + adcRPGpioInit(adcDefinition.gpio); + } + + // Start ADC + adcStart(&ADCD1, NULL); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetChannelCount___I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + stack.SetResult_I4(AdcChannelCount); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMaxValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // RP2040 ADC is 12-bit: max value = 4095 + stack.SetResult_I4(4095); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetMinValue___I4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + stack.SetResult_I4(0); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeIsChannelModeSupported___BOOLEAN__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int mode = stack.Arg1().NumericByRef().s4; + + // Only single-ended mode supported + stack.SetResult_Boolean((mode == (int)AdcChannelMode_SingleEnded)); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeGetResolutionInBits___I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + // RP2040 ADC is 12-bit + stack.SetResult_I4(12); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_adc_native_System_Device_Adc_AdcController::NativeInit___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + NANOCLR_NOCLEANUP_NOLABEL(); +} diff --git a/targets/ChibiOS/_RP2040/sys_dev_adc_native_target.h b/targets/ChibiOS/_RP2040/sys_dev_adc_native_target.h new file mode 100644 index 0000000000..1e5e42896d --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_adc_native_target.h @@ -0,0 +1,24 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef SYS_DEV_ADC_NATIVE_TARGET_H +#define SYS_DEV_ADC_NATIVE_TARGET_H + +#include +#include + +// RP2040 ADC: single ADC with 5 channels +// Ch 0-3 = GPIO26-GPIO29, Ch 4 = internal temperature sensor +typedef struct +{ + uint8_t adcIndex; + uint8_t gpio; // GPIO number (26-29) or 0xFF for internal channels + uint32_t adcChannel; +} NF_PAL_ADC_PORT_PIN_CHANNEL; + +extern const NF_PAL_ADC_PORT_PIN_CHANNEL AdcPortPinConfig[]; +extern const int AdcChannelCount; + +#endif // SYS_DEV_ADC_NATIVE_TARGET_H diff --git a/targets/ChibiOS/_RP2040/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp b/targets/ChibiOS/_RP2040/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp new file mode 100644 index 0000000000..5759b04438 --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_i2c_native_System_Device_I2c_I2cDevice.cpp @@ -0,0 +1,453 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include "sys_dev_i2c_native_target.h" + +typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cConnectionSettings I2cConnectionSettings; +typedef Library_sys_dev_i2c_native_System_Device_I2c_I2cTransferResult I2cTransferResult; +typedef Library_corlib_native_System_SpanByte SpanByte; + +//////////////////////////////////////////// +// declaration of the I2C PAL structs // +//////////////////////////////////////////// +#if RP_I2C_USE_I2C0 +NF_PAL_I2C I2C0_PAL; +uint8_t I2C0_DeviceCounter; +#endif +#if RP_I2C_USE_I2C1 +NF_PAL_I2C I2C1_PAL; +uint8_t I2C1_DeviceCounter; +#endif + +void GetI2cConfig(CLR_RT_HeapBlock *managedConfig, I2CConfig *llConfig) +{ + I2cBusSpeed busSpeed = (I2cBusSpeed)managedConfig[I2cConnectionSettings::FIELD___busSpeed].NumericByRef().s4; + + // RP2040 I2CConfig only has baudrate field + llConfig->baudrate = busSpeed == I2cBusSpeed_StandardMode ? 100000U : 400000U; +} + +// estimate the time required to perform the I2C transaction +bool IsLongRunningOperation( + uint16_t writeSize, + uint16_t readSize, + float byteTime, + uint32_t &estimatedDurationMiliseconds) +{ + estimatedDurationMiliseconds = byteTime * (writeSize + readSize + 1); + + if (estimatedDurationMiliseconds > CLR_RT_Thread::c_TimeQuantum_Milliseconds) + { + return true; + } + + return false; +} + +// ChibiOS I2C working thread +static THD_FUNCTION(I2CWorkingThread, arg) +{ + NF_PAL_I2C *palI2c = (NF_PAL_I2C *)arg; + msg_t result; + int estimatedDurationMiliseconds = palI2c->ByteTime * (palI2c->WriteSize + palI2c->ReadSize + 1); + + if (palI2c->ReadSize != 0 && palI2c->WriteSize != 0) + { + result = i2cMasterTransmitTimeout( + palI2c->Driver, + palI2c->Address, + palI2c->WriteBuffer, + palI2c->WriteSize, + palI2c->ReadBuffer, + palI2c->ReadSize, + TIME_MS2I(estimatedDurationMiliseconds)); + } + else + { + if (palI2c->ReadSize == 0) + { + estimatedDurationMiliseconds = palI2c->ByteTime * (palI2c->WriteSize + 1); + + result = i2cMasterTransmitTimeout( + palI2c->Driver, + palI2c->Address, + palI2c->WriteBuffer, + palI2c->WriteSize, + NULL, + 0, + TIME_MS2I(estimatedDurationMiliseconds)); + } + else + { + estimatedDurationMiliseconds = palI2c->ByteTime * (palI2c->ReadSize + 1); + + result = i2cMasterReceiveTimeout( + palI2c->Driver, + palI2c->Address, + palI2c->ReadBuffer, + palI2c->ReadSize, + TIME_MS2I(estimatedDurationMiliseconds)); + } + } + + Events_Set(SYSTEM_EVENT_FLAG_I2C_MASTER); + + chThdExit(result); +} + +HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeInit___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + NF_PAL_I2C *palI2c = NULL; + CLR_RT_HeapBlock *connectionSettings; + uint8_t busIndex; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + connectionSettings = pThis[FIELD___connectionSettings].Dereference(); + + // get bus index (0-based for RP2040) + busIndex = (uint8_t)connectionSettings[I2cConnectionSettings::FIELD___busId].NumericByRef().s4; + + switch (busIndex) + { +#if RP_I2C_USE_I2C0 + case 0: + if (I2C0_PAL.Driver == NULL) + { + ConfigPins_I2C0(); + I2C0_PAL.Driver = &I2CD0; + palI2c = &I2C0_PAL; + I2C0_DeviceCounter++; + } + break; +#endif +#if RP_I2C_USE_I2C1 + case 1: + if (I2C1_PAL.Driver == NULL) + { + ConfigPins_I2C1(); + I2C1_PAL.Driver = &I2CD1; + palI2c = &I2C1_PAL; + I2C1_DeviceCounter++; + } + break; +#endif + + default: + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; + } + + GetI2cConfig(connectionSettings, &palI2c->Configuration); + + if ((I2cBusSpeed)connectionSettings[I2cConnectionSettings::FIELD___busSpeed].NumericByRef().s4 == + I2cBusSpeed_StandardMode) + { + palI2c->ByteTime = 0.1; + } + else + { + palI2c->ByteTime = 0.02; + } + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice::NativeDispose___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + uint8_t busIndex; + CLR_RT_HeapBlock *connectionSettings; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + connectionSettings = pThis[FIELD___connectionSettings].Dereference(); + + busIndex = (uint8_t)connectionSettings[I2cConnectionSettings::FIELD___busId].NumericByRef().s4; + + switch (busIndex) + { +#if RP_I2C_USE_I2C0 + case 0: + I2C0_DeviceCounter--; + if (I2C0_DeviceCounter == 0) + { + i2cStop(&I2CD0); + I2C0_PAL.Driver = NULL; + } + break; +#endif +#if RP_I2C_USE_I2C1 + case 1: + I2C1_DeviceCounter--; + if (I2C1_DeviceCounter == 0) + { + i2cStop(&I2CD1); + I2C1_PAL.Driver = NULL; + } + break; +#endif + + default: + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; + } + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_i2c_native_System_Device_I2c_I2cDevice:: + NativeTransmit___SystemDeviceI2cI2cTransferResult__SystemSpanByte__SystemSpanByte(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + uint8_t busIndex; + NF_PAL_I2C *palI2c = NULL; + bool isLongRunningOperation = false; + msg_t transactionResult = MSG_OK; + + CLR_RT_HeapBlock hbTimeout; + CLR_INT64 *timeout; + bool eventResult = true; + uint32_t estimatedDurationMiliseconds; + + CLR_RT_HeapBlock *result; + CLR_RT_HeapBlock *writeSpanByte; + CLR_RT_HeapBlock *readSpanByte; + CLR_RT_HeapBlock *connectionSettings; + CLR_RT_HeapBlock_Array *writeBuffer = NULL; + CLR_RT_HeapBlock_Array *readBuffer = NULL; + int readOffset = 0; + int writeOffset = 0; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + connectionSettings = pThis[FIELD___connectionSettings].Dereference(); + + busIndex = (uint8_t)connectionSettings[I2cConnectionSettings::FIELD___busId].NumericByRef().s4; + + switch (busIndex) + { +#if RP_I2C_USE_I2C0 + case 0: + palI2c = &I2C0_PAL; + break; +#endif +#if RP_I2C_USE_I2C1 + case 1: + palI2c = &I2C1_PAL; + break; +#endif + default: + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + break; + } + + writeSpanByte = stack.Arg1().Dereference(); + if (writeSpanByte != NULL) + { + writeBuffer = writeSpanByte[SpanByte::FIELD___array].DereferenceArray(); + if (writeBuffer != NULL) + { + writeOffset = writeSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + palI2c->WriteSize = writeSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + writeBuffer->Pin(); + } + } + + if (writeBuffer == NULL) + { + palI2c->WriteSize = 0; + } + + readSpanByte = stack.Arg2().Dereference(); + if (readSpanByte != NULL) + { + readBuffer = readSpanByte[SpanByte::FIELD___array].DereferenceArray(); + if (readBuffer != NULL) + { + readOffset = readSpanByte[SpanByte::FIELD___start].NumericByRef().s4; + palI2c->ReadSize = readSpanByte[SpanByte::FIELD___length].NumericByRef().s4; + readBuffer->Pin(); + } + } + + if (readBuffer == NULL) + { + palI2c->ReadSize = 0; + } + + isLongRunningOperation = IsLongRunningOperation( + palI2c->WriteSize, + palI2c->ReadSize, + palI2c->ByteTime, + (uint32_t &)estimatedDurationMiliseconds); + + if (isLongRunningOperation) + { + hbTimeout.SetInteger((CLR_INT64)estimatedDurationMiliseconds * TIME_CONVERSION__TO_MILLISECONDS); + NANOCLR_CHECK_HRESULT(stack.SetupTimeoutFromTicks(hbTimeout, timeout)); + } + + if (!isLongRunningOperation || stack.m_customState == 1) + { + palI2c->Address = (i2caddr_t)connectionSettings[I2cConnectionSettings::FIELD___deviceAddress].NumericByRef().s4; + + if (writeBuffer != NULL) + { + palI2c->WriteBuffer = (uint8_t *)writeBuffer->GetElement(writeOffset); + } + + if (readBuffer != NULL) + { + palI2c->ReadBuffer = (uint8_t *)readBuffer->GetElement(readOffset); + } + + i2cAcquireBus(palI2c->Driver); + i2cStart(palI2c->Driver, &palI2c->Configuration); + } + + if (isLongRunningOperation) + { + if (stack.m_customState == 1) + { + palI2c->WorkingThread = + chThdCreateFromHeap(NULL, THD_WORKING_AREA_SIZE(256), "I2CWT", NORMALPRIO, I2CWorkingThread, palI2c); + + if (palI2c->WorkingThread == NULL) + { + NANOCLR_SET_AND_LEAVE(CLR_E_PROCESS_EXCEPTION); + } + + stack.m_customState = 2; + } + } + else + { + if (palI2c->ReadSize != 0 && palI2c->WriteSize != 0) + { + transactionResult = i2cMasterTransmitTimeout( + palI2c->Driver, + palI2c->Address, + palI2c->WriteBuffer, + palI2c->WriteSize, + palI2c->ReadBuffer, + palI2c->ReadSize, + TIME_MS2I(20)); + } + else + { + if (palI2c->ReadSize == 0) + { + transactionResult = i2cMasterTransmitTimeout( + palI2c->Driver, + palI2c->Address, + palI2c->WriteBuffer, + palI2c->WriteSize, + NULL, + 0, + TIME_MS2I(20)); + } + else + { + transactionResult = i2cMasterReceiveTimeout( + palI2c->Driver, + palI2c->Address, + palI2c->ReadBuffer, + palI2c->ReadSize, + TIME_MS2I(20)); + } + } + } + + while (eventResult) + { + if (!isLongRunningOperation) + { + break; + } + + if (palI2c->WorkingThread->state == CH_STATE_FINAL) + { + break; + } + + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.WaitEvents(stack.m_owningThread, *timeout, Event_I2cMaster, eventResult)); + } + + if (isLongRunningOperation) + { + stack.PopValue(); + } + + if (eventResult || !isLongRunningOperation) + { + i2cReleaseBus(palI2c->Driver); + + CLR_RT_HeapBlock &top = stack.PushValueAndClear(); + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.NewObjectFromIndex(top, g_CLR_RT_WellKnownTypes.m_I2cTransferResult)); + result = top.Dereference(); + FAULT_ON_NULL(result); + + if (isLongRunningOperation) + { + transactionResult = chThdWait(palI2c->WorkingThread); + } + + if (transactionResult != MSG_OK) + { + int errors = i2cGetErrors(palI2c->Driver); + + switch (errors) + { + case I2C_ACK_FAILURE: + result[I2cTransferResult::FIELD___status].SetInteger( + (CLR_UINT32)I2cTransferStatus_SlaveAddressNotAcknowledged); + break; + + case I2C_TIMEOUT: + result[I2cTransferResult::FIELD___status].SetInteger( + (CLR_UINT32)I2cTransferStatus_ClockStretchTimeout); + break; + + default: + result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)I2cTransferStatus_UnknownError); + } + + result[I2cTransferResult::FIELD___bytesTransferred].SetInteger(0); + } + else + { + result[I2cTransferResult::FIELD___status].SetInteger((CLR_UINT32)I2cTransferStatus_FullTransfer); + result[I2cTransferResult::FIELD___bytesTransferred].SetInteger( + (CLR_UINT32)(palI2c->WriteSize + palI2c->ReadSize)); + } + } + + NANOCLR_CLEANUP(); + + if (hr != CLR_E_THREAD_WAITING) + { + if (writeBuffer != NULL && writeBuffer->IsPinned()) + { + writeBuffer->Unpin(); + } + + if (readBuffer != NULL && readBuffer->IsPinned()) + { + readBuffer->Unpin(); + } + } + + NANOCLR_CLEANUP_END(); +} diff --git a/targets/ChibiOS/_RP2040/sys_dev_i2c_native_target.h b/targets/ChibiOS/_RP2040/sys_dev_i2c_native_target.h new file mode 100644 index 0000000000..e2c4a6b717 --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_i2c_native_target.h @@ -0,0 +1,53 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef SYS_DEV_I2C_NATIVE_TARGET_H +#define SYS_DEV_I2C_NATIVE_TARGET_H + +#include +#include +#include +#include + +// struct representing the I2C +typedef struct NF_PAL_I2C_ +{ + I2CDriver *Driver; + I2CConfig Configuration; + thread_t *WorkingThread; + i2caddr_t Address; + float ByteTime; + + uint8_t *WriteBuffer; + uint8_t WriteSize; + + uint8_t *ReadBuffer; + uint8_t ReadSize; +} NF_PAL_I2C; + +//////////////////////////////////////////// +// declaration of the the I2C PAL structs // +//////////////////////////////////////////// +#if RP_I2C_USE_I2C0 +extern NF_PAL_I2C I2C0_PAL; +#endif +#if RP_I2C_USE_I2C1 +extern NF_PAL_I2C I2C1_PAL; +#endif + +// RP2040 I2C pin configuration macro +// I2C function select = 3 on RP2040 +#define I2C_CONFIG_PINS(num, scl_pin, sda_pin) \ + void ConfigPins_I2C##num() \ + { \ + palSetPadMode(IOPORT1, scl_pin, PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_PUE); \ + palSetPadMode(IOPORT1, sda_pin, PAL_MODE_ALTERNATE_I2C | PAL_RP_PAD_PUE); \ + } + +// RP2040 has 2 I2C buses (I2C0, I2C1) +void ConfigPins_I2C0(); +void ConfigPins_I2C1(); + +#endif // SYS_DEV_I2C_NATIVE_TARGET_H diff --git a/targets/ChibiOS/_RP2040/sys_dev_pwm_native_System_Device_Pwm_PwmChannel.cpp b/targets/ChibiOS/_RP2040/sys_dev_pwm_native_System_Device_Pwm_PwmChannel.cpp new file mode 100644 index 0000000000..750bae2450 --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_pwm_native_System_Device_Pwm_PwmChannel.cpp @@ -0,0 +1,238 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include +#include +#include + +// RP2040 PWM mapping: +// 8 PWM slices (0-7), each with channels A (0) and B (1) +// GPIO to slice: slice = GPIO / 2 +// GPIO to channel: channel = GPIO % 2 + +typedef Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel PwmChannel; + +// Get PWM driver for a given slice (timer) ID +static PWMDriver *GetDriverPwm(int timerId) +{ + switch (timerId) + { +#if RP_PWM_USE_PWM0 + case 0: + return &PWMD0; +#endif +#if RP_PWM_USE_PWM1 + case 1: + return &PWMD1; +#endif +#if RP_PWM_USE_PWM2 + case 2: + return &PWMD2; +#endif +#if RP_PWM_USE_PWM3 + case 3: + return &PWMD3; +#endif +#if RP_PWM_USE_PWM4 + case 4: + return &PWMD4; +#endif +#if RP_PWM_USE_PWM5 + case 5: + return &PWMD5; +#endif +#if RP_PWM_USE_PWM6 + case 6: + return &PWMD6; +#endif +#if RP_PWM_USE_PWM7 + case 7: + return &PWMD7; +#endif + default: + return NULL; + } +} + +// RP2040: derive channel from pin number +// pin / 2 = slice, pin % 2 = channel +static int GetChannelPwm(int pin, int timerId) +{ + // validate the pin maps to the requested slice + if ((pin / 2) != timerId) + { + return -1; + } + + return pin % 2; +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::NativeInit___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::NativeSetDesiredFrequency___VOID__I4( + CLR_RT_StackFrame &stack) +{ + uint32_t timerId; + int32_t desiredFrequency; + uint32_t period; + PWMConfig pwmConfig; + PWMDriver *pwmDriver; + + NANOCLR_HEADER(); + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + timerId = pThis[PwmChannel::FIELD___pwmTimer].NumericByRef().s4; + desiredFrequency = stack.Arg1().NumericByRef().s4; + + if (desiredFrequency < 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + pwmDriver = GetDriverPwm(timerId); + + // Set period for precision + period = 1000; + if (desiredFrequency >= 1000) + { + period = 100; + } + else if (desiredFrequency >= 1000000) + { + period = 10; + } + + // Build RP2040 PWM config (2 channels per slice) + pwmConfig = { + (desiredFrequency * period), // clock frequency + (pwmcnt_t)period, // period + NULL, // callback + { + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + {PWM_OUTPUT_ACTIVE_HIGH, NULL}, + }, + }; + + pwmStop(pwmDriver); + osDelay(5); + pwmStart(pwmDriver, &pwmConfig); + + pThis[PwmChannel::FIELD___frequency].NumericByRef().s4 = desiredFrequency; + + stack.SetResult_R8((double)desiredFrequency); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::NativeSetActiveDutyCyclePercentage___VOID__R8( + CLR_RT_StackFrame &stack) +{ + int32_t timerId; + int32_t channelId; + uint32_t dutyCycle; + PWMDriver *pwmDriver; + + NANOCLR_HEADER(); + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + timerId = pThis[PwmChannel::FIELD___pwmTimer].NumericByRef().s4; + channelId = pThis[PwmChannel::FIELD___channelNumber].NumericByRef().s4; + + if (stack.Arg1().NumericByRef().r8 < 0 || stack.Arg1().NumericByRef().r8 > 1.0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + dutyCycle = (uint32_t)(stack.Arg1().NumericByRef().r8 * PwmChannel::CONST_DutyCycleFactor); + + pwmDriver = GetDriverPwm(timerId); + + pwmEnableChannel(pwmDriver, channelId, PWM_PERCENTAGE_TO_WIDTH(pwmDriver, dutyCycle)); + + pThis[PwmChannel::FIELD___dutyCycle].NumericByRef().u4 = dutyCycle; + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::NativeStart___VOID(CLR_RT_StackFrame &stack) +{ + int32_t timerId; + int32_t pinNumber; + uint32_t dutyCycle; + int32_t channelId; + PWMDriver *pwmDriver; + + NANOCLR_HEADER(); + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + timerId = pThis[PwmChannel::FIELD___pwmTimer].NumericByRef().s4; + pinNumber = pThis[PwmChannel::FIELD___pinNumber].NumericByRef().s4; + dutyCycle = pThis[PwmChannel::FIELD___dutyCycle].NumericByRef().u4; + channelId = pThis[PwmChannel::FIELD___channelNumber].NumericByRef().s4; + + pwmDriver = GetDriverPwm(timerId); + + // RP2040: set pin to PWM alternate function (FUNCSEL=4) + palSetPadMode(IOPORT1, pinNumber, PAL_MODE_ALTERNATE_PWM); + + pwmEnableChannel(pwmDriver, channelId, PWM_PERCENTAGE_TO_WIDTH(pwmDriver, dutyCycle)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::NativeStop___VOID(CLR_RT_StackFrame &stack) +{ + int32_t timerId; + int32_t channelId; + + NANOCLR_HEADER(); + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + timerId = pThis[PwmChannel::FIELD___pwmTimer].NumericByRef().s4; + channelId = pThis[PwmChannel::FIELD___channelNumber].NumericByRef().s4; + + pwmDisableChannel(GetDriverPwm(timerId), channelId); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::DisposeNative___VOID(CLR_RT_StackFrame &stack) +{ + (void)stack; + + NANOCLR_HEADER(); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_sys_dev_pwm_native_System_Device_Pwm_PwmChannel::GetChannel___STATIC__I4__I4__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int pin = stack.Arg0().NumericByRef().s4; + int timerId = stack.Arg1().NumericByRef().s4; + + stack.SetResult_I4(GetChannelPwm(pin, timerId)); + + NANOCLR_NOCLEANUP_NOLABEL(); +} diff --git a/targets/ChibiOS/_RP2040/sys_dev_spi_native_target.h b/targets/ChibiOS/_RP2040/sys_dev_spi_native_target.h new file mode 100644 index 0000000000..7f807a2b98 --- /dev/null +++ b/targets/ChibiOS/_RP2040/sys_dev_spi_native_target.h @@ -0,0 +1,65 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef SYS_DEV_SPI_NATIVE_TARGET_H +#define SYS_DEV_SPI_NATIVE_TARGET_H + +#include +#include + +// struct representing the SPI bus +struct NF_PAL_SPI +{ + int BusIndex; + SPIDriver *Driver; + SPIConfig Configuration; + SpiBusConfiguration BusConfiguration; + + SPI_Callback Callback; + + bool SequentialTxRx; + bool BufferIs16bits; + + uint8_t *WriteBuffer; + uint16_t WriteSize; + + uint8_t *ReadBuffer; + uint16_t ReadSize; + + // -1 = Chip Select is not handled | >0 Chip Select is to be controlled with this GPIO + int32_t ChipSelect; +}; + +// RP2040 SPI pin configuration macro +// RP2040 has flexible pin muxing — SPI function is always FUNCSEL=1 +// Configure SCK, MOSI, MISO pins with SPI alternate function and CS as GPIO output +#define SPI_CONFIG_PINS(num, sck_pin, miso_pin, mosi_pin) \ + void ConfigPins_SPI##num(const SPI_DEVICE_CONFIGURATION &spiDeviceConfig) \ + { \ + palSetPadMode(IOPORT1, sck_pin, PAL_MODE_ALTERNATE_SPI); \ + palSetPadMode(IOPORT1, mosi_pin, PAL_MODE_ALTERNATE_SPI); \ + if (spiDeviceConfig.BusConfiguration != SpiBusConfiguration_HalfDuplex) \ + { \ + palSetPadMode(IOPORT1, miso_pin, PAL_MODE_ALTERNATE_SPI); \ + } \ + if (spiDeviceConfig.DeviceChipSelect >= 0) \ + { \ + palSetPadMode(IOPORT1, spiDeviceConfig.DeviceChipSelect, PAL_MODE_OUTPUT_PUSHPULL); \ + if (spiDeviceConfig.ChipSelectActiveState) \ + { \ + palSetPad(IOPORT1, spiDeviceConfig.DeviceChipSelect); \ + } \ + else \ + { \ + palClearPad(IOPORT1, spiDeviceConfig.DeviceChipSelect); \ + } \ + } \ + } + +// RP2040 has 2 SPI buses (SPI0, SPI1) +void ConfigPins_SPI0(const SPI_DEVICE_CONFIGURATION &spiDeviceConfig); +void ConfigPins_SPI1(const SPI_DEVICE_CONFIGURATION &spiDeviceConfig); + +#endif // SYS_DEV_SPI_NATIVE_TARGET_H diff --git a/targets/ChibiOS/_RP2040/target_BlockStorage.c b/targets/ChibiOS/_RP2040/target_BlockStorage.c new file mode 100644 index 0000000000..d80e7acaff --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_BlockStorage.c @@ -0,0 +1,20 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include + +extern struct BlockStorageDevice Device_BlockStorage; +extern struct MEMORY_MAPPED_NOR_BLOCK_CONFIG Device_BlockStorageConfig; +extern IBlockStorageDevice RP2040Flash_BlockStorageInterface; + +void BlockStorage_AddDevices() +{ + BlockStorageList_AddDevice( + (BlockStorageDevice *)&Device_BlockStorage, + &RP2040Flash_BlockStorageInterface, + &Device_BlockStorageConfig, + false); +} diff --git a/targets/ChibiOS/_RP2040/target_BlockStorage.h b/targets/ChibiOS/_RP2040/target_BlockStorage.h new file mode 100644 index 0000000000..0054b3cbdb --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_BlockStorage.h @@ -0,0 +1,12 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef TARGETPAL_BLOCKSTORAGE_H +#define TARGETPAL_BLOCKSTORAGE_H + +// this device has 1 block storage device (external QSPI flash via XIP) +#define TARGET_BLOCKSTORAGE_COUNT 1 + +#endif // TARGETPAL_BLOCKSTORAGE_H diff --git a/targets/ChibiOS/_RP2040/target_FileSystem.cpp b/targets/ChibiOS/_RP2040/target_FileSystem.cpp new file mode 100644 index 0000000000..ef7d80d564 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_FileSystem.cpp @@ -0,0 +1,46 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include +#include +#include "Target_System_IO_FileSystem.h" + +extern FILESYSTEM_DRIVER_INTERFACE g_LITTLEFS_FILE_SYSTEM_DriverInterface; +extern STREAM_DRIVER_INTERFACE g_LITTLEFS_STREAM_DriverInterface; + +FILESYSTEM_INTERFACES g_AvailableFSInterfaces[] = { + {&g_LITTLEFS_FILE_SYSTEM_DriverInterface, &g_LITTLEFS_STREAM_DriverInterface}, +}; + +const size_t g_InstalledFSCount = ARRAYSIZE(g_AvailableFSInterfaces); + +uint32_t g_FS_NumVolumes; +STREAM_DRIVER_DETAILS *g_FS_DriverDetails; +FileSystemVolume *g_FS_Volumes; + +void FS_AddVolumes() +{ + g_FS_NumVolumes = 1; + + g_FS_Volumes = new FileSystemVolume[g_FS_NumVolumes]; + g_FS_DriverDetails = new STREAM_DRIVER_DETAILS[g_FS_NumVolumes]; + + // Internal flash littlefs, drive I:, volume 0 + FileSystemVolumeList::AddVolume( + &g_FS_Volumes[0], + "I:", + 0, + g_AvailableFSInterfaces[0].streamDriver, + g_AvailableFSInterfaces[0].fsDriver, + 0, + FALSE); +} + +void FS_MountRemovableVolumes() +{ + // No removable volumes on RP2040 +} diff --git a/targets/ChibiOS/_RP2040/target_common.c b/targets/ChibiOS/_RP2040/target_common.c new file mode 100644 index 0000000000..db37c1d9c1 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_common.c @@ -0,0 +1,22 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) Microsoft Corporation. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +#include +#include "target_board.h" +#include "target_common.h" + +HAL_SYSTEM_CONFIG HalSystemConfig = { + {true}, // HAL_DRIVER_CONFIG_HEADER Header; + + 1, // ConvertCOM_DebugHandle(1), + 0, // ConvertCOM_DebugHandle(0), + 921600, + 0, // STDIO = COM2 or COM1 + + {RAM1_MEMORY_StartAddress, RAM1_MEMORY_Size}, + {FLASH1_MEMORY_StartAddress, FLASH1_MEMORY_Size}}; + +HAL_TARGET_CONFIGURATION g_TargetConfiguration; diff --git a/targets/ChibiOS/_RP2040/target_littlefs.c b/targets/ChibiOS/_RP2040/target_littlefs.c new file mode 100644 index 0000000000..fb56bca4a6 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_littlefs.c @@ -0,0 +1,142 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include +#include +#include +#include +#include +#include + +// Reference to ChibiOS EFL driver instance +extern EFlashDriver EFLD1; + +// Buffers required by littlefs_FS_Driver +uint8_t lfs_inputBuffer[RP2040_FLASH_PAGE_SIZE]; +uint8_t lfs_outputBuffer[RP2040_FLASH_PAGE_SIZE]; + +int32_t lfs_inputBufferSize = RP2040_FLASH_PAGE_SIZE; +int32_t lfs_outputBufferSize = RP2040_FLASH_PAGE_SIZE; + +// Convert a littlefs block+offset to a flash offset relative to XIP base +static inline flash_offset_t lfs_to_flash_offset(const struct lfs_config *c, lfs_block_t block, lfs_off_t off) +{ + return (flash_offset_t)((RP2040_LFS_BASE - RP2040_XIP_BASE) + (block * c->block_size) + off); +} + +// target specific implementation of hal_lfs_sync +int32_t hal_lfs_sync_(const struct lfs_config *c) +{ + (void)c; + + __DSB(); + + return 0; +} + +// target specific implementation of hal_lfs_erase +int32_t hal_lfs_erase_0(const struct lfs_config *c, lfs_block_t block) +{ + flash_offset_t offset = lfs_to_flash_offset(c, block, 0); + flash_sector_t sector = (flash_sector_t)(offset / RP2040_FLASH_SECTOR_SIZE); + + flash_error_t err = flashStartEraseSector(&EFLD1, sector); + if (err != FLASH_NO_ERROR) + { + return LFS_ERR_IO; + } + + // Wait for erase to complete (synchronous with ROM functions) + uint32_t wait_time = 0; + do + { + err = flashQueryErase(&EFLD1, &wait_time); + if (err == FLASH_ERROR_ERASE) + { + return LFS_ERR_IO; + } + if (wait_time > 0) + { + chThdSleepMilliseconds(wait_time); + } + } while (err == FLASH_BUSY_ERASING); + + return (err == FLASH_NO_ERROR) ? LFS_ERR_OK : LFS_ERR_IO; +} + +// target specific implementation of hal_lfs_read +int32_t hal_lfs_read_0(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) +{ + // RP2040 flash is XIP memory-mapped, so we can read directly + uint32_t addr = RP2040_LFS_BASE + (block * c->block_size) + off; + memcpy(buffer, (const void *)addr, size); + + return LFS_ERR_OK; +} + +// target specific implementation of hal_lfs_prog +int32_t hal_lfs_prog_0( + const struct lfs_config *c, + lfs_block_t block, + lfs_off_t off, + const void *buffer, + lfs_size_t size) +{ + flash_offset_t offset = lfs_to_flash_offset(c, block, off); + + flash_error_t err = flashProgram(&EFLD1, offset, size, (const uint8_t *)buffer); + + return (err == FLASH_NO_ERROR) ? LFS_ERR_OK : LFS_ERR_IO; +} + +// target specific implementation of chip erase +bool hal_lfs_erase_chip_0() +{ + flash_offset_t base_offset = (flash_offset_t)(RP2040_LFS_BASE - RP2040_XIP_BASE); + uint32_t sector_count = RP2040_LFS_SIZE / RP2040_FLASH_SECTOR_SIZE; + + for (uint32_t i = 0; i < sector_count; i++) + { + flash_sector_t sector = (flash_sector_t)((base_offset / RP2040_FLASH_SECTOR_SIZE) + i); + + flash_error_t err = flashStartEraseSector(&EFLD1, sector); + if (err != FLASH_NO_ERROR) + { + return false; + } + + uint32_t wait_time; + do + { + err = flashQueryErase(&EFLD1, &wait_time); + if (err == FLASH_ERROR_ERASE) + { + return false; + } + if (wait_time > 0) + { + chThdSleepMilliseconds(wait_time); + } + } while (err == FLASH_BUSY_ERASING); + + if (err != FLASH_NO_ERROR) + { + return false; + } + } + + return true; +} + +// Low-level initialization for the littlefs flash target. +// The EFL driver is already started by the block storage driver, +// so we just need to ensure it's running. +int8_t target_lfs_init() +{ + // Start the EFL driver if not already started + eflStart(&EFLD1, NULL); + + return LFS_ERR_OK; +} diff --git a/targets/ChibiOS/_RP2040/target_littlefs.h b/targets/ChibiOS/_RP2040/target_littlefs.h new file mode 100644 index 0000000000..e666a3df75 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_littlefs.h @@ -0,0 +1,74 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef TARGET_LITTLEFS_H +#define TARGET_LITTLEFS_H + +#include +#include +#include + +// Single littlefs instance on internal flash +#define LITTLEFS_INSTANCES_COUNT 1 + +////////////////////////////////// +// RP2040 Internal Flash (W25Q16JV) +// 2 MB total, littlefs region: 0x101F8000 - 0x101FFFFF (32 KB) + +// XIP base address +#define RP2040_XIP_BASE 0x10000000U + +// littlefs partition start address (XIP-mapped) +#define RP2040_LFS_BASE 0x101F8000U + +// littlefs partition size +#define RP2040_LFS_SIZE (32U * 1024U) + +// Flash geometry +#define RP2040_FLASH_SECTOR_SIZE 0x1000 // 4 KB +#define RP2040_FLASH_PAGE_SIZE 0x100 // 256 B + +////////////////////////////////// +// Remap into littlefs defines + +#define LFS0_READ_SIZE 1 +#define LFS0_PROG_SIZE 1 +#define LFS0_BLOCK_SIZE RP2040_FLASH_SECTOR_SIZE +#define LFS0_BLOCK_COUNT (RP2040_LFS_SIZE / RP2040_FLASH_SECTOR_SIZE) +#define LFS0_BLOCK_CYCLES 100 +#define LFS0_CACHE_SIZE RP2040_FLASH_PAGE_SIZE +#define LFS0_LOOKAHEAD_SIZE (LFS0_BLOCK_COUNT / 8) + +#define LFS0_READ_HANDLER hal_lfs_read_0 +#define LFS0_PROG_HANDLER hal_lfs_prog_0 +#define LFS0_ERASE_HANDLER hal_lfs_erase_0 +#define LFS0_SYNC_HANDLER hal_lfs_sync_ + +#ifdef __cplusplus +extern "C" +{ +#endif + + bool hal_lfs_erase_chip_0(); + int32_t hal_lfs_sync_(const struct lfs_config *c); + int32_t hal_lfs_erase_0(const struct lfs_config *c, lfs_block_t block); + int32_t hal_lfs_read_0( + const struct lfs_config *c, + lfs_block_t block, + lfs_off_t off, + void *buffer, + lfs_size_t size); + int32_t hal_lfs_prog_0( + const struct lfs_config *c, + lfs_block_t block, + lfs_off_t off, + const void *buffer, + lfs_size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // TARGET_LITTLEFS_H diff --git a/targets/ChibiOS/_RP2040/target_storage_config.h b/targets/ChibiOS/_RP2040/target_storage_config.h new file mode 100644 index 0000000000..b45faf2b57 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_storage_config.h @@ -0,0 +1,11 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef _TARGET_STORAGE_CONFIG_H_ +#define _TARGET_STORAGE_CONFIG_H_ + +// RP2040 has no SD card or USB mass storage + +#endif // _TARGET_STORAGE_CONFIG_H_ diff --git a/targets/ChibiOS/_RP2040/target_stubs.c b/targets/ChibiOS/_RP2040/target_stubs.c new file mode 100644 index 0000000000..a11056da3f --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_stubs.c @@ -0,0 +1,18 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +// Stub implementations for functions not available when GPIO API is disabled. + +__attribute__((weak)) bool CPU_GPIO_Initialize() +{ + return true; +} + +__attribute__((weak)) bool CPU_GPIO_Uninitialize() +{ + return true; +} diff --git a/targets/ChibiOS/_RP2040/target_stubs.cpp b/targets/ChibiOS/_RP2040/target_stubs.cpp new file mode 100644 index 0000000000..7945b1216a --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_stubs.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +// Currently no stub implementations needed — GPIO driver is provided by cpu_gpio.cpp +// when API_System.Device.Gpio is ON. \ No newline at end of file diff --git a/targets/ChibiOS/_RP2040/target_system_device_adc_config.cpp b/targets/ChibiOS/_RP2040/target_system_device_adc_config.cpp new file mode 100644 index 0000000000..204fb698fe --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_system_device_adc_config.cpp @@ -0,0 +1,22 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +// RP2040 Pico ADC channel configuration +// Ch 0: GPIO26 (ADC0) - Pico pin 31 +// Ch 1: GPIO27 (ADC1) - Pico pin 32 +// Ch 2: GPIO28 (ADC2) - Pico pin 34 +// Ch 3: GPIO29 (ADC3) - Pico pin (used for VSYS/3 on Pico board) +// Ch 4: Internal temperature sensor +const NF_PAL_ADC_PORT_PIN_CHANNEL AdcPortPinConfig[] = { + {1, 26, ADC_CHANNEL_IN0}, + {1, 27, ADC_CHANNEL_IN1}, + {1, 28, ADC_CHANNEL_IN2}, + {1, 29, ADC_CHANNEL_IN3}, + {1, 0xFF, ADC_CHANNEL_TEMPSENSOR}, +}; + +const int AdcChannelCount = sizeof(AdcPortPinConfig) / sizeof(AdcPortPinConfig[0]); diff --git a/targets/ChibiOS/_RP2040/target_system_device_i2c_config.cpp b/targets/ChibiOS/_RP2040/target_system_device_i2c_config.cpp new file mode 100644 index 0000000000..be25bd9cd8 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_system_device_i2c_config.cpp @@ -0,0 +1,24 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +////////// +// I2C0 // +////////// + +// Default Pico pin configuration for I2C0: +// SCL = GP5 +// SDA = GP4 +I2C_CONFIG_PINS(0, 5, 4) + +////////// +// I2C1 // +////////// + +// Default Pico pin configuration for I2C1: +// SCL = GP7 +// SDA = GP6 +I2C_CONFIG_PINS(1, 7, 6) diff --git a/targets/ChibiOS/_RP2040/target_system_device_pwm_config.cpp b/targets/ChibiOS/_RP2040/target_system_device_pwm_config.cpp new file mode 100644 index 0000000000..d853cb363a --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_system_device_pwm_config.cpp @@ -0,0 +1,8 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// RP2040 PWM target configuration +// PWM is defined by slice number, no special pin config needed here. +// Pin-to-slice mapping is fixed by hardware: slice = GPIO / 2, channel = GPIO % 2. diff --git a/targets/ChibiOS/_RP2040/target_system_device_spi_config.cpp b/targets/ChibiOS/_RP2040/target_system_device_spi_config.cpp new file mode 100644 index 0000000000..7fff683ab5 --- /dev/null +++ b/targets/ChibiOS/_RP2040/target_system_device_spi_config.cpp @@ -0,0 +1,26 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include + +////////// +// SPI0 // +////////// + +// Default Pico pin configuration for SPI0: +// SCK = GP18 +// MISO = GP16 +// MOSI = GP19 +SPI_CONFIG_PINS(0, 18, 16, 19) + +////////// +// SPI1 // +////////// + +// Default Pico pin configuration for SPI1: +// SCK = GP10 +// MISO = GP12 +// MOSI = GP11 +SPI_CONFIG_PINS(1, 10, 12, 11) diff --git a/targets/ChibiOS/_WiFi/cyw43/cyw43_arch_chibios.c b/targets/ChibiOS/_WiFi/cyw43/cyw43_arch_chibios.c new file mode 100644 index 0000000000..2f7ccf4063 --- /dev/null +++ b/targets/ChibiOS/_WiFi/cyw43/cyw43_arch_chibios.c @@ -0,0 +1,258 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// CYW43 architecture layer for ChibiOS/RT. +// Provides initialization, synchronization primitives, and poll scheduling. + +#include +#include +#include "cyw43_configport.h" +#include "cyw43.h" +#include "cyw43_country.h" +#include "cyw43_internal.h" +#include "cyw43_spi.h" + +// --------------------------------------------------------------------------- +// MAC address — matches Pico SDK: returns cyw43_state.mac (set from OTP +// during firmware init). Before init, returns zeros. +// --------------------------------------------------------------------------- +void cyw43_hal_get_mac(int itf, uint8_t mac[6]) +{ + (void)itf; + memcpy(mac, cyw43_state.mac, 6); +} + +// CLR event system — fire SYSTEM_EVENT_FLAG_WIFI_STATION to wake NativeConnect +extern void Events_Set(uint32_t events); +#define SYSTEM_EVENT_FLAG_WIFI_STATION 0x01000000 + +// --------------------------------------------------------------------------- +// Synchronization primitives +// --------------------------------------------------------------------------- +// Recursive lock: CYW43 driver nests CYW43_THREAD_ENTER/EXIT, so we track +// the owner thread and a recursion depth. Only the outermost unlock releases +// the underlying ChibiOS mutex. +static mutex_t cyw43_mutex; +static volatile thread_t *cyw43_lock_owner = NULL; +static volatile int cyw43_lock_depth = 0; + +binary_semaphore_t cyw43_sdpcm_sem; +binary_semaphore_t cyw43_ioctl_sem; + +void cyw43_thread_enter(void) +{ + thread_t *self = chThdGetSelfX(); + if (cyw43_lock_owner == self) + { + // Same thread — just bump the depth + cyw43_lock_depth++; + return; + } + chMtxLock(&cyw43_mutex); + cyw43_lock_owner = self; + cyw43_lock_depth = 1; +} + +void cyw43_thread_exit(void) +{ + if (--cyw43_lock_depth == 0) + { + cyw43_lock_owner = NULL; + chMtxUnlock(&cyw43_mutex); + } +} + +// Forward declarations +static void (*cyw43_poll_func)(void); +static event_source_t cyw43_poll_event; + +// Wait functions for SDPCM send stalls and ioctl response polling. +// +// IMPORTANT: These must NOT release the CYW43 mutex. The callers +// (cyw43_do_ioctl, cyw43_sdpcm_send_common) already poll the device +// inline via cyw43_ll_sdpcm_poll_device(). If we release the mutex +// here, the background poll thread can run cyw43_ll_process_packets() +// which consumes response packets (including CONTROL_HEADER) that the +// ioctl loop is waiting for — CONTROL_HEADER has no handler in +// process_packets, so the response is silently discarded and the +// ioctl times out. Keeping the mutex held avoids this race while the +// inline polling in the caller handles all packet types correctly. +void cyw43_sdpcm_wait(void) +{ + chThdSleep(TIME_MS2I(1)); +} + +void cyw43_ioctl_wait(void) +{ + chThdSleep(TIME_MS2I(1)); +} + +// Poll thread +static thread_t *cyw43_poll_thread = NULL; + +// CYW43 poll thread — runs CYW43 internal polling when signaled +#define CYW43_POLL_THREAD_STACK_SIZE 2048 +static THD_WORKING_AREA(wa_cyw43_poll_thread, CYW43_POLL_THREAD_STACK_SIZE); + +static THD_FUNCTION(cyw43_poll_thread_func, arg) +{ + (void)arg; + event_listener_t el; + + chRegSetThreadName("cyw43poll"); + chEvtRegister(&cyw43_poll_event, &el, 0); + + while (true) + { + // Wake on event signal OR every 10 ms for periodic polling. + // The CYW43 interrupt pin (GP24) is not wired to a GPIO IRQ in + // our ChibiOS port, so regular polling is the only way to drain + // async events (scan results, link state, etc.). + chEvtWaitAnyTimeout(EVENT_MASK(0), TIME_MS2I(10)); + chEvtGetAndClearEvents(EVENT_MASK(0)); + + if (cyw43_poll_func != NULL) + { + // Use try-lock: if main thread holds the lock (e.g. sending + // an ioctl), skip this poll cycle — the main thread will + // release the lock during its CYW43_DO_IOCTL_WAIT and we + // will poll on the next cycle. + if (chMtxTryLock(&cyw43_mutex)) + { + cyw43_lock_owner = chThdGetSelfX(); + cyw43_lock_depth = 1; + + cyw43_poll_func(); + + cyw43_lock_depth = 0; + cyw43_lock_owner = NULL; + chMtxUnlock(&cyw43_mutex); + + // Fire Event_Wifi_Station every ~500ms (50 polls × 10ms) to + // wake NativeConnect's WaitEvents loop for periodic re-check. + { + static uint32_t event_fire_counter = 0; + if (++event_fire_counter >= 50) { + event_fire_counter = 0; + Events_Set(SYSTEM_EVENT_FLAG_WIFI_STATION); + } + } + } + } + } +} + +// Called by the CYW43 driver when it needs its poll function called +void cyw43_schedule_internal_poll_dispatch(void (*func)(void)) +{ + cyw43_poll_func = func; + chEvtBroadcast(&cyw43_poll_event); +} + +// Called after poll completes — can signal waiting threads +void cyw43_post_poll_hook(void) +{ + chBSemSignal(&cyw43_sdpcm_sem); + chBSemSignal(&cyw43_ioctl_sem); +} + +// --------------------------------------------------------------------------- +// Architecture initialization (lightweight — no hardware access) +// --------------------------------------------------------------------------- +static volatile int cyw43_hw_initialized = 0; + +void cyw43_arch_init(void) +{ + // Initialize synchronization primitives + chMtxObjectInit(&cyw43_mutex); + chBSemObjectInit(&cyw43_sdpcm_sem, true); + chBSemObjectInit(&cyw43_ioctl_sem, true); + + // Initialize poll event source + chEvtObjectInit(&cyw43_poll_event); + + // Create the CYW43 poll thread + cyw43_poll_thread = chThdCreateStatic( + wa_cyw43_poll_thread, + sizeof(wa_cyw43_poll_thread), + NORMALPRIO + 1, + cyw43_poll_thread_func, + NULL); + + // NOTE: cyw43_init() and cyw43_wifi_set_up() are deferred to + // cyw43_ensure_wifi_up() so that CLR startup is not blocked by + // the ~500ms SPI firmware load. +} + +// --------------------------------------------------------------------------- +// Lazy WiFi hardware initialization — called before scan/connect +// --------------------------------------------------------------------------- + +int cyw43_ensure_wifi_up_impl(void) +{ + if (cyw43_hw_initialized) + { + return 0; + } + + // cyw43_init() only initializes driver state and sets GPIO modes. + // It does NOT do SPI communication — that happens inside + // cyw43_wifi_set_up() → cyw43_ensure_up() → cyw43_ll_bus_init(). + cyw43_init(&cyw43_state); + + // Power on WiFi, do SPI bus init, load firmware, enable STA interface. + cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, CYW43_COUNTRY_WORLDWIDE); + + cyw43_hw_initialized = 1; + + return (cyw43_state.itf_state != 0) ? 0 : -1; +} + +void cyw43_arch_deinit(void) +{ + if (cyw43_poll_thread != NULL) + { + chThdTerminate(cyw43_poll_thread); + chEvtBroadcast(&cyw43_poll_event); // Wake thread to see termination flag + cyw43_poll_thread = NULL; + } + cyw43_poll_func = NULL; +} + +// --------------------------------------------------------------------------- +// WiFi connection state tracking +// --------------------------------------------------------------------------- +static volatile int cyw43_wifi_connected = 0; +static volatile int cyw43_connect_result = -1; + +// Called from the lwIP thread or CYW43 event handler when link state changes +void cyw43_set_wifi_connected(int connected, int result) +{ + cyw43_wifi_connected = connected; + cyw43_connect_result = result; +} + +int cyw43_is_wifi_connected(void) +{ + return cyw43_wifi_connected; +} + +int cyw43_get_connect_result(void) +{ + return cyw43_connect_result; +} + +// WiFi scan state +static volatile int cyw43_scan_active = 0; + +void cyw43_set_scan_active(int active) +{ + cyw43_scan_active = active; +} + +int cyw43_is_scan_active(void) +{ + return cyw43_scan_active; +} diff --git a/targets/ChibiOS/_WiFi/cyw43/cyw43_bus_pio_spi.c b/targets/ChibiOS/_WiFi/cyw43/cyw43_bus_pio_spi.c new file mode 100644 index 0000000000..91bdac3f9a --- /dev/null +++ b/targets/ChibiOS/_WiFi/cyw43/cyw43_bus_pio_spi.c @@ -0,0 +1,678 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2020 Raspberry Pi (Trading) Ltd. (BSD-3-Clause) +// See LICENSE file in the project root for full license information. +// + +// CYW43 PIO SPI bus driver for ChibiOS on RP2040 (Pico W). +// Ported from the Pico SDK cyw43_bus_pio_spi.c reference implementation. +// +// This file provides BOTH the low-level SPI transport AND the higher-level +// register/byte read/write functions. The generic cyw43_spi.c from the +// cyw43-driver repo must NOT be compiled — it assumes full-duplex SPI. +// +// CYW43439 half-duplex gSPI protocol: +// GP23 = WL_REG_ON (power), GP24 = DATA/IRQ (bidirectional), +// GP25 = CS (active low), GP29 = CLK (via PIO sideset) + +#include +#include +#include +#include +#include "rp_pio.h" +#include "cyw43_configport.h" +#include "cyw43.h" +#include "cyw43_ll.h" +#include "cyw43_internal.h" +#include "cyw43_spi.h" + +#if CYW43_USE_SPI + +// --------------------------------------------------------------------------- +// Pin definitions +// --------------------------------------------------------------------------- +#define DATA_PIN CYW43_PIN_WL_DATA_OUT // GP24 +#define CLK_PIN CYW43_PIN_WL_CLK // GP29 +#define CS_PIN CYW43_PIN_WL_CS // GP25 + +// --------------------------------------------------------------------------- +// RP2040 hardware register definitions (direct access) +// --------------------------------------------------------------------------- +#define SIO_BASE 0xD0000000u +#define GPIO_OUT_SET (*(volatile uint32_t *)(SIO_BASE + 0x014)) +#define GPIO_OUT_CLR (*(volatile uint32_t *)(SIO_BASE + 0x018)) +#define GPIO_OE_SET (*(volatile uint32_t *)(SIO_BASE + 0x024)) +#define GPIO_OE_CLR (*(volatile uint32_t *)(SIO_BASE + 0x028)) +#define GPIO_IN_REG (*(volatile uint32_t *)(SIO_BASE + 0x004)) + +#define IO_BANK0_BASE 0x40014000u +#define GPIO_CTRL(n) (*(volatile uint32_t *)(IO_BANK0_BASE + 0x04 + 8 * (n))) + +#define PADS_BANK0_BASE 0x4001C000u +#define PADS_GPIO(n) (*(volatile uint32_t *)(PADS_BANK0_BASE + 0x04 + 4 * (n))) +#define PAD_OD (1u << 7) +#define PAD_IE (1u << 6) +#define PAD_DRIVE_2MA (0u << 4) +#define PAD_DRIVE_4MA (1u << 4) +#define PAD_DRIVE_8MA (2u << 4) +#define PAD_DRIVE_12MA (3u << 4) +#define PAD_PUE (1u << 3) +#define PAD_PDE (1u << 2) +#define PAD_SCHMITT (1u << 1) +#define PAD_SLEWFAST (1u << 0) + +#define FUNCSEL_SIO 5u + +// --------------------------------------------------------------------------- +// GPIO helpers +// --------------------------------------------------------------------------- +static inline void pin_high(uint32_t pin) { GPIO_OUT_SET = 1u << pin; } +static inline void pin_low(uint32_t pin) { GPIO_OUT_CLR = 1u << pin; } +static inline void pin_output(uint32_t pin) { GPIO_OE_SET = 1u << pin; } +static inline void pin_input(uint32_t pin) { GPIO_OE_CLR = 1u << pin; } + +static void gpio_init_pin(uint32_t pin, bool output, uint32_t pad_cfg) +{ + GPIO_OUT_CLR = 1u << pin; + if (output) GPIO_OE_SET = 1u << pin; + else GPIO_OE_CLR = 1u << pin; + GPIO_CTRL(pin) = FUNCSEL_SIO; + PADS_GPIO(pin) = pad_cfg; +} + +// --------------------------------------------------------------------------- +// PIO SPI Program — spi_gap01_sample0 from Pico SDK +// --------------------------------------------------------------------------- +// [0] lp: out pins, 1 side 0 +// [1] jmp x-- lp side 1 +// [2] lp1_end: set pindirs, 0 side 0 +// [3] nop side 1 +// [4] lp2: in pins, 1 side 0 +// [5] jmp y-- lp2 side 1 +// [6] end: +static const uint16_t spi_program[] = { + 0x6001, // [0] out pins, 1 side 0 + 0x1040, // [1] jmp x-- 0 side 1 (X--, addr patched at load) + 0xE080, // [2] set pindirs, 0 side 0 + 0xB042, // [3] nop(mov y,y) side 1 + 0x4001, // [4] in pins, 1 side 0 + 0x1084, // [5] jmp y-- 4 side 1 (Y--, addr patched at load) +}; +#define SPI_PROGRAM_LEN 6 +#define SPI_OFFSET_LP1_END 2 +#define SPI_OFFSET_END 6 + +// Immediate-exec helpers (no sideset applied) +static inline uint16_t pio_encode_jmp(uint32_t addr) { return (uint16_t)(addr & 0x1F); } +static inline uint16_t pio_encode_out_x_32(void) { return 0x6020; } +static inline uint16_t pio_encode_out_y_32(void) { return 0x6040; } +#define PIO_INSTR_SET_PINDIRS_1 0xE081u +#define PIO_INSTR_SET_PINDIRS_0 0xE080u +#define PIO_INSTR_SET_PINS_1 0xE001u +#define PIO_INSTR_MOV_PINS_NULL 0xA003u + +// Read-modify-write EXECCTRL wrap bits only (matches SDK pio_sm_set_wrap). +// pioSmSetExecctrlX does a full register write which zeros all non-wrap bits. +static inline void pio_sm_set_wrap(const rp_pio_sm_t *smp, uint32_t wrap_bottom, uint32_t wrap_top) +{ + PIO_TypeDef *pio = smp->block->pio; + uint32_t sm = smp->smidx; + uint32_t val = pio->SM[sm].EXECCTRL; + val &= ~(PIO_SM_EXECCTRL_WRAP_BOTTOM_Msk | PIO_SM_EXECCTRL_WRAP_TOP_Msk); + val |= (wrap_bottom << PIO_SM_EXECCTRL_WRAP_BOTTOM_Pos) | + (wrap_top << PIO_SM_EXECCTRL_WRAP_TOP_Pos); + pio->SM[sm].EXECCTRL = val; +} + +// --------------------------------------------------------------------------- +// PIO state +// --------------------------------------------------------------------------- +static const rp_pio_sm_t *pio_sm = NULL; +static int32_t pio_offset = -1; + +// --------------------------------------------------------------------------- +// Byte-swap helpers +// --------------------------------------------------------------------------- +// Full byte reversal (emulates DMA bswap on each FIFO word) +static inline uint32_t bswap32(uint32_t x) { return __builtin_bswap32(x); } + +// Pico SDK SWAP32 = rev16 = swap bytes within each 16-bit half +// Used only for the initial swap-mode register access before 32-bit bus switch +static inline uint32_t SWAP32(uint32_t x) +{ + uint32_t r; + __asm volatile ("rev16 %0, %1" : "=l" (r) : "l" (x)); + return r; +} + +// --------------------------------------------------------------------------- +// Command builder — identical to Pico SDK make_cmd / generic pack_cmd +// --------------------------------------------------------------------------- +static inline uint32_t make_cmd(bool write, bool inc, uint32_t fn, + uint32_t addr, uint32_t sz) +{ + return (uint32_t)write << 31 | (uint32_t)inc << 30 | + fn << 28 | (addr & 0x1FFFFu) << 11 | sz; +} + +// --------------------------------------------------------------------------- +// SPI diagnostic trace +// --------------------------------------------------------------------------- +#define SPI_TRACE_MAX_TXNS 8 +#define SPI_TRACE_MAX_BYTES 16 + +typedef struct { + uint8_t tx_bytes[SPI_TRACE_MAX_BYTES]; + uint8_t rx_bytes[SPI_TRACE_MAX_BYTES]; + uint16_t tx_len; + uint16_t rx_len; + uint16_t eff_tx_len; + uint16_t eff_rx_len; + uint32_t gpio_state; + uint32_t raw_pio_rx; +} spi_trace_entry_t; + +static spi_trace_entry_t spi_trace[SPI_TRACE_MAX_TXNS]; +static volatile int spi_trace_count = 0; +static volatile uint32_t spi_txn_total = 0; + +int cyw43_spi_get_trace_count(void) { return spi_trace_count; } +uint32_t cyw43_spi_get_txn_total(void) { return spi_txn_total; } +const void *cyw43_spi_get_trace(int idx) +{ + if (idx < 0 || idx >= spi_trace_count) return NULL; + return &spi_trace[idx]; +} + +// PIO register snapshot +static uint32_t diag_pio_pinctrl, diag_pio_shiftctrl, diag_pio_execctrl, diag_pio_clkdiv; +static uint32_t diag_pio_instr[SPI_PROGRAM_LEN]; +static int32_t diag_pio_offset; +static uint32_t diag_gpio_ctrl_data, diag_gpio_ctrl_clk, diag_gpio_ctrl_cs, diag_gpio_ctrl_regon; +static uint32_t diag_pads_data, diag_pads_clk; + +uint32_t cyw43_spi_get_diag_pinctrl(void) { return diag_pio_pinctrl; } +uint32_t cyw43_spi_get_diag_shiftctrl(void) { return diag_pio_shiftctrl; } +uint32_t cyw43_spi_get_diag_execctrl(void) { return diag_pio_execctrl; } +uint32_t cyw43_spi_get_diag_clkdiv(void) { return diag_pio_clkdiv; } +int32_t cyw43_spi_get_diag_offset(void) { return diag_pio_offset; } +uint32_t cyw43_spi_get_diag_instr(int idx) { return (idx >= 0 && idx < SPI_PROGRAM_LEN) ? diag_pio_instr[idx] : 0; } + +void cyw43_spi_capture_gpio_diag(void) +{ + diag_gpio_ctrl_data = GPIO_CTRL(DATA_PIN); + diag_gpio_ctrl_clk = GPIO_CTRL(CLK_PIN); + diag_gpio_ctrl_cs = GPIO_CTRL(CS_PIN); + diag_gpio_ctrl_regon = GPIO_CTRL(CYW43_PIN_WL_REG_ON); + diag_pads_data = PADS_GPIO(DATA_PIN); + diag_pads_clk = PADS_GPIO(CLK_PIN); +} + +uint32_t cyw43_spi_get_gpio_ctrl(int idx) +{ + switch (idx) { + case 0: return diag_gpio_ctrl_data; + case 1: return diag_gpio_ctrl_clk; + case 2: return diag_gpio_ctrl_cs; + case 3: return diag_gpio_ctrl_regon; + case 4: return diag_pads_data; + case 5: return diag_pads_clk; + default: return 0; + } +} + +// ========================================================================= +// Low-level port functions +// ========================================================================= + +void cyw43_spi_gpio_setup(void) +{ + gpio_init_pin(CS_PIN, true, PAD_IE | PAD_DRIVE_4MA | PAD_SCHMITT); + pin_high(CS_PIN); + + gpio_init_pin(CYW43_PIN_WL_REG_ON, true, PAD_IE | PAD_DRIVE_4MA | PAD_PUE | PAD_SCHMITT); + pin_low(CYW43_PIN_WL_REG_ON); + + // DATA: SIO output LOW during reset (critical for gSPI mode detection). + // No pull — between transfers, chip drives GP24 HIGH for interrupts. + gpio_init_pin(DATA_PIN, true, PAD_IE | PAD_DRIVE_4MA | PAD_SCHMITT); + pin_low(DATA_PIN); +} + +void cyw43_spi_reset(void) +{ + pin_low(CYW43_PIN_WL_REG_ON); + cyw43_delay_ms(20); + pin_high(CYW43_PIN_WL_REG_ON); + cyw43_delay_ms(250); + + // DATA → SIO input after power-on (matches Pico SDK, no pull) + gpio_init_pin(DATA_PIN, false, PAD_IE | PAD_DRIVE_4MA | PAD_SCHMITT); +} + +int cyw43_spi_init(cyw43_int_t *self) +{ + (void)self; + pioInit(); + + pio_sm = pioSmAlloc(RP_PIO0_BLOCK, RP_PIO_SM_ID_ANY, 0, NULL, NULL); + if (pio_sm == NULL) return -1; + + // Load program + uint16_t patched[SPI_PROGRAM_LEN]; + memcpy(patched, spi_program, sizeof(spi_program)); + rp_pio_program_t prog = { .instructions = patched, + .length = SPI_PROGRAM_LEN, + .origin = -1 }; + pio_offset = pioProgramLoad(pio_sm->block, &prog); + if (pio_offset < 0) { pioSmFree(pio_sm); pio_sm = NULL; return -1; } + + // Patch JMP targets to absolute addresses + PIO_TypeDef *pio = pio_sm->block->pio; + patched[1] = 0x1040 | (uint16_t)(pio_offset + 0); // jmp x-- lp + patched[5] = 0x1080 | (uint16_t)(pio_offset + 4); // jmp y-- lp2 + for (int i = 0; i < SPI_PROGRAM_LEN; i++) + pio->INSTR_MEM[pio_offset + i] = patched[i]; + + uint32_t sm = pio_sm->smidx; + + // Clock: 125 MHz / 2 = 62.5 MHz PIO → ~31 MHz SPI + pioSmSetClkdivX(pio_sm, PIO_SM_CLKDIV(2, 0)); + + // Shift: OUT left, IN left, autopull/autopush at 32 bits + pioSmSetShiftctrlX(pio_sm, + PIO_SM_SHIFTCTRL_AUTOPULL | PIO_SM_SHIFTCTRL_AUTOPUSH); + + // Pin mapping + pioSmSetPinctrlX(pio_sm, + (DATA_PIN << PIO_SM_PINCTRL_OUT_BASE_Pos) | + (1u << PIO_SM_PINCTRL_OUT_COUNT_Pos) | + (DATA_PIN << PIO_SM_PINCTRL_SET_BASE_Pos) | + (1u << PIO_SM_PINCTRL_SET_COUNT_Pos) | + (DATA_PIN << PIO_SM_PINCTRL_IN_BASE_Pos) | + (CLK_PIN << PIO_SM_PINCTRL_SIDESET_BASE_Pos) | + (1u << PIO_SM_PINCTRL_SIDESET_COUNT_Pos)); + + // CLK pad: 12 mA, fast slew, Schmitt trigger + PADS_GPIO(CLK_PIN) = PAD_IE | PAD_DRIVE_12MA | PAD_SLEWFAST | PAD_SCHMITT; + pioSmSetPinFunctionX(pio_sm, CLK_PIN); + + // Set CLK as output via PIO (temp point SET at CLK) + { + uint32_t saved = pio->SM[sm].PINCTRL; + pio->SM[sm].PINCTRL = (CLK_PIN << PIO_SM_PINCTRL_SET_BASE_Pos) | + (1u << PIO_SM_PINCTRL_SET_COUNT_Pos); + pioSmExecX(pio_sm, PIO_INSTR_SET_PINDIRS_1); + pio->SM[sm].PINCTRL = saved; + } + + // DATA pad: pull-down and Schmitt (matches SDK gpio_set_pulls(DATA_IN, false, true)) + PADS_GPIO(DATA_PIN) = PAD_IE | PAD_DRIVE_4MA | PAD_PDE | PAD_SCHMITT; + pioSmSetPinFunctionX(pio_sm, DATA_PIN); + + // DATA = output high initially (matches Pico SDK set pins, 1) + pioSmExecX(pio_sm, PIO_INSTR_SET_PINDIRS_1); + pioSmExecX(pio_sm, PIO_INSTR_SET_PINS_1); + + // Bypass input synchronizer for zero-delay reads + pio->INPUT_SYNC_BYPASS |= (1u << DATA_PIN); + + // Diagnostics snapshot + diag_pio_pinctrl = pio->SM[sm].PINCTRL; + diag_pio_shiftctrl = pio->SM[sm].SHIFTCTRL; + diag_pio_execctrl = pio->SM[sm].EXECCTRL; + diag_pio_clkdiv = pio->SM[sm].CLKDIV; + diag_pio_offset = pio_offset; + for (int i = 0; i < SPI_PROGRAM_LEN; i++) + diag_pio_instr[i] = patched[i]; + + return 0; +} + +void cyw43_spi_deinit(cyw43_int_t *self) +{ + (void)self; + if (pio_sm != NULL) { + pioSmDisableX(pio_sm); + if (pio_offset >= 0) + pioProgramUnload(pio_sm->block, pio_offset, SPI_PROGRAM_LEN); + pioSmFree(pio_sm); + pio_sm = NULL; + pio_offset = -1; + } + pin_low(CYW43_PIN_WL_REG_ON); +} + +void cyw43_spi_set_polarity(cyw43_int_t *self, int pol) +{ + (void)self; (void)pol; +} + +// ========================================================================= +// Core SPI transfer — half-duplex PIO +// +// Calling convention (matches Pico SDK cyw43_bus_pio_spi.c): +// tx!=NULL, rx==NULL → write: send tx_length bytes +// tx==NULL, rx!=NULL → read: command in rx[0..3], response in rx[4..] +// tx!=NULL, rx!=NULL → send tx_length from tx, receive rx_length into rx +// ========================================================================= + +static void start_spi_comms(void) +{ + pioSmSetPinFunctionX(pio_sm, DATA_PIN); + pioSmSetPinFunctionX(pio_sm, CLK_PIN); + // Add pull-down on CLK for idle LOW between transfers (matches SDK gpio_pull_down) + PADS_GPIO(CLK_PIN) |= PAD_PDE; + pin_low(CS_PIN); +} + +static void stop_spi_comms(void) +{ + pin_high(CS_PIN); + // We need to wait a bit in case the IRQ line is incorrectly high + // (matches Pico SDK IRQ_SAMPLE_DELAY_NS = 100ns) + __asm volatile ("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;" ::: ); +} + +int cyw43_spi_transfer(cyw43_int_t *self, const uint8_t *tx, size_t tx_length, + uint8_t *rx, size_t rx_length) +{ + (void)self; + if ((tx == NULL) && (rx == NULL)) { + return CYW43_FAIL_FAST_CHECK(-CYW43_EINVAL); + } + if (pio_sm == NULL) return -1; + spi_txn_total++; + + // Trace capture + int tidx = -1; + if (spi_trace_count < SPI_TRACE_MAX_TXNS) { + tidx = spi_trace_count++; + spi_trace_entry_t *t = &spi_trace[tidx]; + memset(t, 0, sizeof(*t)); + t->tx_len = (uint16_t)tx_length; + t->rx_len = (uint16_t)rx_length; + if (tx) { + size_t c = tx_length < SPI_TRACE_MAX_BYTES ? tx_length : SPI_TRACE_MAX_BYTES; + memcpy(t->tx_bytes, tx, c); + } else if (rx) { + size_t c = 4 < SPI_TRACE_MAX_BYTES ? 4 : SPI_TRACE_MAX_BYTES; + memcpy(t->tx_bytes, rx, c); + } + } + if (spi_trace_count <= 1) cyw43_spi_capture_gpio_diag(); + + PIO_TypeDef *pio = pio_sm->block->pio; + uint32_t sm = pio_sm->smidx; + + start_spi_comms(); + if (tidx >= 0) spi_trace[tidx].gpio_state = GPIO_IN_REG; + + if (rx != NULL) { + // ---- TX+RX (read) ------------------------------------------------ + // SDK convention: tx==NULL means command is in rx[0..3] + if (tx == NULL) { tx = rx; } + + if (tidx >= 0) { + spi_trace[tidx].eff_tx_len = (uint16_t)tx_length; + spi_trace[tidx].eff_rx_len = (uint16_t)rx_length; + } + + assert(!(tx_length & 3)); + assert(!(((uintptr_t)tx) & 3)); + assert(!(((uintptr_t)rx) & 3)); + assert(!(rx_length & 3)); + + uint32_t tx_bits = tx_length * 8; + uint32_t rx_bits = (rx_length - tx_length) * 8; + + pioSmDisableX(pio_sm); + pio_sm_set_wrap(pio_sm, pio_offset, pio_offset + SPI_OFFSET_END - 1); + pioSmClearFifosX(pio_sm); + pioSmExecX(pio_sm, PIO_INSTR_SET_PINDIRS_1); // DATA = output + + pioSmRestartX(pio_sm); + pioSmClkdivRestartX(pio_sm); + + pioSmPutX(pio_sm, tx_bits - 1); + pioSmExecX(pio_sm, pio_encode_out_x_32()); + pioSmPutX(pio_sm, rx_bits - 1); + pioSmExecX(pio_sm, pio_encode_out_y_32()); + pioSmExecX(pio_sm, pio_encode_jmp(pio_offset)); + pioSmEnableX(pio_sm); + + // Feed TX words + const uint32_t *tx32 = (const uint32_t *)tx; + for (uint32_t i = 0; i < tx_length / 4; i++) { + while (pioSmIsTxFullX(pio_sm)) {} + pioSmPutX(pio_sm, bswap32(tx32[i])); + } + + // Read RX words + uint32_t *rx32 = (uint32_t *)(rx + tx_length); + uint32_t rx_words = (rx_length - tx_length) / 4; + for (uint32_t i = 0; i < rx_words; i++) { + while (pioSmIsRxEmptyX(pio_sm)) {} + uint32_t raw = pioSmGetX(pio_sm); + if (tidx >= 0 && i == 0) spi_trace[tidx].raw_pio_rx = raw; + rx32[i] = bswap32(raw); + } + __asm volatile("" ::: "memory"); + + memset(rx, 0, tx_length); // zero command portion + + } else if (tx != NULL) { + // ---- TX-only (write) --------------------------------------------- + assert(!(((uintptr_t)tx) & 3)); + assert(!(tx_length & 3)); + uint32_t tx_bits = tx_length * 8; + + pioSmDisableX(pio_sm); + pio_sm_set_wrap(pio_sm, pio_offset, pio_offset + SPI_OFFSET_LP1_END - 1); + pioSmClearFifosX(pio_sm); + pioSmExecX(pio_sm, PIO_INSTR_SET_PINDIRS_1); + + pioSmRestartX(pio_sm); + pioSmClkdivRestartX(pio_sm); + + pioSmPutX(pio_sm, tx_bits - 1); + pioSmExecX(pio_sm, pio_encode_out_x_32()); + pioSmPutX(pio_sm, 0); + pioSmExecX(pio_sm, pio_encode_out_y_32()); + pioSmExecX(pio_sm, pio_encode_jmp(pio_offset)); + pioSmEnableX(pio_sm); + + const uint32_t *tx32 = (const uint32_t *)tx; + for (uint32_t i = 0; i < tx_length / 4; i++) { + while (pioSmIsTxFullX(pio_sm)) {} + pioSmPutX(pio_sm, bswap32(tx32[i])); + } + + // Wait for TX complete + uint32_t stall = PIO_FDEBUG_TXSTALL(sm); + pio->FDEBUG = stall; + while (!(pio->FDEBUG & stall)) {} + __asm volatile("" ::: "memory"); + + pioSmDisableX(pio_sm); + pioSmExecX(pio_sm, PIO_INSTR_SET_PINDIRS_0); // DATA → input + } + + // Set DATA output value to 0 for next transfer (matches SDK mov pins, null) + pioSmExecX(pio_sm, PIO_INSTR_MOV_PINS_NULL); + stop_spi_comms(); + + // Trace: capture RX + if (tidx >= 0 && rx != NULL) { + size_t c = rx_length < SPI_TRACE_MAX_BYTES ? rx_length : SPI_TRACE_MAX_BYTES; + memcpy(spi_trace[tidx].rx_bytes, rx, c); + } + return 0; +} + +// ========================================================================= +// Higher-level SPI protocol functions — replace generic cyw43_spi.c +// ========================================================================= + +// --- Swap-mode register access (used before 32-bit bus mode switch) ------- + +uint32_t read_reg_u32_swap(cyw43_int_t *self, uint32_t fn, uint32_t reg) +{ + uint32_t buf[2] = {0}; + assert(fn != BACKPLANE_FUNCTION); + buf[0] = SWAP32(make_cmd(false, true, fn, reg, 4)); + int ret = cyw43_spi_transfer(self, NULL, 4, (uint8_t *)buf, 8); + if (ret != 0) return (uint32_t)ret; + return SWAP32(buf[1]); +} + +int write_reg_u32_swap(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val) +{ + uint32_t buf[2]; + buf[0] = SWAP32(make_cmd(true, true, fn, reg, 4)); + buf[1] = SWAP32(val); + int ret = cyw43_spi_transfer(self, (uint8_t *)buf, 8, NULL, 0); + return ret; +} + +// --- Normal 32-bit mode register access ----------------------------------- +// Match Pico SDK _cyw43_read_reg / _cyw43_write_reg — these use a local +// buffer and always transfer 8 bytes (+ padding for backplane) instead of +// going through cyw43_read_bytes/cyw43_write_bytes. + +static inline uint32_t _cyw43_read_reg(cyw43_int_t *self, uint32_t fn, + uint32_t reg, uint32_t size) +{ + _Static_assert(CYW43_BACKPLANE_READ_PAD_LEN_BYTES % 4 == 0, ""); + // Padding for BACKPLANE reads, none for BUS/WLAN + const uint32_t padding = (fn == BACKPLANE_FUNCTION) + ? CYW43_BACKPLANE_READ_PAD_LEN_BYTES : 0; + // index = pad_words + cmd_word + data_word + const int index = (CYW43_BACKPLANE_READ_PAD_LEN_BYTES / 4) + 1 + 1; + uint32_t buf32[index]; + uint8_t *buf = (uint8_t *)buf32; + + buf32[0] = make_cmd(false, true, fn, reg, size); + int ret = cyw43_spi_transfer(self, NULL, 4, buf, 8 + padding); + if (ret != 0) return (uint32_t)ret; + + // Result is last word if padded, second word otherwise + return buf32[padding > 0 ? index - 1 : 1]; +} + +int cyw43_read_reg_u8(cyw43_int_t *self, uint32_t fn, uint32_t reg) +{ + // After bswap32, wire byte 0 (the u8 value) is at the LSB of the result. + // Mask to 8 bits to discard any garbage in upper bytes. + return (int)(_cyw43_read_reg(self, fn, reg, 1) & 0xFF); +} + +int cyw43_read_reg_u16(cyw43_int_t *self, uint32_t fn, uint32_t reg) +{ + // Match Pico SDK PIO: no extra byte swap. bswap32 in cyw43_spi_transfer + // maps the CYW43's LE wire bytes so the u16 value lands in the LOWER 16 + // bits of the returned uint32_t. Callers store in uint16_t for correct + // truncation. The UPPER 16 bits contain piggybacked SPI status + // (INTR_WITH_STATUS) and must be discarded. + return _cyw43_read_reg(self, fn, reg, 2); +} + +uint32_t cyw43_read_reg_u32(cyw43_int_t *self, uint32_t fn, uint32_t reg) +{ + return _cyw43_read_reg(self, fn, reg, 4); +} + +static inline int _cyw43_write_reg(cyw43_int_t *self, uint32_t fn, + uint32_t reg, uint32_t val, uint32_t size) +{ + uint32_t buf[2]; + buf[0] = make_cmd(true, true, fn, reg, size); + buf[1] = val; + return cyw43_spi_transfer(self, (uint8_t *)buf, 8, NULL, 0); +} + +int cyw43_write_reg_u8(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val) +{ + return _cyw43_write_reg(self, fn, reg, val, 1); +} + +int cyw43_write_reg_u16(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint16_t val) +{ + // Match Pico SDK PIO: no extra byte swap. val is zero-extended to u32 + // in buf[1]; bswap32 in cyw43_spi_transfer then produces the LE wire + // representation expected by the CYW43. + return _cyw43_write_reg(self, fn, reg, val, 2); +} + +int cyw43_write_reg_u32(cyw43_int_t *self, uint32_t fn, uint32_t reg, uint32_t val) +{ + return _cyw43_write_reg(self, fn, reg, val, 4); +} + +// --- Bulk byte read/write (firmware download, data packets) --------------- + +int cyw43_read_bytes(cyw43_int_t *self, uint32_t fn, uint32_t addr, + size_t len, uint8_t *dest) +{ + assert(fn != BACKPLANE_FUNCTION || (len <= CYW43_BUS_MAX_BLOCK_SIZE)); + const size_t aligned_len = (len + 3u) & ~3u; + assert(aligned_len > 0 && aligned_len <= 0x7f8); + assert(dest == self->spid_buf || dest < self->spid_buf || + dest >= (self->spid_buf + sizeof(self->spid_buf))); + const uint32_t padding = (fn == BACKPLANE_FUNCTION) + ? CYW43_BACKPLANE_READ_PAD_LEN_BYTES : 0; + + // Command goes at spi_header[0] (backplane) or spi_header[pad_words] (bus/wlan) + self->spi_header[padding > 0 ? 0 : (CYW43_BACKPLANE_READ_PAD_LEN_BYTES / 4)] = + make_cmd(false, true, fn, addr, len); + + uint8_t *spi_buf = (uint8_t *)&self->spi_header[padding > 0 ? 0 : + (CYW43_BACKPLANE_READ_PAD_LEN_BYTES / 4)]; + + int ret = cyw43_spi_transfer(self, NULL, 4, spi_buf, aligned_len + 4 + padding); + if (ret != 0) return ret; + + if (dest != self->spid_buf) { + memcpy(dest, self->spid_buf, len); + } + return 0; +} + +int cyw43_write_bytes(cyw43_int_t *self, uint32_t fn, uint32_t addr, + size_t len, const uint8_t *src) +{ + assert(fn != BACKPLANE_FUNCTION || (len <= CYW43_BUS_MAX_BLOCK_SIZE)); + const size_t aligned_len = (len + 3u) & ~3u; + assert(aligned_len > 0 && aligned_len <= 0x7f8); + size_t xfer_len = 4u + aligned_len; + + // For WLAN_FUNCTION writes, wait for F2 to be ready (matches SDK) + if (fn == WLAN_FUNCTION) { + int f2_ready_attempts = 1000; + while (f2_ready_attempts-- > 0) { + uint32_t bus_status = cyw43_read_reg_u32(self, BUS_FUNCTION, SPI_STATUS_REGISTER); + if (bus_status & STATUS_F2_RX_READY) break; + } + if (f2_ready_attempts <= 0) { + return CYW43_FAIL_FAST_CHECK(-CYW43_EIO); + } + } + + if (src == self->spid_buf) { + // Fast path: data already in spid_buf, just prepend command header + self->spi_header[(CYW43_BACKPLANE_READ_PAD_LEN_BYTES / 4)] = + make_cmd(true, true, fn, addr, len); + return cyw43_spi_transfer(self, + (uint8_t *)&self->spi_header[(CYW43_BACKPLANE_READ_PAD_LEN_BYTES / 4)], + xfer_len, NULL, 0); + } else { + assert(src < self->spid_buf || + src >= (self->spid_buf + sizeof(self->spid_buf))); + uint8_t *spi_buf = (uint8_t *)&self->spi_header[CYW43_BACKPLANE_READ_PAD_LEN_BYTES / 4]; + *(uint32_t *)spi_buf = make_cmd(true, true, fn, addr, len); + memcpy(self->spid_buf, src, len); + return cyw43_spi_transfer(self, spi_buf, xfer_len, NULL, 0); + } +} + +#endif // CYW43_USE_SPI diff --git a/targets/ChibiOS/_WiFi/cyw43/cyw43_configport.h b/targets/ChibiOS/_WiFi/cyw43/cyw43_configport.h new file mode 100644 index 0000000000..be55930064 --- /dev/null +++ b/targets/ChibiOS/_WiFi/cyw43/cyw43_configport.h @@ -0,0 +1,301 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// CYW43 driver configuration port for ChibiOS/RT on RP2040 (Pico W). +// This header maps the cyw43-driver HAL requirements to ChibiOS primitives. + +#ifndef CYW43_CONFIGPORT_H +#define CYW43_CONFIGPORT_H + +#include +#include +#include +#include + +// Ensure static_assert is available in C mode +#if !defined(__cplusplus) && !defined(static_assert) +#define static_assert _Static_assert +#endif + +// --------------------------------------------------------------------------- +// Logging — redirect CYW43 driver printf/warn to our debug_printf +// --------------------------------------------------------------------------- +extern void debug_printf(const char *format, ...); +#define CYW43_PRINTF(...) debug_printf(__VA_ARGS__) + +// --------------------------------------------------------------------------- +// Feature configuration +// --------------------------------------------------------------------------- +#define CYW43_LWIP 1 +#define CYW43_SPI_PIO 1 +#define CYW43_USE_SPI 1 +#define CYW43_LOGIC_DEBUG 0 +#define CYW43_USE_STATS 0 +#define CYW43_ENABLE_BLUETOOTH 0 +#define CYW43_USE_OTP_MAC 1 + +#ifndef CYW43_HOST_NAME +#define CYW43_HOST_NAME "PicoW" +#endif + +// WiFi interface indices are defined as enums in cyw43_ll.h (CYW43_ITF_STA, CYW43_ITF_AP) + +// Firmware inclusion — the combined firmware blob for CYW43439 +// Note: path is relative, resolved via cyw43_driver_SOURCE_DIR in include paths +#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "firmware/w43439A0_7_95_49_00_combined.h" +#define CYW43_WIFI_NVRAM_INCLUDE_FILE "firmware/wifi_nvram_43439.h" + +// --------------------------------------------------------------------------- +// Pico W GPIO assignments for CYW43 +// --------------------------------------------------------------------------- +#define CYW43_PIN_WL_REG_ON 23U +#define CYW43_PIN_WL_DATA_OUT 24U +#define CYW43_PIN_WL_CS 25U +#define CYW43_PIN_WL_CLK 29U +// GP24 is also used for interrupt signaling — same physical pin as DATA. +// Define BOTH HOST_WAKE and IRQ to match the Pico SDK: +// - HOST_WAKE → sets INTERRUPT_POLARITY_HIGH in SPI_BUS_CONTROL so the +// chip drives GP24 HIGH when it has events (between SPI transfers) +// - HOST_WAKE also sets host_interrupt_pin_active=1 so the driver's +// interrupt-pin gate in cyw43_ll_sdpcm_poll_device checks for HIGH +// Between transfers DATA is input with no pull — chip can drive it. +#define CYW43_PIN_WL_HOST_WAKE 24U +#define CYW43_PIN_WL_IRQ 24U + +// What CYW43 GPIO controls the LED on Pico W +#define CYW43_WL_GPIO_LED_PIN 0 +#define CYW43_WL_GPIO_COUNT 3 + +// --------------------------------------------------------------------------- +// PIN macros — direct RP2040 register access +// We bypass ChibiOS PAL to preserve pad electrical config (drive strength, +// pulls, Schmitt) that cyw43_spi_init sets up. Only change direction (OE) +// and output level via SIO registers; never touch FUNCSEL or PADS. +// --------------------------------------------------------------------------- +#define SIO_BASE_ADDR 0xD0000000 +#define SIO_GPIO_OUT_SET (*(volatile uint32_t *)(SIO_BASE_ADDR + 0x014)) +#define SIO_GPIO_OUT_CLR (*(volatile uint32_t *)(SIO_BASE_ADDR + 0x018)) +#define SIO_GPIO_OE_SET (*(volatile uint32_t *)(SIO_BASE_ADDR + 0x024)) +#define SIO_GPIO_OE_CLR (*(volatile uint32_t *)(SIO_BASE_ADDR + 0x028)) +#define SIO_GPIO_IN_REG (*(volatile uint32_t *)(SIO_BASE_ADDR + 0x004)) + +#define CYW43_HAL_PIN_MODE_INPUT 0 +#define CYW43_HAL_PIN_MODE_OUTPUT 1 +#define CYW43_HAL_PIN_PULL_NONE 0 +#define CYW43_HAL_PIN_PULL_UP 1 +#define CYW43_HAL_PIN_PULL_DOWN 2 + +static inline void cyw43_hal_pin_config(uint32_t pin, uint32_t mode, uint32_t pull, uint32_t value) +{ + (void)pull; + // Only change direction and output level. FUNCSEL and pad config + // are set once by cyw43_spi_init / cyw43_spi_gpio_setup and must + // not be overwritten. + if (mode == CYW43_HAL_PIN_MODE_OUTPUT) + { + if (value) + SIO_GPIO_OUT_SET = 1U << pin; + else + SIO_GPIO_OUT_CLR = 1U << pin; + SIO_GPIO_OE_SET = 1U << pin; + } + else + { + SIO_GPIO_OE_CLR = 1U << pin; + } +} + +static inline int cyw43_hal_pin_read(uint32_t pin) +{ + // For the HOST_WAKE / IRQ pin (GP24), always return "active" (1). + // This forces cyw43_ll_sdpcm_poll_device to skip its fast-path + // (which checks GP24 and returns early when it reads 0) and instead + // read the SPI status register — the definitive source of truth for + // pending F2 data. + // + // On Pico W, GP24 is shared between SPI DATA and the interrupt line. + // Between SPI transactions the PIO leaves the pad configured as an + // input, but GPIO_IN consistently reads 0 during the poll loop even + // when the CYW43 has pending events (the SPI trace confirms GP24 goes + // HIGH inside SPI transactions that assert CS). The exact cause is + // still under investigation; forcing the full path costs one extra + // SPI status read per poll cycle (~2 µs at 31 MHz) which is negligible + // on a 10 ms poll interval. + if (pin == CYW43_PIN_WL_HOST_WAKE) + return 1; + return (SIO_GPIO_IN_REG >> pin) & 1; +} + +static inline void cyw43_hal_pin_low(uint32_t pin) +{ + SIO_GPIO_OUT_CLR = 1U << pin; +} + +static inline void cyw43_hal_pin_high(uint32_t pin) +{ + SIO_GPIO_OUT_SET = 1U << pin; +} + +static inline void cyw43_hal_pin_config_irq_falling(uint32_t pin, int enable) +{ + (void)pin; + (void)enable; + // IRQ on falling edge not used in polled mode +} + +// --------------------------------------------------------------------------- +// Timing +// --------------------------------------------------------------------------- +static inline uint32_t cyw43_hal_ticks_us(void) +{ + // Convert ChibiOS system ticks to microseconds + return (uint32_t)TIME_I2US(chVTGetSystemTimeX()); +} + +static inline uint32_t cyw43_hal_ticks_ms(void) +{ + return (uint32_t)TIME_I2MS(chVTGetSystemTimeX()); +} + +static inline void cyw43_delay_ms(uint32_t ms) +{ + chThdSleepMilliseconds(ms); +} + +static inline void cyw43_delay_us(uint32_t us) +{ + // ChibiOS doesn't have sub-millisecond sleep on all platforms, + // but the RP2040 port supports microsecond precision via osalThreadSleepMicroseconds + if (us >= 1000) + { + chThdSleepMilliseconds(us / 1000); + } + else if (us > 0) + { + // Busy-wait for short delays (< 1ms) + systime_t start = chVTGetSystemTimeX(); + systime_t target = TIME_US2I(us); + while (chTimeDiffX(start, chVTGetSystemTimeX()) < target) + { + // spin + } + } +} + +// --------------------------------------------------------------------------- +// Thread safety — recursive lock (CYW43 driver nests THREAD_ENTER/EXIT) +// --------------------------------------------------------------------------- +extern void cyw43_thread_enter(void); +extern void cyw43_thread_exit(void); + +#define CYW43_THREAD_ENTER cyw43_thread_enter() +#define CYW43_THREAD_EXIT cyw43_thread_exit() +#define CYW43_THREAD_LOCK_CHECK + +// --------------------------------------------------------------------------- +// SDPCM wait / IOCTL wait — release lock, wait on semaphore, re-lock +// (matches Pico SDK cyw43_arch_wait_for_work_until pattern) +// --------------------------------------------------------------------------- +extern void cyw43_sdpcm_wait(void); +extern void cyw43_ioctl_wait(void); + +#define CYW43_SDPCM_SEND_COMMON_WAIT cyw43_sdpcm_wait() +#define CYW43_SDPCM_SEND_COMMON_WAIT_CHECK /* nothing */ +#define CYW43_DO_IOCTL_WAIT cyw43_ioctl_wait() +#define CYW43_DO_IOCTL_WAIT_CHECK /* nothing */ + +// --------------------------------------------------------------------------- +// Memory allocation +// --------------------------------------------------------------------------- +#define CYW43_MALLOC(size) chHeapAlloc(NULL, size) +#define CYW43_FREE(ptr) chHeapFree(ptr) + +// Fallback to standard if heap allocator not available +#ifndef CYW43_MALLOC +#define CYW43_MALLOC(size) malloc(size) +#define CYW43_FREE(ptr) free(ptr) +#endif + +// --------------------------------------------------------------------------- +// Error codes expected by cyw43_ll.c +// --------------------------------------------------------------------------- +#define CYW43_EPERM 1 +#define CYW43_EIO 5 +#define CYW43_EINVAL 22 +#define CYW43_ETIMEDOUT 110 + +// --------------------------------------------------------------------------- +// MIN macro if not provided +// --------------------------------------------------------------------------- +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +// --------------------------------------------------------------------------- +// Internal poll scheduling +// --------------------------------------------------------------------------- +// Called when the CYW43 driver wants its poll function called soon. +// We signal the WiFi lwIP thread to handle it. +extern void cyw43_schedule_internal_poll_dispatch(void (*func)(void)); +extern void cyw43_post_poll_hook(void); + +// --------------------------------------------------------------------------- +// MAC address — read from cyw43_state after firmware init (OTP MAC) +// --------------------------------------------------------------------------- +#define CYW43_HAL_MAC_WLAN0 0 + +// Implemented in cyw43_arch_chibios.c — must read from cyw43_state.mac +// (which requires cyw43_t to be fully defined, not possible in this header). +void cyw43_hal_get_mac(int itf, uint8_t mac[6]); + +// Generate a locally-administered MAC address as fallback when OTP is unset +static inline void cyw43_hal_generate_laa_mac(int itf, uint8_t mac[6]) +{ + (void)itf; + // Locally administered, unicast MAC address + mac[0] = 0x02; + mac[1] = 0xCF; + mac[2] = 0x43; + mac[3] = 0x39; + mac[4] = 0x00; + mac[5] = 0x01; +} + +// --------------------------------------------------------------------------- +// lwIP integration callbacks — declared in cyw43.h with proper types +// Do NOT redeclare here; the driver headers provide the correct signatures. +// --------------------------------------------------------------------------- +void cyw43_cb_process_ethernet(void *self, int itf, size_t len, const uint8_t *buf); + +// --------------------------------------------------------------------------- +// Misc +// --------------------------------------------------------------------------- + +// Byte swap helper +#ifndef __builtin_bswap32 +static inline uint32_t __builtin_bswap32_impl(uint32_t x) +{ + return ((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | ((x & 0x00FF0000) >> 8) | + ((x & 0xFF000000) >> 24); +} +#define __builtin_bswap32 __builtin_bswap32_impl +#endif + +// After each poll cycle, signal semaphores so waiting threads can proceed +#define CYW43_POST_POLL_HOOK cyw43_post_poll_hook(); + +// Assert +#define CYW43_ASSERT(expr) osalDbgAssert(expr, "cyw43 assert") + +// Printf for debug — route through debug_printf for CYW43_WARN visibility +extern void debug_printf(const char *format, ...); +#define CYW43_PRINTF(...) debug_printf(__VA_ARGS__) + +// Array size helper +#ifndef CYW43_ARRAY_SIZE +#define CYW43_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#endif // CYW43_CONFIGPORT_H diff --git a/targets/ChibiOS/_WiFi/nf_lwipthread_wifi.c b/targets/ChibiOS/_WiFi/nf_lwipthread_wifi.c new file mode 100644 index 0000000000..90b49e7343 --- /dev/null +++ b/targets/ChibiOS/_WiFi/nf_lwipthread_wifi.c @@ -0,0 +1,893 @@ +// +// Copyright (c) .NET Foundation and Contributors +// Portions Copyright (c) 2001-2004 Swedish Institute of Computer Science. All rights reserved. +// Portions Copyright (c) 2006..2015 Giovanni Di Sirio. All rights reserved. +// See LICENSE file in the project root for full license information. +// + +// WiFi-aware lwIP thread for ChibiOS + CYW43. +// This replaces nf_lwipthread.c, using the CYW43 WiFi chip instead of +// ChibiOS ETHD1 (Ethernet MAC). The lwIP stack is reused as-is. + +#include "hal.h" +#include "evtimer.h" +#include "nf_lwipthread_wifi.h" +#include "cyw43_configport.h" +#include "cyw43.h" +#include "cyw43_ll.h" +#include "cyw43_internal.h" +#include + +// CLR event system — fire SYSTEM_EVENT_FLAG_WIFI_STATION on link change +extern void Events_Set(uint32_t events); +#define SYSTEM_EVENT_FLAG_WIFI_STATION 0x01000000 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Default SNTP server addresses (matches lwip_sntp_default_options.h) +#ifndef SNTP_SERVER0_DEFAULT_ADDRESS +#define SNTP_SERVER0_DEFAULT_ADDRESS "0.pool.ntp.org" +#endif +#ifndef SNTP_SERVER1_DEFAULT_ADDRESS +#define SNTP_SERVER1_DEFAULT_ADDRESS "1.pool.ntp.org" +#endif + +#if LWIP_DHCP +#include +#endif + +#if LWIP_AUTOIP +#include +#endif + +#define PERIODIC_TIMER_ID 1 +#define CYW43_POLL_ID 2 + +// Forward declarations for CYW43 driver functions (from cyw43_ll / cyw43_lwip) +extern void cyw43_arch_init(void); +extern void cyw43_arch_deinit(void); +extern int cyw43_is_wifi_connected(void); + +// Suspension point for initialization +thread_reference_t lwip_trp = NULL; + +// Stack area for the WiFi lwIP thread +static THD_WORKING_AREA(wa_lwip_thread, LWIP_THREAD_STACK_SIZE + 512); + +// Single global netif for WiFi +static struct netif thisif = {0}; +static net_addr_mode_t addressMode; +static ip4_addr_t ip, gateway, netmask; + +// --------------------------------------------------------------------------- +// Scan results storage +// --------------------------------------------------------------------------- +#define MAX_SCAN_RESULTS 32 + +static wifi_scan_record_t scan_results[MAX_SCAN_RESULTS]; +static volatile int scan_result_count = 0; +static volatile int scan_complete = 0; + +// Callback invoked by cyw43_wifi_scan for each AP found +static int wifi_scan_result_cb(void *env, const cyw43_ev_scan_result_t *result) +{ + (void)env; + + if (result == NULL) + { + return 0; + } + // Deduplicate: if an AP with the same SSID and BSSID already exists, + // update it only if the new result has a stronger (less negative) RSSI. + uint8_t ssid_len = result->ssid_len < 32 ? result->ssid_len : 32; + for (int i = 0; i < scan_result_count; i++) + { + if (memcmp(scan_results[i].bssid, result->bssid, 6) == 0 && + memcmp(scan_results[i].ssid, result->ssid, ssid_len) == 0 && + scan_results[i].ssid[ssid_len] == 0) + { + // Duplicate found — keep the stronger signal + if (result->rssi > scan_results[i].rssi) + { + scan_results[i].rssi = result->rssi; + scan_results[i].auth_mode = result->auth_mode; + scan_results[i].channel = result->channel; + } + return 0; + } + } + + if (scan_result_count >= MAX_SCAN_RESULTS) + { + return 0; // buffer full, ignore + } + + wifi_scan_record_t *rec = &scan_results[scan_result_count]; + memcpy(rec->bssid, result->bssid, 6); + memset(rec->ssid, 0, sizeof(rec->ssid)); + + memcpy(rec->ssid, result->ssid, ssid_len); + rec->rssi = result->rssi; + rec->auth_mode = result->auth_mode; + rec->channel = result->channel; + scan_result_count++; + + return 0; +} + +struct netif *nf_getNetif(void) +{ + return &thisif; +} + +// --------------------------------------------------------------------------- +// WiFi netif low-level functions +// --------------------------------------------------------------------------- + +// Called to initialize the WiFi network interface +// Matches SDK cyw43_netif_init — sets flags, MAC, MTU. +static void wifi_low_level_init(struct netif *netif) +{ + // Set MAC hardware address from the CYW43 chip (read during firmware init). + // Must be done here (inside netif_add callback) because netif_add may + // zero the struct before calling the init function. + cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, netif->hwaddr); + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + // Maximum transfer unit for WiFi + netif->mtu = 1500; + + // Flags match the SDK exactly: BROADCAST | ETHARP | ETHERNET | IGMP + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP; +} + +static err_t wifi_low_level_output(struct netif *netif, struct pbuf *p) +{ + (void)netif; + + // Linearize the pbuf chain into a contiguous buffer for CYW43 + uint8_t buf[1536]; // Max Ethernet frame + uint16_t offset = 0; + struct pbuf *q; + + for (q = p; q != NULL; q = q->next) + { + if (offset + q->len > sizeof(buf)) + { + return ERR_BUF; + } + memcpy(buf + offset, q->payload, q->len); + offset += q->len; + } + + // Send the Ethernet frame to CYW43 for transmission + // CYW43 driver will handle 802.11 encapsulation + CYW43_THREAD_ENTER; + + // Use the CYW43 bus to send the frame + cyw43_t *state = &cyw43_state; + int ret = cyw43_send_ethernet(state, CYW43_ITF_STA, offset, buf, false); + CYW43_THREAD_EXIT; + if (ret != 0) + { + return ERR_IF; + } + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +// Called by the CYW43 driver when an Ethernet frame is received from WiFi. +// This is a callback invoked from cyw43_cb_process_ethernet(). +void cyw43_cb_process_ethernet(void *self, int itf, size_t len, const uint8_t *buf) +{ + (void)self; + (void)itf; + + if (len == 0 || buf == NULL) + return; + + // Allocate a pbuf and copy the frame data + struct pbuf *p = pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL); + if (p == NULL) + { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + return; + } + + // Copy frame data into pbuf chain + struct pbuf *q; + uint16_t offset = 0; + for (q = p; q != NULL; q = q->next) + { + uint16_t copy_len = q->len; + if (offset + copy_len > len) + { + copy_len = (uint16_t)(len - offset); + } + memcpy(q->payload, buf + offset, copy_len); + offset += copy_len; + } + + MIB2_STATS_NETIF_ADD(&thisif, ifinoctets, p->tot_len); + LINK_STATS_INC(link.recv); + + // Pass to tcpip_input for processing in the tcpip thread + if (thisif.input(p, &thisif) != ERR_OK) + { + pbuf_free(p); + } +} + +// --------------------------------------------------------------------------- +// Network interface init (passed to netifapi_netif_add) +// --------------------------------------------------------------------------- + +static err_t wifiif_init(struct netif *netif) +{ + osalDbgAssert((netif != NULL), "netif != NULL"); + + MIB2_INIT_NETIF(netif, snmp_ifType_ieee80211, 54000000); // 54 Mbps WiFi + + netif->state = NULL; + netif->name[0] = 'w'; + netif->name[1] = 'l'; + netif->output = etharp_output; + netif->linkoutput = wifi_low_level_output; + + wifi_low_level_init(netif); + + return ERR_OK; +} + +// --------------------------------------------------------------------------- +// lwIP callbacks for CYW43 +// --------------------------------------------------------------------------- + +// Netif status callback — fires when IP address changes (e.g., DHCP completes). +// Signal the CLR so NativeConnect's WaitEvents loop wakes up, and start SNTP. +static void wifi_netif_status_cb(struct netif *nif) +{ + Events_Set(SYSTEM_EVENT_FLAG_WIFI_STATION); + +#if SNTP_SERVER_DNS + // Start SNTP once we have an IP address + if (nif->ip_addr.addr != 0) + { + sntp_stop(); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, SNTP_SERVER0_DEFAULT_ADDRESS); + sntp_setservername(1, SNTP_SERVER1_DEFAULT_ADDRESS); + sntp_init(); + } +#endif +} + +// Callback scheduled on tcpip thread from cyw43_cb_tcpip_init. +// At this point the CYW43 firmware is loaded and cyw43_state.mac is valid. +static void wifi_tcpip_init_done(void *arg) +{ + struct netif *ifc = (struct netif *)arg; + + // Copy the real OTP MAC from the CYW43 chip to the netif + cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifc->hwaddr); + + // Update the in-memory network config block so managed code reads + // the real hardware MAC (the stored default is all zeros). + if (g_TargetConfiguration.NetworkInterfaceConfigs != NULL && + g_TargetConfiguration.NetworkInterfaceConfigs->Count > 0) + { + memcpy( + g_TargetConfiguration.NetworkInterfaceConfigs->Configs[0]->MacAddress, + ifc->hwaddr, + NETIF_MAX_HWADDR_LEN); + } + +#if SNTP_SERVER_DNS + // Pre-configure SNTP server names early, before the CLR's + // LWIP_SOCKETS_Driver replaces our netif status callback. + // Server names persist across sntp_stop()/sntp_init() cycles, + // so when the CLR callback later calls sntp_init(), it will + // use these servers. + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, SNTP_SERVER0_DEFAULT_ADDRESS); + sntp_setservername(1, SNTP_SERVER1_DEFAULT_ADDRESS); +#endif + +#if LWIP_DHCP + // Start DHCP — matches SDK flow (dhcp_start in cyw43_cb_tcpip_init). + // DHCP DISCOVER will be sent immediately, but won't reach the AP until + // the WPA handshake completes. When netif_set_link_up fires, + // dhcp_network_changed() restarts DHCP discovery automatically. + dhcp_start(ifc); +#endif +} + +void cyw43_cb_tcpip_init(cyw43_t *self, int itf) +{ + (void)self; + (void)itf; + // CYW43 firmware is loaded — schedule MAC copy + DHCP start on tcpip thread. + // Can't call lwIP APIs directly here (CYW43 mutex is held). + tcpip_callback_with_block(wifi_tcpip_init_done, &thisif, 0); +} + +void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) +{ + (void)self; + (void)itf; +} + +// Forward declaration — defined below +void lwipDefaultLinkUpCB(void *p); + +// Callback queued to tcpip thread for non-blocking link-up. +// Matches SDK: cyw43_cb_tcpip_set_link_up just calls netif_set_link_up. +// lwIP internally fires dhcp_network_changed() which restarts DHCP +// discovery if it is already running. +// Only called from cyw43_cb_tcpip_set_link_up (after WIFI_JOIN_STATE_ALL). +static void wifi_link_up_and_dhcp(void *arg) +{ + struct netif *ifc = (struct netif *)arg; + + // Refresh the chip's real MAC on the netif (should already be set from + // wifiif_init, but re-copy in case of reconnect after MAC change). + cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifc->hwaddr); + + // Set link up flag — lwIP fires dhcp_network_changed() automatically + // which restarts DHCP discovery. This matches the Pico SDK exactly. + netif_set_link_up(ifc); +} + +void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) +{ + (void)self; + (void)itf; + + // Queue link-up to the tcpip thread (NON-BLOCKING). + // Matches SDK: link-up fires when WIFI_JOIN_STATE_ALL + // (auth + link + keyed) is reached. DHCP restart is handled + // by lwIP internally via dhcp_network_changed(). + tcpip_callback_with_block(wifi_link_up_and_dhcp, &thisif, 0); + + // Signal the CLR that WiFi station state changed (link up / connect complete) + Events_Set(SYSTEM_EVENT_FLAG_WIFI_STATION); +} + +// Callback queued to tcpip thread for non-blocking link-down + DHCP stop +static void wifi_link_down_and_dhcp_stop(void *arg) +{ + struct netif *ifc = (struct netif *)arg; + + netif_set_link_down(ifc); + +#if LWIP_DHCP + // Stop DHCP, then immediately re-start so that dhcp_network_changed() + // (fired by the next netif_set_link_up) has an active DHCP session + // to restart discovery on. This matches the Pico SDK where DHCP is + // started once during init and left running forever. + dhcp_release_and_stop(ifc); + dhcp_start(ifc); +#endif +} + +void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) +{ + (void)self; + (void)itf; + + // Non-blocking — same reasoning as cyw43_cb_tcpip_set_link_up + tcpip_callback_with_block(wifi_link_down_and_dhcp_stop, &thisif, 0); + + // Signal the CLR that WiFi station state changed (link down / disconnect) + Events_Set(SYSTEM_EVENT_FLAG_WIFI_STATION); +} + +// --------------------------------------------------------------------------- +// Link up/down callbacks (same as nf_lwipthread.c) +// --------------------------------------------------------------------------- + +void lwipDefaultLinkUpCB(void *p) +{ + struct netif *ifc = (struct netif *)p; + +#if LWIP_AUTOIP + if (addressMode == NET_ADDRESS_AUTO) + { + autoip_start(ifc); + } +#endif + +#if LWIP_DHCP + if (addressMode == NET_ADDRESS_DHCP) + { + dhcp_start(ifc); + } +#endif + +#if SNTP_SERVER_DNS + if (addressMode != NET_ADDRESS_DHCP) + { + sntp_init(); + } +#endif +} + +void lwipDefaultLinkDownCB(void *p) +{ + struct netif *ifc = (struct netif *)p; + +#if LWIP_AUTOIP + if (addressMode == NET_ADDRESS_AUTO) + { + autoip_stop(ifc); + } +#endif + +#if LWIP_DHCP + if (addressMode == NET_ADDRESS_DHCP) + { + dhcp_release_and_stop(ifc); + } +#endif + +#if SNTP_SERVER_DNS + sntp_stop(); +#endif +} + +// --------------------------------------------------------------------------- +// WiFi lwIP thread +// --------------------------------------------------------------------------- + +static THD_FUNCTION(lwip_thread, p) +{ + event_timer_t evt; + event_listener_t el0; + err_t result; + tcpip_callback_fn link_up_cb = NULL; + tcpip_callback_fn link_down_cb = NULL; + bool prev_link_status = false; + + chRegSetThreadName("lwip_wifi"); + + // TCP/IP parameters from configuration + if (p) + { + lwipthread_opts_t *opts = p; + unsigned i; + + for (i = 0; i < 6; i++) + { + thisif.hwaddr[i] = opts->macaddress[i]; + } + + ip.addr = opts->address; + gateway.addr = opts->gateway; + netmask.addr = opts->netmask; + addressMode = opts->addrMode; + +#if LWIP_NETIF_HOSTNAME + thisif.hostname = opts->ourHostName; +#endif + + link_up_cb = opts->link_up_cb; + link_down_cb = opts->link_down_cb; + } + else + { + thisif.hwaddr[0] = LWIP_ETHADDR_0; + thisif.hwaddr[1] = LWIP_ETHADDR_1; + thisif.hwaddr[2] = LWIP_ETHADDR_2; + thisif.hwaddr[3] = LWIP_ETHADDR_3; + thisif.hwaddr[4] = LWIP_ETHADDR_4; + thisif.hwaddr[5] = LWIP_ETHADDR_5; + + LWIP_IPADDR(&ip); + LWIP_GATEWAY(&gateway); + LWIP_NETMASK(&netmask); + } + +#if LWIP_NETIF_HOSTNAME + if (thisif.hostname == NULL) + { + thisif.hostname = LWIP_NETIF_HOSTNAME_STRING; + } +#endif + + if (!link_up_cb) + { + link_up_cb = lwipDefaultLinkUpCB; + } + + if (!link_down_cb) + { + link_down_cb = lwipDefaultLinkDownCB; + } + + // Initialize CYW43 architecture layer (powers on the chip, loads firmware) + cyw43_arch_init(); + + // Add the WiFi network interface + result = netifapi_netif_add(&thisif, &ip, &netmask, &gateway, NULL, wifiif_init, tcpip_input); + if (result != ERR_OK) + { + chThdSleepMilliseconds(1000); + osalSysHalt("wifiif_add error"); + } + + netifapi_netif_set_default(&thisif); + netifapi_netif_set_up(&thisif); + + // NOTE: DHCP is NOT started here — the netif MAC is still a placeholder + // because the CYW43 firmware hasn't been loaded yet (lazy init). + // DHCP is started later from cyw43_cb_tcpip_init, which fires during + // cyw43_wifi_set_up (first ensure_wifi_up call), when the real OTP MAC + // is available. This matches the Pico SDK flow. + + // Register status callback so that DHCP IP assignment fires Event_Wifi_Station, + // waking NativeConnect's WaitEvents loop. + netif_set_status_callback(&thisif, wifi_netif_status_cb); + + // Set up periodic timer for link status polling + evtObjectInit(&evt, LWIP_LINK_POLL_INTERVAL); + evtStart(&evt); + chEvtRegisterMask(&evt.et_es, &el0, PERIODIC_TIMER_ID); + chEvtAddEvents(PERIODIC_TIMER_ID); + + // Resume the caller (lwIPInit is waiting) + chThdResume(&lwip_trp, MSG_OK); + chThdSetPriority(LWIP_THREAD_PRIORITY); + + // Setup SNTP — only after WiFi is connected and DHCP has IP. + // SNTP is started from wifi_netif_status_cb when IP becomes non-zero. + // Starting it here at boot causes ARP/DNS probes on a non-connected interface. + + // Main event loop + while (true) + { + eventmask_t mask = chEvtWaitAny(ALL_EVENTS); + + if (mask & PERIODIC_TIMER_ID) + { + // Check WiFi link status (CYW43 connection state). + // IMPORTANT: Only handle link-DOWN here. Link-UP is handled + // exclusively by the driver's cyw43_cb_tcpip_set_link_up callback, + // which fires when WIFI_JOIN_STATE_ALL (auth+link+keyed) is reached. + // The Pico SDK does NOT have a periodic link-up check. Starting + // DHCP before the WPA 4-way handshake completes sends unencrypted + // frames that the AP drops, poisoning the DHCP server state. + bool current_link_status = (cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) == CYW43_LINK_JOIN); + + if (prev_link_status && !current_link_status) + { + prev_link_status = false; + tcpip_callback_with_block(wifi_link_down_and_dhcp_stop, &thisif, 0); + } + else if (current_link_status) + { + prev_link_status = true; + } + } + } +} + +// --------------------------------------------------------------------------- +// tcpip init completion callback +// --------------------------------------------------------------------------- + +static void tcpIpInitDone(void *arg) +{ + semaphore_t *initDone = arg; + chSemSignal(initDone); +} + +// --------------------------------------------------------------------------- +// lwIPInit — same API as nf_lwipthread.c +// --------------------------------------------------------------------------- + +void lwIPInit(const lwipthread_opts_t *opts) +{ + // Create the WiFi lwIP thread + chThdCreateStatic(wa_lwip_thread, sizeof(wa_lwip_thread), chThdGetPriorityX() - 1, lwip_thread, (void *)opts); + + // Create semaphore for TCP/IP init completion + semaphore_t initDone; + chSemObjectInit(&initDone, 0); + + // Initialize TCP/IP stack + tcpip_init(tcpIpInitDone, &initDone); + + // Wait for lwIP thread initialization + chSysLock(); + chThdSuspendS(&lwip_trp); + chSysUnlock(); + + // Wait for TCP/IP stack init + chSemWait(&initDone); +} + +// --------------------------------------------------------------------------- +// lwipReconfigure — same API as nf_lwipthread.c +// --------------------------------------------------------------------------- + +typedef struct lwip_reconf_params +{ + const lwipreconf_opts_t *opts; + semaphore_t completion; +} lwip_reconf_params_t; + +static void do_reconfigure(void *p) +{ + lwip_reconf_params_t *reconf = (lwip_reconf_params_t *)p; + + switch (addressMode) + { +#if LWIP_DHCP + case NET_ADDRESS_DHCP: + if (netif_is_up(&thisif)) + { + dhcp_release_and_stop(&thisif); + } + break; +#endif + case NET_ADDRESS_STATIC: + { + ip4_addr_t zero = {0}; + netif_set_ipaddr(&thisif, &zero); + netif_set_netmask(&thisif, &zero); + netif_set_gw(&thisif, &zero); + break; + } +#if LWIP_AUTOIP + case NET_ADDRESS_AUTO: + if (netif_is_up(&thisif)) + autoip_stop(&thisif); + break; +#endif + } + + ip.addr = reconf->opts->address; + gateway.addr = reconf->opts->gateway; + netmask.addr = reconf->opts->netmask; + addressMode = reconf->opts->addrMode; + + switch (addressMode) + { +#if LWIP_DHCP + case NET_ADDRESS_DHCP: + dhcp_start(&thisif); + break; +#endif + case NET_ADDRESS_STATIC: + netif_set_ipaddr(&thisif, &ip); + netif_set_netmask(&thisif, &netmask); + netif_set_gw(&thisif, &gateway); + break; +#if LWIP_AUTOIP + case NET_ADDRESS_AUTO: + if (netif_is_up(&thisif)) + autoip_start(&thisif); + break; +#endif + } + + chSemSignal(&reconf->completion); +} + +void lwipReconfigure(const lwipreconf_opts_t *opts) +{ + lwip_reconf_params_t params; + params.opts = opts; + chSemObjectInit(¶ms.completion, 0); + tcpip_callback_with_block(do_reconfigure, ¶ms, 0); + chSemWait(¶ms.completion); +} + +// --------------------------------------------------------------------------- +// WiFi-specific helper functions +// --------------------------------------------------------------------------- + +static volatile bool wifi_powered = false; + +void cyw43_wifi_power_on(void) +{ + if (!wifi_powered) + { + // CYW43 is initialized in the lwip_thread via cyw43_arch_init() + wifi_powered = true; + } +} + +void cyw43_wifi_power_off(void) +{ + if (wifi_powered) + { + cyw43_arch_deinit(); + wifi_powered = false; + } +} + +// WiFi connect — called from Target_Network.cpp +int cyw43_wifi_connect(const char *ssid, const char *password, uint32_t auth_type) +{ + (void)auth_type; + + if (ssid == NULL) + return -1; + + // Ensure WiFi hardware is initialized + if (cyw43_ensure_wifi_up_impl() != 0) + { + return -1; + } + + cyw43_t *state = &cyw43_state; + + size_t ssid_len = strlen(ssid); + size_t key_len = password ? strlen(password) : 0; + + // WPA2_AES_PSK = 0x00400004 + uint32_t auth = key_len > 0 ? 0x00400004 : 0; // Open or WPA2 + + // Clean disconnect first — ensures AP doesn't see stale association state + // and prevents BADAUTH on rapid re-join. EV_DISASSOC will fire link_down + // callback to stop any running DHCP. + CYW43_THREAD_ENTER; + cyw43_wifi_leave(state, CYW43_ITF_STA); + CYW43_THREAD_EXIT; + chThdSleepMilliseconds(100); + + // Disable power management during connect — PM2 may cause the radio + // to sleep and miss the DHCP OFFER response from the AP. + cyw43_wifi_pm(state, CYW43_NONE_PM); + + CYW43_THREAD_ENTER; + int result = cyw43_wifi_join(state, ssid_len, (const uint8_t *)ssid, key_len, (const uint8_t *)password, auth, NULL, + 0); + CYW43_THREAD_EXIT; + + // After successful join, issue an ioctl to kick inline packet processing. + // The ioctl's inline polling may process pending DATA_HEADER packets + // (e.g., DHCP OFFER) that arrived during the join process. + if (result == 0) + { + CYW43_THREAD_ENTER; + uint8_t rssi_buf[4] = {0}; + cyw43_ll_ioctl(&state->cyw43_ll, 127 << 1, 4, rssi_buf, 0); + CYW43_THREAD_EXIT; + } + + return result; +} + +int cyw43_wifi_disconnect(void) +{ + cyw43_t *state = &cyw43_state; + + CYW43_THREAD_ENTER; + int result = cyw43_wifi_leave(state, CYW43_ITF_STA); + CYW43_THREAD_EXIT; + + return result; +} + +// --------------------------------------------------------------------------- +// WiFi scan +// --------------------------------------------------------------------------- + +int cyw43_wifi_scan_start(void) +{ + // Ensure WiFi hardware is initialized + if (cyw43_ensure_wifi_up_impl() != 0) + { + return -1; + } + + cyw43_t *state = &cyw43_state; + + // Reset scan results + scan_result_count = 0; + scan_complete = 0; + + cyw43_wifi_scan_options_t scan_opts = {0}; + CYW43_THREAD_ENTER; + int result = cyw43_wifi_scan(state, &scan_opts, NULL, wifi_scan_result_cb); + CYW43_THREAD_EXIT; + + if (result != 0) + { + return result; + } + + // Wait for scan to complete (wifi_scan_state goes from 1 to 2) + // Timeout after 10 seconds + int timeout_ms = 10000; + int elapsed = 0; + + while (elapsed < timeout_ms) + { + CYW43_THREAD_ENTER; + int scanning = cyw43_wifi_scan_active(state); + CYW43_THREAD_EXIT; + + if (!scanning) + { + scan_complete = 1; + break; + } + + chThdSleepMilliseconds(100); + elapsed += 100; + } + + scan_complete = 1; + return 0; +} + +int cyw43_wifi_scan_get_count(void) +{ + return scan_result_count; +} + +const wifi_scan_record_t *cyw43_wifi_scan_get_results(void) +{ + return scan_results; +} + +int cyw43_wifi_is_connected(void) +{ + return cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) == CYW43_LINK_JOIN; +} + +int cyw43_wifi_get_link_status(void) +{ + return cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA); +} + +int cyw43_wifi_get_join_state(void) +{ + return (int)cyw43_state.wifi_join_state; +} + +void cyw43_wifi_get_mac_addr(uint8_t *mac) +{ + // Copy from the netif (set during initialization) + memcpy(mac, thisif.hwaddr, 6); +} + +void cyw43_wifi_set_netif_mac(const uint8_t *mac) +{ + memcpy(thisif.hwaddr, mac, 6); +} + +uint32_t cyw43_wifi_get_ip4_address(void) +{ + return thisif.ip_addr.addr; +} + +// Direct poll from NativeConnect — calls cyw43_poll to drain SPI packets. +uint32_t cyw43_wifi_direct_poll(void) +{ + CYW43_THREAD_ENTER; + + if (cyw43_poll) + cyw43_poll(); + + CYW43_THREAD_EXIT; + + return 0; +} diff --git a/targets/ChibiOS/_WiFi/nf_lwipthread_wifi.h b/targets/ChibiOS/_WiFi/nf_lwipthread_wifi.h new file mode 100644 index 0000000000..4c6c0bbf6e --- /dev/null +++ b/targets/ChibiOS/_WiFi/nf_lwipthread_wifi.h @@ -0,0 +1,68 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// WiFi-aware lwIP thread header for ChibiOS + CYW43. +// Replaces nf_lwipthread.h when using WiFi instead of Ethernet MAC. + +#ifndef NF_LWIPTHREAD_WIFI_H +#define NF_LWIPTHREAD_WIFI_H + +#include + +// Re-export the standard lwIP thread types and API. +// The WiFi variant uses the same lwipthread_opts_t and API, +// but the underlying transport uses CYW43 instead of ETHD1 MAC. + +#ifdef __cplusplus +extern "C" +{ +#endif + + // WiFi-specific initialization — powers on CYW43 and configures the driver + void cyw43_wifi_power_on(void); + void cyw43_wifi_power_off(void); + + // Lazy hardware init — call before any WiFi operation + int cyw43_ensure_wifi_up_impl(void); + + // WiFi connection management — called from Target_Network.cpp + int cyw43_wifi_connect(const char *ssid, const char *password, uint32_t auth_type); + int cyw43_wifi_disconnect(void); + int cyw43_wifi_scan_start(void); + int cyw43_wifi_is_connected(void); + int cyw43_wifi_get_link_status(void); + int cyw43_wifi_get_join_state(void); + uint32_t cyw43_wifi_get_ip4_address(void); + + // Direct poll — call from NativeConnect wait loop to drain SPI packets + uint32_t cyw43_wifi_direct_poll(void); + + // Set the lwIP netif MAC address (call after CYW43 chip is initialized) + void cyw43_wifi_set_netif_mac(const uint8_t *mac); + + // Scan results + typedef struct + { + uint8_t bssid[6]; + uint8_t ssid[33]; + int16_t rssi; + uint8_t auth_mode; + uint16_t channel; + } wifi_scan_record_t; + + int cyw43_wifi_scan_get_count(void); + const wifi_scan_record_t *cyw43_wifi_scan_get_results(void); + + // Access CYW43 MAC address (read from OTP on chip) + void cyw43_wifi_get_mac_addr(uint8_t *mac); + + // Accessor for the WiFi netif + struct netif *nf_getNetif(void); + +#ifdef __cplusplus +} +#endif + +#endif // NF_LWIPTHREAD_WIFI_H diff --git a/targets/ChibiOS/_common/CMakeLists.txt b/targets/ChibiOS/_common/CMakeLists.txt index 846419b76f..a7ae859f40 100644 --- a/targets/ChibiOS/_common/CMakeLists.txt +++ b/targets/ChibiOS/_common/CMakeLists.txt @@ -9,9 +9,15 @@ list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/nanoSuppor list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/WireProtocol_ReceiverThread.c) list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/WireProtocol_HAL_Interface.c) list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/platform_heap.c) -list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Target_BlockStorage_STM32FlashDriver.c) -# append Target files +# vendor-specific block storage driver +if(TARGET_VENDOR STREQUAL "ST") + list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/Target_BlockStorage_STM32FlashDriver.c) +elseif(TARGET_VENDOR STREQUAL "RP") + # RP block storage driver will be added in Phase 2 +endif() + +# append Target files (block storage platform interface) list(APPEND TARGET_CHIBIOS_COMMON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/platform_BlockStorage.c) # include configuration manager file, if feature is enabled diff --git a/targets/ChibiOS/_common/LaunchCLR.c b/targets/ChibiOS/_common/LaunchCLR.c index f5b051726a..57cb98527b 100644 --- a/targets/ChibiOS/_common/LaunchCLR.c +++ b/targets/ChibiOS/_common/LaunchCLR.c @@ -30,6 +30,14 @@ void LaunchCLR(uint32_t address) // clear any pending interrupts to make sure we are jumping straight to nanoCLR ResetHandler SCB->ICSR &= SCB_ICSR_PENDSVCLR_Msk; + // set VTOR to point to nanoCLR vector table so interrupts use the correct handlers +#if (__CORTEX_M >= 3U) || (defined(__VTOR_PRESENT) && (__VTOR_PRESENT == 1U)) + SCB->VTOR = address; +#elif defined(RP2040) || defined(RP2350) + // RP2040/RP2350 have VTOR but CMSIS header doesn't define __VTOR_PRESENT + *((volatile uint32_t *)0xE000ED08U) = address; +#endif + // need to set stack pointer from CLR vector table __set_MSP((uint32_t)nanoCLRVectorTable->init_stack); diff --git a/targets/ChibiOS/_common/Target_Network.cpp b/targets/ChibiOS/_common/Target_Network.cpp index da3bbd253b..ff25392e70 100644 --- a/targets/ChibiOS/_common/Target_Network.cpp +++ b/targets/ChibiOS/_common/Target_Network.cpp @@ -6,8 +6,15 @@ #include #include +#include +#if defined(RP2040) || defined(RP2350) +extern "C" { +#include +} +#else extern "C" struct netif *nf_getNetif(); +#endif // // Works with the Target_NetworkConfig to map the Network_Interface_XXXXX calls to the correct driver @@ -59,8 +66,80 @@ bool Network_Interface_Close(int index) switch (index) { case 0: +#if defined(RP2040) || defined(RP2350) + cyw43_wifi_disconnect(); +#else macStop(ÐD1); +#endif return true; } return false; } + +#if defined(RP2040) || defined(RP2350) + +int Network_Interface_Disconnect(int index) +{ + (void)index; + return cyw43_wifi_disconnect(); +} + +int Network_Interface_Start_Connect(int index, const char *ssid, const char *passphrase, int options) +{ + (void)index; + (void)options; + + uint32_t auth_type = 0; + if (passphrase != NULL && passphrase[0] != '\0') + { + auth_type = 0x00400004; // WPA2_AES_PSK + } + + return cyw43_wifi_connect(ssid, passphrase, auth_type); +} + +int Network_Interface_Connect_Result(int configIndex) +{ + (void)configIndex; + + if (!cyw43_wifi_is_connected()) + return -1; + + if (cyw43_wifi_get_ip4_address() == 0) + return -1; + + // DHCP has completed — sync the live netif values (IP, gateway, netmask, + // DNS) into the in-memory config block so that managed code reads the + // correct addresses via ConfigurationManager_GetConfigurationBlock. + if (g_TargetConfiguration.NetworkInterfaceConfigs != NULL && + g_TargetConfiguration.NetworkInterfaceConfigs->Count > 0) + { + HAL_Configuration_NetworkInterface *cfg = + g_TargetConfiguration.NetworkInterfaceConfigs->Configs[0]; + + struct netif *nif = nf_getNetif(); + if (nif != NULL) + { + cfg->IPv4Address = nif->ip_addr.addr; + cfg->IPv4NetMask = nif->netmask.addr; + cfg->IPv4GatewayAddress = nif->gw.addr; + +#if LWIP_DNS + cfg->IPv4DNSAddress1 = dns_getserver(0)->addr; + cfg->IPv4DNSAddress2 = dns_getserver(1)->addr; +#endif + } + } + + return 0; +} + +int Network_Interface_Start_Scan(int index) +{ + (void)index; + + cyw43_wifi_scan_start(); + return 0; +} + +#endif diff --git a/targets/ChibiOS/_common/WireProtocol_HAL_Interface.c b/targets/ChibiOS/_common/WireProtocol_HAL_Interface.c index 14c28e0625..18ded30db8 100644 --- a/targets/ChibiOS/_common/WireProtocol_HAL_Interface.c +++ b/targets/ChibiOS/_common/WireProtocol_HAL_Interface.c @@ -17,7 +17,7 @@ extern uint32_t traceLoopCounter; #if (HAL_USE_SERIAL_USB == TRUE) #include -#elif (HAL_USE_SERIAL == TRUE) +#elif (HAL_USE_SERIAL == TRUE) || (HAL_USE_SIO == TRUE) #include #endif diff --git a/targets/ChibiOS/_common/hard_fault_handler.c b/targets/ChibiOS/_common/hard_fault_handler.c index 39677d2dae..458e96e664 100644 --- a/targets/ChibiOS/_common/hard_fault_handler.c +++ b/targets/ChibiOS/_common/hard_fault_handler.c @@ -124,9 +124,9 @@ void HardFault_Handler(void) NVIC_SystemReset(); } -#elif defined(STM32F0XX) || defined(STM32L0XX) +#elif defined(STM32F0XX) || defined(STM32L0XX) || defined(RP2040) -// hard fault handler for Cortex-M0 +// hard fault handler for Cortex-M0/M0+ __attribute__((used)) void HardFaultHandler_C(unsigned int *hardfault_args) { @@ -181,7 +181,7 @@ void __attribute__((naked)) HardFault_Handler(void) } #else -#error "No hard fault handler implemented??? Check STM32 series" +#error "No hard fault handler implemented??? Check target series define." #endif void BusFault_Handler(void) __attribute__((alias("HardFault_Handler"))); diff --git a/targets/ChibiOS/_common/platform_BlockStorage.c b/targets/ChibiOS/_common/platform_BlockStorage.c index 3e797bddc4..3ad65142cf 100644 --- a/targets/ChibiOS/_common/platform_BlockStorage.c +++ b/targets/ChibiOS/_common/platform_BlockStorage.c @@ -4,6 +4,26 @@ // #include + +#if defined(RP2040) || defined(RP2350) + +#include + +// Map here the Block Storage Interface to the RP2040 flash driver +IBlockStorageDevice RP2040Flash_BlockStorageInterface = { + &RP2040FlashDriver_InitializeDevice, + &RP2040FlashDriver_UninitializeDevice, + &RP2040FlashDriver_GetDeviceInfo, + &RP2040FlashDriver_Read, + &RP2040FlashDriver_Write, + NULL, + &RP2040FlashDriver_IsBlockErased, + &RP2040FlashDriver_EraseBlock, + NULL, + NULL}; + +#else + #include // map here the Block Storage Interface to the STM32 driver @@ -20,3 +40,5 @@ IBlockStorageDevice STM32Flash_BlockStorageInterface = NULL, NULL }; + +#endif diff --git a/targets/ChibiOS/_common/rules_code.ld b/targets/ChibiOS/_common/rules_code.ld index 1234cf604b..4cc2295647 100644 --- a/targets/ChibiOS/_common/rules_code.ld +++ b/targets/ChibiOS/_common/rules_code.ld @@ -18,9 +18,11 @@ __deployment_end__ = __deployment_start__ + __deployment_size__; ENTRY(Reset_Handler) +__vectors_align__ = DEFINED(__vectors_align__) ? __vectors_align__ : 1024; + SECTIONS { - .vectors : ALIGN(1024) + .vectors : ALIGN(__vectors_align__) { __textvectors_base__ = LOADADDR(.vectors); __vectors_base__ = .; diff --git a/targets/ChibiOS/_common/targetHAL_ConfigurationManager.cpp b/targets/ChibiOS/_common/targetHAL_ConfigurationManager.cpp index 1649fdef6f..5470b8d478 100644 --- a/targets/ChibiOS/_common/targetHAL_ConfigurationManager.cpp +++ b/targets/ChibiOS/_common/targetHAL_ConfigurationManager.cpp @@ -6,7 +6,18 @@ #include #include #include -#include + +// Diagnostic output macro — disabled (was used for debugging config updates) +#define CFGDBG(...) ((void)0) + +// Use the block storage interface for flash operations (vendor-neutral) +#if defined(RP2040) || defined(RP2350) +extern IBlockStorageDevice RP2040Flash_BlockStorageInterface; +#define g_ConfigFlashDriver RP2040Flash_BlockStorageInterface +#else +extern IBlockStorageDevice STM32Flash_BlockStorageInterface; +#define g_ConfigFlashDriver STM32Flash_BlockStorageInterface +#endif uint32_t GetExistingConfigSize() { @@ -78,6 +89,35 @@ __nfweak void ConfigurationManager_EnumerateConfigurationBlocks() (uint32_t)&__nanoConfig_start__, (uint32_t)&__nanoConfig_end__); + // check wireless configs count — create a default if none exist + if (networkWirelessConfigs->Count == 0) + { + HAL_Configuration_Wireless80211 *wirelessConfig = + (HAL_Configuration_Wireless80211 *)platform_malloc(sizeof(HAL_Configuration_Wireless80211)); + + if (wirelessConfig != NULL) + { + InitialiseWirelessDefaultConfig(wirelessConfig, 0); + + ConfigurationManager_StoreConfigurationBlock( + wirelessConfig, + DeviceConfigurationOption_Wireless80211Network, + 0, + sizeof(HAL_Configuration_Wireless80211), + 0, + false); + + // re-enumerate to pick it up + networkWirelessConfigs = + (HAL_CONFIGURATION_NETWORK_WIRELESS80211 *) + ConfigurationManager_FindNetworkWireless80211ConfigurationBlocks( + (uint32_t)&__nanoConfig_start__, + (uint32_t)&__nanoConfig_end__); + + platform_free(wirelessConfig); + } + } + // find X509 CA certificate blocks HAL_CONFIGURATION_X509_CERTIFICATE *certificateStore = (HAL_CONFIGURATION_X509_CERTIFICATE *)ConfigurationManager_FindX509CertificateConfigurationBlocks( @@ -275,16 +315,29 @@ __nfweak bool ConfigurationManager_StoreConfigurationBlock( else if (configuration == DeviceConfigurationOption_Wireless80211Network) { if (g_TargetConfiguration.Wireless80211Configs == NULL || - (g_TargetConfiguration.Wireless80211Configs->Count == 0 || - (configurationIndex + 1) > g_TargetConfiguration.Wireless80211Configs->Count)) + (g_TargetConfiguration.Wireless80211Configs->Count == 0 && configurationIndex == 0)) + { + // no wireless config block exists yet, storing the first one + // scan flash to find the end of existing config data (network configs come first) + HAL_CONFIGURATION_NETWORK *existingNet = + (HAL_CONFIGURATION_NETWORK *)ConfigurationManager_FindNetworkConfigurationBlocks( + (uint32_t)&__nanoConfig_start__, + (uint32_t)&__nanoConfig_end__); + uint32_t existingSize = existingNet->Count * sizeof(HAL_Configuration_NetworkInterface); + platform_free(existingNet); + storageAddress = (uint32_t)&__nanoConfig_start__ + existingSize; + } + else if (g_TargetConfiguration.Wireless80211Configs->Count == 0 || + (configurationIndex + 1) > g_TargetConfiguration.Wireless80211Configs->Count) { - // there is no room for this block, or there are no blocks stored at all - // failing the operation return FALSE; } - - // set storage address from block address, plus the requested offset - storageAddress = (ByteAddress)g_TargetConfiguration.Wireless80211Configs->Configs[configurationIndex] + offset; + else + { + // set storage address from block address, plus the requested offset + storageAddress = + (ByteAddress)g_TargetConfiguration.Wireless80211Configs->Configs[configurationIndex] + offset; + } // set block size, in case it's not already set blockSize = sizeof(HAL_Configuration_Wireless80211); @@ -329,7 +382,7 @@ __nfweak bool ConfigurationManager_StoreConfigurationBlock( } // now check if memory is erase, so the block can be stored - if (!STM32FlashDriver_IsBlockErased(NULL, storageAddress, blockSize)) + if (!g_ConfigFlashDriver.IsBlockErased(NULL, storageAddress, blockSize)) { // memory not erased, can't store return FALSE; @@ -379,7 +432,7 @@ __nfweak bool ConfigurationManager_StoreConfigurationBlock( } // now check if memory is erase, so the block can be stored - if (!STM32FlashDriver_IsBlockErased(NULL, storageAddress, blockSize)) + if (!g_ConfigFlashDriver.IsBlockErased(NULL, storageAddress, blockSize)) { // memory not erased, can't store return FALSE; @@ -410,7 +463,7 @@ __nfweak bool ConfigurationManager_StoreConfigurationBlock( } // copy the config block content to the config block storage - success = STM32FlashDriver_Write(NULL, storageAddress, blockSize, (unsigned char *)configurationBlock, true); + success = g_ConfigFlashDriver.Write(NULL, storageAddress, blockSize, (unsigned char *)configurationBlock, true); // enumeration is required after we are DONE with SUCCESSFULLY storing all the config chunks requiresEnumeration = (success && done); @@ -448,6 +501,11 @@ __nfweak UpdateConfigurationResult ConfigurationManager_UpdateConfigurationBlock // config sector size int sizeOfConfigSector = (uint32_t)&__nanoConfig_end__ - (uint32_t)&__nanoConfig_start__; + CFGDBG("CFGUPD: opt=%d idx=%d secSize=%d\r\n", (int)configuration, (int)configurationIndex, sizeOfConfigSector); + CFGDBG("CFGUPD: W80211=0x%08X cnt=%d\r\n", + (unsigned)(uintptr_t)g_TargetConfiguration.Wireless80211Configs, + g_TargetConfiguration.Wireless80211Configs ? g_TargetConfiguration.Wireless80211Configs->Count : -1); + // allocate memory from CRT heap uint8_t *configSectorCopy = (uint8_t *)platform_malloc(sizeOfConfigSector); @@ -490,6 +548,38 @@ __nfweak UpdateConfigurationResult ConfigurationManager_UpdateConfigurationBlock } else if (configuration == DeviceConfigurationOption_Wireless80211Network) { + // If no Wireless80211 config exists yet, delegate to StoreConfigurationBlock + // to create the initial block (like ESP32 does), then re-enumerate. + if (g_TargetConfiguration.Wireless80211Configs == NULL || + g_TargetConfiguration.Wireless80211Configs->Count == 0) + { + CFGDBG("CFGUPD: W80211 Count==0, delegating to Store\r\n"); + platform_free(configSectorCopy); + + // set marker before storing + memcpy( + configurationBlock, + c_MARKER_CONFIGURATION_WIRELESS80211_V1, + sizeof(c_MARKER_CONFIGURATION_WIRELESS80211_V1)); + + bool storeRc = ConfigurationManager_StoreConfigurationBlock( + configurationBlock, + configuration, + configurationIndex, + sizeof(HAL_Configuration_Wireless80211), + 0, + true); + CFGDBG("CFGUPD: Store rc=%d\r\n", (int)storeRc); + if (storeRc) + { + return UpdateConfigurationResult_Success; + } + else + { + return UpdateConfigurationResult_Failed; + } + } + // make sure the config block marker is set memcpy( configurationBlock, @@ -513,6 +603,7 @@ __nfweak UpdateConfigurationResult ConfigurationManager_UpdateConfigurationBlock // storage address from block address storageAddress = (ByteAddress)g_TargetConfiguration.Wireless80211Configs->Configs[configurationIndex]; + CFGDBG("CFGUPD: W80211 update addr=0x%08X blkSz=%d\r\n", (unsigned)storageAddress, (int)sizeof(HAL_Configuration_Wireless80211)); // set block size, in case it's not already set blockSize = sizeof(HAL_Configuration_Wireless80211); @@ -589,35 +680,65 @@ __nfweak UpdateConfigurationResult ConfigurationManager_UpdateConfigurationBlock } // erase config sector - if (STM32FlashDriver_EraseBlock(NULL, (uint32_t)&__nanoConfig_start__) == TRUE) + CFGDBG("CFGUPD: erasing 0x%08X\r\n", (unsigned)(uint32_t)&__nanoConfig_start__); { - // flash block is erased - - // subtract the start address of config sector to get the offset - blockOffset = storageAddress - (uint32_t)&__nanoConfig_start__; - - // set pointer to block to udpate - blockAddressInCopy = configSectorCopy + blockOffset; - - // replace config block with new content by replacing memory - memcpy(blockAddressInCopy, configurationBlock, blockSize); - - // copy the config block copy back to the config block storage - if (STM32FlashDriver_Write( - NULL, - (uint32_t)&__nanoConfig_start__, - sizeOfConfigSector, - (unsigned char *)configSectorCopy, - true)) +#if defined(RP2040) || defined(RP2350) + // RP2040 has 4KB erase sectors — need to erase all sectors in the config region + bool eraseOk = TRUE; + for (uint32_t eraseAddr = (uint32_t)&__nanoConfig_start__; + eraseAddr < (uint32_t)&__nanoConfig_end__ && eraseOk; + eraseAddr += 4096) { - success = UpdateConfigurationResult_Success; + eraseOk = g_ConfigFlashDriver.EraseBlock(NULL, eraseAddr); + } +#else + bool eraseOk = (g_ConfigFlashDriver.EraseBlock(NULL, (uint32_t)&__nanoConfig_start__) == TRUE); +#endif + if (eraseOk) + { + // flash block is erased + + // subtract the start address of config sector to get the offset + blockOffset = storageAddress - (uint32_t)&__nanoConfig_start__; + CFGDBG("CFGUPD: writing offset=%d blkSz=%d secSz=%d\r\n", (int)blockOffset, (int)blockSize, sizeOfConfigSector); + + // set pointer to block to udpate + blockAddressInCopy = configSectorCopy + blockOffset; + + // replace config block with new content by replacing memory + memcpy(blockAddressInCopy, configurationBlock, blockSize); + + // copy the config block copy back to the config block storage + if (g_ConfigFlashDriver.Write( + NULL, + (uint32_t)&__nanoConfig_start__, + sizeOfConfigSector, + (unsigned char *)configSectorCopy, + true)) + { + CFGDBG("CFGUPD: write OK\r\n"); + success = UpdateConfigurationResult_Success; + } + else + { + CFGDBG("CFGUPD: write FAILED\r\n"); + } + } + else + { + CFGDBG("CFGUPD: erase FAILED\r\n"); } } // free memory platform_free(configSectorCopy); } + else + { + CFGDBG("CFGUPD: malloc(%d) FAILED\r\n", sizeOfConfigSector); + } + CFGDBG("CFGUPD: result=%d\r\n", (int)success); return success; } @@ -648,9 +769,12 @@ __nfweak void ConfigurationManager_GetSystemSerialNumber(char *serialNumber, siz { // do the thing to get unique device ID memset(serialNumber, 0, serialNumberSize); + +#if defined(UID_BASE) // Use the 96 bit unique device ID => 12 bytes // memory copy from the address pointed by UID_BASE define (from STM32 HAL) memcpy(&serialNumber[serialNumberSize - 12], ((uint8_t *)UID_BASE), 12); +#endif // Disambiguation is needed because the hardware-specific identifier used to create the // default serial number on other platforms may be in the same range. diff --git a/targets/ChibiOS/_common/targetHAL_Network.cpp b/targets/ChibiOS/_common/targetHAL_Network.cpp index a90b136d65..8548ab58b2 100644 --- a/targets/ChibiOS/_common/targetHAL_Network.cpp +++ b/targets/ChibiOS/_common/targetHAL_Network.cpp @@ -6,13 +6,20 @@ // This file includes the platform and board specific Network Intialisation #include + +#if defined(RP2040) || defined(RP2350) +extern "C" { +#include +} +#else #include +#endif // this is the declaration for the callback implement in nf_sys_arch.c extern "C" void set_signal_sock_function(void (*funcPtr)()); // buffer with host name -char hostName[18] = "nanodevice_"; +static char hostName[18] = "nanodevice_"; // // Callback from lwIP on event @@ -45,10 +52,25 @@ void nanoHAL_Network_Initialize() // init config memset(&lwipOptions, 0, sizeof(lwipOptions)); +#if defined(RP2040) || defined(RP2350) + // WiFi targets: use CYW43 chip MAC if available + uint8_t wifiMac[6]; + cyw43_wifi_get_mac_addr(wifiMac); + + if (wifiMac[0] != 0 || wifiMac[1] != 0 || wifiMac[2] != 0) + { + lwipOptions.macaddress = wifiMac; + } + else + { + lwipOptions.macaddress = (uint8_t *)networkConfig.MacAddress; + } +#else // grab MAC address lwipOptions.macaddress = (uint8_t *)networkConfig.MacAddress; +#endif - // static or dinamic address + // static or dynamic address if (networkConfig.StartupAddressMode == AddressMode_Static) { // IPv4 configs @@ -58,7 +80,7 @@ void nanoHAL_Network_Initialize() } else if (networkConfig.StartupAddressMode == AddressMode_DHCP) { - // clear IPv4 configs + // clear IPv4 configs lwipOptions.address = 0; lwipOptions.netmask = 0; lwipOptions.gateway = 0; @@ -75,7 +97,7 @@ void nanoHAL_Network_Initialize() // copy over last 3 bytes of MAC address for (int index = 3; index < 6; index++) { - sprintf(macPosition, "%02X", (int)networkConfig.MacAddress[index]); + sprintf(macPosition, "%02X", (int)lwipOptions.macaddress[index]); macPosition += 2; } @@ -84,10 +106,26 @@ void nanoHAL_Network_Initialize() // Start lwIP thread in ChibiOS bindings using the above options lwIPInit(&lwipOptions); + +#if defined(RP2040) || defined(RP2350) + // Ensure CYW43 WiFi is powered on and set netif MAC from chip + cyw43_ensure_wifi_up_impl(); + + { + uint8_t chipMac[6]; + cyw43_wifi_get_mac_addr(chipMac); + if (chipMac[0] != 0 || chipMac[1] != 0 || chipMac[2] != 0) + { + cyw43_wifi_set_netif_mac(chipMac); + } + } +#endif } } void nanoHAL_Network_Uninitialize() { - // Empty +#if defined(RP2040) || defined(RP2350) + cyw43_wifi_power_off(); +#endif } diff --git a/targets/ChibiOS/_include/TargetHAL_Spi.h b/targets/ChibiOS/_include/TargetHAL_Spi.h index 2f4b56d8a1..d3d25c503a 100644 --- a/targets/ChibiOS/_include/TargetHAL_Spi.h +++ b/targets/ChibiOS/_include/TargetHAL_Spi.h @@ -7,7 +7,13 @@ #define TARGET_HAL_SPI_H // # of buses +#if defined(RP_GPIO_NUM_LINES) +// RP2040/RP2350: 2 SPI controllers (SPI0, SPI1) +#define NUM_SPI_BUSES 2 +#else +// STM32: up to 5 SPI buses #define NUM_SPI_BUSES 5 +#endif // Maximum number of devices per SPI bus #define MAX_SPI_DEVICES 5 diff --git a/targets/ChibiOS/_include/lwipopts.h b/targets/ChibiOS/_include/lwipopts.h index c2de38cb6f..0292bd15f0 100644 --- a/targets/ChibiOS/_include/lwipopts.h +++ b/targets/ChibiOS/_include/lwipopts.h @@ -1052,6 +1052,9 @@ // empty define to keep the compiler when enabling lwIP debug #define sntp_format_time +// SNTP servers can be specified as DNS names (required by nanoFramework SNTP API) +#define SNTP_SERVER_DNS 1 + // required as we are defining priority-aware mutexes #define LWIP_COMPAT_MUTEX_ALLOWED diff --git a/targets/ChibiOS/_include/targetHAL_Watchdog.h b/targets/ChibiOS/_include/targetHAL_Watchdog.h index f44389550e..9a91255f86 100644 --- a/targets/ChibiOS/_include/targetHAL_Watchdog.h +++ b/targets/ChibiOS/_include/targetHAL_Watchdog.h @@ -9,9 +9,11 @@ #define TARGETHAL_WATCHDOG_H #if (HAL_USE_WDG) + #if !defined(RP2040) && !defined(RP2350) #if (STM32_LSI_ENABLED == FALSE) #error "LSI clock must be enabled for independent watchdog (IWDG) to work" #endif + #endif // if the timeout isn't set at target level, set a default value (10 seconds) #if !defined(IWATCHDOG_TIMEOUT_MILLIS) diff --git a/targets/ChibiOS/_nanoBooter/WireProtocol_MonitorCommands.c b/targets/ChibiOS/_nanoBooter/WireProtocol_MonitorCommands.c index f244c40de6..f0db0127b0 100644 --- a/targets/ChibiOS/_nanoBooter/WireProtocol_MonitorCommands.c +++ b/targets/ChibiOS/_nanoBooter/WireProtocol_MonitorCommands.c @@ -13,6 +13,16 @@ #include #include +// Vendor-abstracted flash operations +#if (HAL_NF_USE_STM32_FLASH == TRUE) +#define nf_TargetFlashWrite stm32FlashWrite +#define nf_TargetFlashErase stm32FlashErase +#else +// Forward declarations for target-provided flash operations +int nf_TargetFlashWrite(uint32_t startAddress, uint32_t length, const uint8_t *buffer); +int nf_TargetFlashErase(uint32_t address); +#endif + int AccessMemory(uint32_t location, uint32_t lengthInBytes, uint8_t *buffer, int32_t mode, uint32_t *errorCode) { // reset error code @@ -22,13 +32,11 @@ int AccessMemory(uint32_t location, uint32_t lengthInBytes, uint8_t *buffer, int { case AccessMemory_Write: // use FLASH driver to perform write operation - // this requires that HAL_NF_USE_STM32_FLASH is set to TRUE on halconf_nf.h - return stm32FlashWrite(location, lengthInBytes, buffer); + return nf_TargetFlashWrite(location, lengthInBytes, buffer); case AccessMemory_Erase: // erase using FLASH driver - // this requires that HAL_NF_USE_STM32_FLASH is set to TRUE on halconf_nf.h - return stm32FlashErase(location); + return nf_TargetFlashErase(location); case AccessMemory_Check: // compute CRC32 of the memory segment diff --git a/targets/ChibiOS/_nanoCLR/CMakeLists.txt b/targets/ChibiOS/_nanoCLR/CMakeLists.txt index 25449db7a4..bbd5c739b1 100644 --- a/targets/ChibiOS/_nanoCLR/CMakeLists.txt +++ b/targets/ChibiOS/_nanoCLR/CMakeLists.txt @@ -33,7 +33,7 @@ list(APPEND TARGET_CHIBIOS_NANOCLR_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/nanoCRT.c # append TRNG only if option is ON if(NF_FEATURE_USE_RNG) - # append random implementation for all series, except F0 + # append random implementation for supported series if( ${TARGET_SERIES} STREQUAL "STM32L0xx" OR ${TARGET_SERIES} STREQUAL "STM32L4xx" OR ${TARGET_SERIES} STREQUAL "STM32F4xx" OR @@ -42,6 +42,10 @@ if(NF_FEATURE_USE_RNG) list(APPEND TARGET_CHIBIOS_NANOCLR_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/targetRandom.cpp) + elseif(${TARGET_SERIES} STREQUAL "RP2040") + # RP2040 does not have hardware TRNG + message(ERROR "RP2040 doesn't have a hardware Random Number Generator. Please change USE_RNG option to OFF.") + else() # this series doesn't feature hardware TRNG, report message(ERROR "This CPU doesn't have a Random Number Generation. Please change NF_FEATURE_USE_RNG option to OFF.") diff --git a/targets/ChibiOS/_nanoCLR/System.Device.Gpio/cpu_gpio.cpp b/targets/ChibiOS/_nanoCLR/System.Device.Gpio/cpu_gpio.cpp index 1f3d25af14..b1af095287 100644 --- a/targets/ChibiOS/_nanoCLR/System.Device.Gpio/cpu_gpio.cpp +++ b/targets/ChibiOS/_nanoCLR/System.Device.Gpio/cpu_gpio.cpp @@ -10,7 +10,20 @@ #include #include "sys_dev_gpio_native_target.h" +#if defined(RP_GPIO_NUM_LINES) +// RP2040/RP2350: single GPIO bank, pin number IS the pad number +#define GPIO_MAX_PIN RP_GPIO_NUM_LINES + +// RP2040 PAL doesn't define PAL_MODE_OUTPUT_OPENDRAIN; compose it from RP-specific flags +#if !defined(PAL_MODE_OUTPUT_OPENDRAIN) +#define PAL_MODE_OUTPUT_OPENDRAIN (PAL_RP_IOCTRL_FUNCSEL_SIO | PAL_RP_GPIO_OE | PAL_RP_PAD_IE | PAL_RP_PAD_OD) +#endif + +#else +// STM32: multiple GPIO ports, 16 pins per port #define GPIO_MAX_PIN 256 +#endif + #define TOTAL_GPIO_PORTS ((GPIO_MAX_PIN + 15) / 16) // Double linkedlist to hold the state of each Input pin @@ -33,10 +46,16 @@ static uint16_t pinReserved[TOTAL_GPIO_PORTS]; // reserved - 1 bit p // this is an utility function to get a ChibiOS PAL IoLine from our "encoded" pin number static ioline_t GetIoLine(int16_t pinNumber) { +#if defined(RP_GPIO_NUM_LINES) + // RP2040/RP2350: single GPIO bank, ioline_t is just the pad number + return (ioline_t)pinNumber; +#else + // STM32: port/pad encoding (16 pins per port) stm32_gpio_t *port = GPIO_PORT(pinNumber); int16_t pad = pinNumber % 16; return PAL_LINE(port, pad); +#endif } bool IsValidGpioPin(GPIO_PIN pinNumber) diff --git a/targets/ChibiOS/_nanoCLR/System.Device.Wifi/sys_dev_wifi_native_System_Device_Wifi_WifiAdapter.cpp b/targets/ChibiOS/_nanoCLR/System.Device.Wifi/sys_dev_wifi_native_System_Device_Wifi_WifiAdapter.cpp new file mode 100644 index 0000000000..0d3c282ba7 --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/System.Device.Wifi/sys_dev_wifi_native_System_Device_Wifi_WifiAdapter.cpp @@ -0,0 +1,313 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +// ChibiOS WiFi adapter native implementation for Pico W (CYW43439). +// Implements the System.Device.Wifi managed API using the CYW43 driver. + +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +//////////////////////////////////////////////////////////////////////////////////// +// !!! KEEP IN SYNC WITH System.Device.Wifi (in managed code) !!! // +//////////////////////////////////////////////////////////////////////////////////// +struct ScanRecord +{ + uint8_t bssid[6]; + uint8_t ssid[33]; + uint8_t rssi; + uint8_t authMode; + uint8_t cypherType; +}; + +// --------------------------------------------------------------------------- +// GetNetInterfaceIndex — helper to retrieve network interface index +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::GetNetInterfaceIndex( + CLR_RT_StackFrame &stack, + int *pNetIndex) +{ + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + if (pThis[Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::FIELD___disposedValue] + .NumericByRef() + .u1 != 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + *pNetIndex = pThis[FIELD___networkInterface].NumericByRefConst().s4; + } + NANOCLR_NOCLEANUP(); +} + +// --------------------------------------------------------------------------- +// NativeSetDeviceName +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::NativeSetDeviceName___VOID__STRING( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + { + // hostname is set via lwIP netif, not separately configurable on CYW43 + (void)stack; + } + NANOCLR_NOCLEANUP_NOLABEL(); +} + +// --------------------------------------------------------------------------- +// DisposeNative +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::DisposeNative___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + (void)stack; + NANOCLR_NOCLEANUP_NOLABEL(); +} + +// --------------------------------------------------------------------------- +// NativeInit +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::NativeInit___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + (void)stack; + // CYW43 is initialized by the lwIP WiFi thread on startup + NANOCLR_NOCLEANUP_NOLABEL(); +} + +// --------------------------------------------------------------------------- +// NativeConnect — connect to a WiFi network +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter:: + NativeConnect___SystemDeviceWifiWifiConnectionStatus__STRING__STRING__SystemDeviceWifiWifiReconnectionKind( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + { + const char *szSsid; + const char *szPassPhrase; + int netIndex; + CLR_RT_HeapBlock hbTimeout; + CLR_INT64 *timeout; + bool eventResult = true; + WifiConnectionStatus status = WifiConnectionStatus_UnspecifiedFailure; + + NANOCLR_CHECK_HRESULT(GetNetInterfaceIndex(stack, &netIndex)); + + if (stack.m_customState == 0) + { + szSsid = stack.Arg1().RecoverString(); + FAULT_ON_NULL(szSsid); + + szPassPhrase = stack.Arg2().RecoverString(); + // password can be NULL for open networks + + // Initiate WiFi connection via CYW43 driver (non-blocking) + int result = Network_Interface_Start_Connect( + netIndex, szSsid, szPassPhrase ? szPassPhrase : "", 0); + + if (result != 0) + { + status = WifiConnectionStatus_NetworkNotAvailable; + eventResult = false; + } + + // Set 20-second timeout for connect + hbTimeout.SetInteger((CLR_INT64)20000 * TIME_CONVERSION__TO_MILLISECONDS); + } + + while (eventResult) + { + int connectResult = Network_Interface_Connect_Result(netIndex); + if (connectResult >= 0) + { + status = (connectResult == 0) + ? WifiConnectionStatus_Success + : WifiConnectionStatus_UnspecifiedFailure; + break; + } + + // Do a direct SPI poll from this thread context to help drain packets + cyw43_wifi_direct_poll(); + + // Wait for Event_Wifi_Station OR 500ms poll timeout + NANOCLR_CHECK_HRESULT(stack.SetupTimeoutFromTicks(hbTimeout, timeout)); + + bool woke = true; + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.WaitEvents( + stack.m_owningThread, *timeout, Event_Wifi_Station, woke)); + + if (!woke) + { + status = WifiConnectionStatus_Timeout; + break; + } + } + + stack.SetResult_I4(status); + } + NANOCLR_NOCLEANUP(); +} + +// --------------------------------------------------------------------------- +// NativeDisconnect — disconnect from current WiFi network +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::NativeDisconnect___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + { + int netIndex; + NANOCLR_CHECK_HRESULT(GetNetInterfaceIndex(stack, &netIndex)); + Network_Interface_Disconnect(netIndex); + } + NANOCLR_NOCLEANUP(); +} + +// --------------------------------------------------------------------------- +// NativeScanAsync — initiate a WiFi network scan +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::NativeScanAsync___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + { + int netIndex; + NANOCLR_CHECK_HRESULT(GetNetInterfaceIndex(stack, &netIndex)); + + int startScanResult = Network_Interface_Start_Scan(netIndex); + + if (startScanResult != 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION); + } + + // Signal the managed layer that the scan is complete. + // The managed WiFi API waits for this event before calling GetNativeScanReport. + PostManagedEvent(EVENT_WIFI, WiFiEventType_ScanComplete, 0, 0); + } + NANOCLR_NOCLEANUP(); +} + +// --------------------------------------------------------------------------- +// GetNativeScanReport — return scan results as byte array +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::GetNativeScanReport___SZARRAY_U1( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock &top = stack.PushValueAndClear(); + + uint16_t number = (uint16_t)cyw43_wifi_scan_get_count(); + const wifi_scan_record_t *results = cyw43_wifi_scan_get_results(); + + if (number == 0) + { + // Return empty array with count = 0 + int rlen = sizeof(uint16_t); + NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(top, rlen, g_CLR_RT_WellKnownTypes.m_UInt8)); + CLR_RT_HeapBlock_Array *array = top.DereferenceArray(); + CLR_UINT8 *buf = array->GetFirstElement(); + *buf = 0; + } + else + { + int rlen = sizeof(uint16_t) + (number * sizeof(ScanRecord)); + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstance(top, rlen, g_CLR_RT_WellKnownTypes.m_UInt8)); + CLR_RT_HeapBlock_Array *array = top.DereferenceArray(); + CLR_UINT8 *buf = array->GetFirstElement(); + + // Store record count as first byte (matches ESP32 format) + *buf++ = (uint8_t)number; + + ScanRecord *pScanRec = (ScanRecord *)buf; + + for (int i = 0; i < number; i++) + { + memcpy(pScanRec->bssid, results[i].bssid, 6); + memset(pScanRec->ssid, 0, 33); + memcpy(pScanRec->ssid, results[i].ssid, 33); + pScanRec->rssi = (uint8_t)(results[i].rssi & 0xFF); + pScanRec->authMode = results[i].auth_mode; + pScanRec->cypherType = 0; + pScanRec++; + } + } + } + NANOCLR_NOCLEANUP(); +} + +// --------------------------------------------------------------------------- +// NativeFindWirelessAdapters — return array of WiFi interface indices +// --------------------------------------------------------------------------- +HRESULT Library_sys_dev_wifi_native_System_Device_Wifi_WifiAdapter::NativeFindWirelessAdapters___STATIC__SZARRAY_U1( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + { + CLR_RT_HeapBlock_Array *array; + CLR_UINT8 *arrayOfIndexes; + int index; + int interfaceCount = 0; + + CLR_RT_HeapBlock &top = stack.PushValueAndClear(); + + HAL_Configuration_NetworkInterface *netInterfaceConfig = + (HAL_Configuration_NetworkInterface *)platform_malloc(sizeof(HAL_Configuration_NetworkInterface)); + + if (netInterfaceConfig == NULL) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY); + } + + for (index = 0; index < g_TargetConfiguration.NetworkInterfaceConfigs->Count; index++) + { + if (!ConfigurationManager_GetConfigurationBlock( + netInterfaceConfig, DeviceConfigurationOption_Network, index)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); + } + + if (netInterfaceConfig->InterfaceType == NetworkInterfaceType_Wireless80211) + { + interfaceCount++; + } + } + + NANOCLR_CHECK_HRESULT( + CLR_RT_HeapBlock_Array::CreateInstance(top, interfaceCount, g_CLR_RT_WellKnownTypes.m_UInt8)); + array = top.DereferenceArray(); + arrayOfIndexes = array->GetFirstElement(); + + for (index = 0; index < g_TargetConfiguration.NetworkInterfaceConfigs->Count; index++) + { + if (!ConfigurationManager_GetConfigurationBlock( + netInterfaceConfig, DeviceConfigurationOption_Network, index)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); + } + + if (netInterfaceConfig->InterfaceType == NetworkInterfaceType_Wireless80211) + { + *arrayOfIndexes = index; + arrayOfIndexes++; + } + } + + platform_free(netInterfaceConfig); + } + NANOCLR_NOCLEANUP(); +} diff --git a/targets/ChibiOS/_nanoCLR/targetHAL_Power.c b/targets/ChibiOS/_nanoCLR/targetHAL_Power.c index 87ecb08657..75c7d79f85 100644 --- a/targets/ChibiOS/_nanoCLR/targetHAL_Power.c +++ b/targets/ChibiOS/_nanoCLR/targetHAL_Power.c @@ -13,10 +13,10 @@ #include #include -#if (STM32_USE_FSMC_SDRAM == TRUE) +#if defined(STM32_USE_FSMC_SDRAM) && (STM32_USE_FSMC_SDRAM == TRUE) #include #endif -#if (STM32_USE_FSMC_SRAM == TRUE) +#if defined(STM32_USE_FSMC_SRAM) && (STM32_USE_FSMC_SRAM == TRUE) #include #endif @@ -54,10 +54,10 @@ void CPU_SetPowerMode(PowerLevel_type powerLevel) #endif // shutdown memory -#if (STM32_USE_FSMC_SDRAM == TRUE) +#if defined(STM32_USE_FSMC_SDRAM) && (STM32_USE_FSMC_SDRAM == TRUE) fsmcSdramStop(&SDRAMD); #endif -#if (STM32_USE_FSMC_SRAM == TRUE) +#if defined(STM32_USE_FSMC_SRAM) && (STM32_USE_FSMC_SRAM == TRUE) #if (STM32_SRAM_USE_FSMC_SRAM1 == TRUE) fsmcSramStop(&SRAMD1); #endif @@ -157,7 +157,7 @@ void CPU_SetPowerMode(PowerLevel_type powerLevel) #endif // set SLEEPDEEP bit of Cortex SCR - SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); + SCB->SCR |= ((uint32_t)SCB_SCR_SLEEPDEEP_Msk); // wait for interrupt, and the execution dies here __WFI(); diff --git a/targets/ChibiOS/_nanoCLR/targetHAL_Watchdog.c b/targets/ChibiOS/_nanoCLR/targetHAL_Watchdog.c index fadfc71785..ea36eee299 100644 --- a/targets/ChibiOS/_nanoCLR/targetHAL_Watchdog.c +++ b/targets/ChibiOS/_nanoCLR/targetHAL_Watchdog.c @@ -8,6 +8,35 @@ #include #include +#if defined(RP2040) || defined(RP2350) + +// RP2040/RP2350 watchdog implementation +// The RP2040 watchdog timer counts down and resets the chip when it reaches zero. +// A tick rate of 1 MHz gives 1 microsecond per tick. + +static WDGConfig wdgConfig = {0}; + +void Watchdog_Init() +{ + // RP2040 watchdog reload value is in microseconds at 1 MHz tick rate + // Set to IWATCHDOG_TIMEOUT_MILLIS converted to microseconds +#if defined(IWATCHDOG_TIMEOUT_MILLIS) + wdgConfig.rlr = IWATCHDOG_TIMEOUT_MILLIS * 1000U; +#else + // Default 10 second timeout + wdgConfig.rlr = 10000U * 1000U; +#endif + + wdgStart(&WDGD1, &wdgConfig); +} + +void Watchdog_Reset() +{ + wdgReset(&WDGD1); +} + +#else // STM32 targets + // Watchdog configuration structure required by ChibiOS #if (STM32_IWDG_IS_WINDOWED == TRUE) static WDGConfig wdgConfig = {STM32_IWDG_PR_256, STM32_IWDG_RL(0xFFF), 0x0FFF}; // default is max @@ -79,3 +108,5 @@ void Watchdog_Reset() { wdgReset(&WDGD1); } + +#endif // RP2040 || RP2350 diff --git a/targets/ChibiOS/_nanoCLR/target_platform.h.in b/targets/ChibiOS/_nanoCLR/target_platform.h.in index 3943683e6e..2066d61699 100644 --- a/targets/ChibiOS/_nanoCLR/target_platform.h.in +++ b/targets/ChibiOS/_nanoCLR/target_platform.h.in @@ -26,7 +26,7 @@ #define HAL_USE_SDC @HAL_USE_SDC_OPTION@ #define HAL_USE_WDG @HAL_USE_WDG_OPTION@ #define HAL_USE_CAN @HAL_USE_CAN_OPTION@ -#define HAL_NF_USE_STM32_CRC TRUE +#define HAL_NF_USE_STM32_CRC @HAL_NF_USE_STM32_CRC_OPTION@ #define HAL_NF_USE_STM32_ONEWIRE @HAL_USE_STM32_ONEWIRE_OPTION@ #define HAL_USBH_USE_MSD @HAL_USBH_USE_MSD_OPTION@ diff --git a/targets/ChibiOS/_nf-overlay/os/hal/include/hal_nf_community.h b/targets/ChibiOS/_nf-overlay/os/hal/include/hal_nf_community.h index 85f627c7fd..ef6235654b 100644 --- a/targets/ChibiOS/_nf-overlay/os/hal/include/hal_nf_community.h +++ b/targets/ChibiOS/_nf-overlay/os/hal/include/hal_nf_community.h @@ -46,12 +46,26 @@ // #include "hal_nnnn.h" // Normal drivers +// STM32-specific overlay drivers — only include for STM32 targets +#if defined(STM32F0XX) || defined(STM32F4XX) || defined(STM32F7XX) || defined(STM32H7XX) || defined(STM32L0XX) || defined(STM32L4XX) #include "stm32_qspi/hal_stm32_qspi.h" #include "stm32_flash/hal_stm32_flash.h" #include "stm32_crc/hal_stm32_crc.h" #include "stm32_rng/hal_stm32_rng.h" #include "stm32_fsmc/hal_stm32_fsmc.h" #include "stm32_onewire/hal_stm32_onewire.h" +#elif defined(RP2040) +// RP2040 RNG stubs (ROSC-based) — provided by target_rng.c +#ifdef __cplusplus +extern "C" { +#endif + void rngStart(void); + void rngStop(void); + uint32_t rngGenerateRandomNumber(void); +#ifdef __cplusplus +} +#endif +#endif // Complex drivers // #include "hal_nnnn.h"