1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-15 17:43:51 +01:00

boards: Raspberry Pi Pico 2 support

This commit is contained in:
AnnsAnn 2025-06-10 12:02:30 +02:00
parent 014b17250b
commit 359d3a9efd
31 changed files with 950 additions and 379 deletions

11
boards/rpi-pico-2/Kconfig Normal file
View File

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
# 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

View File

@ -0,0 +1,3 @@
MODULE = board
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
CPU := rp2350

View File

@ -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

15
boards/rpi-pico-2/board.c Normal file
View File

@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
#include "board.h"
void board_init(void) {
/* Re-enable the LED0 pin
* Otherwise the LED will not work after a reset
* This is needed, esp. when the LED is used via
* the define macros */
gpio_init(LED0_PIN_ID, GPIO_OUT);
}

7
boards/rpi-pico-2/dist/openocd.cfg vendored Normal file
View File

@ -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

116
boards/rpi-pico-2/doc.md Normal file
View File

@ -0,0 +1,116 @@
@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 (Pico 2 has 4 MB by default)|
| 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.
If you are using picotool, you need to hold the bootselect button
(the only button on the board) while connecting the board to
your computer via USB. This will put the board into bootloader mode,
allowing you to flash it.
### 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.
- UART does not work via USB, you need to connect it directly to the GPIO pins.
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.

View File

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* 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 <git@annsann.eu>
*/
#include "RP2350.h"
#include "cpu.h"
#include "cpu_conf.h"
#include "periph_conf.h"
#include "periph_cpu.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)"
#ifdef __cplusplus
extern "C" {
#endif
/** Initialize the board, called from the cpu startup code */
void board_init(void);
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* 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

View File

@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
#pragma once
#include <stdint.h>
#include "RP2350.h"
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,6 @@
# Copyright (C) 2021 Otto-von-Guericke-Universität Magdeburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
# SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
# SPDX-FileCopyrightText: 2025 HAW Hamburg
# SPDX-License-Identifier: LGPL-2.1-only
config CPU_FAM_RP2350
bool

View File

@ -1,13 +1,6 @@
MODULE = cpu
USEPKG += picosdk
DIRS = $(RIOTCPU)/cortexm_common periph
DIRS += $(RIOTCPU)/cortexm_common
DIRS += periph
include $(RIOTBASE)/Makefile.base
# Check if picosdk directory exists, otherwise build it
ifeq (,$(wildcard $(RIOTBASE)/dist/tools/picosdk/picosdk))
$(info Building picosdk...)
$(shell $(MAKE) -C $(RIOTBASE)/dist/tools/picosdk)
endif

View File

@ -1,2 +1,3 @@
USEPKG += picosdk
include $(RIOTCPU)/cortexm_common/Makefile.dep

View File

@ -1,5 +1,7 @@
CPU_CORE := cortex-m33
CPU_FAM := RP2350
CPU_ARCH = armv8m
CPU_MODEL = rp2350
include $(RIOTCPU)/cortexm_common/Makefile.features

View File

@ -4,19 +4,16 @@ 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
# Specify CPU and FPU options
CPU_ARCH = armv8m
CPU_MODEL ?= 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
INCLUDES += -isystem$(RIOTBASE)/build/pkg/picosdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include
INCLUDES += -isystem$(RIOTBASE)/build/pkg/picosdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2350/Include
# Linker flags
LINKFLAGS += -mcpu=$(CPU_ARCH) -mthumb
@ -29,7 +26,7 @@ VECTORS_FILE := $(RIOTCPU)/rp2350/vectors.c
# Supported programmers and debuggers
PROGRAMMERS_SUPPORTED := picotool openocd jlink
PROGRAMMER ?= openocd
PROGRAMMER ?= picotool
OPENOCD_DEBUG_ADAPTER ?= dap
# Include the base Cortex-M makefile

View File

@ -1,51 +1,71 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* 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 <git@annsann.eu>
*/
#include "periph_cpu.h"
void clock_reset(void) {
// Reset the clock system
/* 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
* @note RP2350 Docs Chapter 8, mostly 8.2 for more details
*/
* @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
/* Enable the XOSC */
xosc_start();
/**
* Setup the PLL using the XOSC as the reference clock.
*/
//PLL_SYS->CS = REF_DIV; // Set the reference divider
PLL_SYS->FBDIV_INT = 125; // Set the feedback divider
/* 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.
*/
/* 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);
/* 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
/* sleep 10ms to allow the PLL to stabilize */
xosc_sleep(10);
// // Wait for lock
// while (!(PLL_SYS->CS & PLL_CS_LOCK_BITS)) {
// // Wait for the PLL to lock
// }
/* 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. */
// AUXSRC = 0x0 7:5 && SRC == 0x0 0
// CLOCKS: CLK_SYS_CTRL CLK_PERI_CTRL_ENABLE_BIT
CLOCKS->CLK_SYS_CTRL = 1;
/* Wait for lock */
/* while (!(PLL_SYS->CS & PLL_CS_LOCK_BITS)) { */
/* Wait for the PLL to lock */
/* } */
// 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 != 2) {}
/* AUXSRC = 0x0 7:5 && SRC == 0x0 0 */
CLOCKS->CLK_SYS_CTRL = CLK_SYS_PERI_CTRL_ENABLE_BIT;
// src: CLOCKS: CLK_PERI_CTRL
// AUXSRC = 0x0 -> CLK_SYS Indirectly through lower line
/* 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;
}
/** @} */

View File

@ -1,3 +1,19 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* 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 <git@annsann.eu>
*/
#include "cpu.h"
#include "RP2350.h"
@ -17,17 +33,27 @@ void gpio_reset(void) {
}
void cpu_init(void) {
/* initialize the Cortex-M core */
//cortexm_init();
/* initialize the Cortex-M core, once UART support is moved
* to shared driver as currently this will cause unhandled interrupts */
/* cortexm_init(); */
/* Reset GPIO state */
gpio_reset();
//_cpu_reset();
/* initialize stdio prior to periph_init() to allow use of DEBUG() there */
early_init();
/* Reset clock to default state */
clock_reset();
/* initialize the CPU clock */
cpu_clock_init();
/* initialize the early peripherals */
early_init();
/* trigger static peripheral initialization */
periph_init();
/* initialize the board */
board_init();
}
/** @} */

5
cpu/rp2350/doc.md Normal file
View File

@ -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.

View File

@ -1,8 +0,0 @@
/**
@defgroup cpu_rp23xx RP23xx MCUs
@ingroup cpu
@brief RP23xx MCU code and definitions
This module contains the code and definitions for MCUs of the RP23xx family used by the Pi Pico 2
*/

View File

@ -1,69 +1,127 @@
/*
* 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 Clock configuration for the RP2350
*
* @author Tom Hert <git@annsann.eu>
*/
#include "RP2350.h"
#include "macros/units.h"
// Based on hardware/regs/xosc.h and 8.2.8
/** 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
#define XOSC_HZ MHZ(12)
#define REF_DIV 2
#define VCO_FREQ 750000000u
#define PD1 6
#define PD2 2
/** 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
#define CLK_PERI_CTRL_ENABLE_BIT 1 << 11
#define XOSC_FREQ 12000000
#define POSTDIV1 6
#define POSTDIV2 2
#define CPUFREQ 125000000
#define CLOCK_XOSC_MAX MHZ(15) /**< Maximum crystal frequency */
#define CLOCK_XOSC_MIN MHZ(5) /**< Minimum crystal frequency */
#define CLOCK_XOSC (XOSC_HZ) /**< Crystal frequency */
#define PLL_POSTDIV_MIN (1U) /**< Minimum value of the post PLL clock divers */
#define PLL_POSTDIV_MAX (7U) /**< Maximum value of the post PLL clock divers */
#define PLL_VCO_FEEDBACK_SCALE_MIN (16U) /**< Minimum value of the PLL VCO feedback scaler */
#define PLL_VCO_FEEDBACK_SCALE_MAX (320U) /**< Maximum value of the PLL VCO feedback scaler */
#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) /**< Minimum value of the clock divider applied before
/** 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"
#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"
# 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"
# 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"
# error "Value for CLOCK_XOSC out of range, check config"
#endif
#define PDIV ((PD1 << PLL_PRIM_POSTDIV1_LSB) | (PD2 << PLL_PRIM_POSTDIV2_LSB))
#define FBDIV ((VCO_FREQ / XOSC_HZ) / REF_DIV)
/** 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.
*
* @param f_ref Desired frequency in Hz
*
* @pre 1 MHz <= @p f_ref <= 15 MHz.
*
* The reference hardware manual suggests to use a 12 MHz crystal.
* @note The reference hardware manual suggests to use a 12 MHz crystal, which we
* use by default.
*/
void xosc_start(void);
@ -73,9 +131,10 @@ void xosc_start(void);
void xosc_stop(void);
/**
* @brief Sleep for a given number of cycles.
* @brief Sleep for a given time in milliseconds.
* @param milliseconds The time to sleep in milliseconds.
*/
void xosc_sleep(int32_t cycles);
void xosc_sleep(uint32_t milliseconds);
/**
* @brief Reset the clock system.
@ -87,7 +146,14 @@ 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
* @note RP2350 Docs Chapter 8, mostly 8.2 for more details
*/
* @pre 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
/** @} */

View File

@ -1,13 +1,26 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
#pragma once
#include "cpu_conf_common.h"
/**
* @ingroup cpu_rp2350
* @{
* @file
* @brief CPU configuration for the RP2350
*
* @author Tom Hert <git@annsann.eu>
*/
#include "RP2350.h"
#include "core_cm33.h"
#include "cpu_conf_common.h"
#define __CHECK_DEVICE_DEFINES
#define CPU_DEFAULT_IRQ_PRIO (1U)
#define CPU_IRQ_NUMOF (52U)
#define CPU_DEFAULT_IRQ_PRIO 1u
#define CPU_IRQ_NUMOF 52u
#ifdef __cplusplus
extern "C" {
@ -16,3 +29,5 @@ extern "C" {
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -1,23 +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 <git@annsann.eu>
*/
/** 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 {
FUNCTION_SELECT_SPI = 1, /**< connect pin to the SPI peripheral
* (MISO/MOSI/SCK depends on pin) */
FUNCTION_SELECT_UART = 2, /**< connect pin to the UART peripheral
* (TXD/RXD depends on pin) */
FUNCTION_SELECT_I2C = 3, /**< connect pin to the I2C peripheral
* (SCL/SDA depends on pin) */
FUNCTION_SELECT_PWM = 4, /**< connect pin to the timer for PWM
* (channel depends on pin) */
FUNCTION_SELECT_SIO = 5, /**< use pin as vanilla GPIO */
FUNCTION_SELECT_PIO0 = 6, /**< connect pin to the first PIO peripheral */
FUNCTION_SELECT_PIO1 = 7, /**< connect pin to the second PIO peripheral */
FUNCTION_SELECT_CLOCK = 8, /**< connect pin to the timer (depending on pin: external clock,
/** 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_USB = 9, /**< connect pin to the USB peripheral
* (function depends on pin) */
FUNCTION_SELECT_NONE = 31, /**< Reset value, pin unconnected */
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
/** @} */

View File

@ -1,48 +1,80 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
#pragma once
#include "RP2350.h"
#define ATOMIC_XOR_WRITE 0x1000
#define ATOMIC_BITMASK_SET_WRITE 0x2000
#define ATOMIC_BITMASK_CLEAR_WRITE 0x3000
/**
* @ingroup cpu_rp2350
* @{
*
* @file
* @brief Helper functions for atomic register operations
*
* @author Tom Hert <git@annsann.eu>
*/
/** 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] reg Pointer to the target 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)
{
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] reg Pointer to the target register
* @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)
{
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] reg Pointer to the target register
* @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)
{
static inline void atomic_clear(volatile uint32_t *reg, uint32_t val) {
*(volatile uint32_t *)((uintptr_t)reg | ATOMIC_BITMASK_CLEAR_WRITE) = val;
}
static inline void reset_component(uint32_t reset_value, uint32_t reset_done_value)
{
/**
* @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
while (~RESETS->RESET_DONE & reset_done_value) {
/* Wait for the reset to complete */
}
}
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -1,52 +1,97 @@
/*
* 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 Peripheral CPU definitions for the RP2350
*
* @author Tom Hert <git@annsann.eu>
*/
#include <stdbool.h>
#include <stdint.h>
#include "cpu.h"
#include "RP2350.h"
#include "uart_conf.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
/** Overwrite the default GPIO type to use uint32_t */
#define HAVE_GPIO_T
typedef uint32_t gpio_t;
#define LED0_PIN_ID 25
#define OSC_DEBUG_PIN_ID 15
#include "periph/gpio.h"
#define RESET_PLL_SYS 1 << 14
#define RESET_PADS_BANK0 1 << 9
#define RESET_UART0 1 << 26
#define RESET_UART1 1 << 27
#define RESET_IO_BANK0 1 << 6
/** GPIO Pin ID for oscillator debugging */
#define OSC_DEBUG_PIN_ID 15u
#define PADS_BANK0_GPIO0_IE_BITS 1<<6
#define PADS_BANK0_ISO_BITS 1<<8
/** 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
static inline volatile 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
/**
* @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);
}
static volatile uint32_t calculate_gpio_io_status_register_addr(gpio_t pin) {
// Each status register is followed by a ctrl register,
/**
* @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;
}
static inline volatile 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
/**
* @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;
}
@ -54,3 +99,4 @@ static inline volatile uint32_t calculate_gpio_io_ctrl_register_addr(gpio_t pin)
}
#endif
/** @} */

View File

@ -1,24 +1,55 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
#pragma once
#include "periph_cpu.h"
#include "macros/units.h"
/**
* @ingroup cpu_rp2350
* @{
*
* @file
* @brief UART configuration for the RP2350
*
* @author Tom Hert <git@annsann.eu>
*/
#include "RP2350.h"
#include "macros/units.h"
#include "periph_cpu.h"
/** 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)
#ifdef __cplusplus
extern "C" {
#endif
#define BAUDRATE 115200
#define IBRD ((8*CPUFREQ + BAUDRATE)/(2*BAUDRATE))/64
#define FBRD ((8*CPUFREQ + BAUDRATE)/(2*BAUDRATE))%64
#define UART_UARTCR_UARTEN_BITS 1<<0
#define UART_UARTCR_RXE_BITS 1<<9
#define UART_UARTCR_TXE_BITS 1<<8
#define UART_UARTFR_RXFF_BITS 1<<6
#define UART_UARTFR_TXFE_BITS 1<<7
#ifdef __cplusplus
}
#endif
/** @} */

View File

@ -1,3 +1,19 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* 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 <git@annsann.eu>
*/
#include "periph/gpio.h"
#include <errno.h>
@ -10,56 +26,71 @@
#define ENABLE_DEBUG 0
#include "debug.h"
#define GPIO_PIN_NUMOF 30U
int gpio_init(gpio_t pin, gpio_mode_t mode) {
// Check if we exceed the maximum number of GPIO pins
/* Check if we exceed the maximum number of GPIO pins */
assert(pin < GPIO_PIN_NUMOF);
// Clear the pin's output enable and output state
/* 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;
*(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);
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)
/* 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
SIO->GPIO_OE_SET = 1 << pin; /* Set the pin as output */
break;
default:
// Unsupported mode
/* Unsupported mode */
return -ENOTSUP;
}
return 0;
}
bool gpio_read(gpio_t pin) {}
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) {
SIO->GPIO_OUT_SET = 1 << pin; // Set the pin to HIGH
/* 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) {
SIO->GPIO_OUT_CLR = 1 << pin; // Set the pin to LOW
/* 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) {
SIO->GPIO_OUT_XOR = 1 << pin; // Toggle the pin state (XOR)
/* 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
gpio_set(pin); /* Set the pin to HIGH */
} else {
gpio_clear(pin); // Set the pin to LOW
gpio_clear(pin); /* Set the pin to LOW */
}
}
/** @} */

View File

@ -1,52 +1,86 @@
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* 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 <git@annsann.eu>
*/
#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
(void)uart;
(void)baud;
(void)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
/* 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
/* 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
/* 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;
uart_mode(0, 8, UART_PARITY_NONE, 1);
return 0;
}
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits) {
(void)uart;
(void)data_bits;
(void)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;
/* Set the data bits, parity, and stop bits
* Set to 8 bits (0b11) based on Table 1035 page 976
*/
UART0->UARTLCR_H = 0b11 << 5;
switch (parity) {
case UART_PARITY_NONE:
break;
default:
// @todo: Implement other parity modes lel
return UART_NOMODE;
}
UART0->UARTCR =
UART_UARTCR_RXE_BITS | UART_UARTCR_TXE_BITS | UART_UARTCR_UARTEN_BITS;
UART0->UARTCR = UART_UARTCR_TXE_BITS | UART_UARTCR_UARTEN_BITS;
return UART_OK;
}
void uart_write(uart_t uart, const uint8_t *data, size_t len) {
(void)uart;
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));
/* 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) {}
void uart_poweron(uart_t uart) {
(void)uart;
}
void uart_poweroff(uart_t uart) {
(void)uart;
}
/** @} */

View File

@ -1,28 +1,34 @@
// 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
/*
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
.section .picobin_block, "a" // "a" means "allocatable" (can be moved by the linker)
/* 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 */
// PICOBIN_BLOCK_MARKER_START
.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
/* 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
/* 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 */

View File

@ -1,33 +1,26 @@
/*
* Copyright (C) 2021 Ishraq Ibne Ashraf
*
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
/**
* @ingroup cpu_ro2040
* @ingroup cpu_rp2350
* @{
*
* @file vectors.c
* @brief Startup code and interrupt vector definition
* @file
* @brief Interrupt vector table for the RP2350
*
* @author Ishraq Ibne Ashraf <ishraq.i.ashraf@gmail.com>
*
* @}
* @author Tom Hert <git@annsann.eu>
*/
#include "RP2350.h"
#include "cpu_conf.h"
#include "vectors_cortexm.h"
#include "RP2350.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();
}
void dummy_handler(void) { dummy_handler_default(); }
/* rp2350 specific interrupt vector */
WEAK_DEFAULT void isr_timer0_0(void);
@ -84,57 +77,60 @@ 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 */
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 */
};
/** @} */

View File

@ -1,22 +1,17 @@
/*
* Copyright (C) 2021 Otto-von-Guericke Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
* SPDX-FileCopyrightText: 2025 Tom Hert <git@annsann.eu>
* SPDX-FileCopyrightText: 2025 HAW Hamburg
* SPDX-License-Identifier: LGPL-2.1-only
*/
/**
* @ingroup cpu_rpx0xx
* @ingroup cpu_rp2350
* @{
*
* @file
* @brief Implementation of the crystal oscillator (XOSC)
* @brief XOSC implementation for the RP2350
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
* @author Fabian Hüßler <fabian.huessler@ovgu.de>
*
* @}
* @author Tom Hert <git@annsann.eu>
*/
#include <assert.h>
@ -26,33 +21,35 @@
#include "macros/units.h"
#include "periph_cpu.h"
// Based on datasheet 8.2.4 (1ms wait time)
/* Based on datasheet 8.2.4 (1ms wait time) */
#define STARTUP_DELAY 47
#define MAX_XOSC_COUNTER_SIZE 0xFFFF
#define Sleep100HzSpeed 60000
#define CYCLES_PER_MS (Sleep100HzSpeed / 1000)
#define SLEEP_100HZ_SPEED 12000000UL
#define CYCLES_PER_MS (SLEEP_100HZ_SPEED / 1000)
void xosc_start(void) {
// Set the FREQ_RANGE
/* Set the FREQ_RANGE */
XOSC->CTRL = XOSC_CTRL_FREQ_RANGE_VALUE_1_15MHZ;
// Set the startup delay (default 1ms)
/* 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);
/* 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
/* 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_sleep(uint32_t milliseconds) {
for (uint32_t i = milliseconds; i > 0; i--) {
XOSC->COUNT = CYCLES_PER_MS;
while (XOSC->COUNT != 0) {};
}
}
void xosc_stop(void) {
// @TODO
/* @TODO */
}
/** @} */

View File

@ -85,8 +85,8 @@ FEATURES_EXISTING := \
cpu_nrf53 \
cpu_nrf9160 \
cpu_qn908x \
cpu_rpx0xx \
cpu_rp2350 \
cpu_rpx0xx \
cpu_sam3 \
cpu_sam4s \
cpu_samd21 \