diff --git a/CMake/Modules/FindNF_NativeAssemblies.cmake b/CMake/Modules/FindNF_NativeAssemblies.cmake index 2d52b64b7b..c6c6ebdab9 100644 --- a/CMake/Modules/FindNF_NativeAssemblies.cmake +++ b/CMake/Modules/FindNF_NativeAssemblies.cmake @@ -1,4 +1,4 @@ -# +# # Copyright (c) .NET Foundation and Contributors # See LICENSE file in the project root for full license information. # @@ -42,6 +42,7 @@ option(API_nanoFramework.Networking.Thread "option for nanoFramewor # Stm32 only option(API_Hardware.Stm32 "option for Hardware.Stm32") +option(API_Hardware.Pico "option for Hardware.Pico") # TI CC13xxCC26xx option(API_nanoFramework.TI.EasyLink "option for nanoFramework.TI.EasyLink API") @@ -270,6 +271,12 @@ if(API_Hardware.Stm32) PerformSettingsForApiEntry("nanoFramework.Hardware.Stm32") endif() +# Hardware.Pico +if(API_Hardware.Pico) + ##### API name here (doted name) + PerformSettingsForApiEntry("nanoFramework.Hardware.Pico") +endif() + # nanoFramework.Device.Can if(API_nanoFramework.Device.Can) ##### API name here (doted name) diff --git a/CMake/Modules/FindnanoFramework.Hardware.Pico.cmake b/CMake/Modules/FindnanoFramework.Hardware.Pico.cmake new file mode 100644 index 0000000000..f05b0b7df9 --- /dev/null +++ b/CMake/Modules/FindnanoFramework.Hardware.Pico.cmake @@ -0,0 +1,46 @@ +# +# Copyright (c) .NET Foundation and Contributors +# See LICENSE file in the project root for full license information. +# + + +# native code directory +set(BASE_PATH_FOR_THIS_MODULE "${BASE_PATH_FOR_CLASS_LIBRARIES_MODULES}/nanoFramework.Hardware.Pico") + + +# set include directories +list(APPEND nanoFramework.Hardware.Pico_INCLUDE_DIRS "${BASE_PATH_FOR_THIS_MODULE}") + + +# source files +set(nanoFramework.Hardware.Pico_SRCS + + nanoFramework_hardware_pico.cpp + nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio.cpp + nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock.cpp + nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine.cpp +) + +foreach(SRC_FILE ${nanoFramework.Hardware.Pico_SRCS}) + + set(nanoFramework.Hardware.Pico_SRC_FILE SRC_FILE-NOTFOUND) + + find_file(nanoFramework.Hardware.Pico_SRC_FILE ${SRC_FILE} + PATHS + ${BASE_PATH_FOR_THIS_MODULE} + + CMAKE_FIND_ROOT_PATH_BOTH + ) + + if (BUILD_VERBOSE) + message("${SRC_FILE} >> ${nanoFramework.Hardware.Pico_SRC_FILE}") + endif() + + list(APPEND nanoFramework.Hardware.Pico_SOURCES ${nanoFramework.Hardware.Pico_SRC_FILE}) + +endforeach() + + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(nanoFramework.Hardware.Pico DEFAULT_MSG nanoFramework.Hardware.Pico_INCLUDE_DIRS nanoFramework.Hardware.Pico_SOURCES) diff --git a/CMake/Modules/NF_Kconfig.cmake b/CMake/Modules/NF_Kconfig.cmake index 1183cbba72..5b3fa9c2a3 100644 --- a/CMake/Modules/NF_Kconfig.cmake +++ b/CMake/Modules/NF_Kconfig.cmake @@ -43,6 +43,7 @@ set(_NF_KCONFIG_API_MAP # Platform-specific APIs "API_HARDWARE_STM32|API_Hardware.Stm32" + "API_HARDWARE_PICO|API_Hardware.Pico" "API_HARDWARE_ESP32|API_Hardware.Esp32" "API_NANOFRAMEWORK_HARDWARE_ESP32_RMT|API_nanoFramework.Hardware.Esp32.Rmt" "API_NANOFRAMEWORK_HARDWARE_TI|API_nanoFramework.Hardware.TI" diff --git a/Kconfig.apis b/Kconfig.apis index 39b81eff66..d9148e7411 100644 --- a/Kconfig.apis +++ b/Kconfig.apis @@ -113,6 +113,11 @@ config API_HARDWARE_STM32 depends on RTOS_CHIBIOS default n +config API_HARDWARE_PICO + bool "Hardware.Pico" + depends on RTOS_CHIBIOS + default n + config API_HARDWARE_ESP32 bool "Hardware.Esp32" depends on RTOS_ESP32 diff --git a/src/CLR/Core/Hardware/Hardware.cpp b/src/CLR/Core/Hardware/Hardware.cpp index 8f6c144d8d..7cc54aed26 100644 --- a/src/CLR/Core/Hardware/Hardware.cpp +++ b/src/CLR/Core/Hardware/Hardware.cpp @@ -173,6 +173,11 @@ void CLR_HW_Hardware::ProcessActivity() eventsCLR |= Event_StorageIo; } + if (events & SYSTEM_EVENT_FLAG_PICOPIO) + { + eventsCLR |= Event_PicoPio; + } + if (events & SYSTEM_EVENT_FLAG_RADIO) { eventsCLR |= Event_Radio; diff --git a/src/CLR/Include/nanoCLR_Hardware.h b/src/CLR/Include/nanoCLR_Hardware.h index cae49ba20e..db4113a777 100644 --- a/src/CLR/Include/nanoCLR_Hardware.h +++ b/src/CLR/Include/nanoCLR_Hardware.h @@ -22,11 +22,11 @@ struct CLR_HW_Hardware static const CLR_UINT32 c_Default_PowerLevel = PowerLevel__Sleep; static const CLR_UINT32 c_Default_WakeupEvents = SYSTEM_EVENT_FLAG_COM_IN | SYSTEM_EVENT_FLAG_COM_OUT | SYSTEM_EVENT_FLAG_STORAGE_IO | - SYSTEM_EVENT_FLAG_SYSTEM_TIMER | SYSTEM_EVENT_FLAG_USB_IN | SYSTEM_EVENT_FLAG_USB_OUT | - SYSTEM_EVENT_FLAG_SPI_MASTER | SYSTEM_EVENT_FLAG_I2C_MASTER | SYSTEM_EVENT_FLAG_I2C_SLAVE | - SYSTEM_EVENT_HW_INTERRUPT | SYSTEM_EVENT_FLAG_SOCKET | SYSTEM_EVENT_FLAG_DEBUGGER_ACTIVITY | - SYSTEM_EVENT_FLAG_MESSAGING_ACTIVITY | SYSTEM_EVENT_FLAG_ONEWIRE_MASTER | SYSTEM_EVENT_FLAG_RADIO | - SYSTEM_EVENT_FLAG_WIFI_STATION | SYSTEM_EVENT_FLAG_BLUETOOTH; + SYSTEM_EVENT_FLAG_PICOPIO | SYSTEM_EVENT_FLAG_SYSTEM_TIMER | SYSTEM_EVENT_FLAG_USB_IN | + SYSTEM_EVENT_FLAG_USB_OUT | SYSTEM_EVENT_FLAG_SPI_MASTER | SYSTEM_EVENT_FLAG_I2C_MASTER | + SYSTEM_EVENT_FLAG_I2C_SLAVE | SYSTEM_EVENT_HW_INTERRUPT | SYSTEM_EVENT_FLAG_SOCKET | + SYSTEM_EVENT_FLAG_DEBUGGER_ACTIVITY | SYSTEM_EVENT_FLAG_MESSAGING_ACTIVITY | SYSTEM_EVENT_FLAG_ONEWIRE_MASTER | + SYSTEM_EVENT_FLAG_RADIO | SYSTEM_EVENT_FLAG_WIFI_STATION | SYSTEM_EVENT_FLAG_BLUETOOTH; //--// diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 2d1e666eb0..6dc60dfb84 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -3441,6 +3441,7 @@ typedef enum Events Event_SerialPortIn = 0x00000002, Event_SerialPortOut = 0x00000004, Event_EndPoint = 0x00000008, + Event_PicoPio = 0x00000010, Event_StorageIo = 0x00000020, Event_I2cMaster = 0x00000080, Event_SpiMaster = 0x00000100, diff --git a/src/HAL/Include/nanoHAL_v2.h b/src/HAL/Include/nanoHAL_v2.h index c3a637be4c..0ac96299fe 100644 --- a/src/HAL/Include/nanoHAL_v2.h +++ b/src/HAL/Include/nanoHAL_v2.h @@ -60,6 +60,7 @@ typedef enum SLEEP_LEVEL #define SYSTEM_EVENT_FLAG_COM_IN 0x00000001 #define SYSTEM_EVENT_FLAG_COM_OUT 0x00000002 #define SYSTEM_EVENT_FLAG_STORAGE_IO 0x00000004 +#define SYSTEM_EVENT_FLAG_PICOPIO 0x00000008 #define SYSTEM_EVENT_FLAG_SYSTEM_TIMER 0x00000010 #define SYSTEM_EVENT_FLAG_USB_IN 0x00000020 #define SYSTEM_EVENT_FLAG_USB_OUT 0x00000040 @@ -115,6 +116,7 @@ typedef enum SLEEP_LEVEL #define EVENT_TOUCH 120 #define EVENT_GESTURE 130 #define EVENT_OPENTHREAD 140 +#define EVENT_PICO_PIO 160 #define PAL_EVENT_TOUCH 0x1 #define PAL_EVENT_KEY 0x2 diff --git a/targets/ChibiOS/PICO2_RP2350/CMakeLists.txt b/targets/ChibiOS/PICO2_RP2350/CMakeLists.txt index eb45bed043..70de6f6efd 100644 --- a/targets/ChibiOS/PICO2_RP2350/CMakeLists.txt +++ b/targets/ChibiOS/PICO2_RP2350/CMakeLists.txt @@ -20,6 +20,10 @@ list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/Target_Bl list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_stubs.cpp") list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_core1_stubs.c") +# PIO LLD sources +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 @@ -31,6 +35,7 @@ nf_setup_target_build( CLR_EXTRA_COMPILE_DEFINITIONS -DRUNTIME_MEMORY_PROFILE__small=1 + -DRP_PIO_REQUIRED=1 # RP flash is XIP-mapped and shared with code execution; this flag enables # runtime handling that avoids USB/WP activity while XIP flash operations are in progress. -DTARGET_XIP_FLASH_BLOCKS_USB=1 diff --git a/targets/ChibiOS/PICO2_RP2350/README.md b/targets/ChibiOS/PICO2_RP2350/README.md index d8c9725567..c489342b69 100644 --- a/targets/ChibiOS/PICO2_RP2350/README.md +++ b/targets/ChibiOS/PICO2_RP2350/README.md @@ -134,6 +134,34 @@ int raw = tempChannel.ReadValue(); - **Resolution:** 12-bit (0–4095) - **Reference voltage:** 3.3V (internal) +### PIO (Programmable I/O) + +The RP2350's **three PIO blocks** (4 state machines each) are exposed through the `nanoFramework.Hardware.Pico` library. Write small PIO programs with the inline `PioAssembler`, load them onto a block and run them on a state machine — useful for precise or custom protocols (WS2812, bit-banged SPI/UART, etc.) the fixed peripherals don't cover. + +```csharp +using nanoFramework.Hardware.Pico.Pio; + +// pull a word and drive its low bit onto the OUT pin +var asm = new PioAssembler(); +PioLabel loop = asm.DefineLabel(); +asm.MarkLabel(loop); +asm.Pull(ifEmpty: false, block: true); +asm.Out(DestinationOperand.Pins, 1); +asm.Jmp(PioCondition.Always, loop); +PioProgram program = asm.Build(); + +PioBlock pio = Pio.Get(0); +uint offset = pio.AddProgram(program); +PioStateMachine sm = pio.ClaimStateMachine(); +sm.Init(offset, PioStateMachineConfig.FromProgram(program, (int)offset).OutPins(25, 1)); +pio.InitGpio(25); +sm.SetConsecutivePinDirs(25, 1, true); +sm.Enabled = true; +sm.Put(1); // drive the on-board LED +``` + +> Provided by the `nanoFramework.Hardware.Pico` NuGet package. State machine interrupts surface as the managed `PioBlock.Interrupt` event. + ## Pico Board Pinout Reference ``` @@ -182,6 +210,7 @@ Key CMake preset options (`CMakePresets.json`): "API_System.Device.I2c": "ON", "API_System.Device.Pwm": "ON", "API_System.Device.Adc": "ON", + "API_Hardware.Pico": "ON", "USE_RNG": "OFF" } ``` diff --git a/targets/ChibiOS/PICO2_RP2350/defconfig b/targets/ChibiOS/PICO2_RP2350/defconfig index a23ec3e4b3..34177cc1b0 100644 --- a/targets/ChibiOS/PICO2_RP2350/defconfig +++ b/targets/ChibiOS/PICO2_RP2350/defconfig @@ -9,6 +9,7 @@ CONFIG_API_SYSTEM_IO_PORTS=y CONFIG_API_NANOFRAMEWORK_RESOURCEMANAGER=y CONFIG_API_NANOFRAMEWORK_SYSTEM_COLLECTIONS=y CONFIG_API_NANOFRAMEWORK_SYSTEM_TEXT=y +CONFIG_API_HARDWARE_PICO=y # CONFIG_CHIBIOS_CONTRIB_REQUIRED is not set # CONFIG_CHIBIOS_SWO_OUTPUT is not set # CONFIG_NF_BUILD_RTM is not set diff --git a/targets/ChibiOS/PICO2_RP2350_W/defconfig b/targets/ChibiOS/PICO2_RP2350_W/defconfig index 33c68cebd1..20f2c2d88d 100644 --- a/targets/ChibiOS/PICO2_RP2350_W/defconfig +++ b/targets/ChibiOS/PICO2_RP2350_W/defconfig @@ -9,6 +9,7 @@ CONFIG_API_SYSTEM_DEVICE_WIFI=y CONFIG_API_SYSTEM_IO_FILESYSTEM=y CONFIG_API_SYSTEM_IO_PORTS=y CONFIG_API_SYSTEM_NET=y +CONFIG_API_HARDWARE_PICO=y CONFIG_API_NANOFRAMEWORK_RESOURCEMANAGER=y CONFIG_API_NANOFRAMEWORK_SYSTEM_COLLECTIONS=y CONFIG_API_NANOFRAMEWORK_SYSTEM_TEXT=y diff --git a/targets/ChibiOS/PICO_RP2040/CMakeLists.txt b/targets/ChibiOS/PICO_RP2040/CMakeLists.txt index 2d1856cd7f..a5491de8ea 100644 --- a/targets/ChibiOS/PICO_RP2040/CMakeLists.txt +++ b/targets/ChibiOS/PICO_RP2040/CMakeLists.txt @@ -19,6 +19,11 @@ list(APPEND TARGET_CHIBIOS_COMMON_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/comm list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/Target_BlockStorage_RP2040FlashDriver.c") list(APPEND TARGET_CHIBIOS_COMMON_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/target_stubs.cpp") + +# PIO LLD sources +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 @@ -31,6 +36,7 @@ nf_setup_target_build( CLR_EXTRA_COMPILE_DEFINITIONS -DRUNTIME_MEMORY_PROFILE__small=1 -DTARGET_XIP_FLASH_BLOCKS_USB=1 + -DRP_PIO_REQUIRED=1 LFS_CONFIG=lfs_config.h BOOTER_EXTRA_LINKMAP_PROPERTIES diff --git a/targets/ChibiOS/PICO_RP2040/README.md b/targets/ChibiOS/PICO_RP2040/README.md index 4418093ff4..6bb594addb 100644 --- a/targets/ChibiOS/PICO_RP2040/README.md +++ b/targets/ChibiOS/PICO_RP2040/README.md @@ -137,6 +137,34 @@ int raw = tempChannel.ReadValue(); - **Resolution:** 12-bit (0–4095) - **Reference voltage:** 3.3V (internal) +### PIO (Programmable I/O) + +The RP2040's **two PIO blocks** (4 state machines each) are exposed through the `nanoFramework.Hardware.Pico` library. Write small PIO programs with the inline `PioAssembler`, load them onto a block and run them on a state machine — useful for precise or custom protocols (WS2812, bit-banged SPI/UART, etc.) the fixed peripherals don't cover. + +```csharp +using nanoFramework.Hardware.Pico.Pio; + +// pull a word and drive its low bit onto the OUT pin +var asm = new PioAssembler(); +PioLabel loop = asm.DefineLabel(); +asm.MarkLabel(loop); +asm.Pull(ifEmpty: false, block: true); +asm.Out(DestinationOperand.Pins, 1); +asm.Jmp(PioCondition.Always, loop); +PioProgram program = asm.Build(); + +PioBlock pio = Pio.Get(0); +uint offset = pio.AddProgram(program); +PioStateMachine sm = pio.ClaimStateMachine(); +sm.Init(offset, PioStateMachineConfig.FromProgram(program, (int)offset).OutPins(25, 1)); +pio.InitGpio(25); +sm.SetConsecutivePinDirs(25, 1, true); +sm.Enabled = true; +sm.Put(1); // drive the on-board LED +``` + +> Provided by the `nanoFramework.Hardware.Pico` NuGet package. State machine interrupts surface as the managed `PioBlock.Interrupt` event. + ## Pico Board Pinout Reference ``` @@ -185,6 +213,7 @@ Key CMake preset options (`CMakePresets.json`): "API_System.Device.I2c": "ON", "API_System.Device.Pwm": "ON", "API_System.Device.Adc": "ON", + "API_Hardware.Pico": "ON", "USE_RNG": "OFF" } ``` diff --git a/targets/ChibiOS/PICO_RP2040/defconfig b/targets/ChibiOS/PICO_RP2040/defconfig index 50f77e58a9..a36ad109e1 100644 --- a/targets/ChibiOS/PICO_RP2040/defconfig +++ b/targets/ChibiOS/PICO_RP2040/defconfig @@ -6,6 +6,7 @@ CONFIG_API_SYSTEM_DEVICE_I2C=y CONFIG_API_SYSTEM_DEVICE_PWM=y CONFIG_API_SYSTEM_DEVICE_SPI=y CONFIG_API_SYSTEM_IO_PORTS=y +CONFIG_API_HARDWARE_PICO=y CONFIG_API_NANOFRAMEWORK_RESOURCEMANAGER=y CONFIG_API_NANOFRAMEWORK_SYSTEM_COLLECTIONS=y CONFIG_API_NANOFRAMEWORK_SYSTEM_TEXT=y diff --git a/targets/ChibiOS/PICO_RP2040_W/defconfig b/targets/ChibiOS/PICO_RP2040_W/defconfig index 5c5759133e..802c4522fd 100644 --- a/targets/ChibiOS/PICO_RP2040_W/defconfig +++ b/targets/ChibiOS/PICO_RP2040_W/defconfig @@ -9,6 +9,8 @@ CONFIG_API_SYSTEM_DEVICE_WIFI=y CONFIG_API_SYSTEM_IO_FILESYSTEM=y CONFIG_API_SYSTEM_IO_PORTS=y CONFIG_API_SYSTEM_NET=y +CONFIG_API_HARDWARE_PICO=y +CONFIG_API_HARDWARE_RP2040=y CONFIG_API_NANOFRAMEWORK_RESOURCEMANAGER=y CONFIG_API_NANOFRAMEWORK_SYSTEM_COLLECTIONS=y CONFIG_API_NANOFRAMEWORK_SYSTEM_TEXT=y diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico.cpp b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico.cpp new file mode 100644 index 0000000000..2276b877fb --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico.cpp @@ -0,0 +1,234 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include "nanoFramework_hardware_pico.h" + +// clang-format off + +static const CLR_RT_MethodHandler method_lookup[] = +{ + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_MinIndex___STATIC__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_BlockCount___STATIC__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_MaxPin___STATIC__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_SystemClock___STATIC__I4, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::AddProgram___U4__nanoFrameworkHardwarePicoPioPioProgram, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::RemoveProgram___VOID__nanoFrameworkHardwarePicoPioPioProgram__U4, + NULL, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::InitGpio___VOID__I4__nanoFrameworkHardwarePicoPioPioPinPull, + NULL, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::ForceIrq___VOID__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::ClearIrq___VOID__I4, + NULL, + NULL, + NULL, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::NativeClaimSm___I4__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::NativeSetIrqEnabled___VOID__BOOLEAN, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_Enabled___BOOLEAN, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::set_Enabled___VOID__BOOLEAN, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_IsTxFull___BOOLEAN, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_IsRxEmpty___BOOLEAN, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_TxLevel___U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_RxLevel___U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_ProgramCounter___U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_ClockDivisor___R4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::set_ClockDivisor___VOID__R4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Put___VOID__U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Get___U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::TryPut___BOOLEAN__U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::TryGet___BOOLEAN__BYREF_U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::ClearFifos___VOID, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::DrainTxFifo___VOID, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Restart___VOID, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::ClockDivRestart___VOID, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Exec___VOID__U2, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::SetConsecutivePinDirs___VOID__I4__I4__BOOLEAN, + NULL, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Read___I4__SZARRAY_U4__I4__I4__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Write___I4__SZARRAY_U4__I4__I4__I4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::NativeInit___VOID__I4__SZARRAY_U4, + Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::NativeUnclaim___VOID, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_nanoFramework_Hardware_Pico = +{ + "nanoFramework.Hardware.Pico", + 0xFC6F7F0C, + method_lookup, + { 1, 0, 0, 0 } +}; + +// clang-format on diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico.h b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico.h new file mode 100644 index 0000000000..ebc05923a9 --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico.h @@ -0,0 +1,360 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef NANOFRAMEWORK_HARDWARE_PICO_H +#define NANOFRAMEWORK_HARDWARE_PICO_H + +#include +#include +#include +#include + +typedef enum __nfpack DestinationOperand +{ + DestinationOperand_Pins = 0, + DestinationOperand_RegisterX = 1, + DestinationOperand_RegisterY = 2, + DestinationOperand_DiscardsData = 3, + DestinationOperand_PinDirs = 4, + DestinationOperand_Pc = 5, + DestinationOperand_Status = 5, + DestinationOperand_InputShiftRegister = 6, + DestinationOperand_OutputShiftRegister = 7, + DestinationOperand_Executes = 7, +} DestinationOperand; + +typedef enum __nfpack PioCondition +{ + PioCondition_Always = 0, + PioCondition_XZero = 1, + PioCondition_XPostDec = 2, + PioCondition_YZero = 3, + PioCondition_YPostDec = 4, + PioCondition_XNotEqualY = 5, + PioCondition_Pin = 6, + PioCondition_OsrNotEmpty = 7, +} PioCondition; + +typedef enum __nfpack PioFifoJoin +{ + PioFifoJoin_None = 0, + PioFifoJoin_Tx = 1, + PioFifoJoin_Rx = 2, + PioFifoJoin_TxGet = 4, + PioFifoJoin_TxPut = 8, + PioFifoJoin_PutGet = 12, +} PioFifoJoin; + +typedef enum __nfpack PioInterruptFlags +{ + PioInterruptFlags_None = 0, + PioInterruptFlags_Sm0 = 1, + PioInterruptFlags_Sm1 = 2, + PioInterruptFlags_Sm2 = 4, + PioInterruptFlags_Sm3 = 8, +} PioInterruptFlags; + +typedef enum __nfpack PioMovOp +{ + PioMovOp_None = 0, + PioMovOp_Invert = 1, + PioMovOp_BitReverse = 2, +} PioMovOp; + +typedef enum __nfpack PioMovStatusSel +{ + PioMovStatusSel_TxLevel = 0, + PioMovStatusSel_RxLevel = 1, +} PioMovStatusSel; + +typedef enum __nfpack PioPinPull +{ + PioPinPull_None = 0, + PioPinPull_Up = 1, + PioPinPull_Down = 2, +} PioPinPull; + +typedef enum __nfpack PioStateMachineIndex +{ + PioStateMachineIndex_Sm0 = 0, + PioStateMachineIndex_Sm1 = 1, + PioStateMachineIndex_Sm2 = 2, + PioStateMachineIndex_Sm3 = 3, + PioStateMachineIndex_Any = 4, +} PioStateMachineIndex; + +typedef enum __nfpack PioVersion +{ + PioVersion_Rp2040 = 0, + PioVersion_Rp2350 = 1, +} PioVersion; + +typedef enum __nfpack PioWaitSource +{ + PioWaitSource_Gpio = 0, + PioWaitSource_Pin = 1, + PioWaitSource_Irq = 2, +} PioWaitSource; + +typedef enum __nfpack ShiftDirection +{ + ShiftDirection_Left = 0, + ShiftDirection_Right = 1, +} ShiftDirection; + +typedef enum __nfpack SourceOperand +{ + SourceOperand_Pins = 0, + SourceOperand_RegisterX = 1, + SourceOperand_RegisterY = 2, + SourceOperand_Null = 3, + SourceOperand_Status = 5, + SourceOperand_InputShiftRegister = 6, + SourceOperand_OutputShiftRegister = 7, +} SourceOperand; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio +{ + static const int FIELD_STATIC___blocks = 0; + static const int FIELD_STATIC___lock = 1; + + NANOCLR_NATIVE_DECLARE(get_MinIndex___STATIC__I4); + NANOCLR_NATIVE_DECLARE(get_BlockCount___STATIC__I4); + NANOCLR_NATIVE_DECLARE(get_MaxPin___STATIC__I4); + NANOCLR_NATIVE_DECLARE(get_SystemClock___STATIC__I4); + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioAssemblerOptions +{ + // renamed backing field 'k__BackingField' + static const int FIELD__Version = 1; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetCount = 2; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetOption = 3; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetPinDirs = 4; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioInstructionRef +{ + static const int FIELD___owner = 1; + static const int FIELD___index = 2; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioLabel +{ + // renamed backing field 'k__BackingField' + static const int FIELD__Id = 1; + // renamed backing field 'k__BackingField' + static const int FIELD__Owner = 2; + // renamed backing field '
k__BackingField' + static const int FIELD__Address = 3; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioAssembler +{ + static const int FIELD___baseBits = 1; + static const int FIELD___delay = 2; + static const int FIELD___sideValue = 3; + static const int FIELD___sideUsed = 4; + static const int FIELD___jmpLabel = 5; + static const int FIELD___count = 6; + static const int FIELD___labelCount = 7; + static const int FIELD___version = 8; + static const int FIELD___sideSetCount = 9; + static const int FIELD___sideSetOpt = 10; + static const int FIELD___sideSetPinDirs = 11; + static const int FIELD___wrapTarget = 12; + static const int FIELD___wrap = 13; + static const int FIELD___origin = 14; + static const int FIELD___outShiftDir = 15; + static const int FIELD___autoPull = 16; + static const int FIELD___pullThreshold = 17; + static const int FIELD___inShiftDir = 18; + static const int FIELD___autoPush = 19; + static const int FIELD___pushThreshold = 20; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock +{ + static const int FIELD_STATIC__s_eventListener = 2; + + static const int FIELD___index = 1; + static const int FIELD___interruptCallbacks = 2; + static const int FIELD___irqLock = 3; + + NANOCLR_NATIVE_DECLARE(AddProgram___U4__nanoFrameworkHardwarePicoPioPioProgram); + NANOCLR_NATIVE_DECLARE(RemoveProgram___VOID__nanoFrameworkHardwarePicoPioPioProgram__U4); + NANOCLR_NATIVE_DECLARE(InitGpio___VOID__I4__nanoFrameworkHardwarePicoPioPioPinPull); + NANOCLR_NATIVE_DECLARE(ForceIrq___VOID__I4); + NANOCLR_NATIVE_DECLARE(ClearIrq___VOID__I4); + NANOCLR_NATIVE_DECLARE(NativeClaimSm___I4__I4); + NANOCLR_NATIVE_DECLARE(NativeSetIrqEnabled___VOID__BOOLEAN); + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioEvent +{ + static const int FIELD__BlockIndex = 3; + static const int FIELD__Flags = 4; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioEventListener +{ + static const int FIELD___pioMap = 1; + static const int FIELD___syncRoot = 2; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioProgramOptions +{ + // renamed backing field 'k__BackingField' + static const int FIELD__Version = 1; + // renamed backing field 'k__BackingField' + static const int FIELD__Origin = 2; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetCount = 3; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetOptional = 4; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetPinDirs = 5; + // renamed backing field 'k__BackingField' + static const int FIELD__OutShiftDir = 6; + // renamed backing field 'k__BackingField' + static const int FIELD__AutoPull = 7; + // renamed backing field 'k__BackingField' + static const int FIELD__PullThreshold = 8; + // renamed backing field 'k__BackingField' + static const int FIELD__InShiftDir = 9; + // renamed backing field 'k__BackingField' + static const int FIELD__AutoPush = 10; + // renamed backing field 'k__BackingField' + static const int FIELD__PushThreshold = 11; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioProgram +{ + // renamed backing field 'k__BackingField' + static const int FIELD__Instructions = 1; + // renamed backing field 'k__BackingField' + static const int FIELD__Wrap = 2; + // renamed backing field 'k__BackingField' + static const int FIELD__WrapTarget = 3; + // renamed backing field 'k__BackingField' + static const int FIELD__Origin = 4; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetCount = 5; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetOptional = 6; + // renamed backing field 'k__BackingField' + static const int FIELD__SideSetPinDirs = 7; + // renamed backing field 'k__BackingField' + static const int FIELD__OutShiftDir = 8; + // renamed backing field 'k__BackingField' + static const int FIELD__AutoPull = 9; + // renamed backing field 'k__BackingField' + static const int FIELD__PullThreshold = 10; + // renamed backing field 'k__BackingField' + static const int FIELD__InShiftDir = 11; + // renamed backing field 'k__BackingField' + static const int FIELD__AutoPush = 12; + // renamed backing field 'k__BackingField' + static const int FIELD__PushThreshold = 13; + // renamed backing field 'k__BackingField' + static const int FIELD__Version = 14; + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine +{ + static const int FIELD___block = 1; + static const int FIELD___sm = 2; + static const int FIELD___owned = 3; + static const int FIELD___disposed = 4; + static const int FIELD___enabled = 5; + + NANOCLR_NATIVE_DECLARE(get_Enabled___BOOLEAN); + NANOCLR_NATIVE_DECLARE(set_Enabled___VOID__BOOLEAN); + NANOCLR_NATIVE_DECLARE(get_IsTxFull___BOOLEAN); + NANOCLR_NATIVE_DECLARE(get_IsRxEmpty___BOOLEAN); + NANOCLR_NATIVE_DECLARE(get_TxLevel___U4); + NANOCLR_NATIVE_DECLARE(get_RxLevel___U4); + NANOCLR_NATIVE_DECLARE(get_ProgramCounter___U4); + NANOCLR_NATIVE_DECLARE(get_ClockDivisor___R4); + NANOCLR_NATIVE_DECLARE(set_ClockDivisor___VOID__R4); + NANOCLR_NATIVE_DECLARE(Put___VOID__U4); + NANOCLR_NATIVE_DECLARE(Get___U4); + NANOCLR_NATIVE_DECLARE(TryPut___BOOLEAN__U4); + NANOCLR_NATIVE_DECLARE(TryGet___BOOLEAN__BYREF_U4); + NANOCLR_NATIVE_DECLARE(ClearFifos___VOID); + NANOCLR_NATIVE_DECLARE(DrainTxFifo___VOID); + NANOCLR_NATIVE_DECLARE(Restart___VOID); + NANOCLR_NATIVE_DECLARE(ClockDivRestart___VOID); + NANOCLR_NATIVE_DECLARE(Exec___VOID__U2); + NANOCLR_NATIVE_DECLARE(SetConsecutivePinDirs___VOID__I4__I4__BOOLEAN); + NANOCLR_NATIVE_DECLARE(Read___I4__SZARRAY_U4__I4__I4__I4); + NANOCLR_NATIVE_DECLARE(Write___I4__SZARRAY_U4__I4__I4__I4); + NANOCLR_NATIVE_DECLARE(NativeInit___VOID__I4__SZARRAY_U4); + NANOCLR_NATIVE_DECLARE(NativeUnclaim___VOID); + + //--// +}; + +struct Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachineConfig +{ + static const int FIELD___outBase = 1; + static const int FIELD___outCount = 2; + static const int FIELD___setBase = 3; + static const int FIELD___setCount = 4; + static const int FIELD___sideSetBase = 5; + static const int FIELD___inBase = 6; + static const int FIELD___inBaseSet = 7; + static const int FIELD___jmpPin = 8; + static const int FIELD___jmpPinSet = 9; + static const int FIELD___sideSetCount = 10; + static const int FIELD___sideSetOpt = 11; + static const int FIELD___sideSetPinDirs = 12; + static const int FIELD___outShiftDir = 13; + static const int FIELD___autoPull = 14; + static const int FIELD___pullThreshold = 15; + static const int FIELD___inShiftDir = 16; + static const int FIELD___autoPush = 17; + static const int FIELD___pushThreshold = 18; + static const int FIELD___wrapTarget = 19; + static const int FIELD___wrap = 20; + static const int FIELD___clkDivInt = 21; + static const int FIELD___clkDivFrac = 22; + static const int FIELD___fifoJoin = 23; + static const int FIELD___gpioBase = 24; + static const int FIELD___movStatusSel = 25; + static const int FIELD___movStatusN = 26; + static const int FIELD___outSticky = 27; + static const int FIELD___inlineOutEn = 28; + static const int FIELD___outEnSel = 29; + + //--// +}; + +extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_nanoFramework_Hardware_Pico; + +#endif // NANOFRAMEWORK_HARDWARE_PICO_H diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio.cpp b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio.cpp new file mode 100644 index 0000000000..9e76ae58a3 --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio.cpp @@ -0,0 +1,48 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include "nanoFramework_hardware_pico.h" +#include "nanoFramework_hardware_pico_target.h" +#include + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_MinIndex___STATIC__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + stack.SetResult_I4(PIO_MIN_BLOCK); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_BlockCount___STATIC__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + stack.SetResult_I4(PIO_MAX_BLOCK + 1); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_MaxPin___STATIC__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + stack.SetResult_I4(PIO_MAX_PIN); + + NANOCLR_NOCLEANUP_NOLABEL(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_Pio::get_SystemClock___STATIC__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + stack.SetResult_I4(static_cast(RP_CORE_CLK)); + + NANOCLR_NOCLEANUP_NOLABEL(); +} diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock.cpp b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock.cpp new file mode 100644 index 0000000000..65427ef884 --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock.cpp @@ -0,0 +1,309 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include "nanoFramework_hardware_pico.h" +#include "nanoFramework_hardware_pico_target.h" +#if defined(RP2350) +#include "rp2350.h" +#else +#include "rp2040.h" +#endif + +#define EVENT_TYPE_PICO_PIO 160 + +const rp_pio_sm_t *g_AllocatedSMs[3][4] = {{nullptr}}; + +static void PioChibiOSCallback(void *param, const uint32_t flags) +{ + const int block = reinterpret_cast(param); + PIO_TypeDef *pio = __rp_pio_blocks[block].pio; + + // IRQ0_INTS bits [11:8] are the SM-raised flags, IRQ holds the same flags live + + if (const uint32_t fifoFlags = flags & 0xFFu; fifoFlags != 0u) + { + NfPioBlockDisableInterrupt(&__rp_pio_blocks[block], fifoFlags); + Events_Set(SYSTEM_EVENT_FLAG_PICOPIO); + } + + const uint32_t live = (flags >> 8) & 0x0Fu; + const uint32_t latched = live & pio->IRQ; + const uint32_t forced = live & pio->IRQ_FORCE; + const uint32_t smFlags = latched | forced; + + if (smFlags == 0u) + { + return; + } + + if (latched != 0u) + { + pio->IRQ = latched; + } + + if (forced != 0u) + { + pio->CLR.IRQ_FORCE = forced; + } + + PostManagedEvent(EVENT_PICO_PIO, EVENT_TYPE_PICO_PIO, static_cast(block), smFlags); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock:: + AddProgram___U4__nanoFrameworkHardwarePicoPioPioProgram(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + rp_pio_program_t prog; + int offset, origin, length; + uint8_t block; + CLR_RT_HeapBlock_Array *program_array; + + CLR_RT_HeapBlock *pProgram = stack.Arg1().Dereference(); + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + VALIDATE_PIO_BLOCK(block); + + program_array = + pProgram + [Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioProgram::FIELD__Instructions] + .DereferenceArray(); + + FAULT_ON_NULL(program_array); + + length = static_cast(program_array->m_numOfElements); + origin = + pProgram[Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioProgram::FIELD__Origin] + .NumericByRef() + .s4; + + if (program_array == nullptr || length <= 0 || length > 32 || + static_cast(program_array->m_numOfElements) < length) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + prog.instructions = reinterpret_cast(program_array->GetFirstElement()); + prog.length = length; + prog.origin = origin; + + offset = pioProgramLoad(&__rp_pio_blocks[block], &prog); + + if (offset < 0) + { + // No memory left + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION); + } + + stack.SetResult_I4(offset); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock:: + RemoveProgram___VOID__nanoFrameworkHardwarePicoPioPioProgram__U4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + uint8_t block; + int length; + CLR_RT_HeapBlock_Array *program; + + const CLR_RT_HeapBlock *pProgram = stack.Arg1().Dereference(); + const int offset = stack.Arg2().NumericByRef().s4; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + program = + pProgram + [Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioProgram::FIELD__Instructions] + .DereferenceArray(); + + FAULT_ON_NULL(program); + + length = static_cast(program->m_numOfElements); + + VALIDATE_PIO_BLOCK(block); + + if (offset < 0 || length <= 0 || length > 32 || offset > 32 - length) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + pioProgramUnload(&__rp_pio_blocks[block], offset, length); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::NativeClaimSm___I4__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int block; + const rp_pio_sm_t *smp; + + const int wanted = stack.Arg1().NumericByRef().s4; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + VALIDATE_PIO_BLOCK(block); + + if (wanted != static_cast(RP_PIO_SM_ID_ANY)) + { + VALIDATE_SM(wanted); + } + + smp = pioSmAlloc( + &__rp_pio_blocks[block], + static_cast(wanted), + NF_PICO_PIO_IRQ_PRIORITY, + PioChibiOSCallback, + reinterpret_cast(static_cast(block))); + + if (smp == nullptr) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION); + } + + g_AllocatedSMs[block][smp->smidx] = smp; + + stack.SetResult_I4(static_cast(smp->smidx)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::InitGpio___VOID__I4__nanoFrameworkHardwarePicoPioPioPinPull( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int block; + uint32_t padbits = RP_PIO_PAD_DEFAULT; + + const int pin = stack.Arg1().NumericByRef().s4; + const int pull = stack.Arg2().NumericByRef().s4; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + VALIDATE_PIO_BLOCK(block); + + if (pin < 0 || pin > PIO_MAX_PIN) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + if (pull == 1) + { + padbits |= RP_PIO_PAD_PUE; + } + else if (pull == 2) + { + padbits |= RP_PIO_PAD_PDE; + } + else if (pull != 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + NfPioBlockGpioInit(&__rp_pio_blocks[block], static_cast(pin), padbits); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::ForceIrq___VOID__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int block; + + const int irq = stack.Arg1().NumericByRef().s4; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + VALIDATE_PIO_BLOCK(block); + + if (irq < 0 || irq > 7) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + NfPioBlockForceIrq(&__rp_pio_blocks[block], static_cast(irq)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::ClearIrq___VOID__I4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int block; + + const int irq = stack.Arg1().NumericByRef().s4; + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + VALIDATE_PIO_BLOCK(block); + + if (irq < 0 || irq > 7) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + NfPioBlockClearIrq(&__rp_pio_blocks[block], static_cast(irq)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock:: + NativeSetIrqEnabled___VOID__BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + int block; + + const uint32_t mask = PIO_IRQ_SM(0) | PIO_IRQ_SM(1) | PIO_IRQ_SM(2) | PIO_IRQ_SM(3); + + const bool enabled = static_cast(stack.Arg1().NumericByRef().u1); + + CLR_RT_HeapBlock *pThis = stack.This(); + FAULT_ON_NULL(pThis); + + block = pThis[FIELD___index].NumericByRef().s4; + + VALIDATE_PIO_BLOCK(block); + + if (enabled) + { + NfPioBlockEnableInterrupt(&__rp_pio_blocks[block], mask); + } + else + { + NfPioBlockDisableInterrupt(&__rp_pio_blocks[block], mask); + } + + NANOCLR_NOCLEANUP(); +} diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine.cpp b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine.cpp new file mode 100644 index 0000000000..5def2793c2 --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine.cpp @@ -0,0 +1,830 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#include "nanoFramework_hardware_pico.h" +#if defined(RP2350) +#include "rp2350.h" +#else +#include "rp2040.h" +#endif +#include "nanoFramework_hardware_pico_target.h" +#include +#include +#include +#include + +enum PioCfgBlob +{ + PIO_CFG_OUT_BASE = 0, + PIO_CFG_OUT_COUNT = 1, + PIO_CFG_SET_BASE = 2, + PIO_CFG_SET_COUNT = 3, + PIO_CFG_SIDESET_BASE = 4, + PIO_CFG_SIDESET_COUNT = 5, + PIO_CFG_SIDESET_OPT = 6, + PIO_CFG_SIDESET_PINDIRS = 7, + PIO_CFG_IN_BASE = 8, + PIO_CFG_JMP_PIN = 9, + PIO_CFG_OUT_SHIFT_RIGHT = 10, + PIO_CFG_AUTOPULL = 11, + PIO_CFG_PULL_THRESHOLD = 12, + PIO_CFG_IN_SHIFT_RIGHT = 13, + PIO_CFG_AUTOPUSH = 14, + PIO_CFG_PUSH_THRESHOLD = 15, + PIO_CFG_WRAP_TARGET = 16, + PIO_CFG_WRAP = 17, + PIO_CFG_CLKDIV_INT = 18, + PIO_CFG_CLKDIV_FRAC = 19, + PIO_CFG_FIFO_JOIN = 20, + PIO_CFG_GPIO_BASE = 21, + PIO_CFG_MOV_STATUS_SEL = 22, + PIO_CFG_MOV_STATUS_N = 23, + PIO_CFG_OUT_STICKY = 24, + PIO_CFG_INLINE_OUT_EN = 25, + PIO_CFG_OUT_EN_SEL = 26, + PIO_CFG_BLOB_LENGTH = 27, +}; + +static inline unsigned int PioRelPin(unsigned int gpio, unsigned int gpioBase) +{ + return (gpio >= gpioBase && (gpio - gpioBase) < 32u) ? (gpio - gpioBase) : (gpio & 0x1Fu); +} + +static inline unsigned int PioShiftThreshold(unsigned int threshold) +{ + return (threshold == 0u || threshold > 32u) ? 32u : threshold; +} + +enum PioFifoDir +{ + PioFifoRx = 0, + PioFifoTx = 1, +}; + +struct PioDmaWork +{ + const rp_dma_channel_t *Channel; + uint32_t *Buffer; + uint32_t Count; + uint32_t Status; +}; + +static PioDmaWork g_PioDmaWork[3][4][2] = {}; + +#define PIO_DMA_ERROR_MASK (DMA_CTRL_TRIG_AHB_ERROR | DMA_CTRL_TRIG_READ_ERROR | DMA_CTRL_TRIG_WRITE_ERROR) + +static void PioDmaCallback(void *p, const uint32_t ct) +{ + + if (auto *work = static_cast(p); work != nullptr) + { + work->Status = ct & PIO_DMA_ERROR_MASK; + } + + Events_Set(SYSTEM_EVENT_FLAG_PICOPIO); +} + +// Stops a transfer and gives the channel and bounce buffer back. +static void PioDmaFinish(PioDmaWork *work) +{ + const rp_dma_channel_t *ch = work->Channel; + + if (ch == nullptr) + { + return; + } + + if (dmaChannelIsBusyX(ch)) + { + dmaChannelDisableX(ch); + } + + (void)dmaChannelGetAndClearInterrupts(ch); + dmaChannelFree(ch); + + if (work->Buffer != nullptr) + { + platform_free(work->Buffer); + } + + work->Channel = nullptr; + work->Buffer = nullptr; + work->Count = 0; + work->Status = 0; +} + +// Aborts and releases both directions of a state machine. +void PioDmaReleaseSm(const int block, const int sm) +{ + PioDmaFinish(&g_PioDmaWork[block][sm][PioFifoRx]); + PioDmaFinish(&g_PioDmaWork[block][sm][PioFifoTx]); +} + +// Arms a channel to move count words between the state machine FIFO and the bounce buffer. +static void PioDmaArm( + const rp_dma_channel_t *ch, + const rp_pio_sm_t *smp, + const PioFifoDir dir, + uint32_t *buf, + const uint32_t count) +{ + if (dir == PioFifoRx) + { + dmaChannelSetSourceX(ch, reinterpret_cast(pioSmRxFifoAddrX(smp))); + dmaChannelSetDestinationX(ch, reinterpret_cast(buf)); + dmaChannelSetCounterX(ch, count); + dmaChannelSetModeX( + ch, + DMA_CTRL_TRIG_DATA_SIZE_WORD | DMA_CTRL_TRIG_INCR_WRITE | DMA_CTRL_TRIG_TREQ_SEL(pioSmRxDreqX(smp))); + } + else + { + dmaChannelSetSourceX(ch, reinterpret_cast(buf)); + dmaChannelSetDestinationX(ch, reinterpret_cast(pioSmTxFifoAddrX(smp))); + dmaChannelSetCounterX(ch, count); + dmaChannelSetModeX( + ch, + DMA_CTRL_TRIG_DATA_SIZE_WORD | DMA_CTRL_TRIG_INCR_READ | DMA_CTRL_TRIG_TREQ_SEL(pioSmTxDreqX(smp))); + } + dmaChannelEnableInterruptX(ch); + dmaChannelEnableX(ch); +} + +// Shared body of Read and Write. +static HRESULT PioDmaTransfer(CLR_RT_StackFrame &stack, const PioFifoDir dir) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + CLR_RT_HeapBlock hbTimeout{}; + CLR_INT64 *timeoutTicks; + CLR_RT_HeapBlock_Array *buffer; + PioDmaWork *work; + PioDmaWork *ownedWork = nullptr; + uint32_t dmaStatus = 0; + bool eventResult = true; + bool timeoutPushed = false; + int transferred = 0; + int offset, count, timeoutMs; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + buffer = stack.Arg1().DereferenceArray(); + offset = stack.Arg2().NumericByRef().s4; + count = stack.Arg3().NumericByRef().s4; + timeoutMs = stack.Arg4().NumericByRef().s4; + + FAULT_ON_NULL(buffer); + + if (offset < 0 || count < 0 || timeoutMs < 0 || count > static_cast(buffer->m_numOfElements) || + offset > static_cast(buffer->m_numOfElements) - count) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + if (count == 0) + { + stack.SetResult_I4(0); + NANOCLR_SET_AND_LEAVE(S_OK); + } + + work = &g_PioDmaWork[ctx.block][ctx.sm][dir]; + + if (stack.m_customState != 1) + { + ownedWork = work; + } + + hbTimeout.SetInteger(static_cast(timeoutMs) * TIME_CONVERSION__TO_MILLISECONDS); + NANOCLR_CHECK_HRESULT(stack.SetupTimeoutFromTicks(hbTimeout, timeoutTicks)); + timeoutPushed = true; + + if (stack.m_customState == 1) + { + if (work->Channel != nullptr) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION); + } + + const rp_dma_channel_t *ch = + dmaChannelAlloc(RP_DMA_CHANNEL_ID_ANY, NF_PICO_PIO_IRQ_PRIORITY, PioDmaCallback, work); + if (ch == nullptr) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_OPERATION); + } + + const auto buf = static_cast(platform_malloc(static_cast(count) * sizeof(uint32_t))); + if (buf == nullptr) + { + dmaChannelFree(ch); + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_MEMORY); + } + + if (dir == PioFifoTx) + { + memcpy( + buf, + buffer->GetFirstElement() + static_cast(offset) * sizeof(uint32_t), + static_cast(count) * sizeof(uint32_t)); + } + + work->Channel = ch; + work->Buffer = buf; + work->Count = static_cast(count); + work->Status = 0; + ownedWork = work; + + PioDmaArm(ch, ctx.smp, dir, buf, static_cast(count)); + + Events_Get(SYSTEM_EVENT_FLAG_PICOPIO); + stack.m_customState = 2; + } + + while (work->Channel != nullptr && dmaChannelIsBusyX(work->Channel)) + { + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.WaitEvents(stack.m_owningThread, *timeoutTicks, Event_PicoPio, eventResult)); + + if (!eventResult) + { + break; + } + } + + if (work->Channel != nullptr) + { + const uint32_t remaining = NfDmaChannelGetCounter(work->Channel); + + dmaStatus = work->Status; + transferred = static_cast(work->Count - (remaining > work->Count ? work->Count : remaining)); + + if (dir == PioFifoRx && transferred > 0) + { + memcpy( + buffer->GetFirstElement() + static_cast(offset) * sizeof(uint32_t), + work->Buffer, + static_cast(transferred) * sizeof(uint32_t)); + } + + PioDmaFinish(work); + } + + stack.PopValue(); + timeoutPushed = false; + + if (dmaStatus != 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_FAIL); + } + + stack.SetResult_I4(transferred); + + NANOCLR_CLEANUP(); + + if (hr != CLR_E_THREAD_WAITING) + { + if (timeoutPushed) + { + stack.PopValue(); + } + + if (ownedWork != nullptr) + { + PioDmaFinish(ownedWork); + } + } + + NANOCLR_CLEANUP_END(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + NativeInit___VOID__I4__SZARRAY_U4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + rp_pio_sm_config_t cfg; + CLR_RT_HeapBlock_Array *blobArray; + const unsigned int *b; + unsigned int gpioBase; + int offset; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + offset = stack.Arg1().NumericByRef().s4; + blobArray = stack.Arg2().DereferenceArray(); + + FAULT_ON_NULL(blobArray); + + if (offset < 0 || offset >= static_cast(RP_PIO_NUM_INSTR_MEM)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + if (static_cast(blobArray->m_numOfElements) < PIO_CFG_BLOB_LENGTH) + { + NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER); + } + + b = reinterpret_cast(blobArray->GetFirstElement()); + +#if defined(RP2350) + gpioBase = (b[PIO_CFG_GPIO_BASE] == 16) ? 16u : 0u; + ctx.smp->block->pio->GPIOBASE = gpioBase; +#else + gpioBase = 0; +#endif + + pioSmConfigDefaultX(&cfg); + + pioSmConfigSetClkdivX(&cfg, b[PIO_CFG_CLKDIV_INT] & 0xFFFFu, b[PIO_CFG_CLKDIV_FRAC] & 0xFFu); + pioSmConfigSetWrapX(&cfg, b[PIO_CFG_WRAP_TARGET] & 0x1Fu, b[PIO_CFG_WRAP] & 0x1Fu); + + pioSmConfigSetOutPinsX(&cfg, PioRelPin(b[PIO_CFG_OUT_BASE], gpioBase), b[PIO_CFG_OUT_COUNT] & 0x3Fu); + pioSmConfigSetSetPinsX(&cfg, PioRelPin(b[PIO_CFG_SET_BASE], gpioBase), b[PIO_CFG_SET_COUNT] & 0x7u); + pioSmConfigSetInPinsX(&cfg, PioRelPin(b[PIO_CFG_IN_BASE], gpioBase)); + pioSmConfigSetJmpPinX(&cfg, PioRelPin(b[PIO_CFG_JMP_PIN], gpioBase)); + + pioSmConfigSetSidesetX( + &cfg, + (b[PIO_CFG_SIDESET_COUNT] + b[PIO_CFG_SIDESET_OPT]) & 0x7u, + b[PIO_CFG_SIDESET_OPT] != 0, + b[PIO_CFG_SIDESET_PINDIRS] != 0); + pioSmConfigSetSidesetPinsX(&cfg, PioRelPin(b[PIO_CFG_SIDESET_BASE], gpioBase)); + + pioSmConfigSetInShiftX( + &cfg, + b[PIO_CFG_IN_SHIFT_RIGHT] != 0, + b[PIO_CFG_AUTOPUSH] != 0, + PioShiftThreshold(b[PIO_CFG_PUSH_THRESHOLD])); + pioSmConfigSetOutShiftX( + &cfg, + b[PIO_CFG_OUT_SHIFT_RIGHT] != 0, + b[PIO_CFG_AUTOPULL] != 0, + PioShiftThreshold(b[PIO_CFG_PULL_THRESHOLD])); + + NfPioSmConfigSetFifoJoin(&cfg, b[PIO_CFG_FIFO_JOIN]); + + pioSmConfigSetMovStatusX( + &cfg, + static_cast(b[PIO_CFG_MOV_STATUS_SEL]), + b[PIO_CFG_MOV_STATUS_N] & (PIO_SM_EXECCTRL_STATUS_N_Msk >> PIO_SM_EXECCTRL_STATUS_N_Pos)); + + pioSmConfigSetOutSpecialX( + &cfg, + b[PIO_CFG_OUT_STICKY] != 0, + b[PIO_CFG_INLINE_OUT_EN] != 0, + b[PIO_CFG_OUT_EN_SEL] & 0x1Fu); + + pioSmInit(ctx.smp, static_cast(offset), &cfg); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + get_Enabled___BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + CLR_RT_HeapBlock *pThis = stack.This(); + VALIDATE_NOT_DISPOSED(pThis); + + stack.SetResult_Boolean(pThis[FIELD___enabled].NumericByRef().u1); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + set_Enabled___VOID__BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + bool value; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + value = stack.Arg1().NumericByRef().u1; + + stack.This()[FIELD___enabled].NumericByRef().u1 = value; + + if (value) + { + pioSmEnableX(ctx.smp); + } + else + { + pioSmDisableX(ctx.smp); + } + + NANOCLR_NOCLEANUP(); +} + +static inline bool PioFifoBlocked(const rp_pio_sm_t *smp, const PioFifoDir dir) +{ + return (dir == PioFifoTx) ? pioSmIsTxFullX(smp) : pioSmIsRxEmptyX(smp); +} + +static HRESULT PioFifoTransfer(CLR_RT_StackFrame &stack, const PioFifoDir dir) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + CLR_RT_HeapBlock hbTimeout{}; + CLR_INT64 *timeoutTicks; + const rp_pio_block_t *blockp = nullptr; + uint32_t inteMask = 0; + bool eventResult = true; + bool timeoutPushed = false; + bool interruptEnabled = false; + bool blocked; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + blockp = &__rp_pio_blocks[ctx.block]; + inteMask = (dir == PioFifoTx) ? PIO_IRQ_TXNFULL(ctx.sm) : PIO_IRQ_RXNEMPTY(ctx.sm); + + hbTimeout.SetInteger(static_cast(NF_PICO_PIO_FIFO_TIMEOUT_MS) * TIME_CONVERSION__TO_MILLISECONDS); + NANOCLR_CHECK_HRESULT(stack.SetupTimeoutFromTicks(hbTimeout, timeoutTicks)); + timeoutPushed = true; + + if (stack.m_customState == 1) + { + Events_Get(SYSTEM_EVENT_FLAG_PICOPIO); + stack.m_customState = 2; + } + + while (PioFifoBlocked(ctx.smp, dir)) + { + NfPioBlockEnableInterrupt(blockp, inteMask); + interruptEnabled = true; + + NANOCLR_CHECK_HRESULT( + g_CLR_RT_ExecutionEngine.WaitEvents(stack.m_owningThread, *timeoutTicks, Event_PicoPio, eventResult)); + + if (!eventResult) + { + break; + } + } + + NfPioBlockDisableInterrupt(blockp, inteMask); + interruptEnabled = false; + + blocked = PioFifoBlocked(ctx.smp, dir); + + stack.PopValue(); + timeoutPushed = false; + + if (blocked) + { + NANOCLR_SET_AND_LEAVE(CLR_E_TIMEOUT); + } + + if (dir == PioFifoTx) + { + pioSmPutX(ctx.smp, stack.Arg1().NumericByRef().u4); + } + else + { + stack.SetResult_U4(pioSmGetX(ctx.smp)); + } + + NANOCLR_CLEANUP(); + + if (hr != CLR_E_THREAD_WAITING) + { + if (interruptEnabled) + { + NfPioBlockDisableInterrupt(blockp, inteMask); + } + + if (timeoutPushed) + { + stack.PopValue(); + } + } + + NANOCLR_CLEANUP_END(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Put___VOID__U4( + CLR_RT_StackFrame &stack) +{ + return PioFifoTransfer(stack, PioFifoTx); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Get___U4( + CLR_RT_StackFrame &stack) +{ + return PioFifoTransfer(stack, PioFifoRx); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + TryPut___BOOLEAN__U4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + if (pioSmIsTxFullX(ctx.smp)) + { + stack.SetResult_Boolean(false); + NANOCLR_SET_AND_LEAVE(S_OK); + } + + pioSmPutX(ctx.smp, stack.Arg1().NumericByRef().u4); + stack.SetResult_Boolean(true); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + TryGet___BOOLEAN__BYREF_U4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + CLR_RT_HeapBlock *value; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + value = stack.Arg1().Dereference(); + FAULT_ON_NULL(value); + + if (pioSmIsRxEmptyX(ctx.smp)) + { + value->NumericByRef().u4 = 0; + stack.SetResult_Boolean(false); + NANOCLR_SET_AND_LEAVE(S_OK); + } + + value->NumericByRef().u4 = pioSmGetX(ctx.smp); + stack.SetResult_Boolean(true); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + get_IsTxFull___BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + stack.SetResult_Boolean(pioSmIsTxFullX(ctx.smp)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + get_IsRxEmpty___BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + stack.SetResult_Boolean(pioSmIsRxEmptyX(ctx.smp)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + NativeUnclaim___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_TEARDOWN_PROLOGUE(ctx); + + pioSmDisableX(ctx.smp); + PioDmaReleaseSm(ctx.block, ctx.sm); + pioSmFree(ctx.smp); + g_AllocatedSMs[ctx.block][ctx.sm] = nullptr; + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + SetConsecutivePinDirs___VOID__I4__I4__BOOLEAN(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + int basePin, count, gpioBase; + bool output; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + basePin = stack.Arg1().NumericByRef().s4; + count = stack.Arg2().NumericByRef().s4; + output = stack.Arg3().NumericByRef().u1 != 0; + + if (count == 0) + { + NANOCLR_SET_AND_LEAVE(S_OK); + } + +#if defined(RP2350) + gpioBase = static_cast(ctx.smp->block->pio->GPIOBASE); +#else + gpioBase = 0; +#endif + + if (basePin < 0 || basePin > PIO_MAX_PIN || count < 0 || count > 32 || (basePin + count) > (PIO_MAX_PIN + 1) || + basePin < gpioBase || (basePin - gpioBase + count) > 32) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + pioSmSetConsecutivePindirsX(ctx.smp, static_cast(basePin), static_cast(count), output); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::ClearFifos___VOID( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + pioSmClearFifosX(ctx.smp); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::DrainTxFifo___VOID( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + if (!NfPioSmDrainTxFifo(ctx.smp, NF_PICO_PIO_DRAIN_LIMIT)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_TIMEOUT); + } + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Restart___VOID( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + pioSmRestartX(ctx.smp); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + ClockDivRestart___VOID(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + pioSmClkdivRestartX(ctx.smp); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::Exec___VOID__U2( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + pioSmExecX(ctx.smp, stack.Arg1().NumericByRef().u2); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_TxLevel___U4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + stack.SetResult_U4(pioSmTxFifoLevelX(ctx.smp)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::get_RxLevel___U4( + CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + stack.SetResult_U4(pioSmRxFifoLevelX(ctx.smp)); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + get_ProgramCounter___U4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + stack.SetResult_U4(pioSmGetAddrX(ctx.smp) & 0x1Fu); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + get_ClockDivisor___R4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + uint32_t clkdiv, intPart, frac; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + clkdiv = ctx.smp->block->pio->SM[ctx.smp->smidx].CLKDIV; + intPart = (clkdiv & PIO_SM_CLKDIV_INT_Msk) >> PIO_SM_CLKDIV_INT_Pos; + frac = (clkdiv & PIO_SM_CLKDIV_FRAC_Msk) >> PIO_SM_CLKDIV_FRAC_Pos; + + stack.SetResult_R4((intPart == 0u ? 65536.0f : static_cast(intPart)) + static_cast(frac) / 256.0f); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + set_ClockDivisor___VOID__R4(CLR_RT_StackFrame &stack) +{ + NANOCLR_HEADER(); + + PioSmContext ctx{}; + int intPart, frac; + float value; + + NANOCLR_PIO_SM_PROLOGUE(ctx); + + value = stack.Arg1().NumericByRef().r4; + + if (!(value >= 1.0f && value <= 65536.0f)) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); + } + + intPart = static_cast(value); + frac = static_cast(roundf((value - static_cast(intPart)) * 256.0f)); + if (frac > 255) + { + frac = 0; + intPart += 1; + } + + pioSmSetClkdivX(ctx.smp, PIO_SM_CLKDIV(intPart >= 65536 ? 0 : intPart, frac)); + pioSmClkdivRestartX(ctx.smp); + + NANOCLR_NOCLEANUP(); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + Read___I4__SZARRAY_U4__I4__I4__I4(CLR_RT_StackFrame &stack) +{ + return PioDmaTransfer(stack, PioFifoRx); +} + +HRESULT Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + Write___I4__SZARRAY_U4__I4__I4__I4(CLR_RT_StackFrame &stack) +{ + return PioDmaTransfer(stack, PioFifoTx); +} diff --git a/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_target.h b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_target.h new file mode 100644 index 0000000000..927176a465 --- /dev/null +++ b/targets/ChibiOS/_nanoCLR/nanoFramework.Hardware.Pico/nanoFramework_hardware_pico_target.h @@ -0,0 +1,231 @@ +// +// Copyright (c) .NET Foundation and Contributors +// See LICENSE file in the project root for full license information. +// + +#ifndef NANOFRAMEWORK_HARDWARE_PICO_TARGET_H +#define NANOFRAMEWORK_HARDWARE_PICO_TARGET_H + +#include +#include +#include +#include + +#if defined(RP2350) +#define PIO_MAX_BLOCK 2 +#define PIO_MAX_PIN 47 +#else +#define PIO_MAX_BLOCK 1 +#define PIO_MAX_PIN 29 +#endif + +#if defined(TARGET_HAS_WIFI) +#define PIO_MIN_BLOCK 1 +#else +#define PIO_MIN_BLOCK 0 +#endif + +#define NF_PICO_PIO_IRQ_PRIORITY 3 +#define NF_PICO_PIO_FIFO_TIMEOUT_MS 1000u +#define NF_PICO_PIO_DRAIN_LIMIT 0x10000u + +#define VALIDATE_PIO_BLOCK(block) \ + if ((block) < 0 || (block) > PIO_MAX_BLOCK) \ + { \ + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); \ + } \ + if ((block) < PIO_MIN_BLOCK) \ + { \ + NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED); \ + } + +#define VALIDATE_SM(sm) \ + if ((sm) < 0 || (sm) > 3) \ + { \ + NANOCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE); \ + } + +#define VALIDATE_NOT_DISPOSED(pThis) \ + FAULT_ON_NULL(pThis); \ + if (pThis[FIELD___disposed].NumericByRef().u1 != 0) \ + { \ + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); \ + } + +extern const rp_pio_sm_t *g_AllocatedSMs[3][4]; +void PioDmaReleaseSm(int block, int sm); + +struct PioSmContext +{ + const rp_pio_sm_t *smp; + int block; + int sm; +}; + +inline HRESULT PioGetSmContext(CLR_RT_HeapBlock *pThis, PioSmContext &ctx, const bool allowDisposed = false) +{ + NANOCLR_HEADER(); + + CLR_RT_HeapBlock *pPioBlock; + + FAULT_ON_NULL(pThis); + + if (!allowDisposed && + pThis[Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine:: + FIELD___disposed] + .NumericByRef() + .u1 != 0) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + pPioBlock = + pThis[Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::FIELD___block] + .Dereference(); + FAULT_ON_NULL(pPioBlock); + + ctx.block = + pPioBlock[Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioBlock::FIELD___index] + .NumericByRef() + .s4; + ctx.sm = + pThis[Library_nanoFramework_hardware_pico_nanoFramework_Hardware_Pico_Pio_PioStateMachine::FIELD___sm] + .NumericByRef() + .s4; + + VALIDATE_PIO_BLOCK(ctx.block); + VALIDATE_SM(ctx.sm); + + ctx.smp = g_AllocatedSMs[ctx.block][ctx.sm]; + if (ctx.smp == nullptr) + { + NANOCLR_SET_AND_LEAVE(CLR_E_OBJECT_DISPOSED); + } + + NANOCLR_NOCLEANUP(); +} + +#define NANOCLR_PIO_SM_PROLOGUE(ctx) \ + { \ + NANOCLR_CHECK_HRESULT(PioGetSmContext(stack.This(), ctx)); \ + } + +#define NANOCLR_PIO_SM_TEARDOWN_PROLOGUE(ctx) \ + { \ + NANOCLR_CHECK_HRESULT(PioGetSmContext(stack.This(), ctx, true)); \ + } + +#define NF_PIO_INSTR_OUT_NULL_32 0x6060u +#define NF_PIO_INSTR_PULL_NOBLOCK 0x8080u + +#if defined(RP2350) +#define NF_PIO_SM_SHIFTCTRL_FJOIN_RX_GET (1u << 14) +#define NF_PIO_SM_SHIFTCTRL_FJOIN_RX_PUT (1u << 15) +#endif + +inline void NfPioSmConfigSetFifoJoin(rp_pio_sm_config_t *cfgp, const unsigned int join) +{ + pioSmConfigSetFifoJoinX(cfgp, static_cast(join & 3u)); + +#if defined(RP2350) + cfgp->shiftctrl &= ~(NF_PIO_SM_SHIFTCTRL_FJOIN_RX_GET | NF_PIO_SM_SHIFTCTRL_FJOIN_RX_PUT); + + if (join & 4u) + { + cfgp->shiftctrl |= NF_PIO_SM_SHIFTCTRL_FJOIN_RX_GET; + } + if (join & 8u) + { + cfgp->shiftctrl |= NF_PIO_SM_SHIFTCTRL_FJOIN_RX_PUT; + } +#endif +} + +inline void NfPioBlockEnableInterrupt(const rp_pio_block_t *block, const uint32_t mask) +{ + if (SIO->CPUID == 0u) + { + block->pio->SET.IRQ0_INTE = mask; + } + else + { + block->pio->SET.IRQ1_INTE = mask; + } +} + +inline void NfPioBlockDisableInterrupt(const rp_pio_block_t *block, const uint32_t mask) +{ + block->pio->CLR.IRQ0_INTE = mask; + block->pio->CLR.IRQ1_INTE = mask; +} + +inline void NfPioBlockForceIrq(const rp_pio_block_t *block, const uint32_t irq) +{ + block->pio->IRQ_FORCE = 1u << irq; +} + +inline void NfPioBlockClearIrq(const rp_pio_block_t *block, const uint32_t irq) +{ + block->pio->IRQ = 1u << irq; +} + +inline void NfPioBlockGpioInit(const rp_pio_block_t *block, uint32_t gpio, uint32_t padbits) +{ + static constexpr uint32_t funcsels[] = { + RP_PIO_FUNCSEL_PIO0, + RP_PIO_FUNCSEL_PIO1, +#if RP_HAS_PIO2 == TRUE + RP_PIO_FUNCSEL_PIO2, +#endif + }; + + const uint32_t funcsel = funcsels[block->pioidx]; + +#if defined(RP2350) + PADS_BANK0->GPIO[gpio] = padbits | RP_PIO_PAD_ISO; + IO_BANK0->GPIO[gpio].CTRL = funcsel; + PADS_BANK0->GPIO[gpio] = padbits; +#else + PADS_BANK0->GPIO[gpio] = padbits; + IO_BANK0->GPIO[gpio].CTRL = funcsel; +#endif +} + +inline bool NfPioSmDrainTxFifo(const rp_pio_sm_t *smp, unsigned int spinLimit) +{ + const uint32_t shiftctrl = smp->block->pio->SM[smp->smidx].SHIFTCTRL; + bool drained = true; + + if ((shiftctrl & PIO_SM_SHIFTCTRL_AUTOPULL) != 0u) + { + smp->block->pio->SM[smp->smidx].SHIFTCTRL = shiftctrl & ~PIO_SM_SHIFTCTRL_AUTOPULL; + } + + while ((smp->block->pio->FSTAT & PIO_FSTAT_TXEMPTY(smp->smidx)) == 0u) + { + if (spinLimit-- == 0u) + { + drained = false; + break; + } + + pioSmExecX(smp, NF_PIO_INSTR_PULL_NOBLOCK); + } + + pioSmExecX(smp, NF_PIO_INSTR_OUT_NULL_32); + + smp->block->pio->SM[smp->smidx].SHIFTCTRL = shiftctrl; + + return drained; +} + +inline uint32_t NfDmaChannelGetCounter(const rp_dma_channel_t *dmachp) +{ +#if defined(RP2350) + return dmachp->channel->TRANS_COUNT & ~DMA_TRANS_COUNT_MODE_Msk; +#else + return dmachp->channel->TRANS_COUNT; +#endif +} + +#endif // NANOFRAMEWORK_HARDWARE_PICO_TARGET_H