diff --git a/boards/rpi-pico-2/Kconfig b/boards/rpi-pico-2/Kconfig new file mode 100644 index 000000000000..d0ac0bb5744c --- /dev/null +++ b/boards/rpi-pico-2/Kconfig @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2025 Tom Hert +# SPDX-FileCopyrightText: 2025 HAW Hamburg +# SPDX-License-Identifier: LGPL-2.1-only + +config BOARD + default "rpi-pico-2" if BOARD_RPI_PICO_2 + +config BOARD_RPI_PICO_2 + bool + default y + select CPU_MODEL_RP2350 diff --git a/boards/rpi-pico-2/Makefile b/boards/rpi-pico-2/Makefile new file mode 100644 index 000000000000..f8fcbb53a065 --- /dev/null +++ b/boards/rpi-pico-2/Makefile @@ -0,0 +1,3 @@ +MODULE = board + +include $(RIOTBASE)/Makefile.base diff --git a/boards/rpi-pico-2/Makefile.dep b/boards/rpi-pico-2/Makefile.dep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/boards/rpi-pico-2/Makefile.features b/boards/rpi-pico-2/Makefile.features new file mode 100644 index 000000000000..b19f996d1407 --- /dev/null +++ b/boards/rpi-pico-2/Makefile.features @@ -0,0 +1 @@ +CPU := rp2350 diff --git a/boards/rpi-pico-2/Makefile.include b/boards/rpi-pico-2/Makefile.include new file mode 100644 index 000000000000..b80aa5b4da25 --- /dev/null +++ b/boards/rpi-pico-2/Makefile.include @@ -0,0 +1,7 @@ +CPU_MODEL := RP2350 +PORT_LINUX ?= /dev/ttyACM0 + +# JLink isnt tested yet on RP2350 +# ifeq ($(PROGRAMMER),jlink) +# JLINK_DEVICE = RP2350_M33_0 +# endif diff --git a/boards/rpi-pico-2/dist/openocd.cfg b/boards/rpi-pico-2/dist/openocd.cfg new file mode 100644 index 000000000000..69faf2c879bd --- /dev/null +++ b/boards/rpi-pico-2/dist/openocd.cfg @@ -0,0 +1,7 @@ +echo "Make sure to use the Raspberry Pi OpenOCD version!" +source [find target/rp2350.cfg] +set USE_CORE 0 +set RESCUE 1 +$_TARGETNAME_0 configure -rtos auto +adapter speed 5000 +rp2350.dap.core1 cortex_m reset_config sysresetreq diff --git a/boards/rpi-pico-2/doc.md b/boards/rpi-pico-2/doc.md new file mode 100644 index 000000000000..a7254f7d9525 --- /dev/null +++ b/boards/rpi-pico-2/doc.md @@ -0,0 +1,86 @@ +@defgroup boards_rpi_pico_2 Raspberry Pi Pico 2 +@ingroup boards +@brief Support for the RP2350 based Raspberry Pi Pico board + +@warning The support for the Raspberry Pi Pico 2 is still in a very early stage! See [Known Issues](#rpi_pico_2_known_issues). + +## Overview + +The Raspberry Pi Pico 2 is a microcontroller board based on the RP2350 chip, featuring dual-core Arm Cortex-M0+ processors and RISC-V Hazard secondary architecture. It is designed for a wide range of applications, from hobbyist projects to professional embedded systems for a fairly affordable price. + +![The Raspberry Pi Pico 2 Board](https://www.raspberrypi.com/documentation/microcontrollers/images/pico-2.png) + +## Hardware + +| MCU | RP2350 | +|:-----------|:------------------------------------------------------------| +| Family | Dual Cortex-M33 or Hazard3 (RISC-V) | +| Vendor | Raspberry Pi | +| RAM | 520 kB on-chip SRAM (10 independent banks) | +| Flash | Up to 16 MB external QSPI flash (expandable to 32 MB) | +| Frequency | up to 150 MHz (Set to 125 MHz in RIOT) | +| Security | Boot signing, key storage, SHA-256 accelerator | +| PIOs | 12 state machines | +| UARTs | 2 | +| SPIs | 2 | +| I2Cs | 2 | +| PWM | 24 channels | +| USB | USB 1.1 controller with host and device support | +| Power | On-chip switched-mode power supply with LDO sleep mode | +| OTP | 8 kB of one-time-programmable storage | +| Datasheet | [RP2350 Datasheet](https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf) | + +## User Interfaces + +| Interface | Description | +|:-----------|:-------------------------------------------------------------| +| LED0 | User LED (GPIO 0 at Pin 25) | +| SW0 | Button used in flash process, can be accessed using registers but difficult | + +## Pinout + +![Pinout Diagram](https://www.raspberrypi.com/documentation/microcontrollers/images/pico-2-r4-pinout.svg) + +## Flashing the Board + +The Raspberry Pi Pico 2 has a built-in bootloader that allows flashing via USB. However, you can also use OpenOCD for flashing the board. + +### Flashing using OpenOCD + +If you have two Raspberry Pi Pico boards, you can utilize one as a programmer to program the other board. +Please refer to the [Debugprobe documentation](https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html#getting-started) for more details. + +Note that Raspberry Pi actually uses their own OpenOCD fork, which is available in the [RP2040 OpenOCD repository](https://github.com/raspberrypi/openocd). While technically you can use the standard OpenOCD, it is recommended to use the Raspberry Pi fork for better compatibility with the RP2350, as its still fairly "new" and under development, which is why even their own Pico SDK Extension uses the Raspberry Pi fork of OpenOCD, instead of the standard one. + +To do this, you need to connect the board to your computer and use the following command: + +```bash +PROGRAMMER=openocd BOARD=rpi-pico-2 make flash +``` + +You can then debug your application using GDB with the following command: + +```bash +PROGRAMMER=openocd BOARD=rpi-pico-2 make debug +``` + +### Flashing using Picotool + +Simply connect the board to your computer via USB and use the following command: + +```bash +BOARD=rpi-pico-2 make flash +``` + +This is the default method for flashing the Raspberry Pi Pico 2. However, it does not allow for debugging using GDB. + +@note When programming the board with the Picotool for the first time, RIOT will download and install the Picotool locally in the RIOT folder. This process will take some minutes to complete. + +## Known Issues {#rpi_pico_2_known_issues} + +Currently RP2350 support is rather minimal, as such peripheral support is extremely limited. The following peripherals are supported: +- GPIO +- Non-configurable write-only UART (UART0 using Pin 0 and 1) + - The UART Baudrate is set to 115200. + +More peripherals will be added in the future. It should also be noted that we currently only support the Cortex M33 cores, not the RISC-V Hazard cores. diff --git a/boards/rpi-pico-2/include/board.h b/boards/rpi-pico-2/include/board.h new file mode 100644 index 000000000000..1561a5aedcad --- /dev/null +++ b/boards/rpi-pico-2/include/board.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup boards_rpi_pico_2 + * @{ + * + * @file + * @brief Board specific definitions for the Raspberry Pi Pico 2 + * + * @author Tom Hert + */ + +#include "RP2350.h" +#include "cpu.h" +#include "cpu_conf.h" +#include "periph_conf.h" +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/boards/rpi-pico-2/include/gpio_params.h b/boards/rpi-pico-2/include/gpio_params.h new file mode 100644 index 000000000000..1998b8afaa24 --- /dev/null +++ b/boards/rpi-pico-2/include/gpio_params.h @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +#include "board.h" +#include "saul/periph.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/boards/rpi-pico-2/include/periph_conf.h b/boards/rpi-pico-2/include/periph_conf.h new file mode 100644 index 000000000000..ed237d2c3b58 --- /dev/null +++ b/boards/rpi-pico-2/include/periph_conf.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +#include + +#include "RP2350.h" +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif diff --git a/cpu/cortexm_common/ldscripts/cortexm_base.ld b/cpu/cortexm_common/ldscripts/cortexm_base.ld index 6dc5e0428f6b..76f21ab8f075 100644 --- a/cpu/cortexm_common/ldscripts/cortexm_base.ld +++ b/cpu/cortexm_common/ldscripts/cortexm_base.ld @@ -53,6 +53,7 @@ SECTIONS _sfixed = .; _isr_vectors = DEFINED(_isr_vectors) ? _isr_vectors : . ; KEEP(*(SORT(.vectors*))) + KEEP(*(SORT(.picobin_block*))) /* Keep picobin block used by RP2350 */ *(.text .text.* .gnu.linkonce.t.*) *(.glue_7t) *(.glue_7) *(.rodata .rodata* .gnu.linkonce.r.*) diff --git a/cpu/rp2350/Kconfig b/cpu/rp2350/Kconfig new file mode 100644 index 000000000000..867bcf84f90b --- /dev/null +++ b/cpu/rp2350/Kconfig @@ -0,0 +1,23 @@ +# SPDX-FileCopyrightText: 2025 Tom Hert +# SPDX-FileCopyrightText: 2025 HAW Hamburg +# SPDX-License-Identifier: LGPL-2.1-only + +config CPU_FAM_RP2350 + bool + select CPU_CORE_CORTEX_M33 + +config CPU_FAM + default "RP2350" if CPU_FAM_RP2350 + +config CPU_MODEL_RP2350 + bool + select CPU_FAM_RP2350 + +config CPU_MODEL + default "RP2350" if CPU_MODEL_RP2350 + +config CPU + default "rp2350" if CPU_FAM_RP2350 + + +source "$(RIOTCPU)/cortexm_common/Kconfig" diff --git a/cpu/rp2350/Makefile b/cpu/rp2350/Makefile new file mode 100644 index 000000000000..64aa4ed4092a --- /dev/null +++ b/cpu/rp2350/Makefile @@ -0,0 +1,8 @@ +MODULE = cpu + +USEPKG += picosdk + +DIRS += $(RIOTCPU)/cortexm_common +DIRS += periph + +include $(RIOTBASE)/Makefile.base diff --git a/cpu/rp2350/Makefile.dep b/cpu/rp2350/Makefile.dep new file mode 100644 index 000000000000..849cc8d1163c --- /dev/null +++ b/cpu/rp2350/Makefile.dep @@ -0,0 +1 @@ +include $(RIOTCPU)/cortexm_common/Makefile.dep diff --git a/cpu/rp2350/Makefile.features b/cpu/rp2350/Makefile.features new file mode 100644 index 000000000000..5fc956bd1ba3 --- /dev/null +++ b/cpu/rp2350/Makefile.features @@ -0,0 +1,9 @@ +CPU_CORE := cortex-m33 +CPU_FAM := RP2350 +CPU_ARCH = armv8m +CPU_MODEL = rp2350 + +include $(RIOTCPU)/cortexm_common/Makefile.features + +FEATURES_PROVIDED += periph_gpio +FEATURES_PROVIDED += periph_uart diff --git a/cpu/rp2350/Makefile.include b/cpu/rp2350/Makefile.include new file mode 100644 index 000000000000..c6245591bd43 --- /dev/null +++ b/cpu/rp2350/Makefile.include @@ -0,0 +1,33 @@ +ROM_LEN ?= 2097152 # = 2 MiB used in the RPi Pico +ROM_OFFSET := 0 # bootloader size +RAM_LEN := 0x82000 # 520kB = 532479 used in the RPi Pico 2350 +ROM_START_ADDR := 0x10000000 # XIP Non-Secure address for rp2350 +RAM_START_ADDR := 0x20000000 # Non-Secure RAM address for rp2350 + +# CPU and architecture specific flags +CFLAGS += -D$(CPU_MODEL) +CFLAGS += -DROM_START_ADDR=$(ROM_START_ADDR) +CFLAGS += -DRAM_START_ADDR=$(RAM_START_ADDR) +CFLAGS += -Wno-error + +# Include paths +INCLUDES += -I$(RIOTCPU)/rp2350/include +INCLUDES += -isystem$(RIOTBASE)/dist/tools/picosdk/picosdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include +INCLUDES += -isystem$(RIOTBASE)/dist/tools/picosdk/picosdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2350/Include + +# Linker flags +LINKFLAGS += -mcpu=$(CPU_ARCH) -mthumb +LINKFLAGS += -Wl,--gc-sections +LINKFLAGS += -Wl,--start-group -lc -lm -Wl,--end-group + +# Vector table configuration +VECTORS_O ?= $(BINDIR)/cpu/vectors.o +VECTORS_FILE := $(RIOTCPU)/rp2350/vectors.c + +# Supported programmers and debuggers +PROGRAMMERS_SUPPORTED := picotool openocd jlink +PROGRAMMER ?= picotool +OPENOCD_DEBUG_ADAPTER ?= dap + +# Include the base Cortex-M makefile +include $(RIOTMAKE)/arch/cortexm.inc.mk diff --git a/cpu/rp2350/clock.c b/cpu/rp2350/clock.c new file mode 100644 index 000000000000..e696dabaed48 --- /dev/null +++ b/cpu/rp2350/clock.c @@ -0,0 +1,71 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief Clock configuration implementation for the RP2350 + * + * @author Tom Hert + */ + +#include "periph_cpu.h" + +void clock_reset(void) { + /* Reset the clock system */ + reset_component(RESET_PLL_SYS, RESET_PLL_SYS); +} + +/** + * @brief Configures the XOSC and then sets CLK_SYS, PLL_SYS and CLK_PERI to it + * @warning Make sure to call clock_reset() before this function to reset the + * clock system + * @see RP2350 Docs Chapter 8, mostly 8.2 for more details + */ +void cpu_clock_init(void) { + /* Enable the XOSC */ + xosc_start(); + + /* Setup the PLL using the XOSC as the reference clock. */ + PLL_SYS->FBDIV_INT = + PLL_FEEDBACK_DIVIDER_VALUE; /* Set the feedback divider */ + + /* Set the post-dividers for the PLL output.*/ + PLL_SYS->PRIM = PDIV; + /* Turn on PLL */ + atomic_clear(&PLL_SYS->PWR, + PLL_PWR_PD_BITS | PLL_PWR_VCOPD_BITS | PLL_PWR_POSTDIVPD_BITS); + + /* sleep 10ms to allow the PLL to stabilize */ + xosc_sleep(10); + + /* Based on the description in chapter 8 this is something that should be done + * However, it appears to cause issues and is not done by other examples on the + * internet. This needs to be investigated further. */ + + /* Wait for lock */ + /* while (!(PLL_SYS->CS & PLL_CS_LOCK_BITS)) { */ + /* Wait for the PLL to lock */ + /* } */ + + /* AUXSRC = 0x0 7:5 && SRC == 0x0 0 */ + CLOCKS->CLK_SYS_CTRL = CLK_SYS_PERI_CTRL_ENABLE_BIT; + + /* This register contains one decoded bit for each of the clock sources + * enumerated in the CTRL SRC field. The bit does not directly correlate with + * the value of the SRC field For example 0x0 is the first bit while 0x1 is + * the second bit. In some way this makes sense, in some way I lost too much + * time on this. */ + while (CLOCKS->CLK_SYS_SELECTED != CLK_SYS_SELECTED_PERI_FIELD_VALUE) { + } + + /* AUXSRC = 0x0 -> CLK_SYS Indirectly through lower line */ + CLOCKS->CLK_PERI_CTRL = CLK_PERI_CTRL_ENABLE_BIT; +} + +/** @} */ diff --git a/cpu/rp2350/cpu.c b/cpu/rp2350/cpu.c new file mode 100644 index 000000000000..5fbe2418c9d3 --- /dev/null +++ b/cpu/rp2350/cpu.c @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief CPU initialization implementation for the RP2350 + * + * @author Tom Hert + */ + +#include "cpu.h" + +#include "RP2350.h" +#include "board.h" +#include "kernel_init.h" +#include "macros/units.h" +#include "periph/gpio.h" +#include "periph/init.h" +#include "periph_cpu.h" +#include "stdio_base.h" + +#define DEBUG_WITH_OSC + +void gpio_reset(void) { + reset_component(RESET_PADS_BANK0, RESET_PADS_BANK0); + reset_component(RESET_IO_BANK0, RESET_IO_BANK0); + + /* Since the GPIO pins on the rp2350 are by default disable, + * we need to enable the input for LED0 to be able to use it + * in Macros such as LED0_ON, LED0_OFF, and LED0_TOGGLE. */ + gpio_init(LED0_PIN_ID, GPIO_OUT); +} + +void cpu_init(void) { + /* initialize the Cortex-M core, once UART support is moved + to shared driver as currently this will cause unhandled interrupts */ + /* cortexm_init(); */ + + gpio_reset(); + early_init(); + + clock_reset(); + cpu_clock_init(); + + /* trigger static peripheral initialization */ + periph_init(); +} + +/** @} */ diff --git a/cpu/rp2350/doc.md b/cpu/rp2350/doc.md new file mode 100644 index 000000000000..cc2f01362ef9 --- /dev/null +++ b/cpu/rp2350/doc.md @@ -0,0 +1,5 @@ +@defgroup cpu_rp2350 RP2350 MCUs +@ingroup cpu +@brief RP2350 MCU code and definitions + +This module contains the code and definitions for MCUs of the RP2350 family used by the Pi Pico 2. diff --git a/cpu/rp2350/include/clock_conf.h b/cpu/rp2350/include/clock_conf.h new file mode 100644 index 000000000000..f39cd29905a2 --- /dev/null +++ b/cpu/rp2350/include/clock_conf.h @@ -0,0 +1,157 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief Clock configuration for the RP2350 + * + * @author Tom Hert + */ + +#include "RP2350.h" +#include "macros/units.h" + +/** 1-15 MHz range + * @see hardware/regs/xosc.h and chapter 8.2.8 + */ +#define XOSC_CTRL_FREQ_RANGE_VALUE_1_15MHZ 0xaa0u +/** 10-30 MHz range */ +#define XOSC_CTRL_FREQ_RANGE_VALUE_10_30MHZ 0xaa1u +/** 25-60 MHz range */ +#define XOSC_CTRL_FREQ_RANGE_VALUE_25_60MHZ 0xaa2u +/** 40-100 MHz range */ +#define XOSC_CTRL_FREQ_RANGE_VALUE_40_100MHZ 0xaa3u +/** Disable the XOSC */ +#define XOSC_CTRL_ENABLE_VALUE_DISABLE 0xd1eu +/** Enable the XOSC */ +#define XOSC_CTRL_ENABLE_VALUE_ENABLE 0xfabu +/** LSB of the enable bit */ +#define XOSC_CTRL_ENABLE_LSB 12u +/** Stable bit in the XOSC status register */ +#define XOSC_STATUS_STABLE_BITS 0x80000000u +/** Default crystal frequency is 12 MHz */ +#define XOSC_HZ MHZ(12u) +/** Reference divider for the PLL, set to 2 as per hardware manual */ +#define PLL_REF_DIV 2u +/** VCO frequency for the PLL, set to 750 MHz as per hardware manual */ +#define PLL_VCO_FREQ 750000000u +/** Post divider 1 for the PLL, set to 6 as per hardware manual */ +#define PLL_PD1 6u +/** Post divider 2 for the PLL, set to 2 as per hardware manual */ +#define PLL_PD2 2u +/** Power down bits for the PLL */ +#define PLL_PWR_PD_BITS 0x00000001u +/** VCO power down bits for the PLL */ +#define PLL_PWR_VCOPD_BITS 0x00000020u +/** Lock bit in the PLL control status register */ +#define PLL_CS_LOCK_BITS 0x80000000u +/** LSB of the post divider 1 in the PLL primary register */ +#define PLL_PRIM_POSTDIV1_LSB 16u +/** LSB of the post divider 2 in the PLL primary register */ +#define PLL_PRIM_POSTDIV2_LSB 12u +/** Post divider power down bits for the PLL */ +#define PLL_PWR_POSTDIVPD_BITS 0x00000008u +/** Enable bit for the peripheral clock control register */ +#define CLK_PERI_CTRL_ENABLE_BIT (1u << 11u) +/** Default CPU frequency in Hz, set to 125 MHz as per hardware manual */ +#define CPUFREQ 125000000u +/** Maximum crystal frequency */ +#define CLOCK_XOSC_MAX MHZ(15u) +/** Minimum crystal frequency */ +#define CLOCK_XOSC_MIN MHZ(5u) +/** Crystal frequency */ +#define CLOCK_XOSC (XOSC_HZ) +/** Minimum value of the post PLL clock divers */ +#define PLL_POSTDIV_MIN 1u +/** Maximum value of the post PLL clock divers */ +#define PLL_POSTDIV_MAX 7u +/** Minimum value of the PLL VCO feedback scaler */ +#define PLL_VCO_FEEDBACK_SCALE_MIN 16u +/** Maximum value of the PLL VCO feedback scaler */ +#define PLL_VCO_FEEDBACK_SCALE_MAX 320u +/** Minimum value of the clock divider applied before + * feeding in the reference clock into the PLL */ +#define PLL_REF_DIV_MIN 1u +/** Minimum value of the clock divider applied before feeding in + * the reference clock into the PLL */ +#define PLL_REF_DIV_MAX 1u +/** PLL feedback divider value, set to 125 as per hardware manual */ +#define PLL_FEEDBACK_DIVIDER_VALUE 125u +/** Enable bit for the system clock control register to select the peripheral + * clock */ +#define CLK_SYS_PERI_CTRL_ENABLE_BIT (1u << 0u) +/** Selected field value for the system clock control register + * to select the peripheral clock */ +#define CLK_SYS_SELECTED_PERI_FIELD_VALUE 2u +/** RIOT core clock frequency defined as the CPU frequency */ +#define CLOCK_CORECLOCK MHZ(12u) + +#if (PLL_VCO_FEEDBACK_SCALE_MIN < PLL_VCO_FEEDBACK_SCALE_MIN) || \ + (PLL_VCO_FEEDBACK_SCALE_MAX > PLL_VCO_FEEDBACK_SCALE_MAX) +# error "Value for PLL_VCO_FEEDBACK_SCALE out of range, check config" +#endif +#if (PLL_REF_DIV_MIN < PLL_REF_DIV_MIN) || (PLL_REF_DIV_MAX > PLL_REF_DIV_MAX) +# error "Value for PLLxosc_sleep_REF_DIV out of range, check config" +#endif +#if (PLL_POSTDIV_MIN < PLL_POSTDIV_MIN) || (PLL_POSTDIV_MAX > PLL_POSTDIV_MAX) +# error "Value for PLL_POSTDIV out of range, check config" +#endif +#if ((CLOCK_XOSC > CLOCK_XOSC_MAX) || (CLOCK_XOSC < CLOCK_XOSC_MIN)) +# error "Value for CLOCK_XOSC out of range, check config" +#endif + +/** Post divider for the PLL, calculated based on the post divider values */ +#define PDIV ((PLL_PD1 << PLL_PRIM_POSTDIV1_LSB) | (PLL_PD2 << PLL_PRIM_POSTDIV2_LSB)) +/** Feedback divider for the PLL, calculated based on the VCO frequency and + * reference clock frequency */ +#define FBDIV ((PLL_VCO_FREQ / XOSC_HZ) / PLL_REF_DIV) +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configures the Crystal to run. + * @see The reference hardware manual suggests to use a 12 MHz crystal, which we + * use by default. + */ +void xosc_start(void); + +/** + * @brief Stop the crystal. + */ +void xosc_stop(void); + +/** + * @brief Sleep for a given number of cycles. + */ +void xosc_sleep(int32_t cycles); + +/** + * @brief Reset the clock system. + * + * This function resets the clock system to a known state. + * It is recommended to call this function before configuring the clock system. + */ +void clock_reset(void); + +/** + * @brief Configures the XOSC and then sets CLK_SYS, PLL_SYS and CLK_PERI to it + * @warning Make sure to call clock_reset() before this function to reset the + * clock system + * @see RP2350 Docs Chapter 8, mostly 8.2 for more details + */ +void cpu_clock_init(void); + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/cpu/rp2350/include/cpu_conf.h b/cpu/rp2350/include/cpu_conf.h new file mode 100644 index 000000000000..652be6fe27e5 --- /dev/null +++ b/cpu/rp2350/include/cpu_conf.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup cpu_rp2350 + * @{ + * @file + * @brief CPU configuration for the RP2350 + * + * @author Tom Hert + */ + +#include "RP2350.h" +#include "core_cm33.h" +#include "cpu_conf_common.h" + +#define CPU_DEFAULT_IRQ_PRIO 1u +#define CPU_IRQ_NUMOF 52u + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/cpu/rp2350/include/gpio_conf.h b/cpu/rp2350/include/gpio_conf.h new file mode 100644 index 000000000000..5ed3bbba9eee --- /dev/null +++ b/cpu/rp2350/include/gpio_conf.h @@ -0,0 +1,66 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert git@annsann.eu> + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief GPIO configuration for the RP2350 + * + * @author Tom Hert + */ + +/** The number of GPIO pins available on the RP2350 */ +#define GPIO_PIN_NUMOF 30u + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Possible function values for @ref gpio_io_ctrl_t::function_select + */ +typedef enum { + /** connect pin to the SPI peripheral (MISO/MOSI/SCK depends on pin) */ + FUNCTION_SELECT_SPI = 1, + + /** connect pin to the UART peripheral (TXD/RXD depends on pin) */ + FUNCTION_SELECT_UART = 2, + + /** connect pin to the I2C peripheral (SCL/SDA depends on pin) */ + FUNCTION_SELECT_I2C = 3, + + /** connect pin to the timer for PWM (channel depends on pin) */ + FUNCTION_SELECT_PWM = 4, + + /** use pin as vanilla GPIO */ + FUNCTION_SELECT_SIO = 5, + + /** connect pin to the first PIO peripheral */ + FUNCTION_SELECT_PIO0 = 6, + + /** connect pin to the second PIO peripheral */ + FUNCTION_SELECT_PIO1 = 7, + + /** connect pin to the timer (depending on pin: external clock, + * clock output, or not supported) */ + FUNCTION_SELECT_CLOCK = 8, + + /** connect pin to the USB peripheral (function depends on pin) */ + FUNCTION_SELECT_USB = 9, + + /** Reset value, pin unconnected */ + FUNCTION_SELECT_NONE = 31, +} gpio_function_select_t; + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/cpu/rp2350/include/helpers.h b/cpu/rp2350/include/helpers.h new file mode 100644 index 000000000000..97576b3ad20c --- /dev/null +++ b/cpu/rp2350/include/helpers.h @@ -0,0 +1,80 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +#include "RP2350.h" + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief Helper functions for atomic register operations + * + * @author Tom Hert + */ + +/** Bit to be set for an atomic XOR operation */ +#define ATOMIC_XOR_WRITE 0x1000u +/** Bit to be set for an atomic set operation */ +#define ATOMIC_BITMASK_SET_WRITE 0x2000u +/** Bits to be set for an atomic clear operation */ +#define ATOMIC_BITMASK_CLEAR_WRITE 0x3000u + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Perform an atomic XOR write to a register + * + * @param[in,out] reg Pointer to the target register + * @param[in] val Value to be XORed with the register + */ +static inline void atomic_xor(volatile uint32_t *reg, uint32_t val) { + *(volatile uint32_t *)((uintptr_t)reg | ATOMIC_XOR_WRITE) = val; +} + +/** + * @brief Set bits in a register atomically + * + * @param[in,out] reg Pointer to the target register + * @param[in] val Bit mask of bits to set + */ +static inline void atomic_set(volatile uint32_t *reg, uint32_t val) { + *(volatile uint32_t *)((uintptr_t)reg | ATOMIC_BITMASK_SET_WRITE) = val; +} + +/** + * @brief Clear bits in a register atomically + * + * @param[in,out] reg Pointer to the target register + * @param[in] val Bit mask of bits to clear + */ +static inline void atomic_clear(volatile uint32_t *reg, uint32_t val) { + *(volatile uint32_t *)((uintptr_t)reg | ATOMIC_BITMASK_CLEAR_WRITE) = val; +} + +/** + * @brief Reset a component by clearing its reset bits and waiting for the reset to complete + * + * @param reset_value Bit mask of the reset bits to clear + * @param reset_done_value Bit mask of the reset done bits to wait for + */ +static inline void reset_component(uint32_t reset_value, + uint32_t reset_done_value) { + atomic_clear(&RESETS->RESET, reset_value); + while (~RESETS->RESET_DONE & reset_done_value) { + /* Wait for the reset to complete */ + } +} + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/cpu/rp2350/include/periph_cpu.h b/cpu/rp2350/include/periph_cpu.h new file mode 100644 index 000000000000..515b38820c7f --- /dev/null +++ b/cpu/rp2350/include/periph_cpu.h @@ -0,0 +1,110 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief Peripheral CPU definitions for the RP2350 + * + * @author Tom Hert + */ + +#include +#include + +#include "RP2350.h" +#include "clock_conf.h" +#include "cpu.h" +#include "gpio_conf.h" +#include "helpers.h" +#include "uart_conf.h" + +/** Overwrite the default GPIO type to use uint32_t */ +#define HAVE_GPIO_T +typedef uint32_t gpio_t; + +#include "periph/gpio.h" + +/** GPIO Pin ID for the onboard LED */ +#define LED0_PIN_ID 25u +#define LED0_ON gpio_set(LED0_PIN_ID) +#define LED0_OFF gpio_clear(LED0_PIN_ID) +#define LED0_TOGGLE gpio_toggle(LED0_PIN_ID) +#define LED0_NAME "LED(Green)" + +/** GPIO Pin ID for oscillator debugging */ +#define OSC_DEBUG_PIN_ID 15u + +/** Reset bit for the system PLL */ +#define RESET_PLL_SYS (1u << 14u) + +/** Reset bit for the pads bank 0 */ +#define RESET_PADS_BANK0 (1u << 9u) + +/** Reset bit for UART0 peripheral */ +#define RESET_UART0 (1u << 26u) + +/** Reset bit for UART1 peripheral */ +#define RESET_UART1 (1u << 27u) + +/** Reset bit for the IO bank 0 */ +#define RESET_IO_BANK0 (1u << 6u) + +/** Input enable bit for GPIO0 in PADS_BANK0 */ +#define PADS_BANK0_GPIO0_IE_BITS (1u << 6u) + +/** Isolation bits for PADS_BANK0 */ +#define PADS_BANK0_ISO_BITS (1u << 8u) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Calculate the address of the GPIO pad register for a given pin + * @param pin The GPIO pin number + * @return The address of the GPIO pad register for the given pin + */ +static inline uint32_t calculate_gpio_pad_register_addr(gpio_t pin) { + /* Each pin has a 4 byte register, so we can calculate the address */ + /* by adding 4 bytes for each pin, starting at the base address of PADS_BANK0 + */ + /* and adding 4 bytes to skip VOLTAGE_SELECT */ + return PADS_BANK0_BASE + 4 * (pin + 1); +} + +/** + * @brief Calculate the address of the GPIO IO status register for a given pin + * @param pin The GPIO pin number + * @return The address of the GPIO IO status register for the given pin + */ +static uint32_t calculate_gpio_io_status_register_addr(gpio_t pin) { + /* Each status register is followed by a ctrl register, */ + return IO_BANK0_BASE + 8 * pin; +} + +/** + * @brief Calculate the address of the GPIO IO control register for a given + * pin + * @param pin The GPIO pin number + * @return The address of the GPIO IO control register for the given pin + */ +static inline uint32_t calculate_gpio_io_ctrl_register_addr(gpio_t pin) { + /* Each pin has a 8 byte register (4 Bytes of Status, 4 Bytes of CTRL), */ + /* so we can calculate the address by adding 8 bytes for each pin, */ + /* starting at the base address of IO_BANK0 */ + return calculate_gpio_io_status_register_addr(pin) + 4; +} + +#ifdef __cplusplus +} +#endif + +/** @} */ diff --git a/cpu/rp2350/include/uart_conf.h b/cpu/rp2350/include/uart_conf.h new file mode 100644 index 000000000000..d8246587a457 --- /dev/null +++ b/cpu/rp2350/include/uart_conf.h @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#pragma once + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief UART configuration for the RP2350 + * + * @author Tom Hert + */ + +#include "RP2350.h" +#include "macros/units.h" +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** UART baud rate in bits per second */ +#define BAUDRATE 115200u + +/** Integer baud rate divisor */ +#define IBRD ((((8u * CPUFREQ) + BAUDRATE) / (2u * BAUDRATE)) / 64u) + +/** Fractional baud rate divisor */ +#define FBRD ((((8u * CPUFREQ) + BAUDRATE) / (2u * BAUDRATE)) % 64u) + +/** UART enable bit in control register */ +#define UART_UARTCR_UARTEN_BITS (1u << 0u) + +/** UART receive enable bit in control register */ +#define UART_UARTCR_RXE_BITS (1u << 9u) + +/** UART transmit enable bit in control register */ +#define UART_UARTCR_TXE_BITS (1u << 8u) + +/** UART receive FIFO full flag bit in flag register */ +#define UART_UARTFR_RXFF_BITS (1u << 6u) + +/** UART transmit FIFO empty flag bit in flag register */ +#define UART_UARTFR_TXFE_BITS (1u << 7u) + +/** @} */ diff --git a/cpu/rp2350/ldscripts/RP2350.ld b/cpu/rp2350/ldscripts/RP2350.ld new file mode 100644 index 000000000000..cf42b97976bc --- /dev/null +++ b/cpu/rp2350/ldscripts/RP2350.ld @@ -0,0 +1 @@ +INCLUDE cortexm.ld diff --git a/cpu/rp2350/periph/Makefile b/cpu/rp2350/periph/Makefile new file mode 100644 index 000000000000..a36df249ac1d --- /dev/null +++ b/cpu/rp2350/periph/Makefile @@ -0,0 +1 @@ +include $(RIOTMAKE)/periph.mk diff --git a/cpu/rp2350/periph/gpio.c b/cpu/rp2350/periph/gpio.c new file mode 100644 index 000000000000..8e72598f97cb --- /dev/null +++ b/cpu/rp2350/periph/gpio.c @@ -0,0 +1,95 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief GPIO implementation for the RP2350 + * + * @author Tom Hert + */ + +#include "periph/gpio.h" + +#include + +#include "board.h" +#include "irq.h" +#include "periph_conf.h" +#include "periph_cpu.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +int gpio_init(gpio_t pin, gpio_mode_t mode) { + /* Check if we exceed the maximum number of GPIO pins */ + assert(pin < GPIO_PIN_NUMOF); + + /* Clear the pin's output enable and output state */ + SIO->GPIO_OE_CLR = 1LU << pin; + SIO->GPIO_OUT_CLR = 1LU << pin; + + switch (mode) { + case GPIO_OUT: + *(uint32_t*)calculate_gpio_io_ctrl_register_addr(pin) = + FUNCTION_SELECT_SIO; + + volatile uint32_t* pad_reg = + (uint32_t*)calculate_gpio_pad_register_addr(pin); + + /* We clear all bits except the drive strength bit + * We set that to the highest one possible (12mA) + * to mimic the behavior of the pico1 GPIO driver + * (Not too sure why we do this, but it seems to be the standard) */ + *pad_reg = 0x3 << 4; + + SIO->GPIO_OE_SET = 1 << pin; /* Set the pin as output */ + + break; + default: + /* Unsupported mode */ + return -ENOTSUP; + } +} + +bool gpio_read(gpio_t pin) { + /* Check if we exceed the maximum number of GPIO pins */ + assert(pin < GPIO_PIN_NUMOF); + /* Read the pin state */ + return (SIO->GPIO_IN & (1 << pin)) != 0; /* Return true if the pin is HIGH */ +} + +void gpio_set(gpio_t pin) { + /* Check if we exceed the maximum number of GPIO pins */ + assert(pin < GPIO_PIN_NUMOF); + SIO->GPIO_OUT_SET = 1 << pin; /* Set the pin to HIGH */ +} + +void gpio_clear(gpio_t pin) { + /* Check if we exceed the maximum number of GPIO pins */ + assert(pin < GPIO_PIN_NUMOF); + SIO->GPIO_OUT_CLR = 1 << pin; /* Set the pin to LOW */ +} + +void gpio_toggle(gpio_t pin) { + /* Check if we exceed the maximum number of GPIO pins */ + assert(pin < GPIO_PIN_NUMOF); + SIO->GPIO_OUT_XOR = 1 << pin; /* Toggle the pin state (XOR) */ +} + +void gpio_write(gpio_t pin, bool value) { + /* Check if we exceed the maximum number of GPIO pins */ + assert(pin < GPIO_PIN_NUMOF); + if (value) { + gpio_set(pin); /* Set the pin to HIGH */ + } else { + gpio_clear(pin); /* Set the pin to LOW */ + } +} + +/** @} */ diff --git a/cpu/rp2350/periph/uart.c b/cpu/rp2350/periph/uart.c new file mode 100644 index 000000000000..e35d1a1bfdbb --- /dev/null +++ b/cpu/rp2350/periph/uart.c @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief UART implementation for the RP2350 + * + * @author Tom Hert + */ + +#include "periph/uart.h" + +#include "periph_cpu.h" + +int uart_init(uart_t uart, uint32_t baud, uart_rx_cb_t rx_cb, void *arg) { + /* Set the UART pins to the correct function */ + IO_BANK0->GPIO0_CTRL = FUNCTION_SELECT_UART; + IO_BANK0->GPIO1_CTRL = FUNCTION_SELECT_UART; + /* Clear the ISO bits */ + atomic_clear(&PADS_BANK0->GPIO0, PADS_BANK0_ISO_BITS); + atomic_clear(&PADS_BANK0->GPIO1, PADS_BANK0_ISO_BITS); + /* Set IE bit for gpio1 */ + PADS_BANK0->GPIO1 = PADS_BANK0->GPIO1 | PADS_BANK0_GPIO0_IE_BITS; + + /* We reset UART0 here, so we can be sure it is in a known state */ + reset_component(RESET_UART0, RESET_UART0); + + UART0->UARTIBRD = IBRD; + UART0->UARTFBRD = FBRD; +} + +int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity, + uart_stop_bits_t stop_bits) { + atomic_clear(&UART0->UARTCR, UART_UARTCR_UARTEN_BITS | UART_UARTCR_RXE_BITS | + UART_UARTCR_TXE_BITS); + /* Set the data bits, parity, and stop bits */ + UART0->UARTLCR_H = (uint32_t)data_bits << 5; + + switch (parity) { + case UART_PARITY_NONE: + break; + default: + return UART_NOMODE; + } + + UART0->UARTCR = + UART_UARTCR_RXE_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_UARTEN_BITS; + + return UART_OK; +} + +void uart_write(uart_t uart, const uint8_t *data, size_t len) { + for (size_t i = 0; i < len; i++) { + UART0->UARTDR = data[i]; + /* Wait until the TX FIFO is empty before sending the next byte */ + while (!(UART0->UARTFR & UART_UARTFR_TXFE_BITS)) { + } + } +} + +void uart_poweron(uart_t uart) {} +void uart_poweroff(uart_t uart) {} + +/** @} */ diff --git a/cpu/rp2350/picobin_block.s b/cpu/rp2350/picobin_block.s new file mode 100644 index 000000000000..468d465d4c1c --- /dev/null +++ b/cpu/rp2350/picobin_block.s @@ -0,0 +1,34 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/* Picobin block required for the binary */ +/* This defines the minimum viable image metadata to be recognized by the RP2350 bootloader */ +/* based on RP2350 Chapter 5.9.1 */ + +.section .picobin_block, "a" /* "a" means "allocatable" (can be moved by the linker) */ + +/* PICOBIN_BLOCK_MARKER_START */ +.word 0xffffded3 + /* ITEM 0 START based on 5.9.3.1 */ + .byte 0x42 /* (size_flag == 0, item_type == PICOBIN_BLOCK_ITEM_1BS_IMAGE_TYPE) */ + .byte 0x1 /* Block Size in words */ + /* image_type_flags (2 bytes) [See 5.9.3.1 / p419] */ + /* 15 -> 0 (1 for "Try before you buy" image [Wacky] */ + /* 12-14 -> 001 (RP2350 = 1) */ + /* 11 -> 0 (Reserved) */ + /* 8-10 -> 000 (EXE_CPU_ARM = 0), **WARNING** if I ever want to support RISC-V this needs to be 001 (EXE_CPU_RISCV) */ + /* 6-7 -> 00 (Reserved) */ + /* 4-5 -> 10 (2) EXE Security (As far as I understand we cant run in EXE_SECURITY_NS on the RP2350 [Appears to be correct]) thus EXE_SECURITY_S = 2 */ + /* 0-3 // 0001 IMAGE_TYPE_EXE */ + .hword 0b0001000000100001 + /* ITEM 0 END see 5.1.5.1 for explanation and 5.9.5.1 for the value / structure */ + .byte 0xff /* PICOBIN_BLOCK_ITEM_2BS_LAST */ + .hword 0x0001 /* Size of the item in words (predefined value) */ + .byte 0x00 /* Padding */ + /* Next Block Pointer */ + .word 0x00000000 /* Next block pointer (0 means no more blocks) */ +/* PICOBIN_BLOCK_MARKER_END */ +.word 0xab123579 /* Marker for the end of the picobin block */ diff --git a/cpu/rp2350/vectors.c b/cpu/rp2350/vectors.c new file mode 100644 index 000000000000..36d0079f4c59 --- /dev/null +++ b/cpu/rp2350/vectors.c @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief Interrupt vector table for the RP2350 + * + * @author Tom Hert + */ + +#include "RP2350.h" +#include "cpu_conf.h" +#include "vectors_cortexm.h" + +/* define a local dummy handler as it needs to be in the same compilation unit + * as the alias definition */ +void dummy_handler(void) { dummy_handler_default(); } + +/* rp2350 specific interrupt vector */ +WEAK_DEFAULT void isr_timer0_0(void); +WEAK_DEFAULT void isr_timer0_1(void); +WEAK_DEFAULT void isr_timer0_2(void); +WEAK_DEFAULT void isr_timer0_3(void); +WEAK_DEFAULT void isr_timer1_0(void); +WEAK_DEFAULT void isr_timer1_1(void); +WEAK_DEFAULT void isr_timer1_2(void); +WEAK_DEFAULT void isr_timer1_3(void); +WEAK_DEFAULT void isr_pwm_wrap_0(void); +WEAK_DEFAULT void isr_pwm_wrap_1(void); +WEAK_DEFAULT void isr_dma_0(void); +WEAK_DEFAULT void isr_dma_1(void); +WEAK_DEFAULT void isr_dma_2(void); +WEAK_DEFAULT void isr_dma_3(void); +WEAK_DEFAULT void isr_usbctrl(void); +WEAK_DEFAULT void isr_pio0_0(void); +WEAK_DEFAULT void isr_pio0_1(void); +WEAK_DEFAULT void isr_pio1_0(void); +WEAK_DEFAULT void isr_pio1_1(void); +WEAK_DEFAULT void isr_pio2_0(void); +WEAK_DEFAULT void isr_pio2_1(void); +WEAK_DEFAULT void isr_io_bank0(void); +WEAK_DEFAULT void isr_io_bank0_ns(void); +WEAK_DEFAULT void isr_io_qspi(void); +WEAK_DEFAULT void isr_io_qspi_ns(void); +WEAK_DEFAULT void isr_sio_fifo(void); +WEAK_DEFAULT void isr_sio_bell(void); +WEAK_DEFAULT void isr_sio_fifo_ns(void); +WEAK_DEFAULT void isr_sio_bell_ns(void); +WEAK_DEFAULT void isr_sio_mtimecmp(void); +WEAK_DEFAULT void isr_clocks(void); +WEAK_DEFAULT void isr_spi0(void); +WEAK_DEFAULT void isr_spi1(void); +WEAK_DEFAULT void isr_uart0(void); +WEAK_DEFAULT void isr_uart1(void); +WEAK_DEFAULT void isr_adc_fifo(void); +WEAK_DEFAULT void isr_i2c0(void); +WEAK_DEFAULT void isr_i2c1(void); +WEAK_DEFAULT void isr_otp(void); +WEAK_DEFAULT void isr_trng(void); +WEAK_DEFAULT void isr_proc0_cti(void); +WEAK_DEFAULT void isr_proc1_cti(void); +WEAK_DEFAULT void isr_pll_sys(void); +WEAK_DEFAULT void isr_pll_usb(void); +WEAK_DEFAULT void isr_powman_pow(void); +WEAK_DEFAULT void isr_powman_timer(void); +WEAK_DEFAULT void isr_spareirq_0(void); +WEAK_DEFAULT void isr_spareirq_1(void); +WEAK_DEFAULT void isr_spareirq_2(void); +WEAK_DEFAULT void isr_spareirq_3(void); +WEAK_DEFAULT void isr_spareirq_4(void); +WEAK_DEFAULT void isr_spareirq_5(void); + +/* CPU specific interrupt vector table */ +ISR_VECTOR(1) +const isr_t vector_cpu[CPU_IRQ_NUMOF] = { + (void*)isr_timer0_0, /* 0 TIMER0_IRQ_0 */ + (void*)isr_timer0_1, /* 1 TIMER0_IRQ_1 */ + (void*)isr_timer0_2, /* 2 TIMER0_IRQ_2 */ + (void*)isr_timer0_3, /* 3 TIMER0_IRQ_3 */ + (void*)isr_timer1_0, /* 4 TIMER1_IRQ_0 */ + (void*)isr_timer1_1, /* 5 TIMER1_IRQ_1 */ + (void*)isr_timer1_2, /* 6 TIMER1_IRQ_2 */ + (void*)isr_timer1_3, /* 7 TIMER1_IRQ_3 */ + (void*)isr_pwm_wrap_0, /* 8 PWM_IRQ_WRAP_0 */ + (void*)isr_pwm_wrap_1, /* 9 PWM_IRQ_WRAP_1 */ + (void*)isr_dma_0, /* 10 DMA_IRQ_0 */ + (void*)isr_dma_1, /* 11 DMA_IRQ_1 */ + (void*)isr_dma_2, /* 12 DMA_IRQ_2 */ + (void*)isr_dma_3, /* 13 DMA_IRQ_3 */ + (void*)isr_usbctrl, /* 14 USBCTRL_IRQ */ + (void*)isr_pio0_0, /* 15 PIO0_IRQ_0 */ + (void*)isr_pio0_1, /* 16 PIO0_IRQ_1 */ + (void*)isr_pio1_0, /* 17 PIO1_IRQ_0 */ + (void*)isr_pio1_1, /* 18 PIO1_IRQ_1 */ + (void*)isr_pio2_0, /* 19 PIO2_IRQ_0 */ + (void*)isr_pio2_1, /* 20 PIO2_IRQ_1 */ + (void*)isr_io_bank0, /* 21 IO_IRQ_BANK0 */ + (void*)isr_io_bank0_ns, /* 22 IO_IRQ_BANK0_NS */ + (void*)isr_io_qspi, /* 23 IO_IRQ_QSPI */ + (void*)isr_io_qspi_ns, /* 24 IO_IRQ_QSPI_NS */ + (void*)isr_sio_fifo, /* 25 SIO_IRQ_FIFO */ + (void*)isr_sio_bell, /* 26 SIO_IRQ_BELL */ + (void*)isr_sio_fifo_ns, /* 27 SIO_IRQ_FIFO_NS */ + (void*)isr_sio_bell_ns, /* 28 SIO_IRQ_BELL_NS */ + (void*)isr_sio_mtimecmp, /* 29 SIO_IRQ_MTIMECMP */ + (void*)isr_clocks, /* 30 CLOCKS_IRQ */ + (void*)isr_spi0, /* 31 SPI0_IRQ */ + (void*)isr_spi1, /* 32 SPI1_IRQ */ + (void*)isr_uart0, /* 33 UART0_IRQ */ + (void*)isr_uart1, /* 34 UART1_IRQ */ + (void*)isr_adc_fifo, /* 35 ADC_IRQ_FIFO */ + (void*)isr_i2c0, /* 36 I2C0_IRQ */ + (void*)isr_i2c1, /* 37 I2C1_IRQ */ + (void*)isr_otp, /* 38 OTP_IRQ */ + (void*)isr_trng, /* 39 TRNG_IRQ */ + (void*)isr_proc0_cti, /* 40 PROC0_IRQ_CTI */ + (void*)isr_proc1_cti, /* 41 PROC1_IRQ_CTI */ + (void*)isr_pll_sys, /* 42 PLL_SYS_IRQ */ + (void*)isr_pll_usb, /* 43 PLL_USB_IRQ */ + (void*)isr_powman_pow, /* 44 POWMAN_IRQ_POW */ + (void*)isr_powman_timer, /* 45 POWMAN_IRQ_TIMER */ + (void*)isr_spareirq_0, /* 46 SPAREIRQ_IRQ_0 */ + (void*)isr_spareirq_1, /* 47 SPAREIRQ_IRQ_1 */ + (void*)isr_spareirq_2, /* 48 SPAREIRQ_IRQ_2 */ + (void*)isr_spareirq_3, /* 49 SPAREIRQ_IRQ_3 */ + (void*)isr_spareirq_4, /* 50 SPAREIRQ_IRQ_4 */ + (void*)isr_spareirq_5, /* 51 SPAREIRQ_IRQ_5 */ +}; + +/** @} */ diff --git a/cpu/rp2350/xosc.c b/cpu/rp2350/xosc.c new file mode 100644 index 000000000000..f701bce2fa7e --- /dev/null +++ b/cpu/rp2350/xosc.c @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: 2025 Tom Hert + * SPDX-FileCopyrightText: 2025 HAW Hamburg + * SPDX-License-Identifier: LGPL-2.1-only + */ + +/** + * @ingroup cpu_rp2350 + * @{ + * + * @file + * @brief XOSC implementation for the RP2350 + * + * @author Tom Hert + */ + +#include + +#include "RP2350.h" +#include "board.h" +#include "macros/units.h" +#include "periph_cpu.h" + +/* Based on datasheet 8.2.4 (1ms wait time) */ +#define STARTUP_DELAY 47 +#define MAX_XOSC_COUNTER_SIZE 0xFFFF +#define SLEEP_100HZ_SPEED 60000 +#define CYCLES_PER_MS (SLEEP_100HZ_SPEED / 1000) + +void xosc_start(void) { + /* Set the FREQ_RANGE */ + XOSC->CTRL = XOSC_CTRL_FREQ_RANGE_VALUE_1_15MHZ; + /* Set the startup delay (default 1ms) */ + XOSC->STARTUP = STARTUP_DELAY; + /* set enable bit */ + atomic_set(&XOSC->CTRL, + XOSC_CTRL_ENABLE_VALUE_ENABLE << XOSC_CTRL_ENABLE_LSB); + + while (!(XOSC->STATUS & XOSC_STATUS_STABLE_BITS)) { + /* Wait for the crystal to stabilize */ + } +} + +void xosc_sleep(int32_t milliseconds) { + for (int32_t i = 0; i < milliseconds; i++) { + XOSC->COUNT = CYCLES_PER_MS * milliseconds; + while (XOSC->COUNT != 0) { + } + } +} + +void xosc_stop(void) { + /* @TODO */ +} + +/** @} */ diff --git a/features.yaml b/features.yaml index ed9a77d6cb0f..b2a573b0f26b 100644 --- a/features.yaml +++ b/features.yaml @@ -287,6 +287,8 @@ groups: features: - name: cpu_rpx0xx help: The MCU is part of the Raspberry PI RPx0xx family. + - name: cpu_rp2350 + help: The MCU is a Raspberry Pi RP2350 - title: Silicon Laboratories EFM32 Grouping features: diff --git a/makefiles/features_existing.inc.mk b/makefiles/features_existing.inc.mk index d70d290f389f..e612ac0a146e 100644 --- a/makefiles/features_existing.inc.mk +++ b/makefiles/features_existing.inc.mk @@ -85,6 +85,7 @@ FEATURES_EXISTING := \ cpu_nrf53 \ cpu_nrf9160 \ cpu_qn908x \ + cpu_rp2350 \ cpu_rpx0xx \ cpu_sam3 \ cpu_sam4s \