rp2040 Datasheet
rp2040 Datasheet
rp2040 Datasheet
Colophon
Copyright © 2020 Raspberry Pi (Trading) Ltd.
The documentation of the RP2040 microcontroller is licensed under a Creative Commons Attribution-NoDerivatives 4.0
International (CC BY-ND).
All rights reserved. Used with permission. Synopsys & DesignWare are registered trademarks of Synopsys, Inc.
Portions Copyright © 2000-2001, 2005, 2007, 2009, 2011-2012, 2016 ARM Limited.
build-date: 2021-03-05
build-version: 9bf4a25-clean
Throughout the text "the SDK" refers to our Raspberry Pi Pico SDK. More details about the SDK can be
found in the Raspberry Pi Pico C/C++ SDK book.
RPTL reserves the right to make any enhancements, improvements, corrections or any other modifications to the
RESOURCES or any products described in them at any time and without further notice.
The RESOURCES are intended for skilled users with suitable levels of design knowledge. Users are solely responsible for
their selection and use of the RESOURCES and any application of the products described in them. User agrees to
indemnify and hold RPTL harmless against all liabilities, costs, damages or other losses arising out of their use of the
RESOURCES.
RPTL grants users permission to use the RESOURCES solely in conjunction with the Raspberry Pi products. All other use
of the RESOURCES is prohibited. No licence is granted to any other RPTL or other third party intellectual property right.
HIGH RISK ACTIVITIES. Raspberry Pi products are not designed, manufactured or intended for use in hazardous
environments requiring fail safe performance, such as in the operation of nuclear facilities, aircraft navigation or
communication systems, air traffic control, weapons systems or safety-critical applications (including life support
systems and other medical devices), in which the failure of the products could lead directly to death, personal injury or
severe physical or environmental damage (“High Risk Activities”). RPTL specifically disclaims any express or implied
warranty of fitness for High Risk Activities and accepts no liability for use or inclusions of Raspberry Pi products in High
Risk Activities.
Raspberry Pi products are provided subject to RPTL’s Standard Terms. RPTL’s provision of the RESOURCES does not
expand or otherwise modify RPTL’s Standard Terms including but not limited to the disclaimers and warranties
expressed in them.
Table of Contents
Colophon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2. Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2. System Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2.1. Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.2.2. Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.3.2. Interrupts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
2.3.4. Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.4. Cortex-M0+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.4.1. Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.4.5. NVIC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
2.4.6. MPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2.4.7. Debug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.5.4. Interrupts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Table of Contents 3
RP2040 Datasheet
Table of Contents 4
RP2040 Datasheet
Table of Contents 5
RP2040 Datasheet
Table of Contents 6
RP2040 Datasheet
Table of Contents 7
RP2040 Datasheet
Clocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
RP2040-E7. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640
GPIO / ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
RP2040-E6. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
USB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
RP2040-E2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
RP2040-E3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 641
RP2040-E4. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
RP2040-E5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
Watchdog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
RP2040-E1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
XIP Flash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
RP2040-E8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 643
Appendix C: Documentation Release History . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
Table of Contents 8
RP2040 Datasheet
Chapter 1. Introduction
Microcontrollers connect the world of software to the world of hardware. They allow developers to write software which
interacts with the physical world in the same deterministic, cycle-accurate manner as digital logic. They occupy the
bottom left corner of the price/performance space, outselling their more powerful brethren by a factor of ten to one.
They are the workhorses that power the digital transformation of our world.
RP2040 is the debut microcontroller from Raspberry Pi. It brings our signature values of high performance, low cost,
and ease of use to the microcontroller space.
With a large on-chip memory, symmetric dual-core processor complex, deterministic bus fabric, and rich peripheral set
augmented with our unique Programmable I/O (PIO) subsystem, it provides professional users with unrivalled power
and flexibility. With detailed documentation, a polished MicroPython port, and a UF2 bootloader in ROM, it has the
lowest possible barrier to entry for beginner and hobbyist users.
RP2040 is a stateless device, with support for cached execute-in-place from external QSPI memory. This design
decision allows you to choose the appropriate density of non-volatile storage for your application, and to benefit from
the low pricing of commodity Flash parts.
RP2040 is manufactured on a modern 40nm process node, delivering high performance, low dynamic power
consumption, and low leakage, with a variety of low-power modes to support extended-duration operation on battery
power.
Key features:
3. floor(log2(ram / 16k))
see Figure 1.
Figure 1. An
explanation for the
name of the RP2040
chip. RP 2 0 4 0
floor(log2(nonvolatile / 16k))
floor(log2(ram / 16k))
Type of core (e.g. M0+)
Number of cores
Raspberry Pi
1.2. Summary
RP2040 is a low-cost, high-performance microcontroller device with flexible digital interfaces. Key features:
1.2. Summary 10
RP2040 Datasheet
Figure 2. A system
overview of the
RP2040 chip
Code may be executed directly from external memory through a dedicated SPI, DSPI or QSPI interface. A small cache
improves performance for typical applications.
Internal SRAM can contain code or data. It is addressed as a single 264 kB region, but physically partitioned into 6
banks to allow simultaneous parallel access from different masters.
DMA bus masters are available to offload repetitive data transfer tasks from the processors.
GPIO pins can be driven directly, or from a variety of dedicated logic functions.
Flexible configurable PIO controllers can be used to provide a wide variety of IO functions.
A USB controller with embedded PHY can be used to provide FS/LS Host or Device connectivity under software control.
Two PLLs to provide a fixed 48MHz clock for USB or ADC, and a flexible system clock up to 133MHz.
An internal Voltage Regulator to supply the core voltage so the end product only needs supply the IO voltage.
Figure 3. RP2040
Pinout for QFN-56
7x7mm (reduced ePad
size)
QSPIx Interface to a SPI, Dual-SPI or Quad-SPI flash device, with execute-in-place support. These pins can
also be used as software-controlled GPIOs, if they are not required for flash access.
USB_DM and USB controller, supporting Full Speed device and Full/Low Speed host. A 27Ω series termination
USB_DP resistor is required on each pin, but bus pullups and pulldowns are provided internally.
XIN and XOUT Connect a crystal to RP2040’s crystal oscillator. XIN can also be used as a single-ended CMOS
clock input, with XOUT disconnected. The USB bootloader requires a 12 MHz crystal or 12 MHz
clock input.
RUN Global asynchronous reset pin. Reset when driven low, run when driven high. If no external reset is
required, this pin can be tied directly to IOVDD.
SWCLK and Access to the internal Serial Wire Debug multi-drop bus. Provides debug access to both
SWDIO processors, and can be used to download code.
GND Single external ground connection, bonded to a number of internal ground pads on the RP2040 die.
IOVDD Power supply for digital GPIOs, nominal voltage 1.8 V to 3.3 V
Name Description
USB_VDD Power supply for internal USB Full Speed PHY, nominal voltage 3.3 V
VREG_VIN Power input for the internal core voltage regulator, nominal voltage 1.8 V to 3.3 V
VREG_VOUT Power output for the internal core voltage regulator, nominal voltage 1.1 V, 100 mA max current
DVDD Digital core power supply, nominal voltage 1.1 V. Can be connected to VREG_VOUT, or to some
other board-level power supply.
Table 2. General
Function
Purpose Input/Output
(GPIO) Bank 0
GPIO F1 F2 F3 F4 F5 F6 F7 F8 F9
Functions
0 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB OVCUR DET
1 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS DET
2 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB VBUS EN
3 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB OVCUR DET
4 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 USB VBUS DET
5 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 USB VBUS EN
6 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 USB OVCUR DET
7 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 USB VBUS DET
8 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 USB VBUS EN
9 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 USB OVCUR DET
10 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS DET
11 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB VBUS EN
12 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB OVCUR DET
13 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS DET
14 SPI1 SCK UART0 CTS I2C1 SDA PWM7 A SIO PIO0 PIO1 USB VBUS EN
15 SPI1 TX UART0 RTS I2C1 SCL PWM7 B SIO PIO0 PIO1 USB OVCUR DET
16 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB VBUS DET
17 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS EN
18 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB OVCUR DET
19 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB VBUS DET
20 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 CLOCK GPIN0 USB VBUS EN
21 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 CLOCK GPOUT0 USB OVCUR DET
Function
22 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 CLOCK GPIN1 USB VBUS DET
23 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 CLOCK GPOUT1 USB VBUS EN
24 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 CLOCK GPOUT2 USB OVCUR DET
25 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 CLOCK GPOUT3 USB VBUS DET
26 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS EN
27 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB OVCUR DET
28 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB VBUS DET
29 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS EN
PWMx A/B Connect a PWM slice to GPIO. There are eight PWM slices, each with two output
channels (A/B). The B pin can also be used as an input, for frequency and duty cycle
measurement.
SIO Software control of GPIO, from the single-cycle IO (SIO) block. The SIO function (F5)
must be selected for the processors to drive a GPIO, but the input is always connected,
so software can check the state of GPIOs at any time.
PIOx Connect one of the programmable IO blocks (PIO) to GPIO. PIO can implement a wide
variety of interfaces, and has its own internal pin mapping hardware, allowing flexible
placement of digital interfaces on bank 0 GPIOs. The PIO function (F6, F7) must be
selected for PIO to drive a GPIO, but the input is always connected, so the PIOs can
always see the state of all pins.
CLOCK GPINx General purpose clock inputs. Can be routed to a number of internal clock domains on
RP2040, e.g. to provide a 1 Hz clock for the RTC, or can be connected to an internal
frequency counter.
CLOCK GPOUTx General purpose clock outputs. Can drive a number of internal clocks (including PLL
outputs) onto GPIOs, with optional integer divide.
USB OVCUR DET/VBUS USB power control signals to/from the internal USB controller
DET/VBUS EN
Figure 4 shows the high-level structure of the bus fabric. The main AHB-Lite crossbar routes addresses and data
between its 4 upstream ports and 10 downstream ports: up to four bus transfers can take place each cycle. All data
paths are 32 bits wide. Memory devices have dedicated ports on the main crossbar, to satisfy their high bandwidth
requirements. High-bandwidth AHB-Lite peripherals have a shared port on the crossbar, and an APB bridge provides bus
access to system control registers and lower-bandwidth peripherals.
The bus fabric connects 4 AHB-Lite masters, i.e. devices which generate addresses:
• Processor core 0
• Processor core 1
• DMA controller Read port
• DMA controller Write port
These are routed through to 10 downstream ports on the main crossbar:
• ROM
• Flash XIP
• SRAM 0 to 5 (one port each)
• Fast AHB-Lite peripherals: PIO0, PIO1, USB, DMA control registers, XIP aux (one shared port)
• Bridge to all APB peripherals, and system control registers
The four bus masters can access any four different crossbar ports simultaneously, the bus fabric does not add wait
states to any AHB-Lite slave access. So at a system clock of 125 MHz the maximum sustained bus bandwidth is 2.0
GB/s. The system address map has been arranged to make this parallel bandwidth available to as many software use
cases as possible — for example, the striped SRAM alias (Section 2.6.2) scatters main memory accesses across four
crossbar ports (SRAM0…3), so that more memory accesses can proceed in parallel.
• Splitters
◦ Perform coarse address decode
◦ Route requests (addresses, write data) to the downstream port indicated by the initial address decode
◦ Route responses (read data, bus errors) from the correct arbiter back to the upstream port
• Arbiters
◦ Manage concurrent requests to a downstream port
◦ Route responses (read data, bus errors) to the correct splitter
◦ Implement bus priority rules
The main crossbar on RP2040 consists of 4 1:10 splitters and 10 4:1 arbiters, with a mesh of 40 AHB-Lite bus channels
between them. Note that, as AHB-Lite is a pipelined bus, the splitter may be routing back a response to an earlier
request from downstream port A, whilst a new request to downstream port B is already in progress. This does not incur
any cycle penalty.
The arbiters in the main AHB-Lite crossbar implement a two-level bus priority scheme. Priority levels are configured per-
master, using the BUS_PRIORITY register in the BUSCTRL register block.
When there are multiple simultaneous accesses to same arbiter, any requests from high-priority masters (priority level
1) will be considered before any requests from low-priority masters (priority 0). If multiple masters of the same priority
level attempt to access the same slave simultaneously, a round-robin tie break is applied, i.e. the arbiter grants access
to each master in turn.
NOTE
Priority arbitration only applies to multiple masters attempting to access the same slave on the same cycle.
Accesses to different slaves, e.g. different SRAM banks, can proceed simultaneously.
When accessing a slave with zero wait states, such as SRAM (i.e. can be accessed once per system clock cycle), high-
priority masters will never observe any slowdown or other timing effects caused by accesses from low-priority masters.
This allows guaranteed latency and throughput for hard real time use cases; it does however mean a low-priority master
may get stalled until there is a free cycle.
The performance counters automatically count accesses to the main AHB-Lite crossbar arbiters. This can assist in
diagnosing performance issues, in high-traffic use cases.
There are four performance counters. Each is a 24-bit saturating counter. Counter values can be read from
BUSCTRL_PERFCTRx, and cleared by writing any value to BUSCTRL_PERFCTRx. Each counter can count one of the 20 available
events at a time, as selected by BUSCTRL_PERFSELx. The available bus events are:
0 APB access, Completion of an access to the APB arbiter (which is upstream of all APB
contested peripherals), which was previously delayed due to an access by another master.
2 FASTPERI access, Completion of an access to the FASTPERI arbiter (which is upstream of PIOs, DMA
contested config port, USB, XIP aux FIFO port), which was previously delayed due to an access
by another master.
4 SRAM5 access, Completion of an access to the SRAM5 arbiter, which was previously delayed due to
contested an access by another master.
6 SRAM4 access, Completion of an access to the SRAM4 arbiter, which was previously delayed due to
contested an access by another master.
8 SRAM3 access, Completion of an access to the SRAM3 arbiter, which was previously delayed due to
contested an access by another master.
10 SRAM2 access, Completion of an access to the SRAM2 arbiter, which was previously delayed due to
contested an access by another master.
12 SRAM1 access, Completion of an access to the SRAM1 arbiter, which was previously delayed due to
contested an access by another master.
14 SRAM0 access, Completion of an access to the SRAM0 arbiter, which was previously delayed due to
contested an access by another master.
16 XIP_MAIN access, Completion of an access to the XIP_MAIN arbiter, which was previously delayed due
contested to an access by another master.
18 ROM access, Completion of an access to the ROM arbiter, which was previously delayed due to an
contested access by another master.
The four atomic access aliases occupy a total of 16 kB. Most peripherals on RP2040 provide this functionality natively,
and atomic writes have the same timing as normal read/write access. Some peripherals (I2C, UART, SPI and SSI)
instead have this functionality added using a bus interposer, which translates upstream atomic writes into downstream
read-modify-write sequences, at the boundary of the peripheral. This extends the access time by two system clock
cycles.
The SIO (Section 2.3.1), a single-cycle IO block attached directly to the cores' IO ports, does not support atomic
accesses at the bus level, although some individual registers (e.g. GPIO) have set/clear/xor aliases.
• APB bus accesses take two cycles minimum (setup phase and access phase)
• The bridge adds an additional cycle to read accesses, as the bus request and response are registered
• The bridge adds two additional cycles to write accesses, as the APB setup phase can not begin until the AHB-Lite
write data is valid
As a result, the throughput of the APB portion of the bus fabric is somewhat lower than the AHB-Lite portion. However,
there is more than sufficient bandwidth to saturate the APB serial peripherals.
To update part of an IO register, without a read-modify-write sequence, the best solution on RP2040 is atomic
set/clear/XOR (see Section 2.1.2). Note that this is more flexible than byte or halfword writes, as any combination of
fields can be updated in one operation.
Upon a 8-bit or 16-bit write (such as a strb instruction on the Cortex-M0+), an IO register will sample the entire 32-bit
write databus. The Cortex-M0+ and DMA on RP2040 will always replicate narrow data across the bus:
19 int main() {
20 stdio_init_all();
21
22 // We'll use WATCHDOG_SCRATCH0 as a convenient 32 bit read/write register
23 // that we can assign arbitrary values to
24 io_rw_32 *scratch32 = &watchdog_hw->scratch[0];
25 // Alias the scratch register as two halfwords at offsets +0x0 and +0x2
26 volatile uint16_t *scratch16 = (volatile uint16_t *) scratch32;
27 // Alias the scratch register as four bytes at offsets +0x0, +0x1, +0x2, +0x3:
28 volatile uint8_t *scratch8 = (volatile uint8_t *) scratch32;
29
30 // Show that we can read/write the scratch register as normal:
31 printf("Writing 32 bit value\n");
32 *scratch32 = 0xdeadbeef;
33 printf("Should be 0xdeadbeef: 0x%08x\n", *scratch32);
34
35 // We can do narrow reads just fine -- IO registers treat this as a 32 bit
36 // read, and the processor/DMA will pick out the correct byte lanes based
37 // on transfer size and address LSBs
38 printf("\nReading back 1 byte at a time\n");
39 // Little-endian!
40 printf("Should be ef be ad de: %02x %02x %02x %02x\n",
41 scratch8[0], scratch8[1], scratch8[2], scratch8[3]);
42
43 // The Cortex-M0+ and the RP2040 DMA replicate byte writes across the bus,
44 // and IO registers will sample the entire write bus always.
45 printf("\nWriting 8 bit value 0xa5 at offset 0\n");
46 scratch8[0] = 0xa5;
47 // Read back the whole scratch register in one go
48 printf("Should be 0xa5a5a5a5: 0x%08x\n", *scratch32);
49
50 // The IO register ignores the address LSBs [1:0] as well as the transfer
51 // size, so it doesn't matter what byte offset we use
52 printf("\nWriting 8 bit value at offset 1\n");
53 scratch8[1] = 0x3c;
54 printf("Should be 0x3c3c3c3c: 0x%08x\n", *scratch32);
55
56 // Halfword writes are also replicated across the write data bus
57 printf("\nWriting 16 bit value at offset 0\n");
58 scratch16[0] = 0xf00d;
59 printf("Should be 0xf00df00d: 0x%08x\n", *scratch32);
60 }
Table 4. List of
Offset Name Info
BUSCTRL registers
0x00 BUS_PRIORITY Set the priority of each master for bus arbitration.
Description
Set the priority of each master for bus arbitration.
Table 5.
Bits Name Description Type Reset
BUS_PRIORITY
Register
31:13 Reserved. - - -
11:9 Reserved. - - -
7:5 Reserved. - - -
3:1 Reserved. - - -
Description
Bus priority acknowledge
Table 6.
Bits Description Type Reset
BUS_PRIORITY_ACK
Register
31:1 Reserved. - -
0 Goes to 1 once all arbiters have registered the new global priority levels. RO 0x0
Arbiters update their local priority when servicing a new nonsequential access.
In normal circumstances this will happen almost immediately.
Description
Bus fabric performance counter 0
Table 7. PERFCTR0
Bits Description Type Reset
Register
31:24 Reserved. - -
Description
Bus fabric performance event select for PERFCTR0
Table 8. PERFSEL0
Bits Description Type Reset
Register
31:5 Reserved. - -
4:0 Select an event for PERFCTR0. Count either contested accesses, or all RW 0x1f
accesses, on a downstream port of the main crossbar.
0x00 → apb_contested
0x01 → apb
0x02 → fastperi_contested
0x03 → fastperi
0x04 → sram5_contested
0x05 → sram5
0x06 → sram4_contested
0x07 → sram4
0x08 → sram3_contested
0x09 → sram3
0x0a → sram2_contested
0x0b → sram2
0x0c → sram1_contested
0x0d → sram1
0x0e → sram0_contested
0x0f → sram0
0x10 → xip_main_contested
0x11 → xip_main
0x12 → rom_contested
0x13 → rom
Description
Bus fabric performance counter 1
Table 9. PERFCTR1
Bits Description Type Reset
Register
31:24 Reserved. - -
Description
Bus fabric performance event select for PERFCTR1
31:5 Reserved. - -
4:0 Select an event for PERFCTR1. Count either contested accesses, or all RW 0x1f
accesses, on a downstream port of the main crossbar.
0x00 → apb_contested
0x01 → apb
0x02 → fastperi_contested
0x03 → fastperi
0x04 → sram5_contested
0x05 → sram5
0x06 → sram4_contested
0x07 → sram4
0x08 → sram3_contested
0x09 → sram3
0x0a → sram2_contested
0x0b → sram2
0x0c → sram1_contested
0x0d → sram1
0x0e → sram0_contested
0x0f → sram0
0x10 → xip_main_contested
0x11 → xip_main
0x12 → rom_contested
0x13 → rom
Description
Bus fabric performance counter 2
31:24 Reserved. - -
Description
Bus fabric performance event select for PERFCTR2
31:5 Reserved. - -
4:0 Select an event for PERFCTR2. Count either contested accesses, or all RW 0x1f
accesses, on a downstream port of the main crossbar.
0x00 → apb_contested
0x01 → apb
0x02 → fastperi_contested
0x03 → fastperi
0x04 → sram5_contested
0x05 → sram5
0x06 → sram4_contested
0x07 → sram4
0x08 → sram3_contested
0x09 → sram3
0x0a → sram2_contested
0x0b → sram2
0x0c → sram1_contested
0x0d → sram1
0x0e → sram0_contested
0x0f → sram0
0x10 → xip_main_contested
0x11 → xip_main
0x12 → rom_contested
0x13 → rom
Description
Bus fabric performance counter 3
31:24 Reserved. - -
Description
Bus fabric performance event select for PERFCTR3
31:5 Reserved. - -
4:0 Select an event for PERFCTR3. Count either contested accesses, or all RW 0x1f
accesses, on a downstream port of the main crossbar.
0x00 → apb_contested
0x01 → apb
0x02 → fastperi_contested
0x03 → fastperi
0x04 → sram5_contested
0x05 → sram5
0x06 → sram4_contested
0x07 → sram4
0x08 → sram3_contested
0x09 → sram3
0x0a → sram2_contested
0x0b → sram2
0x0c → sram1_contested
0x0d → sram1
0x0e → sram0_contested
0x0f → sram0
0x10 → xip_main_contested
0x11 → xip_main
0x12 → rom_contested
0x13 → rom
2.2.1. Summary
Table 15. Address
ROM 0x00000000
Map Summary
XIP 0x10000000
SRAM 0x20000000
2.2.2. Detail
ROM:
ROM_BASE 0x00000000
XIP:
XIP_BASE 0x10000000
XIP_NOALLOC_BASE 0x11000000
XIP_NOCACHE_BASE 0x12000000
XIP_NOCACHE_NOALLOC_BASE 0x13000000
XIP_CTRL_BASE 0x14000000
XIP_SRAM_BASE 0x15000000
XIP_SRAM_END 0x15004000
XIP_SSI_BASE 0x18000000
SRAM_BASE 0x20000000
SRAM_STRIPED_BASE 0x20000000
SRAM_STRIPED_END 0x20040000
SRAM4_BASE 0x20040000
SRAM5_BASE 0x20041000
SRAM_END 0x20042000
SRAM0_BASE 0x21000000
SRAM1_BASE 0x21010000
SRAM2_BASE 0x21020000
SRAM3_BASE 0x21030000
APB Peripherals:
SYSINFO_BASE 0x40000000
SYSCFG_BASE 0x40004000
CLOCKS_BASE 0x40008000
RESETS_BASE 0x4000c000
PSM_BASE 0x40010000
IO_BANK0_BASE 0x40014000
IO_QSPI_BASE 0x40018000
PADS_BANK0_BASE 0x4001c000
PADS_QSPI_BASE 0x40020000
XOSC_BASE 0x40024000
PLL_SYS_BASE 0x40028000
PLL_USB_BASE 0x4002c000
BUSCTRL_BASE 0x40030000
UART0_BASE 0x40034000
UART1_BASE 0x40038000
SPI0_BASE 0x4003c000
SPI1_BASE 0x40040000
I2C0_BASE 0x40044000
I2C1_BASE 0x40048000
ADC_BASE 0x4004c000
PWM_BASE 0x40050000
TIMER_BASE 0x40054000
WATCHDOG_BASE 0x40058000
RTC_BASE 0x4005c000
ROSC_BASE 0x40060000
VREG_AND_CHIP_RESET_BASE 0x40064000
TBMAN_BASE 0x4006c000
AHB-Lite peripherals:
DMA_BASE 0x50000000
USBCTRL_BASE 0x50100000
USBCTRL_DPRAM_BASE 0x50100000
USBCTRL_REGS_BASE 0x50110000
PIO0_BASE 0x50200000
PIO1_BASE 0x50300000
XIP_AUX_BASE 0x50400000
IOPORT Peripherals:
SIO_BASE 0xd0000000
PPB_BASE 0xe0000000
The processors use a number of interfaces to communicate with the rest of the system:
• Each processor uses its own independent 32-bit AHB-Lite bus to access memory and memory-mapped peripherals
(more detail in Section 2.1)
• The single-cycle IO block provides high-speed, deterministic access to GPIOs via each processor’s IOPORT
• 26 system-level interrupts are routed to both processors
• A multi-drop Serial Wire Debug bus provides debug access to both processors from an external debug host
2.3.1. SIO
The Single-cycle IO block (SIO) contains several peripherals that require low-latency, deterministic access from the
processors. It is accessed via each processor’s IOPORT: this is an auxiliary bus port on the Cortex-M0+ which can
perform rapid 32-bit reads and writes. The SIO has a dedicated bus interface for each processor’s IOPORT, as shown in
Figure 7. Processors access their IOPORT with normal load and store instructions, directed to the special IOPORT
address segment, 0xd0000000…0xdfffffff. The SIO appears as memory-mapped hardware within the IOPORT space.
NOTE
The SIO is not connected to the main system bus due to its tight timing requirements. It can only be accessed by the
processors, or by the debugger via the processor debug ports.
Interpolator 1 Interpolator 1
GPIO ×36
To GPIO Muxing
All IOPORT reads and writes (and therefore all SIO accesses) take place in exactly one cycle, unlike the main AHB-Lite
system bus, where the Cortex-M0+ requires two cycles for a load or store, and may have to wait longer due to
contention from other system bus masters. This is vital for interfaces such as GPIO, which have tight timing
requirements.
SIO registers are mapped to word-aligned addresses in the range 0xd0000000…0xd000017c. The remainder of the IOPORT
space is reserved for future use.
The SIO peripherals are described in more detail in the following sections.
2.3.1.1. CPUID
The register CPUID is the first register in the IOPORT space. Core 0 reads a value of 0 when accessing this address, and
core 1 reads a value of 1. This is a convenient method for software to determine on which core it is running. This is
checked during the initial boot sequence: both cores start running simultaneously, core 1 goes into a deep sleep state,
and core 0 continues with the main boot sequence.
IMPORTANT
CPUID should not be confused with the Cortex-M0+ CPUID register (Section 2.4.4.1.1) on each processor’s internal
Private Peripheral Bus, which lists the processor’s part number and version.
The processors have access to GPIO registers for fast and direct control of pins with GPIO functionality. There are two
identical sets of registers:
• GPIO_x for direct control of IO bank 0 (user GPIOs 0 to 29, starting at the LSB)
• GPIO_HI_x for direct control of the QSPI IO bank (in the order SCLK, SSn, SD0, SD1, SD2, SD3, starting at the LSB)
NOTE
To drive a pin with the SIO’s GPIO registers, the GPIO multiplexer for this pin must first be configured to select the
SIO GPIO function. See Table 289.
These GPIO registers are shared between the two cores, and both cores can access them simultaneously. There are
three registers for each bank:
• Output registers, GPIO_OUT and GPIO_HI_OUT, are used to set the output level of the GPIO (1/0 for high/low)
• Output enable registers, GPIO_OE and GPIO_HI_OE, are used to enable the output driver. 0 for high-impedance, 1
for drive high/low based on GPIO_OUT and GPIO_HI_OUT.
• Input registers, GPIO_IN and GPIO_HI_IN, allow the processor to sample the current state of the GPIOs
Reading GPIO_IN returns all 30 GPIO values (or 6 for GPIO_HI_IN) in a single read. Software can then mask out
individual pins it is interested in.
The OUT and OE registers also have atomic SET, CLR, and XOR aliases, which allows software to update a subset of the
pins in one operation. This is vital not only for safe parallel GPIO access between the two cores, but also safe
concurrent GPIO access in an interrupt handler and foreground code running on one core.
If both processors write to an OUT or OE register (or any of its SET/CLR/XOR aliases) on the same clock cycle, the result
is as though core 0 wrote first, and core 1 wrote immediately afterward. For example, if core 0 SETs a bit, and core 1
simultaneously XORs it, the bit will be set to 0, irrespective of it original value.
NOTE
This is a conceptual model for the result that is produced when two cores write to a GPIO register simultaneously.
The register does not actually contain this intermediate value at any point. In the previous example, if the pin is
initially 0, and core 0 performs a SET while core 1 performs a XOR, the GPIO output remains low without any positive
glitch.
The SIO provides 32 hardware spinlocks, which can be used to manage mutually-exclusive access to shared software
resources. Each spinlock is a one-bit flag, mapped to a different address (from SPINLOCK0 to SPINLOCK31). Software
interacts with each spinlock with one of the following operations:
• Read: attempt to claim the lock. Read value is nonzero if the lock was successfully claimed, or zero if the lock had
already been claimed by a previous read.
• Write (any value): release the lock. The next attempt to claim the lock will be successful.
If both cores try to claim the same lock on the same clock cycle, core 0 succeeds.
Generally software will acquire a lock by repeatedly polling the lock bit ("spinning" on the lock) until it is successfully
claimed. This is inefficient if the lock is held for long periods, so generally the spinlocks should be used to protect the
short critical sections of higher-level primitives such as mutexes, semaphores and queues.
For debugging purposes, the current state of all 32 spinlocks can be observed via SPINLOCK_ST.
The SIO contains two FIFOs for passing data, messages or ordered events between the two cores. Each FIFO is 32 bits
wide, and eight entries deep. One of the FIFOs can only be written by core 0, and read by core 1. The other can only be
written by core 1, and read by core 0.
Each core writes to its outgoing FIFO by writing to FIFO_WR, and reads from its incoming FIFO by reading from FIFO_RD.
A status register, FIFO_ST, provides the following status signals:
The SIO has a FIFO IRQ output for each core, mapped to system IRQ numbers 15 and 16. Each IRQ output is the logical
OR of the VLD, ROE and WOF bits in that core’s FIFO_ST register: that is, the IRQ is asserted if any of these three bits is high,
and clears again when they are all low. The ROE and WOF flags are cleared by writing any value to FIFO_ST, and the VLD flag
is cleared by reading data from the FIFO until empty.
If the corresponding interrupt line is enabled in the Cortex-M0+ NVIC, then the processor will take an interrupt each time
data appears in its FIFO, or if it has performed some invalid FIFO operation (read on empty, write on full). Typically Core
0 will use IRQ15 and core 1 will use IRQ16. If the IRQs are used the other way round then it is difficult for the core that
has been interrupted to correctly identify the reason for the interrupt as the core doesn’t have access to the other core’s
FIFO status register.
NOTE
ROE and WOF only become set if software misbehaves in some way. Generally, the interrupt handler will trigger when
data appears in the FIFO (raising the VLD flag), and the interrupt handler clears the IRQ by reading data from the FIFO
until VLD goes low once more.
The inter-processor FIFOs and the Cortex-M0+ Event signals are used by the bootrom (Section 2.8) wait_for_vector
routine, where core 1 remains in a sleep state until it is woken, and provided with its initial stack pointer, entry point and
vector table through the FIFO.
The SIO provides one 8-cycle signed/unsigned divide/modulo module to each of the cores. Calculation is started by
writing a dividend and divisor to the two argument registers, DIVIDEND and DIVISOR. The divider calculates the quotient /
and remainder % of this division over the next 8 cycles, and on the 9th cycle the results can be read from the two result
registers DIV_QUOTIENT and DIV_REMAINDER. A 'ready' bit in register DIV_CSR can be polled to wait for the calculation
to complete, or software can insert a fixed 8-cycle delay.
10 .macro __divider_delay
11 // delay 8 cycles
12 b 1f
13 1: b 1f
14 1: b 1f
15 1: b 1f
16 1:
17 .endm
18
19 .align 2
20
21 regular_func_with_section hw_divider_divmod_s32
22 ldr r3, =(SIO_BASE)
23 str r0, [r3, #SIO_DIV_SDIVIDEND_OFFSET]
24 str r1, [r3, #SIO_DIV_SDIVISOR_OFFSET]
25 __divider_delay
26 // return 64 bit value so we can efficiently return both (note quotient must be read
last)
27 ldr r1, [r3, #SIO_DIV_REMAINDER_OFFSET]
28 ldr r0, [r3, #SIO_DIV_QUOTIENT_OFFSET]
29 bx lr
NOTE
Software is free to perform other non divider operations during these 8 cycles.
There are two aliases of the operand registers: writing to the signed alias (DIV_SDIVIDEND and DIV_SDIVISOR) will
initiate a signed calculation, and the other (DIV_UDIVIDEND and DIV_UDIVISOR) will initiate an unsigned calculation.
36 regular_func_with_section hw_divider_divmod_u32
37 ldr r3, =(SIO_BASE)
38 str r0, [r3, #SIO_DIV_UDIVIDEND_OFFSET]
39 str r1, [r3, #SIO_DIV_UDIVISOR_OFFSET]
40 __divider_delay
41 // return 64 bit value so we can efficiently return both (note quotient must be read
last)
42 ldr r1, [r3, #SIO_DIV_REMAINDER_OFFSET]
43 ldr r0, [r3, #SIO_DIV_QUOTIENT_OFFSET]
44 bx lr
NOTE
A new calculation begins immediately with every write to an operand register, and a new operand write immediately
squashes any calculation currently in progress. For example, when dividing many numbers by the same divisor, only
xDIVIDEND needs to be written, and the signedness of each calculation is determined by whether SDIVIDEND or UDIVIDEND
is written.
To support save and restore on interrupt handler entry/exit (or on e.g. an RTOS context switch), the result registers are
also writable. Writing to a result register will cancel any operation in progress at the time. The DIV_CSR.DIRTY flag can
help make save/restore more efficient: this flag is set when any divider register (operand or result) is written to, and
cleared when the quotient is read.
NOTE
When enabled, the default divider AEABI support maps C level / and % to the hardware divider. When building
software using the SDK and using the divider directly, it is important to read the quotient register last. This ensures
the partial divider state will be correctly saved and restored by any interrupt code that uses the divider. You should
read the quotient register whether you need the value or not.
2.3.1.6. Interpolator
Each core is equipped with two interpolators (INTERP0 and INTERP1) which can accelerate tasks by combining certain pre-
configured operations into a single processor cycle. Intended for cases where the pre-configured operation is repeated
many times, this results in code which uses both fewer CPU cycles and fewer CPU registers in the time-critical sections
of the code.
The interpolators are used to accelerate audio operations within the SDK, but their flexible configuration makes it
possible to optimise many other tasks such as quantization and dithering, table lookup address generation, affine
texture mapping, decompression and linear feedback.
Figure 8. An
interpolator. The two
Base 0
accumulator registers
and three base
registers have single-
Result 0 0 0 1 1
cycle read/write Sign-extend
access from the
Accumulator 0 Right Shift Mask
fromMask
+ Result 0
Result 1 1 1 0 0
processor. The Accumulator 1
interpolator is
organised into two Base 2 + Result 2
lanes, which perform
masking, shifting and Accumulator 0
sign-extension Result 0 1 1 0 0
Sign-extend
operations on the two Accumulator 1 Right Shift Mask
fromMask
+ Result 1
accumulators. This Result 1 0 0 1 1
produces three
possible results, by
Base 1
adding the
intermediate
shift/mask values to
the three base
registers. From left to The processor can write or read any interpolator register in one cycle, and the results are ready on the next cycle. The
right, the multiplexers
processor can also perform an addition on one of the two accumulators ACCUM0 or ACCUM1 by writing to the corresponding
on each lane are
controlled by the ACCUMx_ADD register.
following flags in the
CTRL registers: The three results are available in the read-only locations PEEK0, PEEK1, PEEK2. Reading from these locations does not
CROSS_RESULT, change the state of the interpolator. The results are also aliased at the locations POP0, POP1, POP2; reading from a POPx alias
CROSS_INPUT,
returns the same result as the corresponding PEEKx, and simultaneously writes back the lane results to the
SIGNED, ADD_RAW.
accumulators. This can be used to advance the state of interpolator each time a result is read.
Additionally the interpolator supports simple fractional blending between two values as well as clamping values such
that they lie within a given range.
The following example shows a trivial example of popping a lane result to produce simple iterative feedback.
11 void times_table() {
12 puts("9 times table:");
13
14 // Initialise lane 0 on interp0 on this core
15 interp_config cfg = interp_default_config();
16 interp_set_config(interp0, 0, &cfg);
17
18 interp0->accum[0] = 0;
19 interp0->base[0] = 9;
20
21 for (int i = 0; i < 10; ++i)
22 printf("%d\n", interp0->pop[0]);
23 }
NOTE
By sheer coincidence, the interpolators are extremely well suited to SNES MODE7-style graphics routines. For
example, on each core, INTERP0 can provide a stream of tile lookups for some affine transform, and INTERP1 can
provide offsets into the tiles for the same transform.
25 void moving_mask() {
26 interp_config cfg = interp_default_config();
27 interp0->accum[0] = 0x1234abcd;
28
29 puts("Masking:");
30 printf("ACCUM0 = %08x\n", interp0->accum[0]);
31 for (int i = 0; i < 8; ++i) {
32 // LSB, then MSB. These are inclusive, so 0,31 means "the entire 32 bit register"
33 interp_config_set_mask(&cfg, i * 4, i * 4 + 3);
34 interp_set_config(interp0, 0, &cfg);
35 // Reading from ACCUMx_ADD returns the raw lane shift and mask value, without BASEx
added
36 printf("Nibble %d: %08x\n", i, interp0->add_raw[0]);
37 }
38
ACCUM0 = 1234abcd
Nibble 0: 0000000d
Nibble 1: 000000c0
Nibble 2: 00000b00
Nibble 3: 0000a000
Nibble 4: 00040000
Nibble 5: 00300000
Nibble 6: 02000000
Nibble 7: 10000000
Masking with sign extension:
Nibble 0: fffffffd
Nibble 1: ffffffc0
Nibble 2: fffffb00
Nibble 3: ffffa000
Nibble 4: 00040000
Nibble 5: 00300000
Nibble 6: 02000000
Nibble 7: 10000000
Changing the result and input multiplexers can create feedback between the accumulators. This is useful e.g. for audio
dithering.
48 void cross_lanes() {
49 interp_config cfg = interp_default_config();
50 interp_config_set_cross_result(&cfg, true);
51 // ACCUM0 gets lane 1 result:
52 interp_set_config(interp0, 0, &cfg);
53 // ACCUM1 gets lane 0 result:
54 interp_set_config(interp0, 1, &cfg);
55
56 interp0->accum[0] = 123;
57 interp0->accum[1] = 456;
58 interp0->base[0] = 1;
59 interp0->base[1] = 0;
60 puts("Lane result crossover:");
61 for (int i = 0; i < 10; ++i)
62 printf("PEEK0, POP1: %d, %d\n", interp0->peek[0], interp0->pop[1]);
63 }
Blend mode is available on INTERP0 on each core, and is enabled by the CTRL_LANE0_BLEND control flag. It performs linear
interpolation, which we define as follows:
Where is the register BASE0, is the register BASE1, and is a fractional value formed from the least significant 8 bits
of the lane 1 shift and mask value.
• PEEK0, POP0 return the 8-bit alpha value (the 8 LSBs of the lane 1 shift and mask value), with zeroes in result bits 31
down to 24.
• PEEK1, POP1 return the linear interpolation between BASE0 and BASE1
• PEEK2, POP2 do not include lane 1 result in the addition (i.e. it is BASE2 + lane 0 shift and mask value)
The result of the linear interpolation is equal to BASE0 when the alpha value is 0, and equal to BASE0 + 255/256 * (BASE1 -
BASE0) when the alpha value is all-ones.
65 void simple_blend1() {
66 puts("Simple blend 1:");
67
68 interp_config cfg = interp_default_config();
69 interp_config_set_blend(&cfg, true);
70 interp_set_config(interp0, 0, &cfg);
71
72 cfg = interp_default_config();
73 interp_set_config(interp0, 1, &cfg);
74
75 interp0->base[0] = 500;
76 interp0->base[1] = 1000;
77
78 for (int i = 0; i <= 6; i++) {
79 // set fraction to value between 0 and 255
80 interp0->accum[1] = 255 * i / 6;
81 // ≈ 500 + (1000 - 500) * i / 6;
82 printf("%d\n", (int) interp0->peek[1]);
83 }
84 }
This should print (note the 255/256 resulting in 998 not 1000):
500
582
666
748
832
914
998
CTRL_LANE1_SIGNED controls whether BASE0 and BASE1 are sign-extended for this interpolation (this sign extension is
required because the interpolation produces an intermediate product value 40 bits in size). CTRL_LANE0_SIGNED continues
to control the sign extension of the lane 0 intermediate result in PEEK2, POP2 as normal.
signed:
-1000
-672
-336
-8
328
656
992
unsigned:
0xfffffc18
0xd5fffd60
0xaafffeb0
0x80fffff8
0x56000148
0x2c000290
0x010003e0
Finally, in blend mode when using the BASE_1AND0 register to send a 16-bit value to each of BASE0 and BASE1 with a single
32-bit write, the sign-extension of these 16-bit values to full 32-bit values during the write is controlled by
CTRL_LANE1_SIGNED for both bases, as opposed to non-blend-mode operation, where CTRL_LANE0_SIGNED affects extension
into BASE0 and CTRL_LANE1_SIGNED affects extension into BASE1.
0x00004000
0x0000e800
0xffffe800
Clamp mode is available on INTERP1 on each core, and is enabled by the CTRL_LANE0_CLAMP control flag. In clamp mode, the
PEEK0/POP0 result is the lane value (shifted, masked, sign-extended ACCUM0) clamped between BASE0 and BASE1. In other
words, if the lane value is greater than BASE1, a value of BASE1 is produced; if less than BASE0, a value of BASE0 is produced;
otherwise, the value passes through. No addition is performed. The signedness of these comparisons is controlled by
the CTRL_LANE0_SIGNED flag.
Other than this, the interpolator behaves the same as in normal mode.
-1024 0
-768 0
-512 0
-256 0
0 0
256 64
512 128
768 192
1024 255
Linear interpolation is a more complete example of using blend mode in conjunction with other interpolator
functionality:
In this example, ACCUM0 is used to track a fixed point (integer/fraction) position within a list of values to be interpolated.
Lane 0 is used to produce an address into the value array for the integer part of the position. The fractional part of the
position is shifted to produce a value from 0-255 for the blend. The blend is performed between two consecutive values
in the array.
This method is used for fast approximate audio upscaling in the SDK
Simple affine texture mapping can be implemented by using fixed point arithmetic for texture coordinates, and stepping
a fixed amount in each coordinate for every pixel in a scanline. The integer part of the texture coordinates are used to
form an address within the texture to lookup a pixel colour.
By using two lanes, all three base values and the CTRL_LANEx_ADD_RAW flag, it is possible to reduce what would be quite an
expensive CPU operation to a single cycle iteration using the interpolator.
0x00
0x00
0x01
0x01
0x12
0x12
0x13
0x23
0x20
0x20
0x31
0x31
The SIO registers start at a base address of 0xd0000000 (defined as SIO_BASE in SDK).
0x094 INTERP0_POP_LANE0 Read LANE0 result, and simultaneously write lane results to both
accumulators (POP).
0x098 INTERP0_POP_LANE1 Read LANE1 result, and simultaneously write lane results to both
accumulators (POP).
0x09c INTERP0_POP_FULL Read FULL result, and simultaneously write lane results to both
accumulators (POP).
0x0a0 INTERP0_PEEK_LANE0 Read LANE0 result, without altering any internal state (PEEK).
0x0a4 INTERP0_PEEK_LANE1 Read LANE1 result, without altering any internal state (PEEK).
0x0a8 INTERP0_PEEK_FULL Read FULL result, without altering any internal state (PEEK).
0x0bc INTERP0_BASE_1AND0 On write, the lower 16 bits go to BASE0, upper bits to BASE1
simultaneously.
0x0d4 INTERP1_POP_LANE0 Read LANE0 result, and simultaneously write lane results to both
accumulators (POP).
0x0d8 INTERP1_POP_LANE1 Read LANE1 result, and simultaneously write lane results to both
accumulators (POP).
0x0dc INTERP1_POP_FULL Read FULL result, and simultaneously write lane results to both
accumulators (POP).
0x0e0 INTERP1_PEEK_LANE0 Read LANE0 result, without altering any internal state (PEEK).
0x0e4 INTERP1_PEEK_LANE1 Read LANE1 result, without altering any internal state (PEEK).
0x0e8 INTERP1_PEEK_FULL Read FULL result, without altering any internal state (PEEK).
0x0fc INTERP1_BASE_1AND0 On write, the lower 16 bits go to BASE0, upper bits to BASE1
simultaneously.
Description
Processor core identifier
31:0 Value is 0 when read from processor core 0, and 1 when read from processor RO -
core 1.
Description
Input value for GPIO pins
31:30 Reserved. - -
Description
Input value for QSPI pins
31:6 Reserved. - -
5:0 Input value on QSPI IO in order 0..5: SCLK, SSn, SD0, SD1, SD2, SD3 RO 0x00
Description
GPIO output value
31:30 Reserved. - -
Description
GPIO output value set
Table 21.
Bits Description Type Reset
GPIO_OUT_SET
Register
31:30 Reserved. - -
Description
GPIO output value clear
Table 22.
Bits Description Type Reset
GPIO_OUT_CLR
Register
31:30 Reserved. - -
29:0 Perform an atomic bit-clear on GPIO_OUT, i.e. GPIO_OUT &= ~wdata RW 0x00000000
Description
GPIO output value XOR
Table 23.
Bits Description Type Reset
GPIO_OUT_XOR
Register
31:30 Reserved. - -
29:0 Perform an atomic bitwise XOR on GPIO_OUT, i.e. GPIO_OUT ^= wdata RW 0x00000000
Description
GPIO output enable
31:30 Reserved. - -
Description
GPIO output enable set
Table 25.
Bits Description Type Reset
GPIO_OE_SET Register
31:30 Reserved. - -
Description
GPIO output enable clear
Table 26.
Bits Description Type Reset
GPIO_OE_CLR Register
31:30 Reserved. - -
29:0 Perform an atomic bit-clear on GPIO_OE, i.e. GPIO_OE &= ~wdata RW 0x00000000
Description
GPIO output enable XOR
Table 27.
Bits Description Type Reset
GPIO_OE_XOR
Register
31:30 Reserved. - -
29:0 Perform an atomic bitwise XOR on GPIO_OE, i.e. GPIO_OE ^= wdata RW 0x00000000
Description
QSPI output value
Table 28.
Bits Description Type Reset
GPIO_HI_OUT Register
31:6 Reserved. - -
5:0 Set output level (1/0 → high/low) for QSPI IO0…5. RW 0x00
Reading back gives the last value written, NOT the input value from the pins.
If core 0 and core 1 both write to GPIO_HI_OUT simultaneously (or to a
SET/CLR/XOR alias),
the result is as though the write from core 0 took place first,
and the write from core 1 was then applied to that intermediate result.
Description
QSPI output value set
Table 29.
Bits Description Type Reset
GPIO_HI_OUT_SET
Register
31:6 Reserved. - -
Description
QSPI output value clear
Table 30.
Bits Description Type Reset
GPIO_HI_OUT_CLR
Register
31:6 Reserved. - -
5:0 Perform an atomic bit-clear on GPIO_HI_OUT, i.e. GPIO_HI_OUT &= ~wdata RW 0x00
Description
QSPI output value XOR
Table 31.
Bits Description Type Reset
GPIO_HI_OUT_XOR
Register
31:6 Reserved. - -
5:0 Perform an atomic bitwise XOR on GPIO_HI_OUT, i.e. GPIO_HI_OUT ^= wdata RW 0x00
Description
QSPI output enable
31:6 Reserved. - -
5:0 Set output enable (1/0 → output/input) for QSPI IO0…5. RW 0x00
Reading back gives the last value written.
If core 0 and core 1 both write to GPIO_HI_OE simultaneously (or to a
SET/CLR/XOR alias),
the result is as though the write from core 0 took place first,
and the write from core 1 was then applied to that intermediate result.
Description
QSPI output enable set
Table 33.
Bits Description Type Reset
GPIO_HI_OE_SET
Register
31:6 Reserved. - -
Description
QSPI output enable clear
Table 34.
Bits Description Type Reset
GPIO_HI_OE_CLR
Register
31:6 Reserved. - -
5:0 Perform an atomic bit-clear on GPIO_HI_OE, i.e. GPIO_HI_OE &= ~wdata RW 0x00
Description
QSPI output enable XOR
Table 35.
Bits Description Type Reset
GPIO_HI_OE_XOR
Register
31:6 Reserved. - -
5:0 Perform an atomic bitwise XOR on GPIO_HI_OE, i.e. GPIO_HI_OE ^= wdata RW 0x00
Description
Status register for inter-core FIFOs (mailboxes).
There is one FIFO in the core 0 → core 1 direction, and one core 1 → core 0. Both are 32 bits wide and 8 words
deep.
Core 0 can see the read side of the 1→0 FIFO (RX), and the write side of 0→1 FIFO (TX).
Core 1 can see the read side of the 0→1 FIFO (RX), and the write side of 1→0 FIFO (TX).
The SIO IRQ for each core is the logical OR of the VLD, WOF and ROE fields of its FIFO_ST register.
31:4 Reserved. - - -
3 ROE Sticky flag indicating the RX FIFO was read when empty. WC 0x0
This read was ignored by the FIFO.
2 WOF Sticky flag indicating the TX FIFO was written when full. WC 0x0
This write was ignored by the FIFO.
1 RDY Value is 1 if this core’s TX FIFO is not full (i.e. if FIFO_WR RO 0x1
is ready for more data)
Table 39.
Bits Description Type Reset
SPINLOCK_ST
Register
31:0 Spinlock state RO 0x00000000
A bitmap containing the state of all 32 spinlocks (1=locked).
Mainly intended for debugging.
Table 40.
Bits Description Type Reset
DIV_UDIVIDEND
Register
31:0 Divider unsigned dividend RW 0x00000000
Write to the DIVIDEND operand of the divider, i.e. the p in p / q.
Any operand write starts a new calculation. The results appear in QUOTIENT,
REMAINDER.
UDIVIDEND/SDIVIDEND are aliases of the same internal register. The U alias
starts an
unsigned calculation, and the S alias starts a signed calculation.
Table 41.
Bits Description Type Reset
DIV_UDIVISOR
Register
31:0 Divider unsigned divisor RW 0x00000000
Write to the DIVISOR operand of the divider, i.e. the q in p / q.
Any operand write starts a new calculation. The results appear in QUOTIENT,
REMAINDER.
UDIVIDEND/SDIVIDEND are aliases of the same internal register. The U alias
starts an
unsigned calculation, and the S alias starts a signed calculation.
Table 42.
Bits Description Type Reset
DIV_SDIVIDEND
Register
31:0 Divider signed dividend RW 0x00000000
The same as UDIVIDEND, but starts a signed calculation, rather than unsigned.
Table 43.
Bits Description Type Reset
DIV_SDIVISOR
Register
31:0 Divider signed divisor RW 0x00000000
The same as UDIVISOR, but starts a signed calculation, rather than unsigned.
Table 44.
Bits Description Type Reset
DIV_QUOTIENT
Register
31:0 Divider result quotient RW 0x00000000
The result of DIVIDEND / DIVISOR (division). Contents undefined while
CSR_READY is low.
For signed calculations, QUOTIENT is negative when the signs of DIVIDEND
and DIVISOR differ.
This register can be written to directly, for context save/restore purposes. This
halts any
in-progress calculation and sets the CSR_READY and CSR_DIRTY flags.
Reading from QUOTIENT clears the CSR_DIRTY flag, so should read results in
the order
REMAINDER, QUOTIENT if CSR_DIRTY is used.
Table 45.
Bits Description Type Reset
DIV_REMAINDER
Register
31:0 Divider result remainder RW 0x00000000
The result of DIVIDEND % DIVISOR (modulo). Contents undefined while
CSR_READY is low.
For signed calculations, REMAINDER is negative only when DIVIDEND is
negative.
This register can be written to directly, for context save/restore purposes. This
halts any
in-progress calculation and sets the CSR_READY and CSR_DIRTY flags.
Description
Control and status register for divider.
31:2 Reserved. - - -
Table 47.
Bits Description Type Reset
INTERP0_ACCUM0
Register
31:0 Read/write access to accumulator 0 RW 0x00000000
Table 48.
Bits Description Type Reset
INTERP0_ACCUM1
Register
31:0 Read/write access to accumulator 1 RW 0x00000000
Table 49.
Bits Description Type Reset
INTERP0_BASE0
Register
31:0 Read/write access to BASE0 register. RW 0x00000000
Table 50.
Bits Description Type Reset
INTERP0_BASE1
Register
31:0 Read/write access to BASE1 register. RW 0x00000000
Table 51.
Bits Description Type Reset
INTERP0_BASE2
Register
31:0 Read/write access to BASE2 register. RW 0x00000000
Table 52.
Bits Description Type Reset
INTERP0_POP_LANE0
Register
31:0 Read LANE0 result, and simultaneously write lane results to both RO 0x00000000
accumulators (POP).
Table 53.
Bits Description Type Reset
INTERP0_POP_LANE1
Register
31:0 Read LANE1 result, and simultaneously write lane results to both RO 0x00000000
accumulators (POP).
Table 54.
Bits Description Type Reset
INTERP0_POP_FULL
Register
31:0 Read FULL result, and simultaneously write lane results to both accumulators RO 0x00000000
(POP).
Table 55.
Bits Description Type Reset
INTERP0_PEEK_LANE
0 Register
31:0 Read LANE0 result, without altering any internal state (PEEK). RO 0x00000000
Table 56.
Bits Description Type Reset
INTERP0_PEEK_LANE
1 Register
31:0 Read LANE1 result, without altering any internal state (PEEK). RO 0x00000000
Table 57.
Bits Description Type Reset
INTERP0_PEEK_FULL
Register
31:0 Read FULL result, without altering any internal state (PEEK). RO 0x00000000
Description
Control register for lane 0
Table 58.
Bits Name Description Type Reset
INTERP0_CTRL_LANE
0 Register
31:26 Reserved. - - -
22 Reserved. - - -
20:19 FORCE_MSB ORed into bits 29:28 of the lane result presented to the RW 0x0
processor on the bus.
No effect on the internal 32-bit datapath. Handy for using
a lane to generate sequence
of pointers into flash or SRAM.
18 ADD_RAW If 1, mask + shift is bypassed for LANE0 result. This does RW 0x0
not affect FULL result.
17 CROSS_RESULT If 1, feed the opposite lane’s result into this lane’s RW 0x0
accumulator on POP.
16 CROSS_INPUT If 1, feed the opposite lane’s accumulator into this lane’s RW 0x0
shift + mask hardware.
Takes effect even if ADD_RAW is set (the CROSS_INPUT
mux is before the shift+mask bypass)
14:10 MASK_MSB The most-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Setting MSB < LSB may cause chip to turn inside-out
9:5 MASK_LSB The least-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Description
Control register for lane 1
Table 59.
Bits Name Description Type Reset
INTERP0_CTRL_LANE
1 Register
31:21 Reserved. - - -
20:19 FORCE_MSB ORed into bits 29:28 of the lane result presented to the RW 0x0
processor on the bus.
No effect on the internal 32-bit datapath. Handy for using
a lane to generate sequence
of pointers into flash or SRAM.
18 ADD_RAW If 1, mask + shift is bypassed for LANE1 result. This does RW 0x0
not affect FULL result.
17 CROSS_RESULT If 1, feed the opposite lane’s result into this lane’s RW 0x0
accumulator on POP.
16 CROSS_INPUT If 1, feed the opposite lane’s accumulator into this lane’s RW 0x0
shift + mask hardware.
Takes effect even if ADD_RAW is set (the CROSS_INPUT
mux is before the shift+mask bypass)
14:10 MASK_MSB The most-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Setting MSB < LSB may cause chip to turn inside-out
9:5 MASK_LSB The least-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Table 60.
Bits Description Type Reset
INTERP0_ACCUM0_AD
D Register
31:24 Reserved. - -
Table 61.
Bits Description Type Reset
INTERP0_ACCUM1_AD
D Register
31:24 Reserved. - -
Table 62.
Bits Description Type Reset
INTERP0_BASE_1AND
0 Register
31:0 On write, the lower 16 bits go to BASE0, upper bits to BASE1 simultaneously. WO 0x00000000
Each half is sign-extended to 32 bits if that lane’s SIGNED flag is set.
Table 63.
Bits Description Type Reset
INTERP1_ACCUM0
Register
31:0 Read/write access to accumulator 0 RW 0x00000000
Table 64.
Bits Description Type Reset
INTERP1_ACCUM1
Register
31:0 Read/write access to accumulator 1 RW 0x00000000
Table 65.
Bits Description Type Reset
INTERP1_BASE0
Register
31:0 Read/write access to BASE0 register. RW 0x00000000
Table 66.
Bits Description Type Reset
INTERP1_BASE1
Register
31:0 Read/write access to BASE1 register. RW 0x00000000
Table 67.
Bits Description Type Reset
INTERP1_BASE2
Register
31:0 Read/write access to BASE2 register. RW 0x00000000
Table 68.
Bits Description Type Reset
INTERP1_POP_LANE0
Register
31:0 Read LANE0 result, and simultaneously write lane results to both RO 0x00000000
accumulators (POP).
Table 69.
Bits Description Type Reset
INTERP1_POP_LANE1
Register
31:0 Read LANE1 result, and simultaneously write lane results to both RO 0x00000000
accumulators (POP).
Table 70.
Bits Description Type Reset
INTERP1_POP_FULL
Register
31:0 Read FULL result, and simultaneously write lane results to both accumulators RO 0x00000000
(POP).
Table 71.
Bits Description Type Reset
INTERP1_PEEK_LANE
0 Register
31:0 Read LANE0 result, without altering any internal state (PEEK). RO 0x00000000
Table 72.
Bits Description Type Reset
INTERP1_PEEK_LANE
1 Register
31:0 Read LANE1 result, without altering any internal state (PEEK). RO 0x00000000
Table 73.
Bits Description Type Reset
INTERP1_PEEK_FULL
Register
31:0 Read FULL result, without altering any internal state (PEEK). RO 0x00000000
Description
Control register for lane 0
Table 74.
Bits Name Description Type Reset
INTERP1_CTRL_LANE
0 Register
31:26 Reserved. - - -
21 Reserved. - - -
20:19 FORCE_MSB ORed into bits 29:28 of the lane result presented to the RW 0x0
processor on the bus.
No effect on the internal 32-bit datapath. Handy for using
a lane to generate sequence
of pointers into flash or SRAM.
18 ADD_RAW If 1, mask + shift is bypassed for LANE0 result. This does RW 0x0
not affect FULL result.
17 CROSS_RESULT If 1, feed the opposite lane’s result into this lane’s RW 0x0
accumulator on POP.
16 CROSS_INPUT If 1, feed the opposite lane’s accumulator into this lane’s RW 0x0
shift + mask hardware.
Takes effect even if ADD_RAW is set (the CROSS_INPUT
mux is before the shift+mask bypass)
14:10 MASK_MSB The most-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Setting MSB < LSB may cause chip to turn inside-out
9:5 MASK_LSB The least-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Offset: 0x0f0
Description
Control register for lane 1
Table 75.
Bits Name Description Type Reset
INTERP1_CTRL_LANE
1 Register
31:21 Reserved. - - -
20:19 FORCE_MSB ORed into bits 29:28 of the lane result presented to the RW 0x0
processor on the bus.
No effect on the internal 32-bit datapath. Handy for using
a lane to generate sequence
of pointers into flash or SRAM.
18 ADD_RAW If 1, mask + shift is bypassed for LANE1 result. This does RW 0x0
not affect FULL result.
17 CROSS_RESULT If 1, feed the opposite lane’s result into this lane’s RW 0x0
accumulator on POP.
16 CROSS_INPUT If 1, feed the opposite lane’s accumulator into this lane’s RW 0x0
shift + mask hardware.
Takes effect even if ADD_RAW is set (the CROSS_INPUT
mux is before the shift+mask bypass)
14:10 MASK_MSB The most-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Setting MSB < LSB may cause chip to turn inside-out
9:5 MASK_LSB The least-significant bit allowed to pass by the mask RW 0x00
(inclusive)
Table 76.
Bits Description Type Reset
INTERP1_ACCUM0_AD
D Register
31:24 Reserved. - -
Table 77.
Bits Description Type Reset
INTERP1_ACCUM1_AD
D Register
31:24 Reserved. - -
Table 78.
Bits Description Type Reset
INTERP1_BASE_1AND
0 Register
31:0 On write, the lower 16 bits go to BASE0, upper bits to BASE1 simultaneously. WO 0x00000000
Each half is sign-extended to 32 bits if that lane’s SIGNED flag is set.
2.3.2. Interrupts
Each core is equipped with a standard ARM Nested Vectored Interrupt Controller (NVIC) which has 32 interrupt inputs.
Each NVIC has the same interrupts routed to it, with the exception of the GPIO interrupts: there is one GPIO interrupt per
bank, per core. These are completely independent, so e.g. core 0 can be interrupted by GPIO 0 in bank 0, and core 1 by
GPIO 1 in the same bank.
On RP2040, only the lower 26 IRQ signals are connected on the NVIC, and IRQs 26 to 31 are tied to zero (never firing).
The core can still be forced to enter the relevant interrupt handler by writing bits 26 to 31 in the NVIC ISPR register.
The 26 system IRQ signals are masked (NMI mask) and then ORed together creating the NMI signal for the core. The
NMI mask for each core can be configured using PROC0_NMI_MASK and PROC1_NMI_MASK in the Syscfg register
block. Each of these registers has one bit for each system interrupt, and the each core’s NMI is asserted if a system
interrupt is asserted and the corresponding NMI mask bit is set for that core.
CAUTION
If the watchdog is armed, and some bits are set on the core 1 NMI mask, the RESETS block (and hence Syscfg)
should be included in the watchdog reset list. Otherwise, following a watchdog event, core 1 NMI may be asserted
when the core enter the bootrom. It is safe for core 0 to take an NMI when entering the bootrom (the handler will
clear the NMI mask).
NOTE
the event flag is "sticky", so if both processors send an event (SEV) simultaneously, and then both go to sleep (WFE),
they will both wake immediately, rather than getting stuck in a sleep state.
While in a WFE (or WFI) sleep state, the processor can shut off its internal clock gates, consuming much less power. When
both processors are sleeping, and the DMA is inactive, RP2040 as a whole can enter a sleep state, disabling clocks on
unused infrastructure such as the busfabric, and waking automatically when one of the processors wakes. See Section
2.11.2.
2.3.4. Debug
The 2-wire Serial Wire Debug (SWD) port provides access to hardware and software debug features including:
Debug access is via independent DAPs (one per core) attached to a shared multidrop SWD bus (SWD v2). Each DAP will
only respond to debug commands if correctly addressed by a SWD TARGETSEL command; all others tristate their outputs.
Additionally, a Rescue DP (see Section 2.3.4.2) is available which is connected to system control features. Default
addresses of each debug port are given below:
• Core 0: 0x01002927
• Core 1: 0x11002927
• Rescue DP: 0xf1002927
The Instance IDs (top 4 bits of ID above) can be changed via a sysconfig register which may be useful in a multichip
application. However note that ID=0xf is reserved for the internal Rescue DP (see Section 2.3.4.2).
Rescue DP
pam_restart sys_cfg.proc1_dap_instid
The SWD pins for Core 0 and Core 1 can be bit-banged via registers in syscfg (see DBGFORCE). This means that Core 1
could run a USB application that allows debug of Core 0, or similar.
2.3.4.2. Rescue DP
The Rescue DP (debug port) is available over the SWD bus and is only intended for use in the specific case where the
chip has locked up, for example if code has been programmed into flash which permanently halts the system clock: in
such a case, the normal debugger can not communicate with the processors to return the system to a working state, so
more drastic action is needed. A rescue is invoked by setting the CDBGPWRUPREQ bit in the Rescue DP’s CTRL/STAT
register.
This causes a hard reset of the chip (functionally similar to a power-on-reset), and sets a flag in the Chip Level Reset
block to indicate that a rescue reset took place. The bootrom checks this flag almost immediately in the initial boot
process (before watchdog, flash or USB boot), acknowledges by clearing the bit, then halts the processor. This leaves
the system in a safe state, with the system clock running, so that the debugger can reattach to the cores and load fresh
code.
For a practical example of using the Rescue DP, see the Hardware design with RP2040 book.
2.4. Cortex-M0+
ARM Documentation
Excerpted from the Cortex-M0+ Technical Reference Manual. Used with permission.
The ARM Cortex-M0+ processor is a very low gate count, highly energy efficient processor that is intended for
microcontroller and deeply embedded applications that require an area optimized, low-power processor.
2.4.1. Features
The ARM Cortex-M0+ processor features and benefits are:
2.4. Cortex-M0+ 62
RP2040 Datasheet
• Fast code execution enables running the processor with a slower clock or increasing sleep mode time.
• Optimized code fetching for reduced flash and ROM power consumption.
• Hardware multiplier.
• Deterministic, high-performance interrupt handling for time-critical applications.
• Deterministic instruction cycle timing.
• Support for system level debug authentication.
• Serial Wire Debug reduces the number of pins required for debugging.
2.4.1.1. Interfaces
2.4.1.2. Configuration
Each M0+ core has its own interrupt controller which can individually mask out interrupt sources as required. The same
interrupts are routed to both M0+ cores.
2.4. Cortex-M0+ 63
RP2040 Datasheet
The processor implements the ARMv6-M architecture profile. See the ARMv6-M Architecture Reference Manual, and for
further details refer to the ARM Cortex M0+ Technical Reference Manual.
2.4.2.1. Overview
The Cortex-M0+ processor is a configurable, multistage, 32-bit RISC processor. It has an AMBA AHB-Lite interface and
includes an NVIC component. It also has hardware debug, single-cycle I/O interfacing, and memory-protection
functionality. The processor can execute Thumb code and is compatible with other Cortex-M profile processors.
Figure 11 shows the functional blocks of the processor and surrounding blocks.
Reset
RESET CTRL
2.4.2.2. Features
• Low power sleep-mode entry using Wait For Interrupt (WFI), Wait For Event (WFE) instructions, or the return from
interrupt sleep-on-exit feature.
2.4. Cortex-M0+ 64
RP2040 Datasheet
• Wake-up Interrupt Controller (WIC), providing ultra-low power sleep mode support.
• Relocatable vector table.
Further details available in Section 2.4.5.
The processor is implemented with a low gate count Debug Access Port (DAP). The low gate count Debug Access Port
(DAP) provides a Serial Wire debug-port, and connects to the processor slave port to provide full system-level debug
access. For more information on DAP, see the ADI v5.1 version of the ARM Debug Interface v5, Architecture
Specification
Transactions on the AHB-Lite interface are always marked as non-sequential. Processor accesses and debug accesses
share the external interface to external AHB peripherals. The processor accesses take priority over debug accesses.
Any vendor-specific components can populate this bus.
2.4. Cortex-M0+ 65
RP2040 Datasheet
NOTE
Instructions are only fetched using the AHB-Lite interface. To optimize performance, the Cortex-M0+ processor
fetches ahead of the instruction it is executing. To minimize power consumption, the fetch ahead is limited to a
maximum of 32 bits.
The processor implements a single-cycle I/O port that provides high speed access to tightly-coupled peripherals, such
as general-purpose-I/O (GPIO). The port is accessible both by loads and stores from either the processor or the
debugger. You cannot execute code from the I/O port.
Each processor has its own Power Management Unit (PMU) which allows power saving by turning off clocks to parts of
the processor core. There are no separate power domains on RP2040.
The PMU runs from the processor clock which is controlled from the chip level clocks block. The PMU can control the
following clock domains within the processor:
• A debug clock containing the processor debug resources and the rest of the DAP.
• A system clock containing the NVIC.
• A processor clock containing the core and associated interfaces
Control is limited to clock enable/disable. When enabled, all domains run at the same clock speed.
The PMU also interfaces with the WIC, to ensure that power-down and wake-up behaviours are transparent to software
and work with clocking and sleeping requirements. This includes SLEEP or DEEPSLEEP support as controlled in SCR
register.
RP2040 ARM Cortex M0+ uses ARMv6-M which supports the use of Wait For Interrupt (WFI) and Wait For Event (WFE)
instructions as part of system power management:
WFI provides a mechanism for hardware support of entry to one or more sleep states. Hardware can suspend execution
until a wakeup event occurs.
WFE provides a mechanism for software to suspend program execution until a wakeup condition occurs with minimal or
no impact on wakeup latency. Both WFI and WFE are hint instructions that might have no effect on program execution.
Normally, they are used in software idle loops that resume program execution only after an interrupt or event of interest
occurs.
NOTE
Code using WFE and WFI must handle any spurious wakeup events caused by a debug halt or other reasons.
RP2040 can support software-based synchronization to system events using the Send-Event (SEV) and WFE hint
instructions. Software can:
• use the WFE instruction to indicate that it is able to suspend execution of a process or thread until an event occurs,
permitting hardware to enter a low power state.
2.4. Cortex-M0+ 66
RP2040 Datasheet
• rely on a mechanism that is transparent to software and provides low latency wakeup.
The WFE mechanism relies on hardware and software working together to achieve energy saving. For example, stalling
execution of a processor until a device or another processor has set a flag:
• the hardware provides the mechanism to enter the WFE low-power state.
• software enters a polling loop to determine when the flag is set:
• the polling processor issues a WFE instruction as part of a polling loop if the flag is clear.
• an event is generated (hardware interrupt or Send-Event instruction from another processor) when the flag is set.
WFE wake up events
The Event Register is a single bit register. When set, an Event Register indicates that an event has occurred, since the
register was last cleared, that might prevent the processor having to suspend operation on issuing a WFE instruction. The
following conditions apply to the Event Register:
The Send-Event (SEV) instruction causes an event to be signalled to the other processor. The Send-Event instruction
generates a wakeup event.
The action of the WFE instruction depends on the state of the Event Register:
• If the Event Register is set, the instruction clears the register and returns immediately.
• If the Event Register is clear the processor can suspend execution and enter a low-power state. It can remain in
that state until the processor detects a WFE wakeup event or a reset. When the processor detects a WFE wakeup
event, the WFE instruction completes.
WFE wakeup events can occur before a WFE instruction is issued. Software using the WFE mechanism must tolerate
spurious wake up events, including multiple wakeups.
RP2040 supports Wait For Interrupt through the hint instruction, WFI.
When a processor issues a WFI instruction it can suspend execution and enter a low-power state. It can remain in that
state until the processor detects one of the following WFI wake up events:
• A reset.
• An asynchronous exception at a priority that, if PRIMASK.PM was set to 0, would preempt any currently active
exceptions.
2.4. Cortex-M0+ 67
RP2040 Datasheet
Note
If PRIMASK.PM is set to 1, an asynchronous exception that has a higher group priority than any active exception
results in a WFI instruction exit. If the group priority of the exception is less than or equal to the execution group
priority, the exception is ignored.
The processor recognizes WFI wake up events only after issuing the WFI instruction.
The Wakeup Interrupt Controller (WIC) is used to wake the processor from a DEEPSLEEP state as controlled by the SCR
register. In a DEEPSLEEP state clocks to the processor core and NVIC are not running. It can take a few cycles to wake
from a DEEPSLEEP state.
The WIC takes inputs from the receive event signal (from the other processor), 32 interrupts lines, and NMI.
For more power saving, RP2040 supports system level power saving modes as defined in Section 2.11 which also
includes code examples.
The Cortex M0+ Reset Control block controls the following resets:
• Debug reset
• M0+ core reset
• PMU reset
After power up, both processors are released from reset (see details in Section 2.13.2). This releases reset to Debug,
M0+ core and PMU.
Once running, resets can be triggered from the Debugger, NVIC (using AIRCR.SYSRESETREQ), or the RP2040 Power On State
Machine controller (see details in Section 2.13). The NVIC only resets the Cortex-M0+ processor core (not the Debug or
PMU), whereas the Power On State Machine controller can reset the processor subsystem which asserts all resets in
the subsystem (Debug, M0+ core, PMU).
The ARMv6-M Architecture Reference Manual provides a complete description of the programmer’s model. This chapter
gives an overview of the Cortex-M0+ programmer’s model that describes the implementation-defined options. It also
contains the ARMv6-M Thumb instructions it uses and their cycle counts for the processor. Additional details are in
following chapters
• Section 2.4.4 summarizes the system control features of the programmer’s model.
• Section 2.4.5 summarizes the NVIC features of the programmer’s model.
• Section 2.3.4 summarizes the Debug features of the programmer’s model.
2.4. Cortex-M0+ 68
RP2040 Datasheet
See the ARMv6-M Architecture Reference Manual for information about the modes of operation and execution.
The processor implements the ARMv6-M Thumb instruction set, including a number of 32-bit instructions that use
Thumb-2 technology. The ARMv6-M instruction set comprises:
• All of the 16-bit Thumb instructions from ARMv7-M excluding CBZ, CBNZ and IT.
• The 32-bit Thumb instructions BL, DMB, DSB, ISB, MRS and MSR.
Table 81 shows the Cortex-M0+ instructions and their cycle counts. The cycle counts are based on a system with zero
wait-states.
Lo to Lo MOVS Rd, Rm 1
2.4. Cortex-M0+ 69
RP2040 Datasheet
Unconditional B <label> 2
2.4. Cortex-M0+ 70
RP2040 Datasheet
With exchange BX Rm 2
Yield YIELD 1f
No operation NOP 1
Table Notes
a
2 if to AHB interface or SCS, 1 if to single-cycle I/O port.
b
N is the number of elements in the list.
c
N is the number of elements in the list including PC or LR.
d
2 if taken, 1 if not-taken.
e
Cycle count depends on processor and debug configuration.
f
Excludes time spent waiting for an interrupt or event.
g
Executes as NOP.
See the ARMv6-M Architecture Reference Manual for more information about the ARMv6-M Thumb instructions.
The processor contains a bus matrix that arbitrates the processor core and Debug Access Port (DAP) memory
accesses to both the external memory system and to the internal NVIC and debug components.
Priority is always given to the processor to ensure that any debug accesses are as non-intrusive as possible. For a zero
2.4. Cortex-M0+ 71
RP2040 Datasheet
wait-state system, all debug accesses to system memory, NVIC, and debug resources are completely non-intrusive for
typical code execution.
The system memory map is ARMv6-M architecture compliant, and is common both to the debugger and processor
accesses. Transactions are routed as follows:
• All accesses below 0xd0000000 or above 0xefffffff appear as AHB-Lite transactions on the AHB-Lite master port of
the processor.
The processor supports only word size accesses in the range 0xd0000000 - 0xefffffff.
Table 82 shows the code, data, and device suitability for each region of the default memory map. This is the memory
map used by implementations when the MPU is disabled. The attributes and permissions of all regions, except that
targeting the Cortex-M0+ NVIC and debug components, can be modified using an implemented MPU.
0xe0000000 - 0xefffffff No No No a
a
. Space reserved for Cortex-M0+ NVIC and debug components.
Note
Regions not marked as suitable for code behave as eXecute-Never (XN) and generate a HardFault exception if code
attempts to execute from this location.
See the ARMv6-M Architecture Reference Manual for more information about the memory model.
Table 83 shows the processor core register set summary. Each of these registers is 32 bits wide.
MSP/PSP (R13) The Stack Pointer (SP) is register R13. In Thread mode,
the CONTROL register indicates the stack pointer to use,
Main Stack Pointer (MSP) or Process Stack Pointer (PSP).
LR (R14) The Link Register (LR) is register R14. It stores the return
information for subroutines, function calls, and
exceptions.
2.4. Cortex-M0+ 72
RP2040 Datasheet
Name Description
CONTROL The CONTROL register controls the stack used, the code
privilege level, when the processor is in Thread mode.
Note
See the ARMv6-M Architecture Reference Manual for information about the processor core registers and their
addresses, access types, and reset values.
2.4.3.6. Exceptions
The processor implements advanced exception and interrupt handling, as described in the ARMv6-M Architecture
Reference Manual. To minimize interrupt latency, the processor abandons any load-multiple or store-multiple instruction
to take any pending interrupt. On return from the interrupt handler, the processor restarts the load-multiple or store-
multiple instruction from the beginning.
This means that software must not use load-multiple or store-multiple instructions when a device is accessed in a
memory region that is read-sensitive or sensitive to repeated writes. The software must not use these instructions in
any case where repeated reads or writes might cause inconsistent results or unwanted side-effects.
The processor implementation can ensure that a fixed number of cycles are required for the NVIC to detect an interrupt
signal and the processor fetch the first instruction of the associated interrupt handler. If this is done, the highest priority
interrupt is jitter-free. This will depend on where the interrupt handler is located and if another higher priority master is
accessing that memory. SRAM4 and SRAM5 are provided that may be allocated to interrupt handlers for each processor
so this is jitter-free.
To reduce interrupt latency and jitter, the Cortex-M0+ processor implements both interrupt late-arrival and interrupt tail-
chaining mechanisms, as defined by the ARMv6-M architecture. The worst case interrupt latency, for the highest priority
active interrupt in a zero wait-state system not using jitter suppression, is 15 cycles.
The processor exception model has the following implementation-defined behaviour in addition to the architecture
specified behaviour:
2.4. Cortex-M0+ 73
RP2040 Datasheet
Table 84 gives the system control registers. Each of these registers is 32 bits wide.
Note
• All system control registers are only accessible using word transfers. Any attempt to read or write a halfword
or byte is Unpredictable.
• See the List of Registers or ARMv6-M Architecture Reference Manual for more information about the system
control registers, and their addresses and access types, and reset values.
The CPUID contains the part number, version, and implementation information that is specific to the processor.
IMPORTANT
This standard internal Arm register contains information about the type of processor. It should not be confused with
CPUID (Section 2.3.1.1), an RP2040 SIO register which reads as 0 on core 0 and 1 on core 1.
2.4.5. NVIC
External interrupt signals connect to the NVIC, and the NVIC prioritizes the interrupts. Software can set the priority of
each interrupt. The NVIC and the Cortex-M0+ processor core are closely coupled, providing low latency interrupt
processing and efficient processing of late arriving interrupts.
All NVIC registers are only accessible using word transfers. Any attempt to read or write a halfword or byte individually
is unpredictable.
2.4. Cortex-M0+ 74
RP2040 Datasheet
A 24-bit SysTick system timer, extends the functionality of both the processor and the NVIC and provides:
The implementation includes a WIC. This enables the processor and NVIC to be put into a very low-power sleep mode
leaving the WIC to identify and prioritize interrupts.
The processor fully implements the Wait For Interrupt (WFI), Wait For Event (WFE) and the Send Event (SEV)
instructions. In addition, the processor also supports the use of SLEEPONEXIT, that causes the processor core to enter
sleep mode when it returns from an exception handler to Thread mode. See the ARMv6-M Architecture Reference
Manual for more information.
Table 85 shows the NVIC registers. Each of these registers is 32 bits wide.
Note
See the List of Registers or ARMv6-M Architecture Reference Manual for more information about the NVIC registers
and their addresses, access types, and reset values.
2.4.6. MPU
The MPU is a component for memory protection which allows the processor to support the ARMv6 Protected Memory
System Architecture model. The MPU provides full support for:
2.4. Cortex-M0+ 75
RP2040 Datasheet
Table 86 shows the MPU registers. Each of these registers is 32 bits wide.
Note
• See the ARMv6-M Architecture Reference Manual for more information about the MPU registers and their
addresses, access types, and reset values.
• The MPU supports region sizes from 256-bytes to 4Gb, with 8-sub regions per region.
2.4.7. Debug
Basic debug functionality includes processor halt, single-step, processor core register access, Reset and HardFault
Vector Catch, unlimited software breakpoints, and full system memory access. See the ARMv6-M Architecture
Reference Manual.
2.4. Cortex-M0+ 76
RP2040 Datasheet
Description
Use the SysTick Control and Status Register to enable the SysTick features.
31:17 Reserved. - - -
16 COUNTFLAG Returns 1 if timer counted to 0 since last time this was RO 0x0
read. Clears on read by application or debugger.
15:3 Reserved. - - -
2.4. Cortex-M0+ 77
RP2040 Datasheet
Description
Use the SysTick Reload Value Register to specify the start value to load into the current value register when the
counter reaches 0. It can be any value between 0 and 0x00FFFFFF. A start value of 0 is possible, but has no effect
because the SysTick interrupt and COUNTFLAG are activated when counting from 1 to 0. The reset value of this
register is UNKNOWN.
To generate a multi-shot timer with a period of N processor clock cycles, use a RELOAD value of N-1. For example,
if the SysTick interrupt is required every 100 clock pulses, set RELOAD to 99.
31:24 Reserved. - - -
23:0 RELOAD Value to load into the SysTick Current Value Register RW 0x000000
when the counter reaches 0.
Description
Use the SysTick Current Value Register to find the current value in the register. The reset value of this register is
UNKNOWN.
31:24 Reserved. - - -
23:0 CURRENT Reads return the current value of the SysTick counter. This RW 0x000000
register is write-clear. Writing to it with any value clears
the register to 0. Clearing this register also clears the
COUNTFLAG bit of the SysTick Control and Status
Register.
2.4. Cortex-M0+ 78
RP2040 Datasheet
Description
Use the SysTick Calibration Value Register to enable software to scale to any required speed using divide and
multiply.
30 SKEW If reads as 1, the calibration value for 10ms is inexact (due RO 0x0
to clock frequency).
29:24 Reserved. - - -
23:0 TENMS An optional Reload value to be used for 10ms (100Hz) RO 0x000000
timing, subject to system clock skew errors. If the value
reads as 0, the calibration value is not known.
Description
Use the Interrupt Set-Enable Register to enable interrupts and determine which interrupts are currently enabled.
If a pending interrupt is enabled, the NVIC activates the interrupt based on its priority. If an interrupt is not enabled,
asserting its interrupt signal changes the interrupt state to pending, but the NVIC never activates the interrupt,
regardless of its priority.
Description
Use the Interrupt Clear-Enable Registers to disable interrupts and determine which interrupts are currently enabled.
2.4. Cortex-M0+ 79
RP2040 Datasheet
Description
The NVIC_ISPR forces interrupts into the pending state, and shows which interrupts are pending.
Description
Use the Interrupt Clear-Pending Register to clear pending interrupts and determine which interrupts are currently
pending.
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
Note: Writing 1 to an NVIC_ICPR bit does not affect the active state of the corresponding interrupt.
These registers are only word-accessible
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
2.4. Cortex-M0+ 80
RP2040 Datasheet
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
2.4. Cortex-M0+ 81
RP2040 Datasheet
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
2.4. Cortex-M0+ 82
RP2040 Datasheet
5:0 Reserved. - - -
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
Description
Use the Interrupt Priority Registers to assign a priority from 0 to 3 to each of the available interrupts. 0 is the highest
priority, and 3 is the lowest.
29:24 Reserved. - - -
21:16 Reserved. - - -
13:8 Reserved. - - -
5:0 Reserved. - - -
Description
Read the CPU ID Base Register to determine: the ID number of the processor core, the version number of the
processor core, the implementation details of the processor core.
2.4. Cortex-M0+ 83
RP2040 Datasheet
23:20 VARIANT Major revision number n in the rnpm revision status: RO 0x0
0x0 = Revision 0.
19:16 ARCHITECTURE Constant that defines the architecture of the processor: RO 0xc
0xC = ARMv6-M architecture.
3:0 REVISION Minor revision number m in the rnpm revision status: RO 0x1
0x1 = Patch 1.
Description
Use the Interrupt Control State Register to set a pending Non-Maskable Interrupt (NMI), set or clear a pending
PendSV, set or clear a pending SysTick, check for pending exceptions, check the vector number of the highest
priority pended exception, check the vector number of the active exception.
31 NMIPENDSET Setting this bit will activate an NMI. Since NMI is the RW 0x0
highest priority exception, it will activate as soon as it is
registered.
NMI set-pending bit.
Write:
0 = No effect.
1 = Changes NMI exception state to pending.
Read:
0 = NMI exception is not pending.
1 = NMI exception is pending.
Because NMI is the highest-priority exception, normally
the processor enters the NMI
exception handler as soon as it detects a write of 1 to this
bit. Entering the handler then clears
this bit to 0. This means a read of this bit by the NMI
exception handler returns 1 only if the
NMI signal is reasserted while the processor is executing
that handler.
30:29 Reserved. - - -
2.4. Cortex-M0+ 84
RP2040 Datasheet
24 Reserved. - - -
23 ISRPREEMPT The system can only access this bit when the core is RO 0x0
halted. It indicates that a pending interrupt is to be taken
in the next running cycle. If C_MASKINTS is clear in the
Debug Halting Control and Status Register, the interrupt is
serviced.
21 Reserved. - - -
20:12 VECTPENDING Indicates the exception number for the highest priority RO 0x000
pending exception: 0 = no pending exceptions. Non zero =
The pending state includes the effect of memory-mapped
enable and mask registers. It does not include the
PRIMASK special-purpose register qualifier.
11:9 Reserved. - - -
8:0 VECTACTIVE Active exception number field. Reset clears the RO 0x000
VECTACTIVE field.
Description
The VTOR holds the vector table offset address.
2.4. Cortex-M0+ 85
RP2040 Datasheet
31:8 TBLOFF Bits [31:8] of the indicate the vector table offset address. RW 0x000000
7:0 Reserved. - - -
Description
Use the Application Interrupt and Reset Control Register to: determine data endianness, clear all active state
information from debug halt mode, request a system reset.
14:3 Reserved. - - -
1 VECTCLRACTIVE Clears all active state information for fixed and RW 0x0
configurable exceptions. This bit: is self-clearing, can only
be set by the DAP when the core is halted. When set:
clears all active exception status of the processor, forces
a return to Thread mode, forces an IPSR of 0. A debugger
must re-initialize the stack.
0 Reserved. - - -
Description
System Control Register. Use the System Control Register for power-management functions: signal to the system
when the processor can enter a low power state, control how the processor enters and exits low power states.
31:5 Reserved. - - -
2.4. Cortex-M0+ 86
RP2040 Datasheet
3 Reserved. - - -
2 SLEEPDEEP Controls whether the processor uses sleep or deep sleep RW 0x0
as its low power mode:
0 = Sleep.
1 = Deep sleep.
0 Reserved. - - -
Description
The Configuration and Control Register permanently enables stack alignment and causes unaligned accesses to
result in a Hard Fault.
31:10 Reserved. - - -
8:4 Reserved. - - -
3 UNALIGN_TRP Always reads as one, indicates that all unaligned accesses RO 0x0
generate a HardFault.
2:0 Reserved. - - -
2.4. Cortex-M0+ 87
RP2040 Datasheet
Description
System handlers are a special class of exception handler that can have their priority set to any of the priority levels.
Use the System Handler Priority Register 2 to set the priority of SVCall.
29:0 Reserved. - - -
Description
System handlers are a special class of exception handler that can have their priority set to any of the priority levels.
Use the System Handler Priority Register 3 to set the priority of PendSV and SysTick.
29:24 Reserved. - - -
21:0 Reserved. - - -
Description
Use the System Handler Control and State Register to determine or clear the pending status of SVCall.
31:16 Reserved. - - -
14:0 Reserved. - - -
Description
Read the MPU Type Register to determine if the processor implements an MPU, and how many regions the MPU
supports.
31:24 Reserved. - - -
2.4. Cortex-M0+ 88
RP2040 Datasheet
7:1 Reserved. - - -
Description
Use the MPU Control Register to enable and disable the MPU, and to control whether the default memory map is
enabled as a background region for privileged accesses, and whether the MPU is enabled for HardFaults and NMIs.
31:3 Reserved. - - -
1 HFNMIENA Controls the use of the MPU for HardFaults and NMIs. RW 0x0
Setting this bit when ENABLE is clear results in
UNPREDICTABLE behaviour.
When the MPU is enabled:
0 = MPU is disabled during HardFault and NMI handlers,
regardless of the value of the ENABLE bit.
1 = the MPU is enabled during HardFault and NMI
handlers.
0 ENABLE Enables the MPU. If the MPU is disabled, privileged and RW 0x0
unprivileged accesses use the default memory map.
0 = MPU disabled.
1 = MPU enabled.
Description
Use the MPU Region Number Register to select the region currently accessed by MPU_RBAR and MPU_RASR.
2.4. Cortex-M0+ 89
RP2040 Datasheet
31:4 Reserved. - - -
3:0 REGION Indicates the MPU region referenced by the MPU_RBAR RW 0x0
and MPU_RASR registers.
The MPU supports 8 memory regions, so the permitted
values of this field are 0-7.
Description
Read the MPU Region Base Address Register to determine the base address of the region identified by MPU_RNR.
Write to update the base address of said region or that of a specified region, with whose number MPU_RNR will also
be updated.
7:5 Reserved. - - -
4 VALID On writes, indicates whether the write must update the RW 0x0
base address of the region identified by the REGION field,
updating the MPU_RNR to indicate this new region.
Write:
0 = MPU_RNR not changed, and the processor:
Updates the base address for the region specified in the
MPU_RNR.
Ignores the value of the REGION field.
1 = The processor:
Updates the value of the MPU_RNR to the value of the
REGION field.
Updates the base address for the region specified in the
REGION field.
Always reads as zero.
3:0 REGION On writes, specifies the number of the region whose base RW 0x0
address to update provided VALID is set written as 1. On
reads, returns bits [3:0] of MPU_RNR.
Description
Use the MPU Region Attribute and Size Register to define the size, access behaviour and memory type of the region
identified by MPU_RNR, and enable that region.
2.4. Cortex-M0+ 90
RP2040 Datasheet
31:16 ATTRS The MPU Region Attribute field. Use to define the region RW 0x0000
attribute control.
28 = XN: Instruction access disable bit:
0 = Instruction fetches enabled.
1 = Instruction fetches disabled.
26:24 = AP: Access permission field
18 = S: Shareable bit
17 = C: Cacheable bit
16 = B: Bufferable bit
15:8 SRD Subregion Disable. For regions of 256 bytes or larger, each RW 0x00
bit of this field controls whether one of the eight equal
subregions is enabled.
7:6 Reserved. - - -
5:1 SIZE Indicates the region size. Region size in bytes = RW 0x00
2^(SIZE+1). The minimum permitted value is 7 (b00111) =
256Bytes
2.5. DMA
The RP2040 Direct Memory Access (DMA) controller has separate read and write master connections to the bus fabric,
and performs bulk data transfers on a processor’s behalf. This leaves processors free to attend to other tasks, or enter
low-power sleep states. The data throughput of the DMA is also significantly higher than one of RP2040’s processors.
2.5. DMA 91
RP2040 Datasheet
• Peripheral-to-memory: a peripheral signals the DMA when it has received data. The DMA reads this data from the
peripheral’s data FIFO, and writes it to an array in RAM.
• Memory-to-memory: the DMA transfers data between two buffers in RAM, as fast as possible.
Each channel has its own control and status registers (CSRs), with which software can program and monitor the
channel’s progress. When multiple channels are active at the same time, the DMA shares bandwidth evenly between the
channels, with round-robin over all channels which are currently requesting data transfers.
The transfer size can be either 32, 16, or 8 bits. This is configured once per channel: source transfer size and
destination transfer size are the same. The DMA performs standard byte lane replication on narrow writes, so byte data
is available in all 4 bytes of the databus, and halfword data in both halfwords.
Channels can be combined in varied ways for more sophisticated behaviour and greater autonomy. For example, one
channel can configure another, loading configuration data from a sequence of control blocks in memory, and the
second can then call back to the first via the CHAIN_TO option, when it needs to be reconfigured.
Making the DMA more autonomous means that much less processor supervision is required: overall this allows the
system to do more at once, or to dissipate less power.
• CTRL is used to configure all other aspects of the channel’s behaviour, to enable/disable it, and to check for
completion.
These are live registers: they update continuously as the channel progresses.
READ_ADDR and WRITE_ADDR contain the address the channel will next read from, and write to, respectively. These registers
update automatically after each read/write access. They increment by 1, 2 or 4 bytes at a time, depending on the
transfer size configured in CTRL.
Software should generally program these registers with new start addresses each time a new transfer sequence starts.
If READ_ADDR and WRITE_ADDR are not reprogrammed, the DMA will use the current values as start addresses for the next
2.5. DMA 92
RP2040 Datasheet
• If the address does not increment (e.g. it is the address of a peripheral FIFO), and the next transfer sequence is
to/from that same address, there is no need to write to the register again.
• When transferring to/from a consecutive series of buffers in memory (e.g. scattering and gathering), an address
register will already have incremented to the start of the next buffer at the completion of a transfer.
By not programming all four CSRs for each transfer sequence, software can use shorter interrupt handlers, and more
compact control block formats when used with channel chaining (see register aliases in Section 2.5.2.1, chaining in
Section 2.5.2.2).
CAUTION
READ_ADDR and WRITE_ADDR must always be aligned to the current transfer size, as specified in CTRL.DATA_SIZE. It is up to
software to ensure the initial values are correctly aligned.
Reading from TRANS_COUNT yields the number of transfers remaining in the current transfer sequence. This value updates
continuously as the channel progresses. Writing to TRANS_COUNT sets the length of the next transfer sequence. Up to 232-1
transfers can be performed in one sequence.
Each time the channel starts a new transfer sequence, the most recent value written to TRANS_COUNT is copied to the live
transfer counter, which will then start to decrement again as the new transfer sequence makes progress. For debugging
purposes, the last value written can be read from the DBG_TCR (TRANS_COUNT reload value) register.
If the channel is triggered multiple times without intervening writes to TRANS_COUNT, it performs the same number of
transfers each time. For example, when chained to, one channel might load a fixed-size control block into another
channel’s CSRs. TRANS_COUNT would be programmed once by software, and then reload automatically every time.
Alternatively, TRANS_COUNT can be written with a new value before starting each transfer sequence. If TRANS_COUNT is the
channel trigger (see Section 2.5.2.1), the channel will start immediately, and the value just written will be used, not the
value currently in the reload register.
NOTE
the TRANS_COUNT is the number of transfers to be performed. The total number of bytes transferred is TRANS_COUNT times
the size of each transfer in bytes, given by CTRL.DATA_SIZE.
2.5.1.3. Control/Status
The CTRL register has more, smaller fields than the other 3 registers, and full details of these are given in the CTRL register
listings. Among other things, CTRL is used to:
• Configure the size of this channel’s data transfers, via CTRL.DATA_SIZE. Reads and writes are the same size.
• Configure if and how READ_ADDR and WRITE_ADDR increment after each read or write, via CTRL.INCR_WRITE, CTRL.INCR_READ,
CTRL.RING_SEL, CTRL.RING_SIZE. Ring transfers are available, where one of the address pointers wraps at some power-
of-2 boundary.
• Select another channel (or none) to be triggered when this channel completes, via CTRL.CHAIN_TO.
• Select a peripheral data request (DREQ) signal to pace this channel’s transfers, via CTRL.TREQ_SEL.
• See when the channel is idle, via CTRL.BUSY.
• See if the channel has encountered a bus error, e.g. due to a faulty address being accessed, via CTRL.AHB_ERROR,
CTRL.READ_ERROR, or CTRL.WRITE_ERROR.
2.5. DMA 93
RP2040 Datasheet
NOTE
The four CSRs are aliased multiple times in memory. Each alias — of which there are four — exposes the same four
physical registers, but in a different order. The final register in each alias (at offset +0xC, highlighted) is a trigger register.
Writing to the trigger register starts the channel.
Often, only alias 0 is used, and aliases 1-3 can be ignored. The channel is configured and started by writing READ_ADDR,
WRITE_ADDR, TRANS_COUNT and finally CTRL. Since CTRL is the trigger register in alias 0, this starts the channel.
The other aliases allow more compact control block lists when using one channel to configure another, and more
efficient reconfiguration and launch in interrupt handlers:
◦ When scattering from a peripheral to fixed-size buffers, the channel can be configured and launched by
writing only WRITE_ADDR_TRIG.
• Useful combinations of registers appear as naturally-aligned tuples which contain a trigger register. In conjunction
with channel chaining and address wrapping, these implement compressed control block formats, e.g.:
• The channel is disabled via CTRL.EN. (If the trigger is CTRL, the just-written value of EN is used, not the value currently
in the CTRL register.)
2.5. DMA 94
RP2040 Datasheet
• The value 0 is written to the trigger register. (This is useful for ending control block chains. See null triggers,
Section 2.5.2.3)
2.5.2.2. Chaining
When a channel completes, it can name a different channel to immediately be triggered. This can be used as a callback
for the second channel to reconfigure and restart the first.
This feature is configured through the CHAIN_TO field in the channel CTRL register. This 4-bit value selects a channel that
will start when this one finishes. A channel can not chain to itself. Setting CHAIN_TO to a channel’s own index means no
chaining will take place.
Chain triggers behave the same as triggers from other sources, such as trigger registers. For example, they cause
TRANS_COUNT to reload, and they are ignored if the targeted channel is already running.
One application for CHAIN_TO is for a channel to request reconfiguration by another channel, from a sequence of control
blocks in memory. Channel A is configured to perform a wrapped transfer from memory to channel B’s control registers
(including a trigger register), and channel B is configured to chain back to channel A when it completes each transfer
sequence. This is shown more explicitly in the DMA control blocks example (Section 2.5.6.2).
Use of the register aliases (Section 2.5.2.1) enables compact formats for DMA control blocks: as little as one word in
some cases.
Another use of chaining is a "ping-pong" configuration, where two channels each trigger one another. The processor can
respond to the channel completion interrupts, and reconfigure each channel after it completes; however, the chained
channel, which has already been configured, starts immediately. In other words, channel configuration and channel
operation are pipelined. Performance can improve dramatically where many short transfer sequences are required.
The Section 2.5.6 goes into more detail on the possibilities of chain triggers, in the real world.
As mentioned in Section 2.5.2.1, writing all-zeroes to a trigger register does not start the channel. This is called a null
trigger, and it has two purposes:
• Cause a halt at the end of an array of control blocks, by appending an all-zeroes block
• Reduce the number of interrupts generated when control blocks are used
By default, a channel will generate an interrupt each time it finishes a transfer sequence, unless that channel’s IRQ is
masked in INTE0 or INTE1. The rate of interrupts can be excessive, particularly as processor attention is generally not
required while a sequence of control blocks are in progress; however, processor attention is required at the end of a
chain.
The channel CTRL register has a field called IRQ_QUIET. Its default value is 0. When this set to 1, channels generate an
interrupt when they receive a null trigger, and at no other time. The interrupt is generated by the channel which receives
the trigger.
The CTRL.TREQ_SEL (transfer request) field selects an external DREQ. It can also be used to select one of the internal
pacing timers, or select no TREQ at all (the transfer proceeds as fast as possible), e.g. for memory-to-memory transfers.
2.5. DMA 95
RP2040 Datasheet
• The area and power cost of large peripheral data FIFOs is prohibitive
• The bandwidth demands of individual peripherals may be high, e.g. >50% bus injection rate for short periods
• Bus latency is low, but multiple masters may be competing for bus access
In addition, the DMA’s transfer FIFOs and dual-master structure permit multiple accesses to the same peripheral to be in
flight at once, to improve gross throughput. Choice of DREQ mechanism is therefore critical:
• The traditional "turn on the tap" method can cause overflow if multiple writes are backed up in the TDF. Some
systems solve this by overprovisioning peripheral FIFOs and setting the DREQ threshold below the full level, but
this wastes precious area and power
• The ARM-style single and burst handshake does not permit additional requests to be registered while the current
request is being served. This limits performance when FIFOs are very shallow.
The RP2040 DMA uses a credit-based DREQ mechanism. For each peripheral, the DMA attempts to keep as many
transfers in flight as the peripheral has capacity for. This enables full bus throughput (1 word per clock) through an 8-
deep peripheral FIFO with no possibility of overflow or underflow, in the absence of fabric latency or contention.
For each channel, the DMA maintains a counter. Each 1-clock pulse on the dreq signal will increment this counter
(saturating). When nonzero, the channel requests a transfer from the DMA’s internal arbiter, and the counter is
decremented when the transfer is issued to the address FIFOs. At this point the transfer is in flight, but has not yet
necessarily completed.
chan count 0 1 0 1 1 2
chan issue
The effect is to upper bound the number of in-flight transfers based on the amount of room or data available in the
peripheral FIFO. In the steady state, this gives maximum throughput, but can’t underflow or underflow.
One caveat is that the user must not access a FIFO which is currently being serviced by the DMA. This causes the
2.5. DMA 96
RP2040 Datasheet
channel and peripheral to become desynchronised, and can cause corruption or loss of data.
Another caveat is that multiple channels should not be connected to the same DREQ.
2.5.4. Interrupts
Each channel can generate interrupts; these can be masked on a per-channel basis using the INTE0 or INTE1 registers.
There are two circumstances where a channel raises an interrupt request:
The RP2040 DMA provides two system IRQs, with independent masking and status registers (e.g. INTE0, INTE1). Any
combination of channel interrupt requests can be routed to either system IRQ. For example:
• Some channels can be given a higher priority in the system interrupt controller, if they have particularly tight timing
requirements
• In multiprocessor systems, different channel interrupts can be routed independently to different cores
For debugging purposes, the INTF registers can force either IRQ to be asserted.
These allow transfer of data roughly once every n clk_sys clocks instead of using external peripheral DREQ to trigger
transfers. A fractional (X/Y) divider is used, and will generate a maximum of 1 request per clk_sys cycle.
There are 4 timers available in RP2040. Each DMA is able to select any of these in CTRL.TREQ_SEL.
The DMA can watch data from a given channel passing through the data FIFO, and calculate checksums based on this
data. This a purely passive affair: the data is not altered by this hardware, only observed.
The feature is controlled via the SNIFF_CTRL and SNIFF_DATA registers, and can be enabled/disabled per DMA transfer via
the CTRL.SNIFF_EN field.
As this hardware cannot place backpressure on the FIFO, it must keep up with the DMA’s maximum transfer rate of 32
bits per clock.
Bit/byte manipulations are available on the result which may aid specific use cases:
• Bit inversion
2.5. DMA 97
RP2040 Datasheet
• Bit reversal
• Byte swap
These manipulations do not affect the CRC calculation, just how the data is presented in the result register.
It is possible for a channel to get into an irrecoverable state: e.g. if commanded to transfer more data than a peripheral
will ever request, it will never complete. Clearing the CTRL.EN bit merely pauses the channel, and does not solve the
problem. This should not occur under normal circumstances, but it is important that there is a mechanism to recover
without simply hard-resetting the entire DMA block.
The CHAN_ABORT register forces channels to complete early. There is one bit for each channel, and writing a 1
terminates that channel. This clears the transfer counter and forces the channel into an inactive state.
NOTE
Aborting a DMA channel does not cause assertion of its IRQ; abort does not count as a completion for IRQ purposes.
At the point where the corresponding CHAN_ABORT register bit is set high, a channel may have bus transfers currently
in flight between the read and write master, and these transfers cannot be revoked. Once set, a bit in CHAN_ABORT
stays high until these transfers complete, and the channel reaches a safe state, which generally takes only a few cycles.
The correct procedure is to write a bitmap into CHAN_ABORT of the channels you wish to terminate, and then poll the
register until it reads all-zeroes.
CAUTION
Following an abort, the channel must not be restarted until the corresponding bit in CHAN_ABORT is once again
seen low. Starting the channel
2.5.5.4. Debug
Debug registers are available for each DMA channel to show the dreq counter DBG_CTDDREQ and next transfer count
DBG_TCR. These can also be used to reset a DMA channel if required.
When a channel finishes a block of transfers, it becomes available for making more transfers. Software detects that the
channel is no longer busy, and reconfigures and restarts the channel. One approach is to poll the CTRL_BUSY bit until the
channel is done, but this loses one of the key advantages of the DMA, namely that it does not have to operate in
lockstep with a processor. By setting the correct bit in INTE0 or INTE1, we can instruct the DMA to raise one of its two
interrupt request lines when a given channel completes. Rather than repeatedly asking if a channel is done, we are told.
2.5. DMA 98
RP2040 Datasheet
NOTE
Having two system interrupt lines allows different channel completion interrupts to be routed to different cores, or to
preempt one another on the same core if one channel is more time-critical.
When the interrupt is asserted, the processor can be configured to drop whatever it is doing and call a user-specified
handler function. The handler can reconfigure and restart the channel. When the handler exits, the processor returns to
the interrupted code running in the foreground.
35 void dma_handler() {
36 static int pwm_level = 0;
37 static uint32_t wavetable[N_PWM_LEVELS];
38 static bool first_run = true;
39 // Entry number `i` has `i` one bits and `(32 - i)` zero bits.
40 if (first_run) {
41 first_run = false;
42 for (int i = 0; i < N_PWM_LEVELS; ++i)
43 wavetable[i] = ~(~0u << i);
44 }
45
46 // Clear the interrupt request.
47 dma_hw->ints0 = 1u << dma_chan;
48 // Give the channel a new wave table entry to read from, and re-trigger it
49 dma_channel_set_read_addr(dma_chan, &wavetable[pwm_level], true);
50
51 pwm_level = (pwm_level + 1) % N_PWM_LEVELS;
52 }
In many cases, most of the configuration can be done the first time the channel is started, and only addresses and
transfer lengths need reprogramming in the DMA handler.
54 int main() {
55 #ifndef PICO_DEFAULT_LED_PIN
56 #warning dma/channel_irq example requires a board with a regular LED
57 #else
58 // Set up a PIO state machine to serialise our bits
59 uint offset = pio_add_program(pio0, &pio_serialiser_program);
60 pio_serialiser_program_init(pio0, 0, offset, PICO_DEFAULT_LED_PIN, PIO_SERIAL_CLKDIV);
61
62 // Configure a channel to write the same word (32 bits) repeatedly to PIO0
63 // SM0's TX FIFO, paced by the data request signal from that peripheral.
64 dma_chan = dma_claim_unused_channel(true);
65 dma_channel_config c = dma_channel_get_default_config(dma_chan);
66 channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
67 channel_config_set_read_increment(&c, false);
68 channel_config_set_dreq(&c, DREQ_PIO0_TX0);
69
70 dma_channel_configure(
71 dma_chan,
72 &c,
73 &pio0_hw->txf[0], // Write address (only need to set this once)
74 NULL, // Don't provide a read address yet
75 PWM_REPEAT_COUNT, // Write the same value many times, then halt and interrupt
76 false // Don't start yet
77 );
78
2.5. DMA 99
RP2040 Datasheet
79 // Tell the DMA to raise IRQ line 0 when the channel finishes a block
80 dma_channel_set_irq0_enabled(dma_chan, true);
81
82 // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
83 irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);
84 irq_set_enabled(DMA_IRQ_0, true);
85
86 // Manually call the handler once, to trigger the first transfer
87 dma_handler();
88
89 // Everything else from this point is interrupt-driven. The processor has
90 // time to sit and think about its early retirement -- maybe open a bakery?
91 while (true)
92 tight_loop_contents();
93 #endif
94 }
One disadvantage of this technique is that we don’t start to reconfigure the channel until some time after the channel
makes its last transfer. If there is heavy interrupt activity on the processor, this may be quite a long time, and therefore
quite a large gap in transfers, which is problematic if we need to sustain a high data throughput.
This is solved by using two channels, with their CHAIN_TO fields crossed over, so that channel A triggers channel B when it
completes, and vice versa. At any point in time, one of the channels is transferring data, and the other is either already
configured to start the next transfer immediately when the current one finishes, or it is in the process of being
reconfigured. When channel A completes, it immediately starts the cued-up transfer on channel B. At the same time, the
interrupt is fired, and the handler reconfigures channel A so that it is ready for when channel B completes.
Frequently, multiple smaller buffers must be gathered together and sent to the same peripheral. To address this use
case, the RP2040 DMA can execute a long and complex sequence of transfers without processor control. One channel
repeatedly reconfigures a second channel, and the second channel restarts the first each time it completes block of
transfers.
Because the first DMA channel is transferring data directly from memory to the second channel’s control registers, the
format of the control blocks in memory must match those registers. The last register written to, each time, will be one of
the trigger registers (Section 2.5.2.1) which will start the second channel on its programmed block of transfers. The
register aliases (Section 2.5.2.1) give some flexibility for the block layout, and more importantly allow some registers to
be omitted from the blocks, so they occupy less memory and can be loaded more quickly.
This example shows how multiple buffers can be gathered and transferred to the UART, by reprogramming TRANS_COUNT
and READ_ADDR_TRIG:
1 /**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 // Use two DMA channels to make a programmed sequence of data transfers to the
8 // UART (a data gather operation). One channel is responsible for transferring
9 // the actual data, the other repeatedly reprograms that channel.
10
11 #include <stdio.h>
12 #include "pico/stdlib.h"
13 #include "hardware/dma.h"
14 #include "hardware/structs/uart.h"
15
16 // These buffers will be DMA'd to the UART, one after the other.
17
18 const char word0[] = "Transferring ";
19 const char word1[] = "one ";
20 const char word2[] = "word ";
21 const char word3[] = "at ";
22 const char word4[] = "a ";
23 const char word5[] = "time.\n";
24
25 // Note the order of the fields here: it's important that the length is before
26 // the read address, because the control channel is going to write to the last
27 // two registers in alias 3 on the data channel:
28 // +0x0 +0x4 +0x8 +0xC (Trigger)
29 // Alias 0: READ_ADDR WRITE_ADDR TRANS_COUNT CTRL
30 // Alias 1: CTRL READ_ADDR WRITE_ADDR TRANS_COUNT
31 // Alias 2: CTRL TRANS_COUNT READ_ADDR WRITE_ADDR
32 // Alias 3: CTRL WRITE_ADDR TRANS_COUNT READ_ADDR
33 //
34 // This will program the transfer count and read address of the data channel,
35 // and trigger it. Once the data channel completes, it will restart the
36 // control channel (via CHAIN_TO) to load the next two words into its control
37 // registers.
38
39 const struct {uint32_t len; const char *data;} control_blocks[] = {
40 {count_of(word0) - 1, word0}, // Skip null terminator
41 {count_of(word1) - 1, word1},
42 {count_of(word2) - 1, word2},
43 {count_of(word3) - 1, word3},
44 {count_of(word4) - 1, word4},
45 {count_of(word5) - 1, word5},
46 {0, NULL} // Null trigger to end chain.
47 };
48
49 int main() {
50 #ifndef uart_default
51 #warning dma/control_blocks example requires a UART
52 #else
53 stdio_init_all();
54 puts("DMA control block example:");
55
56 // ctrl_chan loads control blocks into data_chan, which executes them.
57 int ctrl_chan = dma_claim_unused_channel(true);
58 int data_chan = dma_claim_unused_channel(true);
59
60 // The control channel transfers two words into the data channel's control
61 // registers, then halts. The write address wraps on a two-word
62 // (eight-byte) boundary, so that the control channel writes the same two
63 // registers when it is next triggered.
64
65 dma_channel_config c = dma_channel_get_default_config(ctrl_chan);
66 channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
67 channel_config_set_read_increment(&c, true);
68 channel_config_set_write_increment(&c, true);
69 channel_config_set_ring(&c, true, 3); // 1 << 3 byte boundary on write ptr
70
71 dma_channel_configure(
72 ctrl_chan,
73 &c,
74 &dma_hw->ch[data_chan].al3_transfer_count, // Initial write address
75 &control_blocks[0], // Initial read address
76 2, // Halt after each control block
77 false // Don't start yet
78 );
79
80 // The data channel is set up to write to the UART FIFO (paced by the
81 // UART's TX data request signal) and then chain to the control channel
82 // once it completes. The control channel programs a new read address and
83 // data length, and retriggers the data channel.
84
85 c = dma_channel_get_default_config(data_chan);
86 channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
87 channel_config_set_dreq(&c, DREQ_UART0_TX + 2 * uart_get_index(uart_default));
88 // Trigger ctrl_chan when data_chan completes
89 channel_config_set_chain_to(&c, ctrl_chan);
90 // Raise the IRQ flag when 0 is written to a trigger register (end of chain):
91 channel_config_set_irq_quiet(&c, true);
92
93 dma_channel_configure(
94 data_chan,
95 &c,
96 &uart_get_hw(uart_default)->dr,
97 NULL, // Initial read address and transfer count are unimportant;
98 0, // the control channel will reprogram them each time.
99 false // Don't start yet.
100 );
101
102 // Everything is ready to go. Tell the control channel to load the first
103 // control block. Everything is automatic from here.
104 dma_start_channel_mask(1u << ctrl_chan);
105
106 // The data channel will assert its IRQ flag when it gets a null trigger,
107 // indicating the end of the control block list. We're just going to wait
108 // for the IRQ flag instead of setting up an interrupt handler.
109 while (!(dma_hw->intr & 1u << data_chan))
110 tight_loop_contents();
111 dma_hw->ints0 = 1u << data_chan;
112
113 puts("DMA finished.");
114 #endif
115 }
0x448 N_CHANNELS The number of channels this DMA instance is equipped with.
This DMA supports up to 16 hardware channels, but can be
configured with as few as one, to minimise silicon area.
0x800 CH0_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x804 CH0_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x840 CH1_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x844 CH1_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x880 CH2_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x884 CH2_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x8c0 CH3_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x8c4 CH3_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x900 CH4_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x904 CH4_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x940 CH5_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x944 CH5_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x980 CH6_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x984 CH6_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0x9c0 CH7_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0x9c4 CH7_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0xa00 CH8_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0xa04 CH8_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0xa40 CH9_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0xa44 CH9_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0xa80 CH10_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0xa84 CH10_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
0xac0 CH11_DBG_CTDREQ Read: get channel DREQ counter (i.e. how many accesses the
DMA expects it can perform on the peripheral without
overflow/underflow. Write any value: clears the counter, and
cause channel to re-initiate DREQ handshake.
0xac4 CH11_DBG_TCR Read to get channel TRANS_COUNT reload value, i.e. the length
of the next transfer
Description
DMA Channel N Read Address pointer
Table 121.
Bits Description Type Reset
CH0_READ_ADDR,
CH1_READ_ADDR, …,
31:0 This register updates automatically each time a read completes. The current RW 0x00000000
CH10_READ_ADDR,
CH11_READ_ADDR value is the next address to be read by this channel.
Registers
Description
DMA Channel N Write Address pointer
Table 122.
Bits Description Type Reset
CH0_WRITE_ADDR,
CH1_WRITE_ADDR, …,
31:0 This register updates automatically each time a write completes. The current RW 0x00000000
CH10_WRITE_ADDR,
CH11_WRITE_ADDR value is the next address to be written by this channel.
Registers
Description
DMA Channel N Transfer Count
Table 123.
Bits Description Type Reset
CH0_TRANS_COUNT,
CH1_TRANS_COUNT,
31:0 Program the number of bus transfers a channel will perform before halting. RW 0x00000000
…,
CH10_TRANS_COUNT, Note that, if transfers are larger than one byte in size, this is not equal to the
CH11_TRANS_COUNT number of bytes transferred (see CTRL_DATA_SIZE).
Registers
When the channel is active, reading this register shows the number of
transfers remaining, updating automatically each time a write transfer
completes.
Writing this register sets the RELOAD value for the transfer counter. Each time
this channel is triggered, the RELOAD value is copied into the live transfer
counter. The channel can be started multiple times, and will perform the same
number of transfers each time, as programmed by most recent write.
Description
DMA Channel N Control and Status
Table 124.
CH0_CTRL_TRIG
Registers
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x0
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (so CHAIN_TO
disabled by default).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Table 125.
Bits Description Type Reset
CH0_AL1_CTRL,
CH1_AL1_CTRL, …,
31:0 Alias for channel N CTRL register RO -
CH10_AL1_CTRL,
CH11_AL1_CTRL
Registers
DMA: CH0_AL1_READ_ADDR, CH1_AL1_READ_ADDR, …,
CH10_AL1_READ_ADDR, CH11_AL1_READ_ADDR Registers
Offsets: 0x014, 0x054, …, 0x294, 0x2d4
Table 126.
Bits Description Type Reset
CH0_AL1_READ_ADDR
,
31:0 Alias for channel N READ_ADDR register RO -
CH1_AL1_READ_ADDR
, …,
CH10_AL1_READ_ADD
R, DMA: CH0_AL1_WRITE_ADDR, CH1_AL1_WRITE_ADDR, …,
CH11_AL1_READ_ADD
R Registers
CH10_AL1_WRITE_ADDR, CH11_AL1_WRITE_ADDR Registers
Offsets: 0x018, 0x058, …, 0x298, 0x2d8
Table 127.
Bits Description Type Reset
CH0_AL1_WRITE_ADD
R,
31:0 Alias for channel N WRITE_ADDR register RO -
CH1_AL1_WRITE_ADD
R, …,
CH10_AL1_WRITE_AD
DR, DMA: CH0_AL1_TRANS_COUNT_TRIG, CH1_AL1_TRANS_COUNT_TRIG, …,
CH11_AL1_WRITE_AD
DR Registers
CH10_AL1_TRANS_COUNT_TRIG, CH11_AL1_TRANS_COUNT_TRIG Registers
Offsets: 0x01c, 0x05c, …, 0x29c, 0x2dc
Table 128.
Bits Description Type Reset
CH0_AL1_TRANS_COU
NT_TRIG,
31:0 Alias for channel N TRANS_COUNT register RO -
CH1_AL1_TRANS_COU
NT_TRIG, …, This is a trigger register (0xc). Writing a nonzero value will
CH10_AL1_TRANS_CO reload the channel counter and start the channel.
UNT_TRIG,
CH11_AL1_TRANS_CO
UNT_TRIG Registers
DMA: CH0_AL2_CTRL, CH1_AL2_CTRL, …, CH10_AL2_CTRL, CH11_AL2_CTRL
Registers
Offsets: 0x020, 0x060, …, 0x2a0, 0x2e0
Table 129.
Bits Description Type Reset
CH0_AL2_CTRL,
CH1_AL2_CTRL, …,
31:0 Alias for channel N CTRL register RO -
CH10_AL2_CTRL,
CH11_AL2_CTRL
Registers
DMA: CH0_AL2_TRANS_COUNT, CH1_AL2_TRANS_COUNT, …,
CH10_AL2_TRANS_COUNT, CH11_AL2_TRANS_COUNT Registers
Offsets: 0x024, 0x064, …, 0x2a4, 0x2e4
Table 130.
Bits Description Type Reset
CH0_AL2_TRANS_COU
NT,
31:0 Alias for channel N TRANS_COUNT register RO -
CH1_AL2_TRANS_COU
NT, …,
CH10_AL2_TRANS_CO
UNT, DMA: CH0_AL2_READ_ADDR, CH1_AL2_READ_ADDR, …,
CH11_AL2_TRANS_CO
UNT Registers
CH10_AL2_READ_ADDR, CH11_AL2_READ_ADDR Registers
Offsets: 0x028, 0x068, …, 0x2a8, 0x2e8
Table 131.
Bits Description Type Reset
CH0_AL2_READ_ADDR
,
31:0 Alias for channel N READ_ADDR register RO -
CH1_AL2_READ_ADDR
, …,
CH10_AL2_READ_ADD
R, DMA: CH0_AL2_WRITE_ADDR_TRIG, CH1_AL2_WRITE_ADDR_TRIG, …,
CH11_AL2_READ_ADD
R Registers
CH10_AL2_WRITE_ADDR_TRIG, CH11_AL2_WRITE_ADDR_TRIG Registers
Offsets: 0x02c, 0x06c, …, 0x2ac, 0x2ec
Table 132.
Bits Description Type Reset
CH0_AL2_WRITE_ADD
R_TRIG,
31:0 Alias for channel N WRITE_ADDR register RO -
CH1_AL2_WRITE_ADD
R_TRIG, …, This is a trigger register (0xc). Writing a nonzero value will
CH10_AL2_WRITE_AD reload the channel counter and start the channel.
DR_TRIG,
CH11_AL2_WRITE_AD
DR_TRIG Registers
DMA: CH0_AL3_CTRL, CH1_AL3_CTRL, …, CH10_AL3_CTRL, CH11_AL3_CTRL
Registers
Offsets: 0x030, 0x070, …, 0x2b0, 0x2f0
Table 133.
Bits Description Type Reset
CH0_AL3_CTRL,
CH1_AL3_CTRL, …,
31:0 Alias for channel N CTRL register RO -
CH10_AL3_CTRL,
CH11_AL3_CTRL
Registers
DMA: CH0_AL3_WRITE_ADDR, CH1_AL3_WRITE_ADDR, …,
CH10_AL3_WRITE_ADDR, CH11_AL3_WRITE_ADDR Registers
Offsets: 0x034, 0x074, …, 0x2b4, 0x2f4
Table 134.
Bits Description Type Reset
CH0_AL3_WRITE_ADD
R,
31:0 Alias for channel N WRITE_ADDR register RO -
CH1_AL3_WRITE_ADD
R, …,
CH10_AL3_WRITE_AD
DR, DMA: CH0_AL3_TRANS_COUNT, CH1_AL3_TRANS_COUNT, …,
CH11_AL3_WRITE_AD
DR Registers
CH10_AL3_TRANS_COUNT, CH11_AL3_TRANS_COUNT Registers
Offsets: 0x038, 0x078, …, 0x2b8, 0x2f8
Table 135.
Bits Description Type Reset
CH0_AL3_TRANS_COU
NT,
31:0 Alias for channel N TRANS_COUNT register RO -
CH1_AL3_TRANS_COU
NT, …,
CH10_AL3_TRANS_CO
UNT, DMA: CH0_AL3_READ_ADDR_TRIG, CH1_AL3_READ_ADDR_TRIG, …,
CH11_AL3_TRANS_CO
UNT Registers
CH10_AL3_READ_ADDR_TRIG, CH11_AL3_READ_ADDR_TRIG Registers
Offsets: 0x03c, 0x07c, …, 0x2bc, 0x2fc
Table 136.
Bits Description Type Reset
CH0_AL3_READ_ADDR
_TRIG,
31:0 Alias for channel N READ_ADDR register RO -
CH1_AL3_READ_ADDR
_TRIG, …, This is a trigger register (0xc). Writing a nonzero value will
CH10_AL3_READ_ADD reload the channel counter and start the channel.
R_TRIG,
CH11_AL3_READ_ADD
R_TRIG Registers
DMA: CH1_CTRL_TRIG Register
Offset: 0x04c
Description
DMA Channel 1 Control and Status
Table 137.
Bits Name Description Type Reset
CH1_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x1
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (1).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 2 Control and Status
Table 138.
Bits Name Description Type Reset
CH2_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x2
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (2).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 3 Control and Status
Table 139.
Bits Name Description Type Reset
CH3_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x3
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (3).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 4 Control and Status
Table 140.
Bits Name Description Type Reset
CH4_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x4
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (4).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 5 Control and Status
Table 141.
Bits Name Description Type Reset
CH5_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x5
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (5).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 6 Control and Status
Table 142.
Bits Name Description Type Reset
CH6_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x6
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (6).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 7 Control and Status
Table 143.
Bits Name Description Type Reset
CH7_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x7
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (7).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 8 Control and Status
Table 144.
Bits Name Description Type Reset
CH8_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x8
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (8).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 9 Control and Status
Table 145.
Bits Name Description Type Reset
CH9_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0x9
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (9).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 10 Control and Status
Table 146.
Bits Name Description Type Reset
CH10_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0xa
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (10).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
DMA Channel 11 Control and Status
Table 147.
Bits Name Description Type Reset
CH11_CTRL_TRIG
Register
31 AHB_ERROR Logical OR of the READ_ERROR and WRITE_ERROR flags. RO 0x0
The channel halts when it encounters any bus error, and
always raises its channel IRQ flag.
30 READ_ERROR If 1, the channel received a read bus error. Write one to WC 0x0
clear.
READ_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 3 transfers later)
29 WRITE_ERROR If 1, the channel received a write bus error. Write one to WC 0x0
clear.
WRITE_ADDR shows the approximate address where the
bus error was encountered (will not to be earlier, or more
than 5 transfers later)
28:25 Reserved. - - -
24 BUSY This flag goes high when the channel starts a new transfer RO 0x0
sequence, and low when the last transfer of that sequence
completes. Clearing EN while BUSY is high pauses the
channel, and BUSY will stay high while paused.
23 SNIFF_EN If 1, this channel’s data transfers are visible to the sniff RW 0x0
hardware, and each transfer will advance the state of the
checksum. This only applies if the sniff hardware is
enabled, and has this channel selected.
21 IRQ_QUIET In QUIET mode, the channel does not generate IRQs at the RW 0x0
end of every transfer block. Instead, an IRQ is raised when
NULL is written to a trigger register, indicating the end of a
control block chain.
14:11 CHAIN_TO When this channel completes, it will trigger the channel RW 0xb
indicated by CHAIN_TO. Disable by setting CHAIN_TO =
(this channel).
Reset value is equal to channel number (11).
9:6 RING_SIZE Size of address wrap region. If 0, don’t wrap. For values n RW 0x0
> 0, only the lower n bits of the address will change. This
wraps the address on a (1 << n) byte boundary, facilitating
access to naturally-aligned ring buffers.
3:2 DATA_SIZE Set the size of each bus transfer (byte/halfword/word). RW 0x0
READ_ADDR and WRITE_ADDR advance by this amount
(1/2/4 bytes) with each transfer.
0x0 → SIZE_BYTE
0x1 → SIZE_HALFWORD
0x2 → SIZE_WORD
Description
Interrupt Status (raw)
31:16 Reserved. - -
15:0 Raw interrupt status for DMA Channels 0..15. Bit n corresponds to channel n. RO 0x0000
Ignores any masking or forcing. Channel interrupts can be cleared by writing a
bit mask to INTR, INTS0 or INTS1.
This can be used vector different channel interrupts to different ISRs: this
might be done to allow NVIC IRQ preemption for more time-critical channels,
or to spread IRQ load across different cores.
Description
Interrupt Enables for IRQ 0
31:16 Reserved. - -
15:0 Set bit n to pass interrupts from channel n to DMA IRQ 0. RW 0x0000
Description
Force Interrupts
31:16 Reserved. - -
15:0 Write 1s to force the corresponding bits in INTE0. The interrupt remains RW 0x0000
asserted until INTF0 is cleared.
Description
Interrupt Status for IRQ 0
31:16 Reserved. - -
15:0 Indicates active channel interrupt requests which are currently causing IRQ 0 WC 0x0000
to be asserted.
Channel interrupts can be cleared by writing a bit mask here.
Description
Interrupt Enables for IRQ 1
31:16 Reserved. - -
15:0 Set bit n to pass interrupts from channel n to DMA IRQ 1. RW 0x0000
Description
Force Interrupts for IRQ 1
31:16 Reserved. - -
15:0 Write 1s to force the corresponding bits in INTE0. The interrupt remains RW 0x0000
asserted until INTF0 is cleared.
Description
Interrupt Status (masked) for IRQ 1
31:16 Reserved. - -
15:0 Indicates active channel interrupt requests which are currently causing IRQ 1 WC 0x0000
to be asserted.
Channel interrupts can be cleared by writing a bit mask here.
Description
Pacing (X/Y) Fractional Timer
The pacing timer produces TREQ assertions at a rate set by ((X/Y) * sys_clk). This equation is evaluated every
sys_clk cycles and therefore can only generate TREQs at a rate of 1 per sys_clk (i.e. permanent TREQ) or less.
15:0 Y Pacing Timer Divisor. Specifies the Y value for the (X/Y) RW 0x0000
fractional timer.
Description
Trigger one or more channels simultaneously
Table 156.
Bits Description Type Reset
MULTI_CHAN_TRIGGE
R Register
31:16 Reserved. - -
15:0 Each bit in this register corresponds to a DMA channel. Writing a 1 to the SC 0x0000
relevant bit is the same as writing to that channel’s trigger register; the
channel will start if it is currently enabled and not already busy.
Description
Sniffer Control
Table 157.
Bits Name Description Type Reset
SNIFF_CTRL Register
31:12 Reserved. - - -
10 OUT_REV If set, the result appears bit-reversed when read. This does RW 0x0
not affect the way the checksum is calculated; the result
is transformed on-the-fly between the result register and
the bus.
9 BSWAP Locally perform a byte reverse on the sniffed data, before RW 0x0
feeding into checksum.
Description
Data accumulator for sniff hardware
Table 158.
Bits Description Type Reset
SNIFF_DATA Register
31:0 Write an initial seed value here before starting a DMA transfer on the channel RW 0x00000000
indicated by SNIFF_CTRL_DMACH. The hardware will update this register each
time it observes a read from the indicated channel. Once the channel
completes, the final result can be read from this register.
Description
Debug RAF, WAF, TDF levels
Table 159.
Bits Name Description Type Reset
FIFO_LEVELS Register
31:24 Reserved. - - -
Description
Abort an in-progress transfer sequence on one or more channels
Table 160.
Bits Description Type Reset
CHAN_ABORT
Register
31:16 Reserved. - -
15:0 Each bit corresponds to a channel. Writing a 1 aborts whatever transfer SC 0x0000
sequence is in progress on that channel. The bit will remain high until any in-
flight transfers have been flushed through the address and data FIFOs.
After writing, this register must be polled until it returns all-zero. Until this
point, it is unsafe to restart the channel.
Table 161.
Bits Description Type Reset
N_CHANNELS Register
31:5 Reserved. - -
4:0 The number of channels this DMA instance is equipped with. This DMA RO -
supports up to 16 hardware channels, but can be configured with as few as
one, to minimise silicon area.
Table 162.
Bits Description Type Reset
CH0_DBG_CTDREQ,
CH1_DBG_CTDREQ, …,
31:6 Reserved. - -
CH10_DBG_CTDREQ,
CH11_DBG_CTDREQ
5:0 Read: get channel DREQ counter (i.e. how many accesses the DMA expects it RO 0x00
Registers
can perform on the peripheral without overflow/underflow. Write any value:
clears the counter, and cause channel to re-initiate DREQ handshake.
Table 163.
Bits Description Type Reset
CH0_DBG_TCR,
CH1_DBG_TCR, …,
31:0 Read to get channel TRANS_COUNT reload value, i.e. the length of the next RO 0x00000000
CH10_DBG_TCR,
CH11_DBG_TCR transfer
Registers
2.6. Memory
RP2040 has embedded ROM and SRAM, and access to external Flash via a QSPI interface. Details of internal memory
are given below.
2.6.1. ROM
A 16kB read-only memory (ROM) is at address 0x00000000. The ROM contents are fixed at the time the silicon is
manufactured. It contains:
https://github.com/raspberrypi/pico-bootrom
The ROM offers single-cycle read-only bus access, and is on a dedicated AHB-Lite arbiter, so it can be accessed
simultaneously with other memory devices. Attempting to write to the ROM has no effect (no bus fault is generated).
2.6.2. SRAM
There is a total of 264kB of on-chip SRAM. Physically this is partitioned into six banks, as this vastly improves memory
bandwidth for multiple masters, but software may treat it as a single 264kB memory region. There are no restrictions on
what is stored in each bank: processor code, data buffers, or a mixture. There are four 16k x 32-bit banks (64kB each)
and two 1k x 32-bit banks (4kB each).
IMPORTANT
Banking is a physical partitioning of SRAM which improves performance by allowing multiple simultaneous
accesses. Logically there is a single 264kB contiguous memory.
Each SRAM bank is accessed via a dedicated AHB-Lite arbiter. This means different bus masters can access different
SRAM banks in parallel, so up to four 32-bit SRAM accesses can take place every system clock cycle (one per master).
SRAM is mapped to system addresses starting at 0x20000000. The first 256kB address region is word-striped across the
four larger banks, which provides a significant memory parallelism benefits for most use cases.
Consecutive words in the system address space are routed to different RAM banks as shown in Table 164.
0x20000004 Bank 1 0
0x20000008 Bank 2 0
0x2000000c Bank 3 0
0x20000010 Bank 0 1
0x20000014 Bank 1 1
0x20000018 Bank 2 1
0x2000001c Bank 3 1
0x20000020 Bank 0 2
0x20000024 Bank 1 2
0x20000028 Bank 2 2
0x2000002c Bank 3 2
etc
The next two 4kB regions (starting at 0x20040000 and 0x20041000) are mapped directly to the smaller, 4kB memory banks.
Software may choose to use these for per-core purposes, e.g. stack and frequently-executed code, guaranteeing that
the processors never stall on these accesses. However, like all SRAM on RP2040, these banks have single-cycle access
from all masters providing no other masters are accessing the bank in the same cycle, so it is reasonable to treat
memory as a single 264kB device.
The four 64kB banks are also available at a non-striped mirror. The four 64kB regions starting at 0x21000000, 0x21010000,
0x21020000, 0x21030000 are each mapped directly to one of the four 64kB SRAM banks. Software can explicitly allocate
data and code across the physical memory banks, for improved memory performance in exceptionally demanding
cases. This is often unnecessary, as memory striping usually provides sufficient parallelism with less software
complexity.
The non-striped mirror starts at an offset of +16MB above the base of SRAM, as this is the maximum offset that allows
ARMv6M subroutine calls between the smaller banks and the non-striped larger banks.
Besides the 264kB main memory, there are two other dedicated RAM blocks that may be used in some circumstances:
• If flash XIP caching is disabled, the cache becomes available as a 16kB memory starting at 0x15000000
• If the USB is not used, the USB data DPRAM can be used as a 4kB memory starting at 0x50100000
This gives a total of 284kB of on-chip SRAM. There are no restrictions on how these memories are used, e.g. it is
possible to execute code from the USB data RAM if you choose.
2.6.3. Flash
External Flash is accessed via the QSPI interface using the execute-in-place (XIP) hardware. This allows an external
flash memory to be addressed and accessed by the system as though it were internal memory. Bus reads to a 16MB
memory window starting at 0x10000000 are translated into a serial flash transfer, and the result is returned to the master
that initiated the read. This process is transparent to the master, so a processor can execute code from the external
flash without first copying the code to internal memory, hence "execute in place". An internal cache remembers the
contents of recently-accessed flash locations, which accelerates the average bandwidth and latency of the interface.
Once correctly configured by RP2040’s bootrom and the flash second stage, the XIP hardware is largely transparent,
and software can treat flash as a large read-only memory. However, it does provide a number of additional features to
serve more demanding software use cases.
NOTE
The serial flash interface is configured by the flash second stage when using the SDK to run at an integer divider of
the system clock. All the included second stage boot implementations support a PICO_FLASH_SPI_CLKDIV setting (e.g.
defaulted to 4 in https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/boot_stage2/
boot2_w25q080.S to make the default interface speed 125/4 = 31.25 MHz). This divider can be overridden by
specifying PICO_FLASH_SPI_CLKDIV in the particular board config header used with the SDK.
The cache is 16 kB, two way set-associative, 1 cycle hit. It is internal to the XIP subsystem, and only affects accesses to
XIP flash, so software does not have to consider cache coherence, unless performing flash programming operations. It
caches reads from a 24-bit flash address space, which is mirrored multiple times in the RP2040 address space, each
alias having different caching behaviour. The eight MSBs of the system address are used for segment decode, leaving
24 bits for flash addressing, so the maximum supported flash size (for XIP operation) is 16MB. The available mirrors
are:
Access to the 0x15… segment produces a bus error unless the cache is disabled by clearing CTRL.EN. Once the cache is
disabled, this region behaves as an additional 16 kB SRAM bank. Reads and writes are one cycle, but there is a wait
state on consecutive write-read sequences, i.e. there is no write forwarding buffer.
The FLUSH register allows the entire cache contents to be flushed. This is necessary if software has reprogrammed the
flash contents, and needs to clear out stale data and code, without performing a reboot. Cache flushes are triggered
either manually by writing 1 to FLUSH, or automatically when the XIP block is brought out of reset. The flush is
implemented by zeroing the cache tag memory using an internal counter, which takes just over 1024 clock cycles (16 kB
total size / 8 bytes per line / 2 ways per set).
Flushing the cache whilst accessing flash data (perhaps initiating the flush on one core whilst another core may be
executing code from flash) is a safe operation, but any master accessing flash data while the flush is in progress will be
stalled until completion.
CAUTION
The cache-as-SRAM alias (0x15…) must not be written whilst a cache flush is in progress. Before writing for the first
time, if a cache flush has recently been initiated (e.g. via a watchdog reset), a dummy read from FLUSH is
recommended to ensure the cache flush has completed. Writing to cache-as-SRAM whilst a flush is in progress can
corrupt the data memory contents.
A complete cache flush dramatically slows subsequent code execution, until the cache "warms up" again. There is an
alternative, which allows cache contents corresponding to only a certain address range to be invalidated. A write to the
0x10… mirror will look up the addressed location in the cache, and delete any matching entry found. Writing to all word-
aligned locations in an address range (e.g. a flash sector that has just been erased and reprogrammed) therefore
eliminates the possibility of stale cached data in this range, without suffering the effects of a complete cache flush.
30 // Flush cache to make sure we miss the first time we access test_data
31 xip_ctrl_hw->flush = 1;
32 while (!(xip_ctrl_hw->stat & XIP_STAT_FLUSH_READY_BITS))
33 tight_loop_contents();
34
35 // Clear counters (write any value to clear)
36 xip_ctrl_hw->ctr_acc = 1;
37 xip_ctrl_hw->ctr_hit = 1;
38
39 (void) *test_data_ptr;
40 check(xip_ctrl_hw->ctr_hit == 0 && xip_ctrl_hw->ctr_acc == 1,
41 "First access to data should miss");
42
43 (void) *test_data_ptr;
44 check(xip_ctrl_hw->ctr_hit == 1 && xip_ctrl_hw->ctr_acc == 2,
45 "Second access to data should hit");
46
47 // Write to invalidate individual cache lines (64 bits)
48 // Writes must be directed to the cacheable, allocatable alias (address 0x10.._....)
49 *test_data_ptr = 0;
50 (void) *test_data_ptr;
51 check(xip_ctrl_hw->ctr_hit == 1 && xip_ctrl_hw->ctr_acc == 3,
52 "Should miss after invalidation");
53 (void) *test_data_ptr;
54 check(xip_ctrl_hw->ctr_hit == 2 && xip_ctrl_hw->ctr_acc == 4,
55 "Second access after invalidation should hit again");
2.6.3.3. SSI
The execute-in-place functionality is provided by the SSI interface, documented in Section 4.10. It supports 1, 2 or 4-bit
SPI flash interfaces (SPI, DSPI and QSPI), and can insert either an instruction prefix or mode continuation bits on each
XIP access. This includes the possibility of issuing a standard 03h serial flash read command for each access, allowing
virtually any serial flash device to be used. The maximum SPI clock frequency is half the system clock frequency.
The SSI can also be used as a standard FIFO-based SPI master, with DMA support. This mode is used by the bootrom to
extract the second stage bootloader from external flash (see Section 2.8.1). The bus interposer allows an atomic set,
clear or XOR operation to be posted to SSI control registers, in the same manner as other memory-mapped IO on
RP2040. This is described in more detail in Section 2.1.2.
As the flash is generally much larger than SRAM, it’s often useful to stream chunks of data into memory from flash. It’s
convenient to have the DMA stream this data in the background while software in the foreground is doing other things,
and it’s even more convenient if code can continue to execute from flash whilst this takes place.
This doesn’t interact well with standard XIP operation, because of the lengthy bus stalls forced on the DMA whilst the
SSI is performing serial transfers. These stalls are tolerable for a processor, because an in-order processor tends to
have nothing better to do while waiting for an instruction fetch to retire, and because typical code execution tends to
have much higher cache hit rates than bulk streaming of infrequently accessed data. In contrast, stalling the DMA
prevents any other active DMA channels from making progress during this time, which slows overall DMA throughput.
The STREAM_ADDR and STREAM_CTR registers are used to program a linear sequence of flash reads, which the XIP subsystem
will perform in the background in a best-effort fashion. To minimise impact on code being executed from flash whilst
the stream is ongoing, the streaming hardware has lower priority access to the SSI than regular XIP accesses, and there
is a brief cooldown (seven cycles) between the last XIP cache miss and resuming streaming. This helps to avoid
increase in initial access latency on XIP cache miss.
The streamed data is pushed to a small FIFO, which generates DREQ signals, telling the DMA to collect the streamed
data. As the DMA does not initiate a read until after the data has been read from flash, the DMA is not stalled when
accessing the data.
Although this scheme ensures that the data is ready in the streaming FIFO once the DREQ is asserted, the DMA can still
be stalled if another master is currently stalled on the XIP slave, e.g. due to a cache miss. This is solved by the auxiliary
bus slave, which is a simple bus interface providing access only to the streaming FIFO. This slave is exposed on the
FASTPERI arbiter, which services only native AHB-Lite peripherals which don’t generate wait states, so the DMA will never
experience stalls when accessing the FIFO at this address, assuming it has high bus priority.
The XIP subsystem provides two performance counters. These are 32 bits in size, saturate upon reaching 0xffffffff,
and are cleared by writing any value. They count:
For common use cases, this allows the cache hit rate to be profiled.
The XIP registers start at a base address of 0x14000000 (defined as XIP_CTRL_BASE in SDK).
Description
Cache control
31:4 Reserved. - - -
3 POWER_DOWN When 1, the cache memories are powered down. They RW 0x0
retain state,
but can not be accessed. This reduces static power
dissipation.
Writing 1 to this bit forces CTRL_EN to 0, i.e. the cache
cannot
be enabled when powered down.
Cache-as-SRAM accesses will produce a bus error
response when
the cache is powered down.
2 Reserved. - - -
1 ERR_BADWRITE When 1, writes to any alias other than 0x0 (caching, RW 0x1
allocating)
will produce a bus fault. When 0, these writes are silently
ignored.
In either case, writes to the 0x0 alias will deallocate on tag
match,
as usual.
0 EN When 1, enable the cache. When the cache is disabled, all RW 0x1
XIP accesses
will go straight to the flash, without querying the cache.
When enabled,
cacheable XIP accesses will query the cache, and the
flash will
not be accessed if the tag matches and the valid bit is set.
Description
Cache Flush control
31:1 Reserved. - -
0 Write 1 to flush the cache. This clears the tag memory, but SC 0x0
the data memory retains its contents. (This means cache-as-SRAM
contents is not affected by flush or reset.)
Reading will hold the bus (stall the processor) until the flush
completes. Alternatively STAT can be polled until completion.
Description
Cache Status
31:3 Reserved. - - -
Description
Cache Hit counter
31:0 A 32 bit saturating counter that increments upon each cache hit, WC 0x00000000
i.e. when an XIP access is serviced directly from cached data.
Write any value to clear.
Description
Cache Access counter
31:0 A 32 bit saturating counter that increments upon each XIP access, WC 0x00000000
whether the cache is hit or not. This includes noncacheable accesses.
Write any value to clear.
Description
FIFO stream address
Table 171.
Bits Description Type Reset
STREAM_ADDR
Register
31:2 The address of the next word to be streamed from flash to the streaming RW 0x00000000
FIFO.
Increments automatically after each flash access.
Write the initial access address here before starting a streaming read.
1:0 Reserved. - -
Description
FIFO stream control
Table 172.
Bits Description Type Reset
STREAM_CTR Register
31:22 Reserved. - -
21:0 Write a nonzero value to start a streaming read. This will then RW 0x000000
progress in the background, using flash idle cycles to transfer
a linear data block from flash to the streaming FIFO.
Decrements automatically (1 at a time) as the stream
progresses, and halts on reaching 0.
Write 0 to halt an in-progress stream, and discard any in-flight
read, so that a new stream can immediately be started (after
draining the FIFO and reinitialising STREAM_ADDR)
Description
FIFO stream data
Table 173.
Bits Description Type Reset
STREAM_FIFO
Register
31:0 Streamed data is buffered here, for retrieval by the system DMA. RF 0x00000000
This FIFO can also be accessed via the XIP_AUX slave, to avoid exposing
the DMA to bus stalls caused by other XIP traffic.
• Power is applied to the chip and the RUN pin is high. (If RUN is low then the chip will be held in reset.)
• The On-Chip Voltage Regulator (Section 2.10) waits until the digital core supply (DVDD) is stable
• The Power-On State Machine (Section 2.13) is started. To summarise the sequence:
◦ The Ring Oscillator (Section 2.17) is started, providing a clock source to the clock generators. clk_sys and
clk_ref are now running at a relatively low frequency (typically 6.5MHz).
◦ The reset controller (Section 2.14), the execute-in-place hardware (Section 2.6.3), memories (Section 2.6.2
and Section 2.6.1), Bus Fabric (Section 2.1), and Processor Subsystem (Section 2.3) are taken out of reset.
◦ Processor core 0 and core 1 begin to execute the bootrom (Section 2.8).
2.8. Bootrom
The Bootrom size is limited to 16 kB. It contains:
The full source for the RP2040 bootrom can be found at https://github.com/raspberrypi/pico-bootrom.
This includes both version 1 and version 2 of the bootrom, which correspond to the B0 and B1 silicon
revisions, respectively.
After the hardware controlled boot sequence described in Section 2.7, the processor controlled boot sequence starts:
◦ The debug host (which initiated the rescue) will provide further instruction.
• If watchdog scratch registers set to indicate pre-loaded code exists in SRAM, jump to that code
• Check if SPI CS pin is tied low ("bootrom button"), and skip flash boot if so.
• Set up IO muxing, pad controls on QSPI pins, and initialise Synopsys SSI for standard SPI mode
• Issue XIP exit sequence, in case flash is still in an XIP mode and has not been power-cycled
• Copy 256 bytes from SPI to internal SRAM (SRAM5) and check for valid CRC32 checksum
• If checksum passes, assume what we have loaded is a valid flash second stage
• Start executing the loaded code from SRAM (SRAM5)
• If no valid image found in SPI after 0.5 seconds of attempting to boot, drop to USB device boot
• USB device boot: appear as a USB Mass Storage Device
◦ Can program the SPI flash, or load directly into SRAM and run, by dragging and dropping an image in UF2
format.
Watchdog boot allows users to install their own boot handler, and divert control away from the main boot sequence on
non-POR/BOR resets. It also simplifies running code over the JTAG test interface. It recognises the following values
written to the watchdog’s upper scratch registers:
One of the main challenges of a warm flash boot is forcing the external flash from XIP mode to a mode where it will
accept standard SPI commands. There is no standard method to discontinue XIP on an unknown flash. The Bootrom
provides a best-effort sequence with broad compatibility, which is as follows:
• CSn=1, IO[3:0]=4’b0000 (via pull downs to avoid contention), issue x32 clocks
• CSn=0, IO[3:0]=4’b1111 (via pull ups to avoid contention), issue x32 clocks
• CSn=1
• CSn=0, MOSI=1’b1 (driven low-Z, all other IOs Hi-Z), issue x16 clocks
This is designed to miss the XIP continuation codes on Cypress, Micron and Winbond parts. If the device is already in
SPI mode, it interprets this sequence as two FFh NOP instructions, which should be ignored.
As this is best effort only, there may be some devices which obstinately remain in XIP mode. There are then two
options:
• Use a less efficient XIP mode where each transfer has an SPI instruction prefix, so the flash device remains
communicative in SPI mode.
• Boot code installs a compatible XIP exit sequence in SRAM, and configures the watchdog such that a warm boot
will jump straight into this sequence, foregoing our canned sequence.
After issuing the XIP exit sequence, the Bootrom attempts to read in the second stage from flash using standard 03h
serial read commands, which are near-universally supported. Since the Bootrom is immutable, it aims for compatibility
rather than performance.
The flash second stage must configure the SSI and the external flash for the best possible execute-in-place
performance. This includes interface width, SCK frequency, SPI instruction prefix and an XIP continuation code for
address-data only modes. Generally some operation can be performed on the external flash so that it does not require
an instruction prefix on each access, and will simply respond to addresses with data.
Until the SSI is correctly configured for the attached flash device, it is not possible to access flash via the XIP address
window. Additionally, the Synopsys SSI can not be reconfigured at all without first disabling it. Therefore the second
stage must be copied from flash to SRAM by the bootrom, and executed in SRAM.
Alternatively, the second stage can simply shadow an image from external flash into SRAM, and not configure execute-
in-place.
This is the only job of the second stage. All other chip setup (e.g. PLLs, Voltage Regulator) can be performed by
platform initialisation code executed over the XIP interface, once the second stage has run.
2.8.1.3.1. Checksum
The last four bytes of the image loaded from flash (which we hope is a valid flash second stage) are a CRC32 checksum
of the first 252 bytes. The parameters of the checksum are:
• Polynomial: 0x04c11db7
• Input reflection: no
• Output reflection: no
• Initial value: 0xffffffff
• Final XOR: 0x00000000
• Checksum value appears as little-endian integer at end of image
The Bootrom makes 128 attempts of approximately 4ms each for a total of approximately 0.5 seconds before giving up
and dropping into USB code to load and checksum the second stage with varying SPI parameters. If it sees a checksum
pass it will immediately jump into the 252-byte payload which contains the flash second stage.
The Bootrom contains a number of public functions that provide useful RP2040 functionality that might be needed in
the absence of any other code on the device, as well as highly optimized versions of certain key functionality that would
otherwise have to take up space in most user binaries.
These functions are normally made available to the user by the SDK, however a lower level method is provided to locate
them (their locations may change with each Bootrom release) and call them directly.
Assuming the three bytes starting at address 0x00000010 are ('M', 'u', 0x01) then the three halfwords starting at offset
0x00000014 are valid.
These three values can be used to dynamically locate other functions or data within the Bootrom. The version byte at
offset 0x00000013 is informational and should not be used to infer the exact location of any functions.
The following code from the SDK shows how the three 16-bit pointers are used to lookup other functions or data.
The code parameter correspond to the CODE values in the tables below, and is calculated as follows:
In general you do not need to call these methods directly as the SDK pico_bit_ops library replaces the corresponding
standard compiler library functions by default so that the standard functions such as __builtin_popcount or __clzdi2 uses
the corresponding Bootrom implementations automatically (see pico_bit_ops for more details).
These functions have changed in speed slightly between version 1 (V1) of the bootrom and version 2 (V2)
Return the number of consecutive high order 0 bits of value. If value is zero, returns
32.
Return the number of consecutive low order 0 bits of value. If value is zero, returns
32.
These are highly optimized bulk memory fill and copy functions commonly provided by most language runtimes.
In general you do not need to call these methods directly as the SDK pico_mem_ops library replaces the corresponding
standard ARM EABI functions by default so that the standard C library functions e.g. memcpy or memset use the Bootrom
implementations automatically (see pico_mem_ops for more details).
Sets n bytes start at ptr to the value c and returns ptr. Note this is a slightly more efficient variant of
_memset that may only be used if ptr is word aligned.
Copies n bytes starting at src to dest and returns dest. The results are undefined if the regions overlap.
Copies n bytes starting at src to dest and returns dest. The results are undefined if the regions overlap.
Note this is a slightly more efficient variant of _memcpy that may only be used if dest and src are word
aligned.
Restore all QSPI pad controls to their default state, and connect the SSI to the QSPI pads
First set up the SSI for serial-mode operations, then issue the fixed XIP exit sequence described in
Section 2.8.1.2. Note that the bootrom code uses the IO forcing logic to drive the CS pin, which must be
cleared before returning the SSI to XIP mode (e.g. by a call to _flash_flush_cache). This function
configures the SSI with a fixed SCK clock divisor of /6.
'R','E' void _flash_range_erase(uint32_t addr, size_t count, uint32_t block_size, uint8_t block_cmd)
Erase a count bytes, starting at addr (offset from start of flash). Optionally, pass a block erase command
e.g. D8h block erase, and the size of the block erased by this command — this function will use the larger
block erase where possible, for much higher erase speed. addr must be aligned to a 4096-byte sector, and
count must be a multiple of 4096 bytes.
Program data to a range of flash addresses starting at addr (offset from the start of flash) and count bytes
in size. addr must be aligned to a 256-byte boundary, and count must be a multiple of 256.
Flush and enable the XIP cache. Also clears the IO forcing on QSPI CSn, so that the SSI can drive the
flash chip select as normal.
Configure the SSI to generate a standard 03h serial read command, with 24 address bits, upon each XIP
access. This is a very slow XIP configuration, but is very widely supported. The debugger calls this
function after performing a flash erase/programming operation, so that the freshly-programmed code
and data is visible to the debug host, without having to know exactly what kind of flash device is
connected.
A typical call sequence for erasing a flash sector from user code would be:
• _connect_internal_flash
• _flash_exit_xip
• _flash_range_erase(addr, 1 << 12, 1 << 16, 0xd8)
• _flash_flush_cache
• Either a call to _flash_enter_cmd_xip or call into a flash second stage that was previously copied out into SRAM
Note that, in between the first and last calls in this sequence, the SSI is not in a state where it can handle XIP accesses,
so the code that calls the intervening functions must be located in SRAM. The SDK hardware_flash library hides these
details.
These two methods simplify the task of calling code on the device and then returning control to the debugger.
'D','T' _debug_trampoline
This methods helps the debugger call ROM routines without setting hardware breakpoints. The function
address is passed in r7 and args are passed through r0 … r3 as per ABI.
This method does not return but executes a BKPT #0 at the end.
'D','E' _debug_trampoline_end
This is the address of the final BKPT #0 instruction of debug_trampoline. This can be compared with the
program counter to detect completion of the debug_trampoline call.
These remaining functions don’t fit in other categories and are exposed in the SDK via the pico_bootrom library (see
pico_bootrom).
Table 179.
CODE Description
Miscellaneous
Functions
'U','B' void _reset_to_usb_boot(uint32_t gpio_activity_pin_mask, uint32_t disable_interface_mask)
Resets the RP2040 and uses the watchdog facility to re-start in BOOTSEL mode:
• gpio_activity_pin_mask is provided to enable an "activity light" via GPIO attached LED for the USB
Mass Storage Device:
This is the method that is entered by core 1 on reset to wait to be launched by core 0. There are few
cases where you should call this method (resetting core 1 is much better). This method does not return
and should only ever be called on core 1.
'E','C' deprecated
The Bootrom contains an optimized single-precision floating point implementation. The function pointers for these are
kept in a single structure found via the rom_data_lookup table (see Section 2.8.2.3).
There is always a trade-off between speed and size. Whilst the overall goal for the floating-point routines is to achieve
good performance within a small footprint, the emphasis is more on improved performance for the basic operations
(add, subtract, multiply, divide and square root) and more on reduced footprint for the scientific functions (trigonometric
functions, logarithms and exponentials).
The IEEE single- and double-precision data formats are used throughout, but in the interests of reducing code size, input
denormals are treated as zero, input NaNs are treated as infinities, output denormals are flushed to zero, and output
NaNs are rendered as infinities. Only the round-to-nearest, even-on-tie rounding mode is supported. Traps are not
supported.
The five basic operations return results that are always correctly rounded.
The scientific functions always return results within 1 ULP (unit in last place) of the exact result. In many cases results
are better.
The scientific functions are calculated using internal fixed-point representations so accuracy (as measured in ULP error
rather than in absolute terms) is poorer in situations where converting the result back to floating point entails a large
normalising shift. This occurs, for example, when calculating the sine of a value near a multiple of pi, the cosine of a
value near an odd multiple of pi/2, or the logarithm of a value near 1. Accuracy of the tangent function is also poorer
when the result is very large. Although covering these cases is possible, it would add considerably to the code footprint,
and there are few types of program where accuracy in these situations is essential.
The sine, cosine and tangent functions also only operate correctly over a limited range: -128 < x < +128 for single-
precision arguments x and -1024 < x < +1024 for double-precision x. This is to avoid the need to (at least in effect) store
the value of pi to high precision within the code, and hence saves code space. Accurate range reduction over a wider
range of arguments can be done externally to the library if required, but again there are few situations where this would
be needed.
NOTE
The SDK cos/sin functions perform this range reduction, so accept the full range of arguments, though are slower
for inputs outside of these ranges.
2.8.2.2.2. Functions
These functions follow the standard ARM EABI for passing floating point values.
You do not need to call these methods directly as the SDK pico_float and pico_double libraries used by default replace
the ARM EABI Float functions such that C/C++ level code (or indirectly code in languages such as MicroPython that are
implemented in C) use these Bootrom functions automatically for the corresponding floating point operations.
Some of these functions do not behave exactly the same as some of the corresponding C library functions. For that
reason if you are using the SDK it is strongly advised that you simply use the regular math.h functions or those in
pico/float.h or pico/double.h and not try to call into the bootrom directly.
Note that double-precision floating point support is not present in version 1 of the bootrom, but the above mentioned
pico_double library in the SDK will take care of pulling in any extra code needed for version 1.
NOTE
for more information on using floating point in the SDK, and real world timings (noting also that some conversion
functions are re-implemented in the SDK to be faster) see floating point support.
Return a / b
Convert a float to a signed integer, rounding towards -Infinity, and clamping the
result to lie within the range -0x80000000 to 0x7FFFFFFF
Convert a float to a signed fixed point integer representation where n specifies the
position of the binary point in the resulting fixed point representation - e.g.
_float2fix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and clamps
the resulting integer to lie within the range -0x80000000 to 0x7FFFFFFF
Convert a signed integer to the nearest float value, rounding to even on tie
Convert a signed fixed point integer representation to the nearest float value,
rounding to even on tie. n specifies the position of the binary point in fixed point,
so
Convert an unsigned integer to the nearest float value, rounding to even on tie
Convert an unsigned fixed point integer representation to the nearest float value,
rounding to even on tie. n specifies the position of the binary point in fixed point,
so
Return the cosine of angle. angle is in radians, and must be in the range -128 to
128
Return the sine of angle. angle is in radians, and must be in the range -128 to 128
Return the tangent of angle. angle is in radians, and must be in the range -128 to
128
• 0 if a == b
• -1 if a < b
• 1 if a > b
0x58 N/A 667 float _fatan2(float y, float x)
Computes the arc tangent of y/x using the signs of arguments to determine the
correct quadrant
Convert a signed 64-bit integer to the nearest float value, rounding to even on tie
Convert a signed fixed point 64-bit integer representation to the nearest float
value, rounding to even on tie. n specifies the position of the binary point in fixed
point, so
Convert an unsigned 64-bit integer to the nearest float value, rounding to even on
tie
Convert an unsigned fixed point 64-bit integer representation to the nearest float
value, rounding to even on tie. n specifies the position of the binary point in fixed
point, so
Convert a float to a signed 64-bit integer, rounding towards -Infinity, and clamping
the result to lie within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF
Note that the V2 bootrom contains an equivalent table of functions for double-precision floating point operations. The
offsets are the same, however where there was now float there is double (and vice versa for the float<>double
conversion)
Convert a double to a signed integer, rounding towards -Infinity, and clamping the result to
lie within the range -0x80000000 to 0x7FFFFFFF
Convert a double to a signed fixed point integer representation where n specifies the
position of the binary point in the resulting fixed point representation - e.g. _double2fix(0.5f,
16) == 0x8000. This method rounds towards -Infinity, and clamps the resulting integer to lie
within the range -0x80000000 to 0x7FFFFFFF
Convert a double to an unsigned integer, rounding towards -Infinity, and clamping the result
to lie within the range 0x00000000 to 0xFFFFFFFF
Convert a double to an unsigned fixed point integer representation where n specifies the
position of the binary point in the resulting fixed point representation, e.g. _double2ufix(0.5f,
16) == 0x8000. This method rounds towards -Infinity, and clamps the resulting integer to lie
within the range 0x00000000 to 0xFFFFFFFF
Convert a signed integer to the nearest double value, rounding to even on tie
Convert a signed fixed point integer representation to the nearest double value, rounding to
even on tie. n specifies the position of the binary point in fixed point, so
Convert an unsigned integer to the nearest double value, rounding to even on tie
Convert an unsigned fixed point integer representation to the nearest double value,
rounding to even on tie. n specifies the position of the binary point in fixed point, so
Return the cosine of angle. angle is in radians, and must be in the range -1024 to 1024
Return the sine of angle. angle is in radians, and must be in the range -1024 to 1024
Return the tangent of angle. angle is in radians, and must be in the range -1024 to 1024
• 0 if a == b
• -1 if a < b
• 1 if a > b
0x58 2168 double _datan2(double y, double x)
Computes the arc tangent of y/x using the signs of arguments to determine the correct
quadrant
Convert a signed 64-bit integer to the nearest double value, rounding to even on tie
Convert a signed fixed point 64-bit integer representation to the nearest double value,
rounding to even on tie. n specifies the position of the binary point in fixed point, so
Convert an unsigned 64-bit integer to the nearest double value, rounding to even on tie
Convert an unsigned fixed point 64-bit integer representation to the nearest double value,
rounding to even on tie. n specifies the position of the binary point in fixed point, so
0x6c 64 _double2int64
Convert a double to a signed 64-bit integer, rounding towards -Infinity, and clamping the
result to lie within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF
0x70 63 _double2fix64
Convert a double to a signed fixed point 64-bit integer representation where n specifies the
position of the binary point in the resulting fixed point representation - e.g. _double2fix(0.5f,
16) == 0x8000. This method rounds towards -Infinity, and clamps the resulting integer to lie
within the range -0x8000000000000000 to 0x7FFFFFFFFFFFFFFF
0x74 53 _double2uint64
Convert a double to an unsigned 64-bit integer, rounding towards -Infinity, and clamping the
result to lie within the range 0x0000000000000000 to 0xFFFFFFFFFFFFFFFF
0x78 52 _double2ufix64
Convert a double to an unsigned fixed point 64-bit integer representation where n specifies
the position of the binary point in the resulting fixed point representation, e.g.
_double2ufix(0.5f, 16) == 0x8000. This method rounds towards -Infinity, and clamps the
resulting integer to lie within the range 0x0000000000000000 to 0xFFFFFFFFFFFFFFFF
'F','S' fplib_start
The start address of the floating point library code and data. This and fplib_end along with the individual
function pointers in soft_float_table can be used to copy the floating point implementation into RAM if
desired.
'S','F' soft_float_table
'F','E' fplib_end
The end address of the floating point library code and data.
'S','D' soft_double_table
This entry is only present in the V2 bootrom. See Table 181 for the contents of this table.
'P','8' deprecated. This entry is not present in the V2 bootrom; do not use it.
'R','8' deprecated. This entry is not present in the V2 bootrom; do not use it.
'L','8' deprecated. This entry is not present in the V2 bootrom; do not use it.
'T','8' deprecated. This entry is not present in the V2 bootrom; do not use it.
A UF2 file copied to the drive is downloaded and written to Flash or RAM, and the device is automatically rebooted,
making it trivial to download and run code on the RP2040 using only a USB connection.
The RP2040 appears as a standard 128MB flash drive named RPI-RP2 formatted as a single partition with FAT16. There
are only ever two actual files visible on the drive specified.
When a UF2 file is written to the device however, the special contents are recognized and data is written to specified
locations in RAM or Flash. On the completed download of an entire valid UF2 file, the RP2040 automatically reboots to
run the newly downloaded code.
NOTE
There are requirements on a UF2 file to be valid to download to the RP2040. It is important that you always use valid
UF2 files (as for example generated by https://github.com/raspberrypi/pico-sdk/tree/master/tools/elf2uf2/main.cpp),
as invalid files may be partially written and then silently fail. Note that on some operating systems you may receive a
disk write error on failure, but this is not guaranteed.
• All data destined for the device must be in a UF2 block with familyID present and set to 0xe48bff56, and a payload_size
of 256.
• All data must be destined for (and fit entirely within) the following memory ranges (depending on the type of binary
being downloaded which is determined by the address of the first UF2 block encountered):
▪ 0x10000000-0x11000000 Flash: All blocks must be targeted at 256 byte alignments. Writes beyond the end of
physical flash will wrap back to the beginning of flash.
▪ 0x15000000-0x15004000 Flash Cache: (since flash is not being targeted, the Flash Cache is available for use
as RAM with same properties as Main RAM).
Note that traditionally UF2 has only been used to write to Flash, but this is more a limitation of using the metadata
free .BIN file as the source to generate the UF2 file. RP2040 takes full advantage of the inherent flexibility of UF2 to
support the full range of binaries in the richer .ELF format produced by the build to be used as the source for the
UF2 file.
• The numBlocks must specify a total size of the binary that fits in the regions specified above
• A change of numBlocks or the binary type (determined by UF2 block target address) will discard the current transfer
in progress.
• All data must be in blocks without the UF2_FLAG_NOT_MAIN_FLASH marking which relates to content to be ignored rather
than Flash vs RAM.
Note that flash is erased a 4K sector at a time, so writing to only a subset of a 4K flash sector will leave the rest of that
flash sector undefined. Beyond that there is no requirement that a binary be contiguous.
Note that a binary is considered "downloaded" when each of the numBlocks blocks has been seen at least once in the
course of a single valid transfer. The data for a block is only written the first time in case of the host resending duplicate
blocks.
Note that after downloading a regular flash binary, a reset is performed after which the flash binary second stage (at
address 0x10000000 - the start of flash) will be entered (if valid) via the bootrom.
A downloaded RAM Only binary is entered by watchdog reset into the start of the binary, which is calculated as the
lowest address of a downloaded block (with Main RAM considered lower than Flash Cache if both are present).
Finally it is possible for host software to temporarily disable UF2 writes via the PICOBOOT interface to prevent
interference with operations being performed via that interface (see below), in which case any UF2 file write in progress
will be aborted.
It provides for flexible reading from and writing to RAM or Flash, rebooting, executing code on the device and a handful
of other management functions.
Constants and structures related to the interface can be found in the SDK header https://github.com/raspberrypi/pico-
sdk/tree/master/src/common/boot_picoboot/include/boot/picoboot.h
A RP2040 device is recognized by the Vendor ID and Product ID in its device descriptor (shown in Table 183).
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x2e8a
idProduct 0x0003
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
The PICOBOOT interface is recognized by the "Vendor Specific" Interface Class and the zero Interface Sub Class and
Interface Protocol (shown in Table 184). Note that you should not rely on the interface number, as that is dependent on
whether the device is also exposing the Mass Storage Interface. Note also that the device equally may not be exposing
the PICOBOOT interface at all, so you should not assume it is present.
bLength 9
bDescriptorType 4
bInterfaceNumber varies
bAlternateSetting 0
bNumEndpoints 2
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
The PICOBOOT interface provides a single BULK OUT and a single BULK IN endpoint. These can be identified by their
direction and type. You should not rely on endpoint numbers.
The two bulk endpoints are used for sending commands and retrieved successful command results. All commands are
exactly 32 bytes (see Table 185) and sent to the BULK OUT endpoint.
0x08 bCmdId The ID of the command. Note that the top bit indicates data transfer direction
(0x80 = IN)
0x0c dTransferLength The number of bytes the host expects to send or receive over the bulk channel
If a command sent is invalid or not recognized, the bulk endpoints will be stalled. Further information will be available
via the GET_COMMAND_STATUS request (see Section 2.8.4.5.2).
Following the initial 32 byte packet, if dTranferLength is non-zero, then that many bytes are transferred over the bulk
pipe and the command is completed with an empty packet in the opposite direction. If dTransferLength is zero then
command success is indicated by an empty IN packet.
The following commands are supported (note common fields dMagic, dToken, reserved are omitted for clarity)
Claim or release exclusive access for writing to the RP2040 over USB (versus the Mass Storage Interface)
EXCLUSIVE (1) Disable USB Mass Storage writes (the host should
see them as write protect failures, but in any case
any active UF2 download will be aborted)
Reboots the RP2040 out of BOOTSEL mode. Note that BOOTSEL mode might be re-entered if rebooting to flash and no
valid second stage bootloader is found.
0x10 dPC The address to start executing from. Valid values are:
0x14 dSP Initial stack pointer post reboot (only used if booting into
RAM)
0x10 dAddr The address in flash to erase, starting at this location. This must be sector
(4K) aligned
0x14 dSize The number of bytes to erase. This must an exact multiple number of sectors
(4K)
Read a contiguous memory (Flash or RAM or ROM) range from the RP2040
0x10 dAddr The address to read from. May be in Flash or RAM or ROM
0x10 dAddr The address to write from. May be in Flash or RAM, however must be page
(256 byte) aligned if in Flash. Note the flash must be erased first or the results
are undefined.
0x14 dSize The number of bytes to write. If writing to flash and the size is not an exact
multiple of pages (256 bytes) then the last page is zero-filled to the end.
Exit Flash XIP mode. This first initialises the SSI for serial transfers, and then issues the XIP exit sequence given in
Section 2.8.1.2, to attempt to make the flash responsive to standard serial SPI commands. The SSI is configured with a
fixed clock divisor of /6, so the USB bootloader will drive SCLK at 8 MHz.
Enter Flash XIP mode. This configures the SSI to issue a standard 03h serial read command, with 24 address clocks and
32 data clocks, for every XIP access. This is a slow but very widely supported way to read flash. The intent of this
function is to make flash easily accessible (i.e. just access addresses in the 0x10…… segment) without having to know
the details of exactly what kind of flash is connected. This mode is suitable for executing code from flash, but is much
slower than e.g. QSPI XIP access.
Executes a function on the device. This function takes no arguments and returns no results, so it must communicate via
RAM. Execution of this method will block any other commands as well as Mass Storage Interface UF2 writes, so should
only be used in exclusive mode and with extreme care (and it should save and restore registers as per the ARM EABI).
This method is called from a regular (non IRQ) context, and has a very limited stack, so the function should use its own.
0x10 dAddr Function address to execute at (a thumb bit will be added for you since you
will have forgotten).
Requests that that the vector table of flash access functions used internally by the Mass Storage and PICOBOOT
interfaces be copied into RAM, such that the method implementations can be replaced with custom versions (For
example, if the board uses flash that does not support standard commands)
struct {
uint32_t size; // 28
uint32_t (*do_flash_enter_cmd_xip)();
uint32_t (*do_flash_exit_xip)();
uint32_t (*do_flash_erase_sector)();
uint32_t (*do_flash_erase_range)(uint32_t addr, uint32_t size);
uint32_t (*do_flash_page_program)(uint32_t addr, uint8_t *data);
uint32_t (*do_flash_page_read)(uint32_t addr, uint8_t *data);
};
These methods have the same signature and arguments as the corresponding flash access functions in the bootrom
(see Section 2.8.2.1.3).
Note that the host must subsequently update the RAM copy of this table via an EXEC command running on the RP2040
as any write to RAM from the host via a PICOBOOT WRITE that overlaps this (now active in RAM) vector table will cause a
reset to the use of the default ROM Flash function vector table.
The following requests are sent to the interface via the default control pipe.
The host sends this control request to reset the PICOBOOT interface. This command:
• Clears the HALT condition (if set) on each of the bulk endpoints
• Aborts any in-process PICOBOOT or Mass Storage transfer and any flash write (this method is the only way to kill a
stuck flash transfer).
Retrieve the status of the last command (which may be a command still in progress). Successful completion of a
PICOBOOT Protocol Command is acknowledged over the bulk pipe, however if the operation is still in progress or has
failed (stalling the bulk pipe), then this method can be used to determine the operation’s status.
INVALID_ADDRESS (4) The address specified was invalid for the command type;
i.e. did not match the type Flash/RAM that the command
was expecting
BAD_ALIGNMENT (5) The address specified was not correctly aligned according
to the requirements of the command
INTERLEAVED_WRITE (6) A Mass Storage Interface UF2 write has interfered with the
current operation. The command was abandoned with
unknown status. Note this will not happen if you have
exclusive access.
The power supplies and a number of potential power supply schemes are described in the following sections. Detailed
power supply parameters are provided in Section 5.3, “Power Supplies”.
IOVDD should be decoupled with a 100nF capacitor close to each of the chip’s IOVDD pins.
CAUTION
If the digital IO is powered at a nominal 1.8V, the IO input thresholds should be adjusted via the VOLTAGE_SELECT
register. By default, the IO input thresholds are valid when the digital IO is powered at a nominal voltage between
2.5V and 3.3V. See Section 2.19, “GPIO” for details. Powering the IO at 1.8V with input thresholds set for a 2.5V to
3.3V supply is a safe operating mode, but will result in input thresholds that do not meet specification. Powering the
IO at voltages greater than a nominal 1.8V with input thresholds set for a 1.8V supply may result in damage to the
chip.
DVDD should be decoupled with a 100nF capacitor close to each of the chip’s DVDD pins.
A 1μF capacitor should be connected between VREG_VIN and ground close to the chip’s VREG_VIN pin.
CAUTION
VREG_VIN also powers the chip’s power-on reset and brown-out detection blocks, so it must be powered even if the
on-chip voltage regulator is not used.
For more details on the on-chip voltage regulator see Section 2.10, “Core Supply Regulator”.
USB_VDD should be decoupled with a 100nF capacitor close to the chip’s USB_VDD pin.
NOTE
It is safe to supply ADC_AVDD at a higher or lower voltage than IOVDD, e.g. to power the ADC at 3.3V, for optimum
performance, while supporting 1.8V signal levels on the digital IO. But the voltage on the ADC analogue inputs must
not exceed IOVDD, e.g. if IOVDD is powered at 1.8V, the voltage on the ADC inputs should be limited to 1.8V.
Voltages greater than IOVDD will result in leakage currents through the ESD protection diodes. See Section 5.2.3,
“Pin Specifications” for details.
ADC_AVDD should be decoupled with a 100nF capacitor close to the chip’s ADC_AVDD pin.
In most applications, RP2040 will be powered from a single 3.3V supply, as shown in Figure 16. The digital IO (IOVDD),
USB PHY (USB_VDD) and ADC (ADC_AVDD) will be powered directly from the 3.3V supply, and the 1.1V digital core
supply (DVDD) will be regulated from the 3.3V supply by the on-chip voltage regulator. Note that the regulator output pin
(VREG_VOUT) must be connected to the chip’s DVDD pins off-chip.
For more details on the on-chip voltage regulator see Section 2.10, “Core Supply Regulator”.
The digital core (DVDD) can be powered directly from an external 1.1V supply, rather than from the on-chip regulator, as
shown in Figure 17. This approach may make sense if a suitable external regulator is available elsewhere in the system,
or for low power applications where an efficient switched-mode regulator could be used instead of the less efficient
linear on-chip voltage regulator.
If an external core supply is used, the output of on-chip voltage regulator (VREG_VOUT) should be left unconnected.
However, power must still be provided to the regulator input (VREG_VIN) to supply the chip’s power-on reset and brown-
out detection blocks. The on-chip voltage regulator will power-on as soon as VREG_VIN is available, but can be
shutdown under software control once the chip is out of reset. See Section 2.10, “Core Supply Regulator” for details.
Applications with digital IO signal levels less than 3.3V will require a separate 3.3V supply for the USB PHY and ADC, as
the USB PHY does not meet specification at voltages below 3.135V and ADC performance is compromised at voltages
below 2.97V. Figure 18 shows an example application with the digital IO (IOVDD) powered at 1.8V and a separate 3.3V
supply for the USB PHY (USB_VDD) and ADC (ADC_AVDD). In this example, the voltage regulator input (VREG_VIN) is
connected to the 1.8V supply, though it could equally have been connected to the 3.3V supply. Connecting it to the 1.8V
supply will reduce overall power consumption if the 1.8V supply is generated by an efficient switched-mode regulator.
If a functional USB PHY and optimum ADC performance are not required, RP2040 can be powered from a single supply
of less than 3.3V. Figure 19 shows an example with a single 1.8V supply. In this example, the core supply (DVDD) is
regulated from the 1.8V supply by the on-chip voltage regulator.
with the chip’s digital IO supply IOVDD, simplifying the overall power supply requirements.
To allow the chip to start up, the voltage regulator is enabled by default and will power-on as soon as its input supply is
available. Once the chip is out of reset, the regulator can be disabled, placed into a high impedance state, or have its
output voltage adjusted, under software control. The output voltage can be set in the range 0.80V to 1.30V in 50mV
steps, but is set to a nominal 1.1V at initial power-on, or after a reset event. The voltage regulator can supply up to
100mA.
Although intended to provide the chip’s digital core supply (DVDD), the voltage regulator can be used for other purposes
if DVDD is powered directly from an external power supply.
The regulator must have 1μF capacitors placed close to its input (VREG_VIN) and output (VREG_VOUT) pins.
Normal Operationa 1 0
High Impedance 1 1
Shutdown 0 X
a
the voltage regulator will be in normal mode at initial power-on or following a reset event
In Normal Operation mode, the voltage regulator’s output is in regulation at the selected voltage, and the regulator is
able to supply power.
In High Impedance mode, the voltage regulator is disabled and its output pin (VREG_VOUT) is set to a high impedance
state. In this mode, the regulator’s power consumption is minimised. This mode allows a load connected to
VREG_VOUT to be powered from a power source other than the on-chip regulator. This could allow, for example, the
load to be initially powered from the on-chip voltage regulator, and then switched to an external regulator under
software control. The external regulator would also need to support a high impedance mode, with only one regulator
supplying the load at a time. The supply voltage is maintained by the regulator’s output capacitor during the brief period
when both regulators are in high impedance mode.
In Shutdown mode, the voltage regulator is disabled, power consumption is minimized and the regulator’s output pin
(VREG_VOUT) is pulled to 0V.
Shutdown mode is only useful if the voltage regulator is not providing the RP2040’s digital core supply (DVDD). If the
regulator is supplying DVDD, and brown-out detection is enabled, entering shutdown mode will cause a reset event and
the voltage regulator will return to normal mode. If brown-out detection isn’t enabled, the voltage regulator will shut
down and will remain in shutdown mode until its input supply (VREG_VIN) is power cycled.
Note that RP2040 may not operate reliably with its digital core supply (DVDD) at a voltage other than 1.1V.
2.10.4. Status
The VREG register contains a single status field, ROK, which indicates whether the voltage regulator’s output is being
correctly regulated.
At power on, ROK remains low until the regulator has started up and the output voltage reaches the ROK assertion
threshold (ROKTH.ASSERT). It then remains high until the voltage drops below the ROK deassertion threshold (ROKTH.DEASSERT),
remaining low until the output voltage is above the assertion threshold again. ROKTH.ASSERT is nominally 90% of the selected
output voltage, 0.99V if the selected output voltage is 1.1V, and ROKTH.DEASSERT is nominally 87% of the selected output
voltage, 0.957V if the selected output voltage is 1.1V.
Note that adjusting the output voltage to a higher voltage will cause ROK to go low until the assertion threshold for the
higher voltage is reached. ROK will also go low if the regulator is placed in high impedance mode.
in SDK).
Description
Voltage regulator control and status
31:13 Reserved. - - -
11:8 Reserved. - - -
3:2 Reserved. - - -
0 EN enable RW 0x1
0=not enabled, 1=enabled
Description
brown-out detection control
31:8 Reserved. - - -
3:1 Reserved. - - -
0 EN enable RW 0x1
0=not enabled, 1=enabled
Description
Chip reset control and status
Table 202.
Bits Name Description Type Reset
CHIP_RESET Register
31:25 Reserved. - - -
23:21 Reserved. - - -
19:17 Reserved. - - -
15:9 Reserved. - - -
8 HAD_POR Last reset was from the power-on reset or brown-out RO 0x0
detection blocks
7:0 Reserved. - - -
a
values will vary with load current and capacitance on VREG_VOUT. Conditions: EN = 1, load current = 0mA, VREG_VIN
ramps up in 100μs
Enabling and disabling a clock gate is glitch-free. If a peripheral clock is temporarily disabled, and subsequently re-
enabled, the peripheral will be in the same state as prior to the clock being disabled. No reset or reinitialisation should
be required.
Clock gates are controlled by two sets of registers: the WAKE_ENx registers (starting at WAKE_EN0) and SLEEP_ENx
registers (starting at SLEEP_EN0). These two sets of registers are identical at the bit level, each possessing a flag to
control each clock endpoint. The WAKE_EN registers specify which clocks are enabled whilst the system is awake, and
the SLEEP_ENx registers select which clocks are enabled while the processor is in the SLEEP state (Section 2.11.2).
The two Cortex-M0+ processors do not have externally-controllable clock gates. Instead, the processors gate the clocks
of their subsystems autonomously, based on execution of WFI/WFE instructions, and external Event and IRQ signals.
When in the SLEEP state, the top-level clock gates are masked by the SLEEP_ENx registers (starting at SLEEP_EN0),
rather than the WAKE_ENx registers. This permits more aggressive pruning of the clock tree when the processors are
asleep.
NOTE
Though it is possible for a clock to be enabled during SLEEP and disabled outside of SLEEP, this is generally not
useful
For example, if the system is sleeping until a character interrupt from a UART, the entire system except for the UART
can be clock-gated (SLEEP_ENx = all-zeroes except for CLK_SYS_UART0 and CLK_PERI_UART0). This includes system
infrastructure such as the bus fabric.
When the UART asserts its interrupt, and wakes a processor, RP2040 leaves SLEEP mode, and switches back to the
WAKE_ENx clock mask. At the minimum this should include the bus fabric, and the memory devices containing the
processor’s stack and interrupt vectors.
A system-level clock request handshake holds the processors off the bus until the clocks are re-enabled.
Note that, if relying on the RTC (Section 4.8) to wake from the DORMANT state, the RTC must have some external clock
source. The RTC accepts clock frequencies as low as 1 Hz.
Note also that DORMANT does not halt PLLs. To avoid unnecessary power dissipation, software should power down
PLLs before entering the DORMANT state, and power up and reconfigure the PLLs again after exiting.
The DORMANT state is entered by writing a keyword to the DORMANT register in whichever oscillator is active: ring
oscillator (Section 2.17) or crystal oscillator (Section 2.16). If both are active then the one providing the processor clock
must be stopped last because it will stop software from executing.
CAUTION
Memories must not be accessed when powered down. Doing so can corrupt memory contents.
When powering a memory back up, a 20 ns delay is required before accessing the memory again.
The XIP cache (see Section 2.6.3) can also be powered down, with CTRL.POWER_DOWN. The XIP hardware will not
generate cache accesses whilst the cache is powered down. Note that this is unlikely to produce a net power savings if
code continues to execute from XIP, due to the comparatively high voltages and switching capacitances of the external
QSPI bus.
2.11.5.1. Sleep
It is necessary to enable deep sleep on both proc0 and proc1 and call __wfi, as well as ensure the DMA is stopped to
enter sleep mode.
hello_sleep makes use of functions in pico_sleep of the Pico Extras. In particular, sleep_goto_sleep_until puts the
processor to sleep until woken up by an RTC time assumed to be in the future.
2.11.5.2. Dormant
• Put the XOSC into dormant mode which stops all processor execution (and all other clocked logic on the chip)
immediately
• When GPIO 10 goes high, the XOSC is started again and execution of the program continues
hello_dormant uses sleep_goto_dormant_until_pin under the hood:
2.12.1. Overview
The chip-level reset subsystem resets the whole chip, placing it in a default state. This happens at initial power-on,
during a power supply brown-out event or when the chip’s RUN pin is taken low. The chip can also be reset via the
Rescue Debug Port. See Section 2.3.4.2, “Rescue DP” for details.
The subsystem has two reset outputs. rst_n_psm, which resets the whole chip, except the debug port, and rst_n_dp, which
only resets the Rescue DP. Both resets are held low at initial power-on, during a brown-out event or when RUN is low.
rst_n_psm can additionally be held low by the Rescue DP via the subsystem’s psm_restart input. This allows the chip to be
reset via the Rescue DP without resetting the Rescue DP itself. The subsystem releases chip level reset by taking
rst_n_psm high, handing control to the Power-on State Machine, which continues to start up the chip. See Section 2.13,
“Power-On State Machine” for details.
The chip level reset subsystem is shown in Figure 21, and more information is available in the following sections.
DVDDTH.POR is fixed at a nominal 0.957V, which should result in a threshold between 0.924V and 0.99V. The threshold
assumes a nominal DVDD of 1.1V at initial power-on, and por_n may never go high if a lower voltage is used. Once the
chip is out of reset, DVDD can be reduced without por_n going low, as long as brown-out detection has been disabled or
a suitable threshold voltage has been set.
DVDD
tPOR.ASSERT
por_n
tPOR.ASSERT
por_n
tBOD.ASSERT
bod_n
Brown-out detection is automatically enabled at initial power-on or after a brown-out initiated reset. There is, however, a
short delay, the brown-out detection activation delay (tBOD.ACTIVE), between por_n going high and detection becoming active.
This is shown in Figure 24.
por_n
tBOD.ASSERT
bod_n
tBOD.ACTIVE tBOD.ACTIVE
Once the chip is out of reset, detection can be disabled under software control. This also saves a small amount of
power. If detection is subsequently re-enabled, there will be another short delay, the brown-out detection enable delay
(tBOD.ENABLE), before it becomes active again. This is shown in Figure 25.
Detection is disabled by writing a zero to the EN field in the BOD register and is re-enabled by writing a one to the same
field. The block’s bod_n output is high when detection is disabled.
tBOD.ENABLE
Detection is re-enabled if the BOD register is reset, as this sets the register’s EN field to one. Again, detection will become
active after a delay equal to the brown-out detection enable delay (tBOD.ENABLE).
NOTE
If the BOD register is reset by a power-on or brown-out initiated reset, the delay between the register being reset and
brown-out detection becoming active will be equal to the brown-out detection activation delay (tBOD.ACTIVE). The delay
will be equal to the brown-out detection enable delay (tBOD.ENABLE) for all other reset sources.
The brown-out detection threshold (DVDDTH.BOD) has a nominal value of 0.86V at initial power-on or after a reset event.
This should result in a detection threshold between 0.83V and 0.89V. Once out of reset, the threshold can be adjusted
under software control. The new detection threshold will take effect after the brown-out detection programming delay
((tBOD.PROG). An example of this is shown in Figure 26.
The threshold is adjusted by writing to the VSEL field in the BOD register. See the BOD register description for details.
tBOD.PROG
threshold threshold
0.86V 0.774V
tBOD.ACTIVE brown-out 55 80 μs
detection
activation delay
tBOD.ASSERT brown-out 3 10 μs
detection
assertion delay
tBOD.ENABLE brown-out 35 55 μs
detection enable
delay
tBOD.PROG brown-out 20 30 μs
detection
programming
delay
and a one in the HAD_PSM_RESTART field indicates the chip has been reset via Rescue Debug Port. There should never be
more than one field set to one.
2.13.1. Overview
The power-on state machine removes the reset from various hardware blocks in a specific order. Each peripheral in the
power-on state machine is controlled by an internal rst_n active-low reset signal and generates an internal rst_done
active-high reset done signal. The power-on state machine deasserts the reset to each peripheral, waits for that
peripheral to assert its rst_done and then deasserts the reset to the next peripheral. An important use of this is to wait
for a clock source to be running cleanly in the chip before the reset to the clock generators is deasserted. This avoids
potentially glitchy clocks being distributed to the chip.
The power-on state machine is itself taken out of reset when the Chip-Level Reset subsystem confirms that the digital
core supply (DVDD) is powered and stable, and the RUN pin is high. The power-on state machine takes a number of other
blocks out of reset at this point via its rst_n_run output. This is used to reset things that need to be reset at start-up but
must not be reset if the power-on state machine is restarted. This list includes:
Processor Complex
• Chip-Level Reset subsystem deasserts power-on state machine reset once digital core supply (DVDD) is powered
and stable, and RUN pin is high (rst_n_run is also deasserted at this point)
• Ring Oscillator is started. rst_done is asserted once the ripple counter has seen a sufficient number of clock edges
to indicate the ring oscillator is stable
• Crystal Oscillator reset is deasserted. The crystal oscillator is not started at this point, so rst_done is asserted
instantly.
• clk_ref and clk_sys clock generators are taken out of reset. In the initial configuration clk_ref is running from the
ring oscillator with no divider. clk_sys is running from clk_ref. These clocks are needed for the rest of the sequence
to progress.
The rest of the sequence is fairly simple, with the following coming out of reset in order one by one:
• XIP (Execute-In-Place) - used by the bootrom to execute code from an external SPI flash
• ROM and SRAM - Boot code is executed from the ROM. SRAM is used by processors and Bus Fabric.
• Bus Fabric - Allows the processors to communicate with peripherals
• Processor complex - Finally the processors can start running
The final thing to come out of reset is the processor complex. This includes both core0 and core1. Both cores will start
executing the bootcode from ROM. One of the first things the bootrom does is read the core id. At this point, core1 will
go to sleep leaving core0 to continue with the bootrom execution. The processor complex has its own reset control and
various low-power modes which is why both the core0 and core1 resets are deasserted, despite only core0 being needed
for the bootrom.
0x8 WDSEL Set to 1 if this peripheral should be reset when the watchdog
fires.
Description
Force block out of reset (i.e. power it on)
31:17 Reserved. - - -
16 PROC1 RW 0x0
15 PROC0 RW 0x0
14 SIO RW 0x0
13 VREG_AND_CHIP_RESET RW 0x0
12 XIP RW 0x0
11 SRAM5 RW 0x0
10 SRAM4 RW 0x0
9 SRAM3 RW 0x0
8 SRAM2 RW 0x0
7 SRAM1 RW 0x0
6 SRAM0 RW 0x0
5 ROM RW 0x0
4 BUSFABRIC RW 0x0
3 RESETS RW 0x0
2 CLOCKS RW 0x0
1 XOSC RW 0x0
0 ROSC RW 0x0
Description
Force into reset (i.e. power it off)
31:17 Reserved. - - -
16 PROC1 RW 0x0
15 PROC0 RW 0x0
14 SIO RW 0x0
13 VREG_AND_CHIP_RESET RW 0x0
12 XIP RW 0x0
11 SRAM5 RW 0x0
10 SRAM4 RW 0x0
9 SRAM3 RW 0x0
8 SRAM2 RW 0x0
7 SRAM1 RW 0x0
6 SRAM0 RW 0x0
5 ROM RW 0x0
4 BUSFABRIC RW 0x0
3 RESETS RW 0x0
2 CLOCKS RW 0x0
1 XOSC RW 0x0
0 ROSC RW 0x0
Description
Set to 1 if this peripheral should be reset when the watchdog fires.
31:17 Reserved. - - -
16 PROC1 RW 0x0
15 PROC0 RW 0x0
14 SIO RW 0x0
13 VREG_AND_CHIP_RESET RW 0x0
12 XIP RW 0x0
11 SRAM5 RW 0x0
10 SRAM4 RW 0x0
9 SRAM3 RW 0x0
8 SRAM2 RW 0x0
7 SRAM1 RW 0x0
6 SRAM0 RW 0x0
5 ROM RW 0x0
4 BUSFABRIC RW 0x0
3 RESETS RW 0x0
2 CLOCKS RW 0x0
1 XOSC RW 0x0
0 ROSC RW 0x0
Description
Indicates the peripheral’s registers are ready to access.
31:17 Reserved. - - -
16 PROC1 RO 0x0
15 PROC0 RO 0x0
14 SIO RO 0x0
13 VREG_AND_CHIP_RESET RO 0x0
12 XIP RO 0x0
11 SRAM5 RO 0x0
10 SRAM4 RO 0x0
9 SRAM3 RO 0x0
8 SRAM2 RO 0x0
7 SRAM1 RO 0x0
6 SRAM0 RO 0x0
5 ROM RO 0x0
4 BUSFABRIC RO 0x0
3 RESETS RO 0x0
2 CLOCKS RO 0x0
1 XOSC RO 0x0
0 ROSC RO 0x0
2.14.1. Overview
The reset controller allows software control of the resets to all of the peripherals that are not critical to boot the
processor in RP2040. This includes:
• USB Controller
• PIO
• Peripherals such as UART, I2C, SPI, PWM, Timer, ADC
• PLLs
• IO and Pad registers
The full list can be seen in the register descriptions.
Every peripheral reset by the reset controller is held in reset at power-up. It is up to software to deassert the reset of
peripherals it intends to use. Note that if you are using the SDK some peripherals may already be out of reset.
13 typedef struct {
14 io_rw_32 reset;
15 io_rw_32 wdsel;
16 io_rw_32 reset_done;
17 } resets_hw_t;
18
19 #define resets_hw ((resets_hw_t *const)RESETS_BASE)
• reset: this register contains a bit for each peripheral that can be reset. If the bit is set to 1 then the reset is asserted.
If the bit is cleared then the reset is deasserted.
• wdsel: if the bit is set then this peripheral will be reset if the watchdog fires (note that the power on state machine
can potentially reset the whole reset controller, which will reset everything)
• reset_done: a bit for each peripheral, that gets set once the peripheral is out of reset. This allows software to wait
for this status bit in case the peripheral has some initialisation to do before it can be used.
An example use of these is in the UART driver, where the driver defines a uart_reset function, selecting a different bit of
the reset register depending on the uart specified:
Description
Reset control. If a bit is set it means the peripheral is in reset. 0 means the peripheral’s reset is deasserted.
31:25 Reserved. - - -
24 USBCTRL RW 0x1
23 UART1 RW 0x1
22 UART0 RW 0x1
21 TIMER RW 0x1
20 TBMAN RW 0x1
19 SYSINFO RW 0x1
18 SYSCFG RW 0x1
17 SPI1 RW 0x1
16 SPI0 RW 0x1
15 RTC RW 0x1
14 PWM RW 0x1
13 PLL_USB RW 0x1
12 PLL_SYS RW 0x1
11 PIO1 RW 0x1
10 PIO0 RW 0x1
9 PADS_QSPI RW 0x1
8 PADS_BANK0 RW 0x1
7 JTAG RW 0x1
6 IO_QSPI RW 0x1
5 IO_BANK0 RW 0x1
4 I2C1 RW 0x1
3 I2C0 RW 0x1
2 DMA RW 0x1
1 BUSCTRL RW 0x1
0 ADC RW 0x1
Description
Watchdog select. If a bit is set then the watchdog will reset this peripheral when the watchdog fires.
31:25 Reserved. - - -
24 USBCTRL RW 0x0
23 UART1 RW 0x0
22 UART0 RW 0x0
21 TIMER RW 0x0
20 TBMAN RW 0x0
19 SYSINFO RW 0x0
18 SYSCFG RW 0x0
17 SPI1 RW 0x0
16 SPI0 RW 0x0
15 RTC RW 0x0
14 PWM RW 0x0
13 PLL_USB RW 0x0
12 PLL_SYS RW 0x0
11 PIO1 RW 0x0
10 PIO0 RW 0x0
9 PADS_QSPI RW 0x0
8 PADS_BANK0 RW 0x0
7 JTAG RW 0x0
6 IO_QSPI RW 0x0
5 IO_BANK0 RW 0x0
4 I2C1 RW 0x0
3 I2C0 RW 0x0
2 DMA RW 0x0
1 BUSCTRL RW 0x0
0 ADC RW 0x0
Description
Reset done. If a bit is set then a reset done signal has been returned by the peripheral. This indicates that the
peripheral’s registers are ready to be accessed.
Table 215.
Bits Name Description Type Reset
RESET_DONE Register
31:25 Reserved. - - -
24 USBCTRL RO 0x0
23 UART1 RO 0x0
22 UART0 RO 0x0
21 TIMER RO 0x0
20 TBMAN RO 0x0
19 SYSINFO RO 0x0
18 SYSCFG RO 0x0
17 SPI1 RO 0x0
16 SPI0 RO 0x0
15 RTC RO 0x0
14 PWM RO 0x0
13 PLL_USB RO 0x0
12 PLL_SYS RO 0x0
11 PIO1 RO 0x0
10 PIO0 RO 0x0
9 PADS_QSPI RO 0x0
8 PADS_BANK0 RO 0x0
7 JTAG RO 0x0
6 IO_QSPI RO 0x0
5 IO_BANK0 RO 0x0
4 I2C1 RO 0x0
3 I2C0 RO 0x0
2 DMA RO 0x0
1 BUSCTRL RO 0x0
0 ADC RO 0x0
2.15. Clocks
2.15.1. Overview
The clocks block provides independent clocks to on-chip and external components. It takes inputs from a variety of
clock sources allowing the user to trade off performance against cost, board area and power consumption. From these
sources it uses multiple clock generators to provide the required clocks. This architecture allows the user flexibility to
start and stop clocks independently and to vary some clock frequencies whilst maintaining others at their optimum
frequencies.
For very low cost or low power applications where precise timing is not required, the chip can be run from the internal
Ring Oscillator (ROSC). Alternatively the user can provide external clocks or construct simple relaxation oscillators
using the GPIOs and appropriate external passive components. Where timing is more critical, the Crystal Oscillator
(XOSC) can provide an accurate reference to the 2 on-chip PLLs to provide fast clocking at precise frequencies.
The clock generators select from the clock sources and optionally divide the selected clock before outputting through
enable logic which provides automatic clock disabling in SLEEP mode (see Section 2.11.2).
An on-chip frequency counter facilitates debugging of the clock setup and also allows measurement of the frequencies
of external clocks. The on-chip resus component restarts the system clock from a known good clock if it is accidentally
stopped. This allows the software debugger to access registers and debug the problem.
The chip has an ultra-low power mode called DORMANT (see Section 2.11.3) in which all on-chip clock sources are
stopped to save power. External sources are not stopped and can be used to provide a clock to the on-chip RTC which
can provide an alarm to wake the chip from DORMANT mode. Alternatively the GPIO interrupts can be configured to
wake the chip from DORMANT mode in response to an external event.
Up to 4 generated clocks can be output to GPIOs at up to 50MHz. This allows the user to supply clocks to external
devices, thus reducing component counts in power, space and cost sensitive applications.
The list of clock sources is different per clock generator and can be found as enumerated values in the CTRL register.
See CLK_SYS_CTRL as an example.
The on-chip Ring Oscillator (Section 2.17) requires no external components. It runs automatically from power-up and is
used to clock the chip during the initial boot stages. The startup frequency is typically 6MHz but varies with PVT
(Process, Voltage and Temperature). The frequency is likely to be in the range 4-8MHz and is guaranteed to be in the
range 1.8-12MHz.
For low cost applications where frequency accuracy is unimportant, the chip can continue to run from the ROSC. If
greater performance is required the frequency can be increased by programming the registers as described in Section
2.17. The frequency will vary with PVT (Process, Voltage and Temperature) so the user must take care to avoid
exceeding the maximum frequencies described in the clock generators section. This variation can be mitigated in
various ways (see Section 2.15.2.1.1) if the user wants to continue running from the ROSC at a frequency close to the
maximum. Alternatively, the user can use an external clock or the XOSC to provide a stable reference clock and use the
PLLs to generate higher frequencies. This will require external components, which will cost board area and increase
power consumption.
If an external clock or the XOSC is used then the ROSC can be stopped to save power. However, the reference clock
generator and the system clock generator must be switched to an alternate source before doing so.
The ROSC is not affected by SLEEP mode. If required the frequency can be reduced before entering SLEEP mode to
save power. On entering DORMANT mode the ROSC is automatically stopped and is restarted in the same configuration
when exiting DORMANT mode. If the ROSC is driving clocks at close to their maximum frequencies then it is
recommended to drop the frequency before entering SLEEP or DORMANT mode to allow for frequency variation due to
changes in environmental conditions during SLEEP or DORMANT mode.
If the user wants to use the ROSC clock externally then it can be output to a GPIO pin using one of the clk_gpclk0-3
generators.
The following sections describe techniques for mitigating PVT variation of the ROSC frequency. They also provide some
interesting design challenges for use in teaching both the effects of PVT and writing software to control real time
functions.
NOTE
The ROSC frequency varies with PVT so the user can send its output to the frequency counter and use it to measure
any 1 of these 3 variables if the other 2 are known.
Process varies for two reasons. Firstly, chips leave the factory with a spread of process parameters which cause
variation in the ROSC frequency across chips. Secondly, process parameters vary slightly as the chip ages, though this
will only be observable over many thousands of hours of operation. To mitigate for process variation, the user can
characterise individual chips and program the ROSC frequency accordingly. This is an adequate solution for small
numbers of chips but is not suitable for volume production. In such applications the user should consider using the
automatic mitigation techniques described below.
Supply voltage varies for two reasons. Firstly, the power supply itself may vary, and secondly, there will be varying on-
chip IR drop as chip activity varies. If the application has a minimum performance target then the user needs to
calibrate for that application and adjust the ROSC frequency to ensure it always exceeds the minimum required.
Temperature varies for two reasons. Firstly, the ambient temperature may vary, and secondly, the chip temperature will
vary as chip activity varies due to self-heating. This can be mitigated by stabilising the temperature using a temperature
controlled environment and passive or active cooling. Alternatively the user can track the temperature using the on-chip
temperature sensor and adjust the ROSC frequency so it remains within the required bounds.
Techniques for automatic ROSC frequency control avoid the need to calibrate individual chips but require periodic
access to a clock reference or to a time reference. If a clock reference is available then it can be used to periodically
measure the ROSC frequency and adjust it accordingly. The reference could be the on-chip XOSC which can be turned
on periodically for this purpose. This may be useful in a very low power application where it is too costly to run the
XOSC continuously and too costly to use the PLLs to achieve high frequencies. If a time reference is available then the
user could clock the on-chip RTC from the ROSC and periodically compare it against the time reference, then adjust the
ROSC frequency as necessary. Using these techniques the ROSC frequency will drift due to VT variation so the user
must take care that these variations do not allow the ROSC frequency to drift out of the acceptable range.
The datasheet maximum frequencies for any digital device are quoted for worst case PVT. Most chips in most normal
environments can run significantly faster than the quoted maximum and can therefore be overclocked. If the RP2040 is
running from the ROSC then both the ROSC and the digital components are similarly affected by PVT, so, as the ROSC
gets faster, the processors can also run faster. This means the user can overclock from the ROSC then rely on the ROSC
frequency tracking with PVT variations. The tracking of ROSC frequency and the processor capability is not perfect and
currently there is insufficient data to specify a safe ROSC setting for this mode of operation, so some experimentation is
required.
This mode of operation will maximise processor performance but will lead to variations in the time taken to complete a
task, which may be unacceptable in some applications. Also, if the user wants to use frequency sensitive interfaces
such as USB or UART then the XOSC and PLL must be used to provide a precise clock for those components.
The Crystal Oscillator (Section 2.16) provides a precise, stable clock reference and should be used where accurate
timing is required and no suitable external clocks are available. The frequency is determined by the external crystal and
the oscillator supports frequencies in the range 1MHz to 15MHz. The on-chip PLLs can be used to synthesise higher
frequencies if required. The RP2040 reference design (see Hardware design with RP2040, Minimal Design Example)
uses a 12MHz crystal. Using the XOSC and the PLLs, the on-chip components can be run at their maximum frequencies.
Appropriate margin is built into the design to tolerate up to 1000ppm variation in the XOSC frequency.
The XOSC is inactive on power up. If required it must be enabled in software. XOSC startup takes several milliseconds
and the software must wait for the XOSC_STABLE flag to be set before starting the PLLs and before changing any clock
generators to use it. Prior to that the output from the XOSC may be non-existent or may have very short pulse widths
which will corrupt logic if used. Once it is running the reference clock (clk_ref) and the system clock (clk_sys) can be
switched to run from the XOSC and the ROSC can be stopped to save power.
The XOSC is not affected by SLEEP mode. It is automatically stopped and restarted in the same configuration when
entering and exiting DORMANT mode.
If the user wants to use the XOSC clock externally then it can be output to a GPIO pin using one of the clk_gpclk0-3
If external clocks exist in your hardware design then they can be used to clock the RP2040 either on their own or in
conjunction with the XOSC or ROSC. This will potentially save power and will allow components on the RP2040 to be run
synchronously with external components to simplify data transfer between chips. External clocks can be input on the
GPIN0 & GPIN1 GPIO inputs and on the XIN input to the XOSC. If the XIN input is used in this way the XOSC must be
configured to pass through the XIN signal. All 3 inputs are limited to 50MHz but the on-chip PLLs can be used to
synthesise higher frequencies from the XIN input if required. If the frequency accuracy of the external clocks is poorer
than 1000ppm then the generated clocks should not be run at their maximum frequencies because they may exceed
their design margins.
Once the external clocks are running, the reference clock (clk_ref) and the system clock (clk_sys) can be switched to run
from the external clocks and the ROSC can be stopped to save power.
The external clock sources are not affected by SLEEP mode or DORMANT mode.
If the user wants to use external clocks to replace or supplement the other clock sources but does not have an
appropriate clock available, then 1 or 2 relaxation oscillators can be constructed using external passive components.
Simply send the clock source (GPIN0 or GPIN1) to one of the gpclk0-3 generators, invert it through the GPIO inverter
OUTOVER and connect back to the clock source input via an RC circuit.
The frequency of clocks generated from relaxation oscillators will depend on the delay through the chip and the drive
current from the GPIO output both of which vary with PVT. They will also depend on the quality and accuracy of the
external components. It may be possible to improve the frequency accuracy using more elaborate external components
such as ceramic resonators but that will increase cost and complexity and can never rival the XOSC. For that reason
they are not discussed here. Given that these oscillators will not achieve 1000ppm then they cannot be used to drive
internal clocks at their maximum frequencies.
The relaxation oscillators are not affected by SLEEP mode or DORMANT mode.
2.15.2.5. PLLs
The PLLs (Section 2.18) are used to provide fast clocks when running from the XOSC (or an external clock source driven
into the XIN pin). In a fully featured application the USB PLL provides a fixed 48MHz clock to the ADC and USB while
clk_rtc and clk_ref are driven from the XOSC or external source. This allows the user to drive clk_sys from the system
PLL and vary the frequency according to demand to save power without having to change the setups of the other
clocks. clk_peri can be driven either from the fixed frequency USB PLL or from the variable frequency system PLL. If
clk_sys never needs to exceed 48MHz then one PLL can be used and the divider in the clk_sys clock generator can be
used to scale the clk_sys frequency according to demand.
When a PLL is started, its output cannot be used until the PLL locks as indicated by the LOCK bit in the STATUS register.
Thereafter the PLL output cannot be used during changes to the reference clock divider, the output dividers or the
bypass mode. The output can be used during feedback divisor changes with the proviso that the output frequency may
overshoot or undershoot on large changes to the feedback divisor. For more information, see Section 2.18.
If the PLL reference clock is accurate to 1000ppm then the PLLs can be used to drive clocks at their maximum
frequency because the frequency of the generated clocks will be within the margins allowed in the design.
The PLLs are not affected by SLEEP mode. If the user wants to save power in SLEEP mode then all clock generators
must be switched away from the PLLs and they must be stopped in software before entering SLEEP mode. The PLLs
are not stopped and restarted automatically when entering and exiting DORMANT mode. If they are left running on entry
to DORMANT mode they will be corrupted and will generate out of control clocks that will consume power
unnecessarily. This happens because their reference clock from XOSC will be stopped. It is therefore essential to switch
all clock generators away from the PLLs and stop the PLLs in software before entering DORMANT mode.
2.15.3.1. Instances
clk_gpout3
For a full list of clock sources for each clock generator see the appropriate CTRL register. For example, CLK_SYS_CTRL.
2.15.3.2. Multiplexers
All clock generators have a multiplexer referred to as the auxiliary (aux) mux. This mux has a conventional design
whose output will glitch when changing the select control. Two clock generators (clk_sys and clk_ref) have an additional
multiplexer, referred to as the glitchless mux. The glitchless mux can switch between clock sources without generating
a glitch on the output.
Clock glitches should be avoided at all costs because they may corrupt the logic running on that clock. This means that
any clock generator with only an aux mux must be disabled while switching the clock source. If the clock generator has
a glitchless mux (clk_sys and clk_ref), then the glitchless mux should switch away from the aux mux while changing the
aux mux source. The clock generators require 2 cycles of the source clock to stop the output and 2 cycles of the new
source to restart the output. The user must wait for the generator to stop before changing the auxiliary mux, and
therefore must be aware of the source clock frequency.
The glitchless mux is only implemented for always-on clocks. On RP2040 the always-on clocks are the reference clock
(clk_ref) and the system clock (clk_sys). Such clocks must run continuously unless the chip is in DORMANT mode. The
glitchless mux has a status output (SELECTED) which indicates which source is selected and can be read from
software to confirm that a change of clock source has been completed.
• switch the glitchless mux to a source that isn’t the aux mux
• poll the SELECTED register until the switch is completed
• change the auxiliary mux select control
• switch the glitchless mux back to the aux mux
• if required, poll the SELECTED register until the switch is completed
To switch the auxiliary mux when the generator does not have a glitchless mux:
2.15.3.3. Divider
A fully featured divider divides by 1 or a fractional number in the range 2.0 to 2^24-0.01. Fractional division is achieved
by toggling between 2 integer divisors therefore it yields a jittery clock which may not be suitable for some applications.
For example, when dividing by 2.4 the divider will divide by 2 for 3 cycles and by 3 for 2 cycles. For divisors with large
integer components the jitter will be much smaller and less critical.
All dividers support on-the-fly divisor changes meaning the output clock will switch cleanly from one divisor to another.
The clock generator does not need to be stopped during clock divisor changes. It does this by synchronising the divisor
change to the end of the clock cycle. Similarly, the enable is synchronised to the end of the clock cycle so will not
generate glitches when the clock generator is enabled or disabled. Clock generators for always-on clocks are
permanently enabled and therefore do not have an enable control.
In the event that a clock generator locks up and never completes the current clock cycle it can be forced to stop using
the KILL control. This may result in an output glitch which may corrupt the logic driven by the clock. It is therefore
recommended the destination logic is reset prior to this operation. It is worth mentioning that this clock generator
design has been used in numerous chips and has never been known to lock up. The KILL control is inelegant and
unnecessary and should not be used as an alternative to the enable. Clock generators for always-on clocks are
permanently active and therefore do not have a KILL control.
The divider operates on the rising edge of the input clock and so does not generate an even duty cycle clock when
dividing by odd numbers.
Divide by 3 will give a duty cycle of 33.3%, divide by 5 will be 40% etc. If enabled, the duty cycle correction logic will shift
the falling edge of the output clock to the falling edge of the input clock and restore a 50% duty cycle. The duty cycle
correction can be enabled and disabled while the clock is running. It will not operate when dividing by an even number.
Each clock goes to multiple destinations and, with a few exceptions, there are 2 enables for each destination. The
WAKE_EN registers are used to enable the clocks when the system is awake and the SLEEP_EN registers are used to enable
the clocks when the system is in sleep mode. The purpose of these enables is to reduce power in the clock distribution
networks for components that are not being used. It is worth noting that a component which is not clocked will retain its
configuration so can be restarted quickly.
NOTE
The WAKE_EN and SLEEP_EN registers reset to 0x1, which means that by default all clocks are enabled. The programmer
only needs to use this feature if they desire a low-power design.
The processor cores do not have clock enables because they require a clock at all times to manage their own power
saving features.
clk_sys_busfabric cannot be disabled in wake mode because that would prevent the cores from accessing any chip
clk_sys_clocks does not have a wake mode enable because disabling it would prevent the cores from accessing the
clocks control registers.
System sleep mode is entered automatically when both cores are in sleep and the DMA has no outstanding
transactions. In system sleep mode, the clock enables described in the previous paragraphs are switched from the
WAKE_EN registers to the SLEEP_EN registers. The intention is to reduce power consumed in the clock distribution networks
when the chip is inactive. If the user has not configured the WAKE_EN and SLEEP_EN registers then system sleep will do
nothing.
There is little value in using system sleep without taking other measures to reduce power before the cores are put to
sleep. Things to consider include:
• stop unused clock sources such as the PLLs and Crystal Oscillator
• reduce the frequencies of generated clocks by increasing the clock divisors
• stop external clocks
For maximum power saving when the chip is inactive, the user should consider DORMANT (see Section 2.11.3) mode in
which clocks are sourced from the Crystal Oscillator and/or the Ring Oscillator and those clock sources are stopped.
The user can pick between accuracy and test time using the FC0_INTERVAL register. Table 217 shows the trade off.
1 2 μs 1024 kHz
2 4 μs 512 kHz
3 8 μs 256 kHz
4 16 μs 128 kHz
5 32 μs 64 kHz
6 64 μs 32 kHz
7 125 μs 16 kHz
8 250 μs 8 kHz
9 500 μs 4 kHz
10 1 ms 2 kHz
11 2 ms 1 kHz
12 4 ms 500 Hz
13 8 ms 250 Hz
14 16 ms 125 Hz
15 32 ms 62.5 Hz
2.15.5. Resus
It is possible to write software that inadvertently stops clk_sys. This will normally cause an unrecoverable lock-up of the
cores and the on-chip debugger, leaving the user unable to trace the problem. To mitigate against that, an automatic
resuscitation circuit is provided which will switch clk_sys to a known good clock source if no edges are detected over a
user-defined interval. The known good source is clk_ref which can be driven from the XOSC, ROSC or an external
source.
The resus block counts edges on clk_sys during a timeout interval controlled by clk_ref, and forces clk_sys to be driven
from clk_ref if no clk_sys edges are detected. The interval is programmable via CLK_SYS_RESUS_CTRL.
WARNING
There is no way for resus to revive the chip if clk_ref is also stopped.
To enable the resus, the programmer must set the timeout interval and then set the ENABLE bit in CLK_SYS_RESUS_CTRL.
To detect a resus event, the CLK_SYS_RESUS interrupt must be enabled by setting the interrupt enable bit in INTE. The
CLOCKS_DEFAULT_IRQ (see Section 2.3.2) must also be enabled at the processor.
Resus is intended as a debugging aid. The intention is for the user to trace the software error that triggered the resus,
then correct the error and reboot. It is possible to continue running after a resus event by reconfiguring clk_sys then
clearing the resus by writing the CLEAR bit in CLK_SYS_RESUS_CTRL However, it should be noted that a resus can be
triggered by clk_sys running more slowly than expected and that could result in a clk_sys glitch when resus is triggered.
That glitch could corrupt the chip. This would be a rare event but is tolerable in a debugging scenario. However it is
unacceptable in normal operation therefore it is recommended to only use resus for debug.
WARNING
Resus is a debugging aid and should not be used as a means of switching clocks in normal operation.
18 enum clock_index {
19 clk_gpout0 = 0, ///< GPIO Muxing 0
20 clk_gpout1, ///< GPIO Muxing 1
21 clk_gpout2, ///< GPIO Muxing 2
22 clk_gpout3, ///< GPIO Muxing 3
23 clk_ref, ///< Watchdog and timers reference clock
24 clk_sys, ///< Processors, bus fabric, memory, memory mapped registers
25 clk_peri, ///< Peripheral clock for UART and SPI
26 clk_usb, ///< USB clock
27 clk_adc, ///< ADC clock
28 clk_rtc, ///< Real time clock
29 CLK_COUNT
30 };
34 typedef struct {
35 io_rw_32 ctrl;
36 io_rw_32 div;
37 io_rw_32 selected;
38 } clock_hw_t;
43 bool clock_configure(enum clock_index clk_index, uint32_t src, uint32_t auxsrc, uint32_t
src_freq, uint32_t freq) {
44 uint32_t div;
45
46 assert(src_freq >= freq);
47
48 if (freq > src_freq)
49 return false;
50
51 // Div register is 24.8 int.frac divider so multiply by 2^8 (left shift by 8)
52 div = (uint32_t) (((uint64_t) src_freq << 8) / freq);
53
54 clock_hw_t *clock = &clocks_hw->clk[clk_index];
55
56 // If increasing divisor, set divisor before source. Otherwise set source
57 // before divisor. This avoids a momentary overspeed when e.g. switching
58 // to a faster source and increasing divisor to compensate.
59 if (div > clock->div)
60 clock->div = div;
61
62 // If switching a glitchless slice (ref or sys) to an aux source, switch
63 // away from aux *first* to avoid passing glitches when changing aux mux.
64 // Assume (!!!) glitchless source 0 is no faster than the aux source.
65 if (has_glitchless_mux(clk_index) && src ==
CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX) {
66 hw_clear_bits(&clock->ctrl, CLOCKS_CLK_REF_CTRL_SRC_BITS);
67 while (!(clock->selected & 1u))
68 tight_loop_contents();
69 }
70 // If no glitchless mux, cleanly stop the clock to avoid glitches
71 // propagating when changing aux mux. Note it would be a really bad idea
72 // to do this on one of the glitchless clocks (clk_sys, clk_ref).
73 else {
74 hw_clear_bits(&clock->ctrl, CLOCKS_CLK_GPOUT0_CTRL_ENABLE_BITS);
75 if (configured_freq[clk_index] > 0) {
76 // Delay for 3 cycles of the target clock, for ENABLE propagation.
77 // Note XOSC_COUNT is not helpful here because XOSC is not
78 // necessarily running, nor is timer... so, 3 cycles per loop:
79 uint delay_cyc = configured_freq[clk_sys] / configured_freq[clk_index] + 1;
80 asm volatile (
81 ".syntax unified \n\t"
It is called in clocks_init for each clock. The following example shows the clk_sys configuration:
Once a clock is configured, clock_get_hz can be called to get the output frequency in Hz.
WARNING
It is assumed the source frequency the programmer provides is correct. If it is not then the frequency returned by
clock_get_hz will be inaccurate.
NOTE
The frequency counter can also be used in a test mode. This allows the hardware to check if the frequency is within
a minimum frequency and a maximum frequency, set in FC0_MIN_KHZ and FC0_MAX_KHZ. In this mode, the PASS bit
in FC0_STATUS will be set when DONE is set if the frequency is within the specified range. Otherwise, either the FAST or
SLOW bit will be set.
If the programmer attempts to count a stopped clock, or the clock stops running then the DIED bit will be set. If any of
DIED, FAST, or SLOW are set then FAIL will be set.
379 if (has_glitchless_mux(clk_index)) {
380 // AUX src is always 1
381 src = 1;
382 }
383
384 // Set the GPIO function
385 gpio_set_function(gpio, GPIO_FUNC_GPCK);
386
387 // Now we have the src, auxsrc, and configured the gpio input
388 // call clock configure to run the clock from a gpio
389 return clock_configure(clk_index, src, auxsrc, src_freq, freq);
390 }
Sleep mode is active when neither processor core or the DMA are requesting clocks. For example, the DMA is not active
and both core0 and core1 are waiting for an interrupt. The SLEEP_EN registers set what clocks are running in sleep mode.
The hello_sleep example (https://github.com/raspberrypi/pico-playground/tree/master/sleep/hello_sleep/
hello_sleep.c) illustrates how to put the chip to sleep until the RTC fires. In this case, only the RTC clock is enabled in the
SLEEP_EN0 register.
NOTE
clk_sys is always sent to proc0 and proc1 during sleep mode as some logic needs to be clocked for the processor to
wake up again.
0x00 CLK_GPOUT0_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x08 CLK_GPOUT0_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x0c CLK_GPOUT1_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x14 CLK_GPOUT1_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x18 CLK_GPOUT2_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x20 CLK_GPOUT2_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x24 CLK_GPOUT3_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x2c CLK_GPOUT3_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x30 CLK_REF_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x38 CLK_REF_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x3c CLK_SYS_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x44 CLK_SYS_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x48 CLK_PERI_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x50 CLK_PERI_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x54 CLK_USB_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x5c CLK_USB_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x60 CLK_ADC_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x68 CLK_ADC_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x6c CLK_RTC_CTRL Clock control, can be changed on-the-fly (except for auxsrc)
0x74 CLK_RTC_SELECTED Indicates which SRC is currently selected by the glitchless mux
(one-hot).
0x78 CLK_SYS_RESUS_CTRL
0x7c CLK_SYS_RESUS_STATUS
0x84 FC0_MIN_KHZ Minimum pass frequency in kHz. This is optional. Set to 0 if you
are not using the pass/fail flags
0x88 FC0_MAX_KHZ Maximum pass frequency in kHz. This is optional. Set to 0x1ffffff
if you are not using the pass/fail flags
0x8c FC0_DELAY Delays the start of frequency counting to allow the mux to settle
Delay is measured in multiples of the reference clock period
0x90 FC0_INTERVAL The test interval is 0.98us * 2**interval, but let’s call it 1us *
2**interval
The default gives a test interval of 250us
0x94 FC0_SRC Clock sent to frequency counter, set to 0 when not required
Writing to this register initiates the frequency count
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 219.
Bits Name Description Type Reset
CLK_GPOUT0_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:13 Reserved. - - -
9 Reserved. - - -
8:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_sys
0x1 → clksrc_gpin0
0x2 → clksrc_gpin1
0x3 → clksrc_pll_usb
0x4 → rosc_clksrc
0x5 → xosc_clksrc
0x6 → clk_sys
0x7 → clk_usb
0x8 → clk_adc
0x9 → clk_rtc
0xa → clk_ref
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 220.
Bits Name Description Type Reset
CLK_GPOUT0_DIV
Register
31:8 INT Integer component of the divisor, 0 → divide by 2^16 RW 0x000001
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 221.
Bits Description Type Reset
CLK_GPOUT0_SELECT
ED Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 222.
Bits Name Description Type Reset
CLK_GPOUT1_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:13 Reserved. - - -
9 Reserved. - - -
8:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_sys
0x1 → clksrc_gpin0
0x2 → clksrc_gpin1
0x3 → clksrc_pll_usb
0x4 → rosc_clksrc
0x5 → xosc_clksrc
0x6 → clk_sys
0x7 → clk_usb
0x8 → clk_adc
0x9 → clk_rtc
0xa → clk_ref
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 223.
Bits Name Description Type Reset
CLK_GPOUT1_DIV
Register
31:8 INT Integer component of the divisor, 0 → divide by 2^16 RW 0x000001
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 224.
Bits Description Type Reset
CLK_GPOUT1_SELECT
ED Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 225.
Bits Name Description Type Reset
CLK_GPOUT2_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:13 Reserved. - - -
9 Reserved. - - -
8:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_sys
0x1 → clksrc_gpin0
0x2 → clksrc_gpin1
0x3 → clksrc_pll_usb
0x4 → rosc_clksrc_ph
0x5 → xosc_clksrc
0x6 → clk_sys
0x7 → clk_usb
0x8 → clk_adc
0x9 → clk_rtc
0xa → clk_ref
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 226.
Bits Name Description Type Reset
CLK_GPOUT2_DIV
Register
31:8 INT Integer component of the divisor, 0 → divide by 2^16 RW 0x000001
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 227.
Bits Description Type Reset
CLK_GPOUT2_SELECT
ED Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 228.
Bits Name Description Type Reset
CLK_GPOUT3_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:13 Reserved. - - -
9 Reserved. - - -
8:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_sys
0x1 → clksrc_gpin0
0x2 → clksrc_gpin1
0x3 → clksrc_pll_usb
0x4 → rosc_clksrc_ph
0x5 → xosc_clksrc
0x6 → clk_sys
0x7 → clk_usb
0x8 → clk_adc
0x9 → clk_rtc
0xa → clk_ref
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 229.
Bits Name Description Type Reset
CLK_GPOUT3_DIV
Register
31:8 INT Integer component of the divisor, 0 → divide by 2^16 RW 0x000001
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 230.
Bits Description Type Reset
CLK_GPOUT3_SELECT
ED Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 231.
Bits Name Description Type Reset
CLK_REF_CTRL
Register
31:7 Reserved. - - -
6:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_usb
0x1 → clksrc_gpin0
0x2 → clksrc_gpin1
4:2 Reserved. - - -
1:0 SRC Selects the clock source glitchlessly, can be changed on- RW -
the-fly
0x0 → rosc_clksrc_ph
0x1 → clksrc_clk_ref_aux
0x2 → xosc_clksrc
Description
Clock divisor, can be changed on-the-fly
Table 232.
Bits Name Description Type Reset
CLK_REF_DIV Register
31:10 Reserved. - - -
7:0 Reserved. - - -
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 233.
Bits Description Type Reset
CLK_REF_SELECTED
Register
31:0 The glitchless multiplexer does not switch instantaneously (to avoid glitches), RO 0x00000001
so software should poll this register to wait for the switch to complete. This
register contains one decoded bit for each of the clock sources enumerated in
the CTRL SRC field. At most one of these bits will be set at any time, indicating
that clock is currently present at the output of the glitchless mux. Whilst
switching is in progress, this register may briefly show all-0s.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 234.
Bits Name Description Type Reset
CLK_SYS_CTRL
Register
31:8 Reserved. - - -
7:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_sys
0x1 → clksrc_pll_usb
0x2 → rosc_clksrc
0x3 → xosc_clksrc
0x4 → clksrc_gpin0
0x5 → clksrc_gpin1
4:1 Reserved. - - -
0 SRC Selects the clock source glitchlessly, can be changed on- RW 0x0
the-fly
0x0 → clk_ref
0x1 → clksrc_clk_sys_aux
Description
Clock divisor, can be changed on-the-fly
Table 235.
Bits Name Description Type Reset
CLK_SYS_DIV Register
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 236.
Bits Description Type Reset
CLK_SYS_SELECTED
Register
31:0 The glitchless multiplexer does not switch instantaneously (to avoid glitches), RO 0x00000001
so software should poll this register to wait for the switch to complete. This
register contains one decoded bit for each of the clock sources enumerated in
the CTRL SRC field. At most one of these bits will be set at any time, indicating
that clock is currently present at the output of the glitchless mux. Whilst
switching is in progress, this register may briefly show all-0s.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 237.
Bits Name Description Type Reset
CLK_PERI_CTRL
Register
31:12 Reserved. - - -
9:8 Reserved. - - -
7:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clk_sys
0x1 → clksrc_pll_sys
0x2 → clksrc_pll_usb
0x3 → rosc_clksrc_ph
0x4 → xosc_clksrc
0x5 → clksrc_gpin0
0x6 → clksrc_gpin1
4:0 Reserved. - - -
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 238.
Bits Description Type Reset
CLK_PERI_SELECTED
Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 239.
Bits Name Description Type Reset
CLK_USB_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:12 Reserved. - - -
9:8 Reserved. - - -
7:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_usb
0x1 → clksrc_pll_sys
0x2 → rosc_clksrc_ph
0x3 → xosc_clksrc
0x4 → clksrc_gpin0
0x5 → clksrc_gpin1
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 240.
Bits Name Description Type Reset
CLK_USB_DIV Register
31:10 Reserved. - - -
7:0 Reserved. - - -
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 241.
Bits Description Type Reset
CLK_USB_SELECTED
Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 242.
Bits Name Description Type Reset
CLK_ADC_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:12 Reserved. - - -
9:8 Reserved. - - -
7:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_usb
0x1 → clksrc_pll_sys
0x2 → rosc_clksrc_ph
0x3 → xosc_clksrc
0x4 → clksrc_gpin0
0x5 → clksrc_gpin1
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 243.
Bits Name Description Type Reset
CLK_ADC_DIV Register
31:10 Reserved. - - -
7:0 Reserved. - - -
Offset: 0x68
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 244.
Bits Description Type Reset
CLK_ADC_SELECTED
Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Description
Clock control, can be changed on-the-fly (except for auxsrc)
Table 245.
Bits Name Description Type Reset
CLK_RTC_CTRL
Register
31:21 Reserved. - - -
20 NUDGE An edge on this signal shifts the phase of the output by 1 RW 0x0
cycle of the input clock
This can be done at any time
19:18 Reserved. - - -
17:16 PHASE This delays the enable signal by up to 3 cycles of the input RW 0x0
clock
This must be set before the clock is enabled to have any
effect
15:12 Reserved. - - -
9:8 Reserved. - - -
7:5 AUXSRC Selects the auxiliary clock source, will glitch when RW 0x0
switching
0x0 → clksrc_pll_usb
0x1 → clksrc_pll_sys
0x2 → rosc_clksrc_ph
0x3 → xosc_clksrc
0x4 → clksrc_gpin0
0x5 → clksrc_gpin1
4:0 Reserved. - - -
Description
Clock divisor, can be changed on-the-fly
Table 246.
Bits Name Description Type Reset
CLK_RTC_DIV Register
Description
Indicates which SRC is currently selected by the glitchless mux (one-hot).
Table 247.
Bits Description Type Reset
CLK_RTC_SELECTED
Register
31:0 This slice does not have a glitchless mux (only the AUX_SRC field is present, RO 0x00000001
not SRC) so this register is hardwired to 0x1.
Table 248.
Bits Name Description Type Reset
CLK_SYS_RESUS_CTR
L Register
31:17 Reserved. - - -
16 CLEAR For clearing the resus after the fault that triggered it has RW 0x0
been corrected
15:13 Reserved. - - -
11:9 Reserved. - - -
Table 249.
Bits Name Description Type Reset
CLK_SYS_RESUS_STA
TUS Register
31:1 Reserved. - - -
0 RESUSSED Clock has been resuscitated, correct the error then send RO 0x0
ctrl_clear=1
Table 250.
Bits Description Type Reset
FC0_REF_KHZ Register
31:20 Reserved. - -
Table 251.
Bits Description Type Reset
FC0_MIN_KHZ
Register
31:25 Reserved. - -
24:0 Minimum pass frequency in kHz. This is optional. Set to 0 if you are not using RW 0x0000000
the pass/fail flags
Table 252.
Bits Description Type Reset
FC0_MAX_KHZ
Register
31:25 Reserved. - -
24:0 Maximum pass frequency in kHz. This is optional. Set to 0x1ffffff if you are RW 0x1ffffff
not using the pass/fail flags
31:3 Reserved. - -
2:0 Delays the start of frequency counting to allow the mux to settle RW 0x1
Delay is measured in multiples of the reference clock period
Table 254.
Bits Description Type Reset
FC0_INTERVAL
Register
31:4 Reserved. - -
3:0 The test interval is 0.98us * 2**interval, but let’s call it 1us * 2**interval RW 0x8
The default gives a test interval of 250us
31:8 Reserved. - -
7:0 Clock sent to frequency counter, set to 0 when not required RW 0x00
Writing to this register initiates the frequency count
0x00 → NULL
0x01 → pll_sys_clksrc_primary
0x02 → pll_usb_clksrc_primary
0x03 → rosc_clksrc
0x04 → rosc_clksrc_ph
0x05 → xosc_clksrc
0x06 → clksrc_gpin0
0x07 → clksrc_gpin1
0x08 → clk_ref
0x09 → clk_sys
0x0a → clk_peri
0x0b → clk_usb
0x0c → clk_adc
0x0d → clk_rtc
Description
Frequency counter status
Table 256.
Bits Name Description Type Reset
FC0_STATUS Register
31:29 Reserved. - - -
27:25 Reserved. - - -
24 FAST Test clock faster than expected, only valid when RO 0x0
status_done=1
23:21 Reserved. - - -
20 SLOW Test clock slower than expected, only valid when RO 0x0
status_done=1
19:17 Reserved. - - -
15:13 Reserved. - - -
11:9 Reserved. - - -
7:5 Reserved. - - -
3:1 Reserved. - - -
Offset: 0x9c
Description
Result of frequency measurement, only valid when status_done=1
Table 257.
Bits Name Description Type Reset
FC0_RESULT Register
31:30 Reserved. - - -
Description
enable clock in wake mode
31 CLK_SYS_SRAM3 RW 0x1
30 CLK_SYS_SRAM2 RW 0x1
29 CLK_SYS_SRAM1 RW 0x1
28 CLK_SYS_SRAM0 RW 0x1
27 CLK_SYS_SPI1 RW 0x1
26 CLK_PERI_SPI1 RW 0x1
25 CLK_SYS_SPI0 RW 0x1
24 CLK_PERI_SPI0 RW 0x1
23 CLK_SYS_SIO RW 0x1
22 CLK_SYS_RTC RW 0x1
21 CLK_RTC_RTC RW 0x1
20 CLK_SYS_ROSC RW 0x1
19 CLK_SYS_ROM RW 0x1
18 CLK_SYS_RESETS RW 0x1
17 CLK_SYS_PWM RW 0x1
16 CLK_SYS_PSM RW 0x1
15 CLK_SYS_PLL_USB RW 0x1
14 CLK_SYS_PLL_SYS RW 0x1
13 CLK_SYS_PIO1 RW 0x1
12 CLK_SYS_PIO0 RW 0x1
11 CLK_SYS_PADS RW 0x1
10 CLK_SYS_VREG_AND_CHIP_RESET RW 0x1
9 CLK_SYS_JTAG RW 0x1
8 CLK_SYS_IO RW 0x1
7 CLK_SYS_I2C1 RW 0x1
6 CLK_SYS_I2C0 RW 0x1
5 CLK_SYS_DMA RW 0x1
4 CLK_SYS_BUSFABRIC RW 0x1
3 CLK_SYS_BUSCTRL RW 0x1
2 CLK_SYS_ADC RW 0x1
1 CLK_ADC_ADC RW 0x1
0 CLK_SYS_CLOCKS RW 0x1
Description
enable clock in wake mode
31:15 Reserved. - - -
14 CLK_SYS_XOSC RW 0x1
13 CLK_SYS_XIP RW 0x1
12 CLK_SYS_WATCHDOG RW 0x1
11 CLK_USB_USBCTRL RW 0x1
10 CLK_SYS_USBCTRL RW 0x1
9 CLK_SYS_UART1 RW 0x1
8 CLK_PERI_UART1 RW 0x1
7 CLK_SYS_UART0 RW 0x1
6 CLK_PERI_UART0 RW 0x1
5 CLK_SYS_TIMER RW 0x1
4 CLK_SYS_TBMAN RW 0x1
3 CLK_SYS_SYSINFO RW 0x1
2 CLK_SYS_SYSCFG RW 0x1
1 CLK_SYS_SRAM5 RW 0x1
0 CLK_SYS_SRAM4 RW 0x1
Description
enable clock in sleep mode
31 CLK_SYS_SRAM3 RW 0x1
30 CLK_SYS_SRAM2 RW 0x1
29 CLK_SYS_SRAM1 RW 0x1
28 CLK_SYS_SRAM0 RW 0x1
27 CLK_SYS_SPI1 RW 0x1
26 CLK_PERI_SPI1 RW 0x1
25 CLK_SYS_SPI0 RW 0x1
24 CLK_PERI_SPI0 RW 0x1
23 CLK_SYS_SIO RW 0x1
22 CLK_SYS_RTC RW 0x1
21 CLK_RTC_RTC RW 0x1
20 CLK_SYS_ROSC RW 0x1
19 CLK_SYS_ROM RW 0x1
18 CLK_SYS_RESETS RW 0x1
17 CLK_SYS_PWM RW 0x1
16 CLK_SYS_PSM RW 0x1
15 CLK_SYS_PLL_USB RW 0x1
14 CLK_SYS_PLL_SYS RW 0x1
13 CLK_SYS_PIO1 RW 0x1
12 CLK_SYS_PIO0 RW 0x1
11 CLK_SYS_PADS RW 0x1
10 CLK_SYS_VREG_AND_CHIP_RESET RW 0x1
9 CLK_SYS_JTAG RW 0x1
8 CLK_SYS_IO RW 0x1
7 CLK_SYS_I2C1 RW 0x1
6 CLK_SYS_I2C0 RW 0x1
5 CLK_SYS_DMA RW 0x1
4 CLK_SYS_BUSFABRIC RW 0x1
3 CLK_SYS_BUSCTRL RW 0x1
2 CLK_SYS_ADC RW 0x1
1 CLK_ADC_ADC RW 0x1
0 CLK_SYS_CLOCKS RW 0x1
Description
enable clock in sleep mode
31:15 Reserved. - - -
14 CLK_SYS_XOSC RW 0x1
13 CLK_SYS_XIP RW 0x1
12 CLK_SYS_WATCHDOG RW 0x1
11 CLK_USB_USBCTRL RW 0x1
10 CLK_SYS_USBCTRL RW 0x1
9 CLK_SYS_UART1 RW 0x1
8 CLK_PERI_UART1 RW 0x1
7 CLK_SYS_UART0 RW 0x1
6 CLK_PERI_UART0 RW 0x1
5 CLK_SYS_TIMER RW 0x1
4 CLK_SYS_TBMAN RW 0x1
3 CLK_SYS_SYSINFO RW 0x1
2 CLK_SYS_SYSCFG RW 0x1
1 CLK_SYS_SRAM5 RW 0x1
0 CLK_SYS_SRAM4 RW 0x1
Description
indicates the state of the clock enable
31 CLK_SYS_SRAM3 RO 0x0
30 CLK_SYS_SRAM2 RO 0x0
29 CLK_SYS_SRAM1 RO 0x0
28 CLK_SYS_SRAM0 RO 0x0
27 CLK_SYS_SPI1 RO 0x0
26 CLK_PERI_SPI1 RO 0x0
25 CLK_SYS_SPI0 RO 0x0
24 CLK_PERI_SPI0 RO 0x0
23 CLK_SYS_SIO RO 0x0
22 CLK_SYS_RTC RO 0x0
21 CLK_RTC_RTC RO 0x0
20 CLK_SYS_ROSC RO 0x0
19 CLK_SYS_ROM RO 0x0
18 CLK_SYS_RESETS RO 0x0
17 CLK_SYS_PWM RO 0x0
16 CLK_SYS_PSM RO 0x0
15 CLK_SYS_PLL_USB RO 0x0
14 CLK_SYS_PLL_SYS RO 0x0
13 CLK_SYS_PIO1 RO 0x0
12 CLK_SYS_PIO0 RO 0x0
11 CLK_SYS_PADS RO 0x0
10 CLK_SYS_VREG_AND_CHIP_RESET RO 0x0
9 CLK_SYS_JTAG RO 0x0
8 CLK_SYS_IO RO 0x0
7 CLK_SYS_I2C1 RO 0x0
6 CLK_SYS_I2C0 RO 0x0
5 CLK_SYS_DMA RO 0x0
4 CLK_SYS_BUSFABRIC RO 0x0
3 CLK_SYS_BUSCTRL RO 0x0
2 CLK_SYS_ADC RO 0x0
1 CLK_ADC_ADC RO 0x0
0 CLK_SYS_CLOCKS RO 0x0
Description
indicates the state of the clock enable
31:15 Reserved. - - -
14 CLK_SYS_XOSC RO 0x0
13 CLK_SYS_XIP RO 0x0
12 CLK_SYS_WATCHDOG RO 0x0
11 CLK_USB_USBCTRL RO 0x0
10 CLK_SYS_USBCTRL RO 0x0
9 CLK_SYS_UART1 RO 0x0
8 CLK_PERI_UART1 RO 0x0
7 CLK_SYS_UART0 RO 0x0
6 CLK_PERI_UART0 RO 0x0
5 CLK_SYS_TIMER RO 0x0
4 CLK_SYS_TBMAN RO 0x0
3 CLK_SYS_SYSINFO RO 0x0
2 CLK_SYS_SYSCFG RO 0x0
1 CLK_SYS_SRAM5 RO 0x0
0 CLK_SYS_SRAM4 RO 0x0
Description
Raw Interrupts
31:1 Reserved. - - -
0 CLK_SYS_RESUS RO 0x0
Description
Interrupt Enable
31:1 Reserved. - - -
0 CLK_SYS_RESUS RW 0x0
Description
Interrupt Force
31:1 Reserved. - - -
0 CLK_SYS_RESUS RW 0x0
Description
Interrupt status after masking & forcing
31:1 Reserved. - - -
0 CLK_SYS_RESUS RO 0x0
2.16.1. Overview
The Crystal Oscillator (XOSC) uses an external crystal to produce an accurate reference clock. The RP2040 supports
1MHz to 15MHz crystals and the RP2040 reference design (see Hardware design with RP2040, Minimal Design
Example) uses a 12MHz crystal. The reference clock is distributed to the PLLs, which can be used to multiply the XOSC
frequency to provide accurate high speed clocks. For example, they can generate a 48MHz clock which meets the
frequency accuracy requirement of the USB interface and a 133MHz maximum speed system clock. The XOSC clock is
also a clock source for the clock generators, so can be used directly if required.
If the user already has an accurate clock source then it is possible to drive an external clock directly into XIN (aka XI),
and disable the oscillator circuit. In this mode XIN can be driven at up to 50MHz.
If the user wants to use the XOSC clock outside the RP2040 then it must be routed out to a GPIO via a clk_gpout clock
generator. It is not recommended to take it directly from XIN (aka XI) or XOUT (aka XO).
2.16.2. Usage
The XOSC is disabled on chip startup and the RP2040 boots using the Ring Oscillator (ROSC). To start the XOSC, the
programmer must set the CTRL_ENABLE register. The XOSC is not immediately usable because it takes time for the
oscillations to build to sufficient amplitude. This time will be dependent on the chosen crystal but will be of the order of
a few milliseconds. The XOSC incorporates a timer controlled by the STARTUP_DELAY register for automatically
managing this and setting a flag (STATUS_STABLE) when the XOSC clock is usable.
Before starting the XOSC the programmer must ensure the STARTUP_DELAY register is correctly configured. The
required value can be calculated by:
So with a 12MHz crystal and a 1ms wait time, the calculation is:
NOTE
the value is rounded up to the nearest integer so the wait time will be just over 1ms
NOTE
41 void xosc_dormant(void) {
42 // WARNING: This stops the xosc until woken up by an irq
43 xosc_hw->dormant = XOSC_DORMANT_VALUE_DORMANT;
44 // Wait for it to become stable once woken up
45 while(!(xosc_hw->status & XOSC_STATUS_STABLE_BITS));
46 }
WARNING
If no IRQ is configured before going into DORMANT mode the XOSC or ROSC will never restart.
See Section 2.11.5.2 for a complete example of DORMANT mode using the XOSC.
15 typedef struct {
16 io_rw_32 ctrl;
17 io_rw_32 status;
18 io_rw_32 dormant;
19 io_rw_32 startup;
20 io_rw_32 _reserved[3];
21 io_rw_32 count;
22 } xosc_hw_t;
23
24 #define xosc_hw ((xosc_hw_t *const)XOSC_BASE)
16 void xosc_init(void) {
17 // Assumes 1-15 MHz input
18 assert(XOSC_MHZ <= 15);
19 xosc_hw->ctrl = XOSC_CTRL_FREQ_RANGE_VALUE_1_15MHZ;
20
21 // Set xosc startup delay
22 uint32_t startup_delay = (((12 * MHZ) / 1000) + 128) / 256;
23 xosc_hw->startup = startup_delay;
24
25 // Set the enable bit now that we have set freq range and startup delay
26 hw_set_bits(&xosc_hw->ctrl, XOSC_CTRL_ENABLE_VALUE_ENABLE << XOSC_CTRL_ENABLE_LSB);
27
28 // Wait for XOSC to be stable
29 while(!(xosc_hw->status & XOSC_STATUS_STABLE_BITS));
30 }
0x1c COUNT A down counter running at the XOSC frequency which counts to
zero and stops.
Description
Crystal Oscillator Control
31:24 Reserved. - - -
Description
Crystal Oscillator Status
30:25 Reserved. - - -
23:13 Reserved. - - -
11:2 Reserved. - - -
Description
Crystal Oscillator pause control
Description
Controls the startup delay
31:21 Reserved. - - -
19:14 Reserved. - - -
31:8 Reserved. - -
7:0 A down counter running at the xosc frequency which counts to zero and stops. RW 0x00
To start the counter write a non-zero value.
Can be used for short software pauses when setting up time sensitive
hardware.
2.17.1. Overview
The Ring Oscillator (ROSC) is an on-chip oscillator built from a ring of inverters. It requires no external components and
is started automatically during RP2040 power up. It provides the clock to the cores during boot. The frequency of the
ROSC is programmable and it can directly provide a high speed clock to the cores, but the frequency varies with
Process, Voltage and Temperature (PVT) so it cannot provide clocks for components which require an accurate
frequency such as the RTC, USB and ADC. Methods for mitigating the frequency variation are discussed in Section 2.15
but these are only relevant to very low power design. For most applications requiring accurate clock frequencies it is
recommended to switch to the XOSC and PLLs. During boot the ROSC runs at a nominal 6.5MHz and is guaranteed to
be in the range 1.8MHz to 12MHz.
Once the chip has booted the programmer can choose to continue running from the ROSC and increase its frequency or
start the Crystal Oscillator (XOSC) and PLLs. The ROSC can be disabled after the system clocks have been switched to
the XOSC. Each oscillator has advantages and the programmer can switch between them to achieve the best solution
The disadvantage of the ROSC is its frequency variation with PVT (Process, Voltage & Temperature) which makes it
unsuitable for generating precise clocks or for applications where software execution timing is important. However, the
PVT frequency variation can be exploited to provide automatic frequency scaling to maximise performance. This is
discussed in Section 2.15.
The only advantage of the XOSC is its accurate frequency, but this is an overriding requirement in many applications.
The disadvantages of the XOSC are its requirement for external components (a crystal etc), its higher power
consumption, slow startup time (>1ms) and fixed, low frequency. PLLs are required to produce higher frequency clocks.
They consume more power and take significant time to start up and to change frequency. Exiting DORMANT mode is
much slower than for ROSC because the XOSC must be restarted and the PLLs must be reconfigured.
The frequency range is changed by writing to the FREQ_RANGE register which controls the number of stages in the
ROSC loop. The default LOW range has 8 (stages 0-7), MEDIUM has 6 (stages 0-5), HIGH has 4 (stages 0-3) and
TOOHIGH has 2 (stages 0-1). It is recommended to change FREQ_RANGE one step at a time until the desired range is
reached. The ROSC output will not glitch when increasing the frequency range, so the output clock can continue to be
used. However, that is not true when going back down the frequency range. An alternate clock source must be selected
for the modules clocked by ROSC, or they must be held in reset during the transition. The behaviour has not been fully
characterised but the MEDIUM range will be approximately 1.33 times the LOW RANGE, the HIGH range will be 2 times
the LOW range and the TOOHIGH range will be 4 times the LOW range. The TOOHIGH range is aptly named. It should
not be used because the internal logic of the ROSC will not run at that frequency.
The FREQA & FREQB registers control the drive strength of the stages in the ROSC loop. Increasing the drive strength
reduces the delay through the stage and increases the oscillation frequency. Each stage has 3 drive strength control
bits. Each bit turns on additional drive, therefore each stage has 4 drive strength settings equal to the number of bits
set, with 0 being the default, 1 being double drive, 2 being triple drive and 3 being quadruple drive. Turning on extra drive
will not have a linear effect on frequency, setting a second bit will have less impact than setting the first bit and so on.
To ensure smooth transitions it is recommended to change one drive strength bit at a time. When FREQ_RANGE is used
to shorten the ROSC loop, the bypassed stages still propagate the signal and therefore their drive strengths must be set
to at least the same level as the lowest drive strength in the stages that are in the loop. This will not affect the
oscillation frequency.
The divider has 2 outputs, rosc_clksrc and rosc_clksrc_ph, the second being a phase shifted version of the first. This is
primarily intended for use during product development and the outputs will be identical if the PHASE register is left in its
default state.
56 void rosc_set_dormant(void) {
57 // WARNING: This stops the rosc until woken up by an irq
58 rosc_write(&rosc_hw->dormant, ROSC_DORMANT_VALUE_DORMANT);
59 // Wait for it to become stable once woken up
60 while(!(rosc_hw->status & ROSC_STATUS_STABLE_BITS));
61 }
WARNING
If no IRQ is configured before going into dormant mode the ROSC will never restart.
0x20 COUNT A down counter running at the ROSC frequency which counts to
zero and stops.
Description
Ring Oscillator control
31:24 Reserved. - - -
11:0 FREQ_RANGE Controls the number of delay stages in the ROSC ring RW 0xaa0
LOW uses stages 0 to 7
MEDIUM uses stages 0 to 5
HIGH uses stages 0 to 3
TOOHIGH uses stages 0 to 1 and should not be used
because its frequency exceeds design specifications
The clock output will not glitch when changing the range
up one step at a time
The clock output will glitch when changing the range
down
Note: the values here are gray coded which is why HIGH
comes before TOOHIGH
0xfa4 → LOW
0xfa5 → MEDIUM
0xfa7 → HIGH
0xfa6 → TOOHIGH
Description
The FREQA & FREQB registers control the frequency by controlling the drive strength of each stage
The drive strength has 4 levels determined by the number of bits set
Increasing the number of bits set increases the drive strength and increases the oscillation frequency
0 bits set is the default drive strength
1 bit set doubles the drive strength
2 bits set triples drive strength
3 bits set quadruples drive strength
15 Reserved. - - -
11 Reserved. - - -
7 Reserved. - - -
3 Reserved. - - -
Description
For a detailed description see freqa register
15 Reserved. - - -
11 Reserved. - - -
7 Reserved. - - -
3 Reserved. - - -
Description
Ring Oscillator pause control
Description
Controls the output divider
31:12 Reserved. - -
Description
Controls the phase shifted output
31:12 Reserved. - - -
1:0 SHIFT phase shift the phase-shifted output by SHIFT input clocks RW 0x0
this can be changed on-the-fly
must be set to 0 before setting div=1
Description
Ring Oscillator Status
30:25 Reserved. - - -
23:17 Reserved. - - -
15:13 Reserved. - - -
11:0 Reserved. - - -
Table 282.
Bits Description Type Reset
RANDOMBIT Register
31:1 Reserved. - -
0 This just reads the state of the oscillator output so randomness is RO 0x1
compromised if the ring oscillator is stopped or run at a harmonic of the bus
frequency
31:8 Reserved. - -
7:0 A down counter running at the ROSC frequency which counts to zero and RW 0x00
stops.
To start the counter write a non-zero value.
Can be used for short software pauses when setting up time sensitive
hardware.
2.18. PLL
2.18.1. Overview
The PLL is designed to take a reference clock, and multiply it using a VCO (Voltage Controlled Oscillator) with a
feedback loop. The VCO must run at high frequencies (between 400 and 1600 MHz), so there are two dividers, known as
post dividers that can divide the VCO frequency before it is distributed to the clock generators on the chip.
• Maximum input frequency (FREF / REFDIV) is VCO frequency divided by 16, due to minimum feedback divisor
Additionally, the maximum frequencies of the chip’s clock generators (attached to FOUTPOSTDIV) must be respected. For
the system PLL this is 133 MHz, and for the USB PLL, 48 MHz.
NOTE
The crystal oscillator on RP2040 is designed for crystals between 5 and 15 MHz, so typically REFDIV should be 1. If
the application circuit drives a faster reference directly into the XI input, and a low VCO frequency is desired, the
reference divisor can be increased to keep the PLL input within a suitable range.
TIP
When two different values are required for POSTDIV1 and POSTDIV2, it’s preferable to assign the higher value to POSTDIV1,
for lower power consumption.
In the RP2040 reference design (see Hardware design with RP2040, Minimal Design Example), which attaches a 12 MHz
crystal to the crystal oscillator, this implies that the minimum achievable and legal VCO frequency is 12 MHz × 34 = 408
MHz, and the maximum VCO is 12 MHz × 133 = 1596 MHz, so FBDIV must remain in the range 34 → 133. For example,
setting FBDIV to 100 would synthesise a 1200 MHz VCO frequency. A POSTDIV1 value of 6 and a POSTDIV2 value of 2 would
divide this by 12 in total, producing a clean 100 MHz at the PLL’s final output.
There are often several sets of PLL configuration parameters which achieve, or are very close to, the desired output
frequency. It is up to the programmer to decide whether to prioritise low PLL power consumption, or lower jitter, which
is cycle-to-cycle variation in the PLL’s output clock period. This is not a concern as far as system stability is concerned,
because RP2040’s digital logic is designed with margin for the worst-case possible jitter on the system clock, but a
highly accurate clock is often needed for audio and video applications, or where data is being transmitted and received
in accordance with a specification. For example, the USB specification defines a maximum amount of allowable jitter.
Jitter is minimised by running the VCO at the highest possible frequency, so that higher post-divide values can be used.
For example, 1500 MHz VCO / 6 / 2 = 125MHz. To reduce power consumption, the VCO frequency should be as low as
possible. For example: 500 MHZ VCO / 4 / 1 = 125 MHz.
Another consideration here is that slightly adjusting the output frequency may allow a much lower VCO frequency to be
achieved, by bringing the output to a closer rational multiple of the input. Indeed the exact desired frequency may not be
exactly achievable with any allowable VCO frequency, or combination of divisors.
SDK provides a Python script that searches for the best VCO and post divider options for a desired output frequency:
1 #!/usr/bin/env python3
2
3 import argparse
4
5 parser = argparse.ArgumentParser(description="PLL parameter calculator")
6 parser.add_argument("--input", "-i", default=12, help="Input (reference) frequency. Default
12 MHz", type=float)
7 parser.add_argument("--vco-max", default=1600, help="Override maximum VCO frequency. Default
1600 MHz", type=float)
8 parser.add_argument("--vco-min", default=400, help="Override minimum VCO frequency. Default
400 MHz", type=float)
9 parser.add_argument("--low-vco", "-l", action="store_true", help="Use a lower VCO frequency
when possible. This reduces power consumption, at the cost of increased jitter")
10 parser.add_argument("output", help="Output frequency in MHz.", type=float)
11 args = parser.parse_args()
12
Given an input and output frequency, this script will find the best possible set of PLL parameters to get as close as
possible. Where multiple equally good combinations are found, it returns the parameters which yield the highest VCO
frequency, for best output stability. The -l or --low-vco flag will instead prefer lower frequencies, for reduced power
consumption.
$ ./vcocalc.py 48
Requested: 48.0 MHz
Achieved: 48.0 MHz
FBDIV: 120 (VCO = 1440 MHz)
PD1: 6
PD2: 5
$ ./vcocalc.py -l 48
Requested: 48.0 MHz
Achieved: 48.0 MHz
FBDIV: 36 (VCO = 432 MHz)
PD1: 3
PD2: 3
For a 125 MHz system clock with a 12 MHz input, the minimum VCO frequency is quite high.
$ ./vcocalc.py -l 125
Requested: 125.0 MHz
Achieved: 125.0 MHz
FBDIV: 125 (VCO = 1500 MHz)
PD1: 6
PD2: 2
We can restrict the search to lower VCO frequencies, so that the script will consider looser frequency matches. Note
that, whilst a 500 MHz VCO would be ideal here, we can’t achieve exactly 500 MHz by multiplying the 12 MHz input by
an integer, which is why the previous invocation returned such a high VCO frequency.
A 126 MHz system clock may be a tolerable deviation from the desired 125 MHz, and generating this clock consumes
less power at the PLL.
2.18.3. Configuration
The SDK uses the following PLL settings:
The pll_init function in the SDK, which we will examine below, asserts that all of these conditions are true before
attempting to configure the PLL.
The SDK defines the PLL control registers as a struct. It then maps them into memory for each instance of the PLL.
14 typedef struct {
15 io_rw_32 cs;
16 io_rw_32 pwr;
17 io_rw_32 fbdiv_int;
18 io_rw_32 prim;
19 } pll_hw_t;
20
21 #define pll_sys_hw ((pll_hw_t *const)PLL_SYS_BASE)
22 #define pll_usb_hw ((pll_hw_t *const)PLL_USB_BASE)
The SDK defines pll_init which is used to configure, or reconfigure a PLL. It starts by clearing any previous power state
in the PLL, then calculates the appropriate feedback divider value. There are assertions to check these values satisfy the
constraints above.
12 void pll_init(PLL pll, uint refdiv, uint vco_freq, uint post_div1, uint post_div2) {
13 // Turn off PLL in case it is already running
14 pll->pwr = 0xffffffff;
15 pll->fbdiv_int = 0;
16
• Program the reference clock divider (is a divide by 1 in the RP2040 case)
• Program the feedback divider
• Turn on the main power and VCO
• Wait for the VCO to lock (i.e. keep its output frequency stable)
• Set up post dividers and turn them on
SDK: https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/hardware_pll/pll.c Lines 38 - 59
Note the VCO is turned on first, followed by the post dividers so the PLL does not output a dirty clock while the VCO is
locking.
0xc PRIM Controls the PLL post dividers for the primary output
PLL: CS Register
Offset: 0x0
Description
Control and Status
GENERAL CONSTRAINTS:
Reference clock frequency min=5MHz, max=800MHz
Feedback divider min=16, max=320
VCO frequency min=400MHz, max=1600MHz
30:9 Reserved. - - -
8 BYPASS Passes the reference clock to the output instead of the RW 0x0
divided VCO. The VCO continues to run so the user can
switch between the reference clock and the divided VCO
but the output will glitch when doing so.
7:6 Reserved. - - -
Description
Controls the PLL power modes.
31:6 Reserved. - - -
4 Reserved. - - -
1 Reserved. - - -
Offset: 0x8
Description
Feedback divisor
(note: this PLL does not support fractional division)
31:12 Reserved. - -
Description
Controls the PLL post dividers for the primary output
(note: this PLL does not have a secondary output)
the primary output is driven from VCO divided by postdiv1*postdiv2
31:19 Reserved. - - -
15 Reserved. - - -
11:0 Reserved. - - -
2.19. GPIO
2.19.1. Overview
RP2040 has 36 multi-functional General Purpose Input / Output (GPIO) pins, divided into two banks. In a typical use
case, the pins in the QSPI bank (QSPI_SS, QSPI_SCLK and QSPI_SD0 to QSPI_SD3) are used to execute code from an
external flash device, leaving the User bank (GPIO0 to GPIO29) for the programmer to use. All GPIOs support digital
input and output, but GPIO26 to GPIO29 can also be used as inputs to the chip’s Analogue to Digital Converter (ADC).
Each GPIO can be controlled directly by software running on the processors, or by a number of other functional blocks.
• Software control via SIO (Single-Cycle IO) - Section 2.3.1.2, “GPIO Control”
• Programmable IO (PIO) - Chapter 3, PIO
• 2 x SPI - Section 4.4, “SPI”
• 2 x UART - Section 4.2, “UART”
• 2 x I2C (two-wire serial interface) - Section 4.3, “I2C”
• 8 x two-channel PWM - Section 4.5, “PWM”
• 2 x external clock inputs - Section 2.15.2.3, “External Clocks”
• 4 x general purpose clock output - Section 2.15, “Clocks”
• Software control via SIO (Single-Cycle IO) - Section 2.3.1.2, “GPIO Control”
• Flash execute in place (XIP) - Section 2.6.3, “Flash”
The logical structure of an example IO is shown in Figure 36.
0 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB OVCUR DET
1 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS DET
2 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB VBUS EN
3 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB OVCUR DET
4 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 USB VBUS DET
5 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 USB VBUS EN
6 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 USB OVCUR DET
7 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 USB VBUS DET
8 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 USB VBUS EN
9 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 USB OVCUR DET
10 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS DET
11 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB VBUS EN
12 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB OVCUR DET
13 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS DET
Function
14 SPI1 SCK UART0 CTS I2C1 SDA PWM7 A SIO PIO0 PIO1 USB VBUS EN
15 SPI1 TX UART0 RTS I2C1 SCL PWM7 B SIO PIO0 PIO1 USB OVCUR DET
16 SPI0 RX UART0 TX I2C0 SDA PWM0 A SIO PIO0 PIO1 USB VBUS DET
17 SPI0 CSn UART0 RX I2C0 SCL PWM0 B SIO PIO0 PIO1 USB VBUS EN
18 SPI0 SCK UART0 CTS I2C1 SDA PWM1 A SIO PIO0 PIO1 USB OVCUR DET
19 SPI0 TX UART0 RTS I2C1 SCL PWM1 B SIO PIO0 PIO1 USB VBUS DET
20 SPI0 RX UART1 TX I2C0 SDA PWM2 A SIO PIO0 PIO1 CLOCK GPIN0 USB VBUS EN
21 SPI0 CSn UART1 RX I2C0 SCL PWM2 B SIO PIO0 PIO1 CLOCK GPOUT0 USB OVCUR DET
22 SPI0 SCK UART1 CTS I2C1 SDA PWM3 A SIO PIO0 PIO1 CLOCK GPIN1 USB VBUS DET
23 SPI0 TX UART1 RTS I2C1 SCL PWM3 B SIO PIO0 PIO1 CLOCK GPOUT1 USB VBUS EN
24 SPI1 RX UART1 TX I2C0 SDA PWM4 A SIO PIO0 PIO1 CLOCK GPOUT2 USB OVCUR DET
25 SPI1 CSn UART1 RX I2C0 SCL PWM4 B SIO PIO0 PIO1 CLOCK GPOUT3 USB VBUS DET
26 SPI1 SCK UART1 CTS I2C1 SDA PWM5 A SIO PIO0 PIO1 USB VBUS EN
27 SPI1 TX UART1 RTS I2C1 SCL PWM5 B SIO PIO0 PIO1 USB OVCUR DET
28 SPI1 RX UART0 TX I2C0 SDA PWM6 A SIO PIO0 PIO1 USB VBUS DET
29 SPI1 CSn UART0 RX I2C0 SCL PWM6 B SIO PIO0 PIO1 USB VBUS EN
Each GPIO can have one function selected at a time. Likewise, each peripheral input (e.g. UART0 RX) should only be
selected on one GPIO at a time. If the same peripheral input is connected to multiple GPIOs, the peripheral sees the
logical OR of these GPIO inputs.
PWMx A/B Connect a PWM slice to GPIO. There are eight PWM slices, each with two output
channels (A/B). The B pin can also be used as an input, for frequency and duty cycle
measurement.
SIO Software control of GPIO, from the single-cycle IO (SIO) block. The SIO function (F5)
must be selected for the processors to drive a GPIO, but the input is always connected,
so software can check the state of GPIOs at any time.
PIOx Connect one of the programmable IO blocks (PIO) to GPIO. PIO can implement a wide
variety of interfaces, and has its own internal pin mapping hardware, allowing flexible
placement of digital interfaces on user bank GPIOs. The PIO function (F6, F7) must be
selected for PIO to drive a GPIO, but the input is always connected, so the PIOs can
always see the state of all pins.
CLOCK GPINx General purpose clock inputs. Can be routed to a number of internal clock domains on
RP2040, e.g. to provide a 1 Hz clock for the RTC, or can be connected to an internal
frequency counter.
CLOCK GPOUTx General purpose clock outputs. Can drive a number of internal clocks onto GPIOs, with
optional integer divide.
USB OVCUR DET/VBUS USB power control signals to/from the internal USB controller
DET/VBUS EN
SIO Software control of GPIO, from the single-cycle IO (SIO) block. The SIO function (F5) must be selected
for the processors to drive a GPIO, but the input is always connected, so software can check the state
of GPIOs at any time. The QSPI IOs are controlled via the SIO_GPIO_HI_x registers, and are mapped to
register bits in the order SCK, CSn, SD0, SD1, SD2, SD3, starting at the LSB.
The six QSPI Bank GPIO pins are typically used by the XIP peripheral to communicate with an external flash device.
However, there are two scenarios where the pins can be used as software-controlled GPIOs:
• If a SPI or Dual-SPI flash device is used for execute-in-place, then the SD2 and SD3 pins are not used for flash
access, and can be used for other GPIO functions on the circuit board.
• If RP2040 is used in a flashless configuration (USB boot only), then all six pins can be used for software-controlled
GPIO functions
2.19.3. Interrupts
An interrupt can be generated for every GPIO pin in four scenarios:
There are enable , status, and force registers for three interrupt destinations: proc 0, proc 1, and dormant_wake. For
proc 0 the registers are enable (PROC0_INTE0), status (PROC0_INTS0), and force (PROC0_INTF0) . Dormant wake is
used to wake the ROSC or XOSC up from dormant mode. See Section 2.11.5.2 for more information on dormant mode.
All interrupts are ORed together per-bank per-destination resulting in a total of six GPIO interrupts:
• IO bank 0 to proc 0
• IO bank 0 to proc 1
• IO QPSI to dormant wake
• IO QPSI to proc 0
• IO QPSI to proc 1
This means the user can watch for several GPIO events at once.
2.19.4. Pads
Each GPIO is connected to the off-chip world via a "pad". Pads are the electrical interface between the chip’s internal
logic and external circuitry. They translate signal voltage levels, support higher currents and offer some protection
against electrostatic discharge (ESD) events. Pad electrical behaviour can be adjusted to meet the requirements of the
external circuitry. The following adjustments are available:
Drive Strength
2
Input Enable
Input Data
Schmitt Trigger
The pad’s Output Enable, Output Data and Input Data ports are connected, via the IO mux, to the function controlling the
pad. All other ports are controlled from the pad control register. The register also allows the pad’s output driver to be
disabled, by overriding the Output Enable signal from the function controlling the pad. See GPIO0 for an example of a
pad control register.
Both the output signal level and acceptable input signal level at the pad are determined by the digital IO supply (IOVDD).
IOVDD can be any nominal voltage between 1.8V and 3.3V, but to meet specification when powered at 1.8V, the pad
input thresholds must be adjusted by writing a 1 to the pad VOLTAGE_SELECT registers. By default the pad input thresholds
are valid for an IOVDD voltage between 2.5V and 3.3V. Using a voltage of 1.8V with the default input thresholds is a safe
operating mode, though it will result in input thresholds that don’t meet specification.
WARNING
Using IOVDD voltages greater than 1.8V, with the input thresholds set for 1.8V may result in damage to the chip.
Pad input threshold are adjusted on a per bank basis, with separate VOLTAGE_SELECT registers for the pads associated with
the User IO bank (IO Bank 0) and the QSPI IO bank. However, both banks share the same digital IO supply (IOVDD), so
both register should always be set to the same value.
Pad register details are available in Section 2.19.6.3, “Pad Control - User Bank” and Section 2.19.6.4, “Pad Control - QSPI
Bank”.
An IO pin can perform many different functions and must be configured before use. For example, you may want it to be
a UART_TX pin, or a PWM output. The SDK provides gpio_set_function for this purpose. Many SDK examples will call
gpio_set_function at the beginning so that it can print to a UART.
The SDK starts by defining a structure to represent the registers of IO bank 0, the User IO bank. Each IO has a status
register, followed by a control register. There are 30 IOs, so the structure containing a status and control register is
instantiated as io[30] to repeat it 30 times.
21 typedef struct {
22 struct {
23 io_rw_32 status;
24 io_rw_32 ctrl;
25 } io[30];
26 io_rw_32 intr[4];
27 io_irq_ctrl_hw_t proc0_irq_ctrl;
28 io_irq_ctrl_hw_t proc1_irq_ctrl;
29 io_irq_ctrl_hw_t dormant_wake_irq_ctrl;
30 } iobank0_hw_t;
A similar structure is defined for the pad control registers for IO bank 1. By default, all pads come out of reset ready to
use, with their input enabled and output disable set to 0. Regardless, gpio_set_function in the SDK sets these to make
sure the pad is ready to use by the selected function. Finally, the desired function select is written to the IO control
register (see GPIO0_CTRL for an example of an IO control register).
26 // Select function for this GPIO, and ensure input/output are enabled at the pad.
27 // This also clears the input/output/irq override bits.
28 void gpio_set_function(uint gpio, enum gpio_function fn) {
29 invalid_params_if(GPIO, gpio >= NUM_BANK0_GPIOS);
30 invalid_params_if(GPIO, fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB &
~IO_BANK0_GPIO0_CTRL_FUNCSEL_BITS);
31 // Set input enable on, output disable off
32 hw_write_masked(&padsbank0_hw->io[gpio],
33 PADS_BANK0_GPIO0_IE_BITS,
34 PADS_BANK0_GPIO0_IE_BITS | PADS_BANK0_GPIO0_OD_BITS
35 );
36 // Zero all fields apart from fsel; we want this IO to do what the peripheral tells it.
37 // This doesn't affect e.g. pullup/pulldown, as these are in pad controls.
38 iobank0_hw->io[gpio].ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB;
39 }
The SDK provides a method of being interrupted when a GPIO pin changes state:
The user provides a pointer to a callback function that is called when the GPIO event happens. An example application
that uses this system is hello_gpio_irq:
1 /**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdio.h>
8 #include "pico/stdlib.h"
9 #include "hardware/gpio.h"
10
11 static char event_str[128];
12
13 void gpio_event_string(char *buf, uint32_t events);
14
15 void gpio_callback(uint gpio, uint32_t events) {
16 // Put the GPIO event(s) that just happened into event_str
17 // so we can print it
18 gpio_event_string(event_str, events);
19 printf("GPIO %d %s\n", gpio, event_str);
20 }
21
22 int main() {
23 stdio_init_all();
24
25 printf("Hello GPIO IRQ\n");
26 gpio_set_irq_enabled_with_callback(2, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true,
&gpio_callback);
27
28 // Wait forever
29 while (1);
30
31 return 0;
32 }
33
34
35 static const char *gpio_irq_str[] = {
36 "LEVEL_LOW", // 0x1
37 "LEVEL_HIGH", // 0x2
38 "EDGE_FALL", // 0x4
39 "EDGE_RISE" // 0x8
40 };
41
42 void gpio_event_string(char *buf, uint32_t events) {
43 for (uint i = 0; i < 4; i++) {
44 uint mask = (1 << i);
45 if (events & mask) {
46 // Copy this event string into the user string
47 const char *event_str = gpio_irq_str[i];
48 while (*event_str != '\0') {
49 *buf++ = *event_str++;
50 }
51 events &= ~mask;
52
53 // If more events add ", "
54 if (events) {
55 *buf++ = ',';
56 *buf++ = ' ';
57 }
58 }
59 }
60 *buf++ = '\0';
61 }
The User Bank IO registers start at a base address of 0x40014000 (defined as IO_BANK0_BASE in SDK).
0x120 PROC0_INTS0 Interrupt status after masking & forcing for proc0
0x124 PROC0_INTS1 Interrupt status after masking & forcing for proc0
0x128 PROC0_INTS2 Interrupt status after masking & forcing for proc0
0x12c PROC0_INTS3 Interrupt status after masking & forcing for proc0
0x150 PROC1_INTS0 Interrupt status after masking & forcing for proc1
0x154 PROC1_INTS1 Interrupt status after masking & forcing for proc1
0x158 PROC1_INTS2 Interrupt status after masking & forcing for proc1
0x15c PROC1_INTS3 Interrupt status after masking & forcing for proc1
0x180 DORMANT_WAKE_INTS0 Interrupt status after masking & forcing for dormant_wake
0x184 DORMANT_WAKE_INTS1 Interrupt status after masking & forcing for dormant_wake
0x188 DORMANT_WAKE_INTS2 Interrupt status after masking & forcing for dormant_wake
0x18c DORMANT_WAKE_INTS3 Interrupt status after masking & forcing for dormant_wake
Description
GPIO status
Table 294.
Bits Name Description Type Reset
GPIO0_STATUS,
GPIO1_STATUS, …,
31:27 Reserved. - - -
GPIO28_STATUS,
GPIO29_STATUS
26 IRQTOPROC interrupt to processors, after override is applied RO 0x0
Registers
25 Reserved. - - -
23:20 Reserved. - - -
18 Reserved. - - -
16:14 Reserved. - - -
11:10 Reserved. - - -
7:0 Reserved. - - -
Description
GPIO control including function select and overrides.
Table 295.
Bits Name Description Type Reset
GPIO0_CTRL,
GPIO1_CTRL, …,
31:30 Reserved. - - -
GPIO28_CTRL,
GPIO29_CTRL
29:28 IRQOVER 0x0 → don’t invert the interrupt RW 0x0
Registers
0x1 → invert the interrupt
0x2 → drive interrupt low
0x3 → drive interrupt high
27:18 Reserved. - - -
15:14 Reserved. - - -
13:12 OEOVER 0x0 → drive output enable from peripheral signal selected RW 0x0
by funcsel
0x1 → drive output enable from inverse of peripheral
signal selected by funcsel
0x2 → disable output
0x3 → enable output
11:10 Reserved. - - -
9:8 OUTOVER 0x0 → drive output from peripheral signal selected by RW 0x0
funcsel
0x1 → drive output from inverse of peripheral signal
selected by funcsel
0x2 → drive output low
0x3 → drive output high
7:5 Reserved. - - -
4:0 FUNCSEL Function select. 31 == NULL. See GPIO function table for RW 0x1f
available functions.
Description
Raw Interrupts
31 GPIO7_EDGE_HIGH WC 0x0
30 GPIO7_EDGE_LOW WC 0x0
29 GPIO7_LEVEL_HIGH RO 0x0
28 GPIO7_LEVEL_LOW RO 0x0
27 GPIO6_EDGE_HIGH WC 0x0
26 GPIO6_EDGE_LOW WC 0x0
25 GPIO6_LEVEL_HIGH RO 0x0
24 GPIO6_LEVEL_LOW RO 0x0
23 GPIO5_EDGE_HIGH WC 0x0
22 GPIO5_EDGE_LOW WC 0x0
21 GPIO5_LEVEL_HIGH RO 0x0
20 GPIO5_LEVEL_LOW RO 0x0
19 GPIO4_EDGE_HIGH WC 0x0
18 GPIO4_EDGE_LOW WC 0x0
17 GPIO4_LEVEL_HIGH RO 0x0
16 GPIO4_LEVEL_LOW RO 0x0
15 GPIO3_EDGE_HIGH WC 0x0
14 GPIO3_EDGE_LOW WC 0x0
13 GPIO3_LEVEL_HIGH RO 0x0
12 GPIO3_LEVEL_LOW RO 0x0
11 GPIO2_EDGE_HIGH WC 0x0
10 GPIO2_EDGE_LOW WC 0x0
9 GPIO2_LEVEL_HIGH RO 0x0
8 GPIO2_LEVEL_LOW RO 0x0
7 GPIO1_EDGE_HIGH WC 0x0
6 GPIO1_EDGE_LOW WC 0x0
5 GPIO1_LEVEL_HIGH RO 0x0
4 GPIO1_LEVEL_LOW RO 0x0
3 GPIO0_EDGE_HIGH WC 0x0
2 GPIO0_EDGE_LOW WC 0x0
1 GPIO0_LEVEL_HIGH RO 0x0
0 GPIO0_LEVEL_LOW RO 0x0
Description
Raw Interrupts
31 GPIO15_EDGE_HIGH WC 0x0
30 GPIO15_EDGE_LOW WC 0x0
29 GPIO15_LEVEL_HIGH RO 0x0
28 GPIO15_LEVEL_LOW RO 0x0
27 GPIO14_EDGE_HIGH WC 0x0
26 GPIO14_EDGE_LOW WC 0x0
25 GPIO14_LEVEL_HIGH RO 0x0
24 GPIO14_LEVEL_LOW RO 0x0
23 GPIO13_EDGE_HIGH WC 0x0
22 GPIO13_EDGE_LOW WC 0x0
21 GPIO13_LEVEL_HIGH RO 0x0
20 GPIO13_LEVEL_LOW RO 0x0
19 GPIO12_EDGE_HIGH WC 0x0
18 GPIO12_EDGE_LOW WC 0x0
17 GPIO12_LEVEL_HIGH RO 0x0
16 GPIO12_LEVEL_LOW RO 0x0
15 GPIO11_EDGE_HIGH WC 0x0
14 GPIO11_EDGE_LOW WC 0x0
13 GPIO11_LEVEL_HIGH RO 0x0
12 GPIO11_LEVEL_LOW RO 0x0
11 GPIO10_EDGE_HIGH WC 0x0
10 GPIO10_EDGE_LOW WC 0x0
9 GPIO10_LEVEL_HIGH RO 0x0
8 GPIO10_LEVEL_LOW RO 0x0
7 GPIO9_EDGE_HIGH WC 0x0
6 GPIO9_EDGE_LOW WC 0x0
5 GPIO9_LEVEL_HIGH RO 0x0
4 GPIO9_LEVEL_LOW RO 0x0
3 GPIO8_EDGE_HIGH WC 0x0
2 GPIO8_EDGE_LOW WC 0x0
1 GPIO8_LEVEL_HIGH RO 0x0
0 GPIO8_LEVEL_LOW RO 0x0
Description
Raw Interrupts
31 GPIO23_EDGE_HIGH WC 0x0
30 GPIO23_EDGE_LOW WC 0x0
29 GPIO23_LEVEL_HIGH RO 0x0
28 GPIO23_LEVEL_LOW RO 0x0
27 GPIO22_EDGE_HIGH WC 0x0
26 GPIO22_EDGE_LOW WC 0x0
25 GPIO22_LEVEL_HIGH RO 0x0
24 GPIO22_LEVEL_LOW RO 0x0
23 GPIO21_EDGE_HIGH WC 0x0
22 GPIO21_EDGE_LOW WC 0x0
21 GPIO21_LEVEL_HIGH RO 0x0
20 GPIO21_LEVEL_LOW RO 0x0
19 GPIO20_EDGE_HIGH WC 0x0
18 GPIO20_EDGE_LOW WC 0x0
17 GPIO20_LEVEL_HIGH RO 0x0
16 GPIO20_LEVEL_LOW RO 0x0
15 GPIO19_EDGE_HIGH WC 0x0
14 GPIO19_EDGE_LOW WC 0x0
13 GPIO19_LEVEL_HIGH RO 0x0
12 GPIO19_LEVEL_LOW RO 0x0
11 GPIO18_EDGE_HIGH WC 0x0
10 GPIO18_EDGE_LOW WC 0x0
9 GPIO18_LEVEL_HIGH RO 0x0
8 GPIO18_LEVEL_LOW RO 0x0
7 GPIO17_EDGE_HIGH WC 0x0
6 GPIO17_EDGE_LOW WC 0x0
5 GPIO17_LEVEL_HIGH RO 0x0
4 GPIO17_LEVEL_LOW RO 0x0
3 GPIO16_EDGE_HIGH WC 0x0
2 GPIO16_EDGE_LOW WC 0x0
1 GPIO16_LEVEL_HIGH RO 0x0
0 GPIO16_LEVEL_LOW RO 0x0
Description
Raw Interrupts
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH WC 0x0
22 GPIO29_EDGE_LOW WC 0x0
21 GPIO29_LEVEL_HIGH RO 0x0
20 GPIO29_LEVEL_LOW RO 0x0
19 GPIO28_EDGE_HIGH WC 0x0
18 GPIO28_EDGE_LOW WC 0x0
17 GPIO28_LEVEL_HIGH RO 0x0
16 GPIO28_LEVEL_LOW RO 0x0
15 GPIO27_EDGE_HIGH WC 0x0
14 GPIO27_EDGE_LOW WC 0x0
13 GPIO27_LEVEL_HIGH RO 0x0
12 GPIO27_LEVEL_LOW RO 0x0
11 GPIO26_EDGE_HIGH WC 0x0
10 GPIO26_EDGE_LOW WC 0x0
9 GPIO26_LEVEL_HIGH RO 0x0
8 GPIO26_LEVEL_LOW RO 0x0
7 GPIO25_EDGE_HIGH WC 0x0
6 GPIO25_EDGE_LOW WC 0x0
5 GPIO25_LEVEL_HIGH RO 0x0
4 GPIO25_LEVEL_LOW RO 0x0
3 GPIO24_EDGE_HIGH WC 0x0
2 GPIO24_EDGE_LOW WC 0x0
1 GPIO24_LEVEL_HIGH RO 0x0
0 GPIO24_LEVEL_LOW RO 0x0
Description
Interrupt Enable for proc0
Table 300.
Bits Name Description Type Reset
PROC0_INTE0 Register
31 GPIO7_EDGE_HIGH RW 0x0
30 GPIO7_EDGE_LOW RW 0x0
29 GPIO7_LEVEL_HIGH RW 0x0
28 GPIO7_LEVEL_LOW RW 0x0
27 GPIO6_EDGE_HIGH RW 0x0
26 GPIO6_EDGE_LOW RW 0x0
25 GPIO6_LEVEL_HIGH RW 0x0
24 GPIO6_LEVEL_LOW RW 0x0
23 GPIO5_EDGE_HIGH RW 0x0
22 GPIO5_EDGE_LOW RW 0x0
21 GPIO5_LEVEL_HIGH RW 0x0
20 GPIO5_LEVEL_LOW RW 0x0
19 GPIO4_EDGE_HIGH RW 0x0
18 GPIO4_EDGE_LOW RW 0x0
17 GPIO4_LEVEL_HIGH RW 0x0
16 GPIO4_LEVEL_LOW RW 0x0
15 GPIO3_EDGE_HIGH RW 0x0
14 GPIO3_EDGE_LOW RW 0x0
13 GPIO3_LEVEL_HIGH RW 0x0
12 GPIO3_LEVEL_LOW RW 0x0
11 GPIO2_EDGE_HIGH RW 0x0
10 GPIO2_EDGE_LOW RW 0x0
9 GPIO2_LEVEL_HIGH RW 0x0
8 GPIO2_LEVEL_LOW RW 0x0
7 GPIO1_EDGE_HIGH RW 0x0
6 GPIO1_EDGE_LOW RW 0x0
5 GPIO1_LEVEL_HIGH RW 0x0
4 GPIO1_LEVEL_LOW RW 0x0
3 GPIO0_EDGE_HIGH RW 0x0
2 GPIO0_EDGE_LOW RW 0x0
1 GPIO0_LEVEL_HIGH RW 0x0
0 GPIO0_LEVEL_LOW RW 0x0
Description
Interrupt Enable for proc0
Table 301.
Bits Name Description Type Reset
PROC0_INTE1 Register
31 GPIO15_EDGE_HIGH RW 0x0
30 GPIO15_EDGE_LOW RW 0x0
29 GPIO15_LEVEL_HIGH RW 0x0
28 GPIO15_LEVEL_LOW RW 0x0
27 GPIO14_EDGE_HIGH RW 0x0
26 GPIO14_EDGE_LOW RW 0x0
25 GPIO14_LEVEL_HIGH RW 0x0
24 GPIO14_LEVEL_LOW RW 0x0
23 GPIO13_EDGE_HIGH RW 0x0
22 GPIO13_EDGE_LOW RW 0x0
21 GPIO13_LEVEL_HIGH RW 0x0
20 GPIO13_LEVEL_LOW RW 0x0
19 GPIO12_EDGE_HIGH RW 0x0
18 GPIO12_EDGE_LOW RW 0x0
17 GPIO12_LEVEL_HIGH RW 0x0
16 GPIO12_LEVEL_LOW RW 0x0
15 GPIO11_EDGE_HIGH RW 0x0
14 GPIO11_EDGE_LOW RW 0x0
13 GPIO11_LEVEL_HIGH RW 0x0
12 GPIO11_LEVEL_LOW RW 0x0
11 GPIO10_EDGE_HIGH RW 0x0
10 GPIO10_EDGE_LOW RW 0x0
9 GPIO10_LEVEL_HIGH RW 0x0
8 GPIO10_LEVEL_LOW RW 0x0
7 GPIO9_EDGE_HIGH RW 0x0
6 GPIO9_EDGE_LOW RW 0x0
5 GPIO9_LEVEL_HIGH RW 0x0
4 GPIO9_LEVEL_LOW RW 0x0
3 GPIO8_EDGE_HIGH RW 0x0
2 GPIO8_EDGE_LOW RW 0x0
1 GPIO8_LEVEL_HIGH RW 0x0
0 GPIO8_LEVEL_LOW RW 0x0
Description
Interrupt Enable for proc0
Table 302.
Bits Name Description Type Reset
PROC0_INTE2 Register
31 GPIO23_EDGE_HIGH RW 0x0
30 GPIO23_EDGE_LOW RW 0x0
29 GPIO23_LEVEL_HIGH RW 0x0
28 GPIO23_LEVEL_LOW RW 0x0
27 GPIO22_EDGE_HIGH RW 0x0
26 GPIO22_EDGE_LOW RW 0x0
25 GPIO22_LEVEL_HIGH RW 0x0
24 GPIO22_LEVEL_LOW RW 0x0
23 GPIO21_EDGE_HIGH RW 0x0
22 GPIO21_EDGE_LOW RW 0x0
21 GPIO21_LEVEL_HIGH RW 0x0
20 GPIO21_LEVEL_LOW RW 0x0
19 GPIO20_EDGE_HIGH RW 0x0
18 GPIO20_EDGE_LOW RW 0x0
17 GPIO20_LEVEL_HIGH RW 0x0
16 GPIO20_LEVEL_LOW RW 0x0
15 GPIO19_EDGE_HIGH RW 0x0
14 GPIO19_EDGE_LOW RW 0x0
13 GPIO19_LEVEL_HIGH RW 0x0
12 GPIO19_LEVEL_LOW RW 0x0
11 GPIO18_EDGE_HIGH RW 0x0
10 GPIO18_EDGE_LOW RW 0x0
9 GPIO18_LEVEL_HIGH RW 0x0
8 GPIO18_LEVEL_LOW RW 0x0
7 GPIO17_EDGE_HIGH RW 0x0
6 GPIO17_EDGE_LOW RW 0x0
5 GPIO17_LEVEL_HIGH RW 0x0
4 GPIO17_LEVEL_LOW RW 0x0
3 GPIO16_EDGE_HIGH RW 0x0
2 GPIO16_EDGE_LOW RW 0x0
1 GPIO16_LEVEL_HIGH RW 0x0
0 GPIO16_LEVEL_LOW RW 0x0
Description
Interrupt Enable for proc0
Table 303.
Bits Name Description Type Reset
PROC0_INTE3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RW 0x0
22 GPIO29_EDGE_LOW RW 0x0
21 GPIO29_LEVEL_HIGH RW 0x0
20 GPIO29_LEVEL_LOW RW 0x0
19 GPIO28_EDGE_HIGH RW 0x0
18 GPIO28_EDGE_LOW RW 0x0
17 GPIO28_LEVEL_HIGH RW 0x0
16 GPIO28_LEVEL_LOW RW 0x0
15 GPIO27_EDGE_HIGH RW 0x0
14 GPIO27_EDGE_LOW RW 0x0
13 GPIO27_LEVEL_HIGH RW 0x0
12 GPIO27_LEVEL_LOW RW 0x0
11 GPIO26_EDGE_HIGH RW 0x0
10 GPIO26_EDGE_LOW RW 0x0
9 GPIO26_LEVEL_HIGH RW 0x0
8 GPIO26_LEVEL_LOW RW 0x0
7 GPIO25_EDGE_HIGH RW 0x0
6 GPIO25_EDGE_LOW RW 0x0
5 GPIO25_LEVEL_HIGH RW 0x0
4 GPIO25_LEVEL_LOW RW 0x0
3 GPIO24_EDGE_HIGH RW 0x0
2 GPIO24_EDGE_LOW RW 0x0
1 GPIO24_LEVEL_HIGH RW 0x0
0 GPIO24_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc0
Table 304.
Bits Name Description Type Reset
PROC0_INTF0 Register
31 GPIO7_EDGE_HIGH RW 0x0
30 GPIO7_EDGE_LOW RW 0x0
29 GPIO7_LEVEL_HIGH RW 0x0
28 GPIO7_LEVEL_LOW RW 0x0
27 GPIO6_EDGE_HIGH RW 0x0
26 GPIO6_EDGE_LOW RW 0x0
25 GPIO6_LEVEL_HIGH RW 0x0
24 GPIO6_LEVEL_LOW RW 0x0
23 GPIO5_EDGE_HIGH RW 0x0
22 GPIO5_EDGE_LOW RW 0x0
21 GPIO5_LEVEL_HIGH RW 0x0
20 GPIO5_LEVEL_LOW RW 0x0
19 GPIO4_EDGE_HIGH RW 0x0
18 GPIO4_EDGE_LOW RW 0x0
17 GPIO4_LEVEL_HIGH RW 0x0
16 GPIO4_LEVEL_LOW RW 0x0
15 GPIO3_EDGE_HIGH RW 0x0
14 GPIO3_EDGE_LOW RW 0x0
13 GPIO3_LEVEL_HIGH RW 0x0
12 GPIO3_LEVEL_LOW RW 0x0
11 GPIO2_EDGE_HIGH RW 0x0
10 GPIO2_EDGE_LOW RW 0x0
9 GPIO2_LEVEL_HIGH RW 0x0
8 GPIO2_LEVEL_LOW RW 0x0
7 GPIO1_EDGE_HIGH RW 0x0
6 GPIO1_EDGE_LOW RW 0x0
5 GPIO1_LEVEL_HIGH RW 0x0
4 GPIO1_LEVEL_LOW RW 0x0
3 GPIO0_EDGE_HIGH RW 0x0
2 GPIO0_EDGE_LOW RW 0x0
1 GPIO0_LEVEL_HIGH RW 0x0
0 GPIO0_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc0
Table 305.
Bits Name Description Type Reset
PROC0_INTF1 Register
31 GPIO15_EDGE_HIGH RW 0x0
30 GPIO15_EDGE_LOW RW 0x0
29 GPIO15_LEVEL_HIGH RW 0x0
28 GPIO15_LEVEL_LOW RW 0x0
27 GPIO14_EDGE_HIGH RW 0x0
26 GPIO14_EDGE_LOW RW 0x0
25 GPIO14_LEVEL_HIGH RW 0x0
24 GPIO14_LEVEL_LOW RW 0x0
23 GPIO13_EDGE_HIGH RW 0x0
22 GPIO13_EDGE_LOW RW 0x0
21 GPIO13_LEVEL_HIGH RW 0x0
20 GPIO13_LEVEL_LOW RW 0x0
19 GPIO12_EDGE_HIGH RW 0x0
18 GPIO12_EDGE_LOW RW 0x0
17 GPIO12_LEVEL_HIGH RW 0x0
16 GPIO12_LEVEL_LOW RW 0x0
15 GPIO11_EDGE_HIGH RW 0x0
14 GPIO11_EDGE_LOW RW 0x0
13 GPIO11_LEVEL_HIGH RW 0x0
12 GPIO11_LEVEL_LOW RW 0x0
11 GPIO10_EDGE_HIGH RW 0x0
10 GPIO10_EDGE_LOW RW 0x0
9 GPIO10_LEVEL_HIGH RW 0x0
8 GPIO10_LEVEL_LOW RW 0x0
7 GPIO9_EDGE_HIGH RW 0x0
6 GPIO9_EDGE_LOW RW 0x0
5 GPIO9_LEVEL_HIGH RW 0x0
4 GPIO9_LEVEL_LOW RW 0x0
3 GPIO8_EDGE_HIGH RW 0x0
2 GPIO8_EDGE_LOW RW 0x0
1 GPIO8_LEVEL_HIGH RW 0x0
0 GPIO8_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc0
Table 306.
Bits Name Description Type Reset
PROC0_INTF2 Register
31 GPIO23_EDGE_HIGH RW 0x0
30 GPIO23_EDGE_LOW RW 0x0
29 GPIO23_LEVEL_HIGH RW 0x0
28 GPIO23_LEVEL_LOW RW 0x0
27 GPIO22_EDGE_HIGH RW 0x0
26 GPIO22_EDGE_LOW RW 0x0
25 GPIO22_LEVEL_HIGH RW 0x0
24 GPIO22_LEVEL_LOW RW 0x0
23 GPIO21_EDGE_HIGH RW 0x0
22 GPIO21_EDGE_LOW RW 0x0
21 GPIO21_LEVEL_HIGH RW 0x0
20 GPIO21_LEVEL_LOW RW 0x0
19 GPIO20_EDGE_HIGH RW 0x0
18 GPIO20_EDGE_LOW RW 0x0
17 GPIO20_LEVEL_HIGH RW 0x0
16 GPIO20_LEVEL_LOW RW 0x0
15 GPIO19_EDGE_HIGH RW 0x0
14 GPIO19_EDGE_LOW RW 0x0
13 GPIO19_LEVEL_HIGH RW 0x0
12 GPIO19_LEVEL_LOW RW 0x0
11 GPIO18_EDGE_HIGH RW 0x0
10 GPIO18_EDGE_LOW RW 0x0
9 GPIO18_LEVEL_HIGH RW 0x0
8 GPIO18_LEVEL_LOW RW 0x0
7 GPIO17_EDGE_HIGH RW 0x0
6 GPIO17_EDGE_LOW RW 0x0
5 GPIO17_LEVEL_HIGH RW 0x0
4 GPIO17_LEVEL_LOW RW 0x0
3 GPIO16_EDGE_HIGH RW 0x0
2 GPIO16_EDGE_LOW RW 0x0
1 GPIO16_LEVEL_HIGH RW 0x0
0 GPIO16_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc0
Table 307.
Bits Name Description Type Reset
PROC0_INTF3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RW 0x0
22 GPIO29_EDGE_LOW RW 0x0
21 GPIO29_LEVEL_HIGH RW 0x0
20 GPIO29_LEVEL_LOW RW 0x0
19 GPIO28_EDGE_HIGH RW 0x0
18 GPIO28_EDGE_LOW RW 0x0
17 GPIO28_LEVEL_HIGH RW 0x0
16 GPIO28_LEVEL_LOW RW 0x0
15 GPIO27_EDGE_HIGH RW 0x0
14 GPIO27_EDGE_LOW RW 0x0
13 GPIO27_LEVEL_HIGH RW 0x0
12 GPIO27_LEVEL_LOW RW 0x0
11 GPIO26_EDGE_HIGH RW 0x0
10 GPIO26_EDGE_LOW RW 0x0
9 GPIO26_LEVEL_HIGH RW 0x0
8 GPIO26_LEVEL_LOW RW 0x0
7 GPIO25_EDGE_HIGH RW 0x0
6 GPIO25_EDGE_LOW RW 0x0
5 GPIO25_LEVEL_HIGH RW 0x0
4 GPIO25_LEVEL_LOW RW 0x0
3 GPIO24_EDGE_HIGH RW 0x0
2 GPIO24_EDGE_LOW RW 0x0
1 GPIO24_LEVEL_HIGH RW 0x0
0 GPIO24_LEVEL_LOW RW 0x0
Description
Interrupt status after masking & forcing for proc0
Table 308.
Bits Name Description Type Reset
PROC0_INTS0
Register
31 GPIO7_EDGE_HIGH RO 0x0
30 GPIO7_EDGE_LOW RO 0x0
29 GPIO7_LEVEL_HIGH RO 0x0
28 GPIO7_LEVEL_LOW RO 0x0
27 GPIO6_EDGE_HIGH RO 0x0
26 GPIO6_EDGE_LOW RO 0x0
25 GPIO6_LEVEL_HIGH RO 0x0
24 GPIO6_LEVEL_LOW RO 0x0
23 GPIO5_EDGE_HIGH RO 0x0
22 GPIO5_EDGE_LOW RO 0x0
21 GPIO5_LEVEL_HIGH RO 0x0
20 GPIO5_LEVEL_LOW RO 0x0
19 GPIO4_EDGE_HIGH RO 0x0
18 GPIO4_EDGE_LOW RO 0x0
17 GPIO4_LEVEL_HIGH RO 0x0
16 GPIO4_LEVEL_LOW RO 0x0
15 GPIO3_EDGE_HIGH RO 0x0
14 GPIO3_EDGE_LOW RO 0x0
13 GPIO3_LEVEL_HIGH RO 0x0
12 GPIO3_LEVEL_LOW RO 0x0
11 GPIO2_EDGE_HIGH RO 0x0
10 GPIO2_EDGE_LOW RO 0x0
9 GPIO2_LEVEL_HIGH RO 0x0
8 GPIO2_LEVEL_LOW RO 0x0
7 GPIO1_EDGE_HIGH RO 0x0
6 GPIO1_EDGE_LOW RO 0x0
5 GPIO1_LEVEL_HIGH RO 0x0
4 GPIO1_LEVEL_LOW RO 0x0
3 GPIO0_EDGE_HIGH RO 0x0
2 GPIO0_EDGE_LOW RO 0x0
1 GPIO0_LEVEL_HIGH RO 0x0
0 GPIO0_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for proc0
Table 309.
Bits Name Description Type Reset
PROC0_INTS1
Register
31 GPIO15_EDGE_HIGH RO 0x0
30 GPIO15_EDGE_LOW RO 0x0
29 GPIO15_LEVEL_HIGH RO 0x0
28 GPIO15_LEVEL_LOW RO 0x0
27 GPIO14_EDGE_HIGH RO 0x0
26 GPIO14_EDGE_LOW RO 0x0
25 GPIO14_LEVEL_HIGH RO 0x0
24 GPIO14_LEVEL_LOW RO 0x0
23 GPIO13_EDGE_HIGH RO 0x0
22 GPIO13_EDGE_LOW RO 0x0
21 GPIO13_LEVEL_HIGH RO 0x0
20 GPIO13_LEVEL_LOW RO 0x0
19 GPIO12_EDGE_HIGH RO 0x0
18 GPIO12_EDGE_LOW RO 0x0
17 GPIO12_LEVEL_HIGH RO 0x0
16 GPIO12_LEVEL_LOW RO 0x0
15 GPIO11_EDGE_HIGH RO 0x0
14 GPIO11_EDGE_LOW RO 0x0
13 GPIO11_LEVEL_HIGH RO 0x0
12 GPIO11_LEVEL_LOW RO 0x0
11 GPIO10_EDGE_HIGH RO 0x0
10 GPIO10_EDGE_LOW RO 0x0
9 GPIO10_LEVEL_HIGH RO 0x0
8 GPIO10_LEVEL_LOW RO 0x0
7 GPIO9_EDGE_HIGH RO 0x0
6 GPIO9_EDGE_LOW RO 0x0
5 GPIO9_LEVEL_HIGH RO 0x0
4 GPIO9_LEVEL_LOW RO 0x0
3 GPIO8_EDGE_HIGH RO 0x0
2 GPIO8_EDGE_LOW RO 0x0
1 GPIO8_LEVEL_HIGH RO 0x0
0 GPIO8_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for proc0
Table 310.
Bits Name Description Type Reset
PROC0_INTS2
Register
31 GPIO23_EDGE_HIGH RO 0x0
30 GPIO23_EDGE_LOW RO 0x0
29 GPIO23_LEVEL_HIGH RO 0x0
28 GPIO23_LEVEL_LOW RO 0x0
27 GPIO22_EDGE_HIGH RO 0x0
26 GPIO22_EDGE_LOW RO 0x0
25 GPIO22_LEVEL_HIGH RO 0x0
24 GPIO22_LEVEL_LOW RO 0x0
23 GPIO21_EDGE_HIGH RO 0x0
22 GPIO21_EDGE_LOW RO 0x0
21 GPIO21_LEVEL_HIGH RO 0x0
20 GPIO21_LEVEL_LOW RO 0x0
19 GPIO20_EDGE_HIGH RO 0x0
18 GPIO20_EDGE_LOW RO 0x0
17 GPIO20_LEVEL_HIGH RO 0x0
16 GPIO20_LEVEL_LOW RO 0x0
15 GPIO19_EDGE_HIGH RO 0x0
14 GPIO19_EDGE_LOW RO 0x0
13 GPIO19_LEVEL_HIGH RO 0x0
12 GPIO19_LEVEL_LOW RO 0x0
11 GPIO18_EDGE_HIGH RO 0x0
10 GPIO18_EDGE_LOW RO 0x0
9 GPIO18_LEVEL_HIGH RO 0x0
8 GPIO18_LEVEL_LOW RO 0x0
7 GPIO17_EDGE_HIGH RO 0x0
6 GPIO17_EDGE_LOW RO 0x0
5 GPIO17_LEVEL_HIGH RO 0x0
4 GPIO17_LEVEL_LOW RO 0x0
3 GPIO16_EDGE_HIGH RO 0x0
2 GPIO16_EDGE_LOW RO 0x0
1 GPIO16_LEVEL_HIGH RO 0x0
0 GPIO16_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for proc0
Table 311.
Bits Name Description Type Reset
PROC0_INTS3
Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RO 0x0
22 GPIO29_EDGE_LOW RO 0x0
21 GPIO29_LEVEL_HIGH RO 0x0
20 GPIO29_LEVEL_LOW RO 0x0
19 GPIO28_EDGE_HIGH RO 0x0
18 GPIO28_EDGE_LOW RO 0x0
17 GPIO28_LEVEL_HIGH RO 0x0
16 GPIO28_LEVEL_LOW RO 0x0
15 GPIO27_EDGE_HIGH RO 0x0
14 GPIO27_EDGE_LOW RO 0x0
13 GPIO27_LEVEL_HIGH RO 0x0
12 GPIO27_LEVEL_LOW RO 0x0
11 GPIO26_EDGE_HIGH RO 0x0
10 GPIO26_EDGE_LOW RO 0x0
9 GPIO26_LEVEL_HIGH RO 0x0
8 GPIO26_LEVEL_LOW RO 0x0
7 GPIO25_EDGE_HIGH RO 0x0
6 GPIO25_EDGE_LOW RO 0x0
5 GPIO25_LEVEL_HIGH RO 0x0
4 GPIO25_LEVEL_LOW RO 0x0
3 GPIO24_EDGE_HIGH RO 0x0
2 GPIO24_EDGE_LOW RO 0x0
1 GPIO24_LEVEL_HIGH RO 0x0
0 GPIO24_LEVEL_LOW RO 0x0
Description
Interrupt Enable for proc1
Table 312.
Bits Name Description Type Reset
PROC1_INTE0 Register
31 GPIO7_EDGE_HIGH RW 0x0
30 GPIO7_EDGE_LOW RW 0x0
29 GPIO7_LEVEL_HIGH RW 0x0
28 GPIO7_LEVEL_LOW RW 0x0
27 GPIO6_EDGE_HIGH RW 0x0
26 GPIO6_EDGE_LOW RW 0x0
25 GPIO6_LEVEL_HIGH RW 0x0
24 GPIO6_LEVEL_LOW RW 0x0
23 GPIO5_EDGE_HIGH RW 0x0
22 GPIO5_EDGE_LOW RW 0x0
21 GPIO5_LEVEL_HIGH RW 0x0
20 GPIO5_LEVEL_LOW RW 0x0
19 GPIO4_EDGE_HIGH RW 0x0
18 GPIO4_EDGE_LOW RW 0x0
17 GPIO4_LEVEL_HIGH RW 0x0
16 GPIO4_LEVEL_LOW RW 0x0
15 GPIO3_EDGE_HIGH RW 0x0
14 GPIO3_EDGE_LOW RW 0x0
13 GPIO3_LEVEL_HIGH RW 0x0
12 GPIO3_LEVEL_LOW RW 0x0
11 GPIO2_EDGE_HIGH RW 0x0
10 GPIO2_EDGE_LOW RW 0x0
9 GPIO2_LEVEL_HIGH RW 0x0
8 GPIO2_LEVEL_LOW RW 0x0
7 GPIO1_EDGE_HIGH RW 0x0
6 GPIO1_EDGE_LOW RW 0x0
5 GPIO1_LEVEL_HIGH RW 0x0
4 GPIO1_LEVEL_LOW RW 0x0
3 GPIO0_EDGE_HIGH RW 0x0
2 GPIO0_EDGE_LOW RW 0x0
1 GPIO0_LEVEL_HIGH RW 0x0
0 GPIO0_LEVEL_LOW RW 0x0
Description
Interrupt Enable for proc1
Table 313.
Bits Name Description Type Reset
PROC1_INTE1 Register
31 GPIO15_EDGE_HIGH RW 0x0
30 GPIO15_EDGE_LOW RW 0x0
29 GPIO15_LEVEL_HIGH RW 0x0
28 GPIO15_LEVEL_LOW RW 0x0
27 GPIO14_EDGE_HIGH RW 0x0
26 GPIO14_EDGE_LOW RW 0x0
25 GPIO14_LEVEL_HIGH RW 0x0
24 GPIO14_LEVEL_LOW RW 0x0
23 GPIO13_EDGE_HIGH RW 0x0
22 GPIO13_EDGE_LOW RW 0x0
21 GPIO13_LEVEL_HIGH RW 0x0
20 GPIO13_LEVEL_LOW RW 0x0
19 GPIO12_EDGE_HIGH RW 0x0
18 GPIO12_EDGE_LOW RW 0x0
17 GPIO12_LEVEL_HIGH RW 0x0
16 GPIO12_LEVEL_LOW RW 0x0
15 GPIO11_EDGE_HIGH RW 0x0
14 GPIO11_EDGE_LOW RW 0x0
13 GPIO11_LEVEL_HIGH RW 0x0
12 GPIO11_LEVEL_LOW RW 0x0
11 GPIO10_EDGE_HIGH RW 0x0
10 GPIO10_EDGE_LOW RW 0x0
9 GPIO10_LEVEL_HIGH RW 0x0
8 GPIO10_LEVEL_LOW RW 0x0
7 GPIO9_EDGE_HIGH RW 0x0
6 GPIO9_EDGE_LOW RW 0x0
5 GPIO9_LEVEL_HIGH RW 0x0
4 GPIO9_LEVEL_LOW RW 0x0
3 GPIO8_EDGE_HIGH RW 0x0
2 GPIO8_EDGE_LOW RW 0x0
1 GPIO8_LEVEL_HIGH RW 0x0
0 GPIO8_LEVEL_LOW RW 0x0
Description
Interrupt Enable for proc1
Table 314.
Bits Name Description Type Reset
PROC1_INTE2 Register
31 GPIO23_EDGE_HIGH RW 0x0
30 GPIO23_EDGE_LOW RW 0x0
29 GPIO23_LEVEL_HIGH RW 0x0
28 GPIO23_LEVEL_LOW RW 0x0
27 GPIO22_EDGE_HIGH RW 0x0
26 GPIO22_EDGE_LOW RW 0x0
25 GPIO22_LEVEL_HIGH RW 0x0
24 GPIO22_LEVEL_LOW RW 0x0
23 GPIO21_EDGE_HIGH RW 0x0
22 GPIO21_EDGE_LOW RW 0x0
21 GPIO21_LEVEL_HIGH RW 0x0
20 GPIO21_LEVEL_LOW RW 0x0
19 GPIO20_EDGE_HIGH RW 0x0
18 GPIO20_EDGE_LOW RW 0x0
17 GPIO20_LEVEL_HIGH RW 0x0
16 GPIO20_LEVEL_LOW RW 0x0
15 GPIO19_EDGE_HIGH RW 0x0
14 GPIO19_EDGE_LOW RW 0x0
13 GPIO19_LEVEL_HIGH RW 0x0
12 GPIO19_LEVEL_LOW RW 0x0
11 GPIO18_EDGE_HIGH RW 0x0
10 GPIO18_EDGE_LOW RW 0x0
9 GPIO18_LEVEL_HIGH RW 0x0
8 GPIO18_LEVEL_LOW RW 0x0
7 GPIO17_EDGE_HIGH RW 0x0
6 GPIO17_EDGE_LOW RW 0x0
5 GPIO17_LEVEL_HIGH RW 0x0
4 GPIO17_LEVEL_LOW RW 0x0
3 GPIO16_EDGE_HIGH RW 0x0
2 GPIO16_EDGE_LOW RW 0x0
1 GPIO16_LEVEL_HIGH RW 0x0
0 GPIO16_LEVEL_LOW RW 0x0
Description
Interrupt Enable for proc1
Table 315.
Bits Name Description Type Reset
PROC1_INTE3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RW 0x0
22 GPIO29_EDGE_LOW RW 0x0
21 GPIO29_LEVEL_HIGH RW 0x0
20 GPIO29_LEVEL_LOW RW 0x0
19 GPIO28_EDGE_HIGH RW 0x0
18 GPIO28_EDGE_LOW RW 0x0
17 GPIO28_LEVEL_HIGH RW 0x0
16 GPIO28_LEVEL_LOW RW 0x0
15 GPIO27_EDGE_HIGH RW 0x0
14 GPIO27_EDGE_LOW RW 0x0
13 GPIO27_LEVEL_HIGH RW 0x0
12 GPIO27_LEVEL_LOW RW 0x0
11 GPIO26_EDGE_HIGH RW 0x0
10 GPIO26_EDGE_LOW RW 0x0
9 GPIO26_LEVEL_HIGH RW 0x0
8 GPIO26_LEVEL_LOW RW 0x0
7 GPIO25_EDGE_HIGH RW 0x0
6 GPIO25_EDGE_LOW RW 0x0
5 GPIO25_LEVEL_HIGH RW 0x0
4 GPIO25_LEVEL_LOW RW 0x0
3 GPIO24_EDGE_HIGH RW 0x0
2 GPIO24_EDGE_LOW RW 0x0
1 GPIO24_LEVEL_HIGH RW 0x0
0 GPIO24_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc1
Table 316.
Bits Name Description Type Reset
PROC1_INTF0 Register
31 GPIO7_EDGE_HIGH RW 0x0
30 GPIO7_EDGE_LOW RW 0x0
29 GPIO7_LEVEL_HIGH RW 0x0
28 GPIO7_LEVEL_LOW RW 0x0
27 GPIO6_EDGE_HIGH RW 0x0
26 GPIO6_EDGE_LOW RW 0x0
25 GPIO6_LEVEL_HIGH RW 0x0
24 GPIO6_LEVEL_LOW RW 0x0
23 GPIO5_EDGE_HIGH RW 0x0
22 GPIO5_EDGE_LOW RW 0x0
21 GPIO5_LEVEL_HIGH RW 0x0
20 GPIO5_LEVEL_LOW RW 0x0
19 GPIO4_EDGE_HIGH RW 0x0
18 GPIO4_EDGE_LOW RW 0x0
17 GPIO4_LEVEL_HIGH RW 0x0
16 GPIO4_LEVEL_LOW RW 0x0
15 GPIO3_EDGE_HIGH RW 0x0
14 GPIO3_EDGE_LOW RW 0x0
13 GPIO3_LEVEL_HIGH RW 0x0
12 GPIO3_LEVEL_LOW RW 0x0
11 GPIO2_EDGE_HIGH RW 0x0
10 GPIO2_EDGE_LOW RW 0x0
9 GPIO2_LEVEL_HIGH RW 0x0
8 GPIO2_LEVEL_LOW RW 0x0
7 GPIO1_EDGE_HIGH RW 0x0
6 GPIO1_EDGE_LOW RW 0x0
5 GPIO1_LEVEL_HIGH RW 0x0
4 GPIO1_LEVEL_LOW RW 0x0
3 GPIO0_EDGE_HIGH RW 0x0
2 GPIO0_EDGE_LOW RW 0x0
1 GPIO0_LEVEL_HIGH RW 0x0
0 GPIO0_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc1
Table 317.
Bits Name Description Type Reset
PROC1_INTF1 Register
31 GPIO15_EDGE_HIGH RW 0x0
30 GPIO15_EDGE_LOW RW 0x0
29 GPIO15_LEVEL_HIGH RW 0x0
28 GPIO15_LEVEL_LOW RW 0x0
27 GPIO14_EDGE_HIGH RW 0x0
26 GPIO14_EDGE_LOW RW 0x0
25 GPIO14_LEVEL_HIGH RW 0x0
24 GPIO14_LEVEL_LOW RW 0x0
23 GPIO13_EDGE_HIGH RW 0x0
22 GPIO13_EDGE_LOW RW 0x0
21 GPIO13_LEVEL_HIGH RW 0x0
20 GPIO13_LEVEL_LOW RW 0x0
19 GPIO12_EDGE_HIGH RW 0x0
18 GPIO12_EDGE_LOW RW 0x0
17 GPIO12_LEVEL_HIGH RW 0x0
16 GPIO12_LEVEL_LOW RW 0x0
15 GPIO11_EDGE_HIGH RW 0x0
14 GPIO11_EDGE_LOW RW 0x0
13 GPIO11_LEVEL_HIGH RW 0x0
12 GPIO11_LEVEL_LOW RW 0x0
11 GPIO10_EDGE_HIGH RW 0x0
10 GPIO10_EDGE_LOW RW 0x0
9 GPIO10_LEVEL_HIGH RW 0x0
8 GPIO10_LEVEL_LOW RW 0x0
7 GPIO9_EDGE_HIGH RW 0x0
6 GPIO9_EDGE_LOW RW 0x0
5 GPIO9_LEVEL_HIGH RW 0x0
4 GPIO9_LEVEL_LOW RW 0x0
3 GPIO8_EDGE_HIGH RW 0x0
2 GPIO8_EDGE_LOW RW 0x0
1 GPIO8_LEVEL_HIGH RW 0x0
0 GPIO8_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc1
Table 318.
Bits Name Description Type Reset
PROC1_INTF2 Register
31 GPIO23_EDGE_HIGH RW 0x0
30 GPIO23_EDGE_LOW RW 0x0
29 GPIO23_LEVEL_HIGH RW 0x0
28 GPIO23_LEVEL_LOW RW 0x0
27 GPIO22_EDGE_HIGH RW 0x0
26 GPIO22_EDGE_LOW RW 0x0
25 GPIO22_LEVEL_HIGH RW 0x0
24 GPIO22_LEVEL_LOW RW 0x0
23 GPIO21_EDGE_HIGH RW 0x0
22 GPIO21_EDGE_LOW RW 0x0
21 GPIO21_LEVEL_HIGH RW 0x0
20 GPIO21_LEVEL_LOW RW 0x0
19 GPIO20_EDGE_HIGH RW 0x0
18 GPIO20_EDGE_LOW RW 0x0
17 GPIO20_LEVEL_HIGH RW 0x0
16 GPIO20_LEVEL_LOW RW 0x0
15 GPIO19_EDGE_HIGH RW 0x0
14 GPIO19_EDGE_LOW RW 0x0
13 GPIO19_LEVEL_HIGH RW 0x0
12 GPIO19_LEVEL_LOW RW 0x0
11 GPIO18_EDGE_HIGH RW 0x0
10 GPIO18_EDGE_LOW RW 0x0
9 GPIO18_LEVEL_HIGH RW 0x0
8 GPIO18_LEVEL_LOW RW 0x0
7 GPIO17_EDGE_HIGH RW 0x0
6 GPIO17_EDGE_LOW RW 0x0
5 GPIO17_LEVEL_HIGH RW 0x0
4 GPIO17_LEVEL_LOW RW 0x0
3 GPIO16_EDGE_HIGH RW 0x0
2 GPIO16_EDGE_LOW RW 0x0
1 GPIO16_LEVEL_HIGH RW 0x0
0 GPIO16_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc1
Table 319.
Bits Name Description Type Reset
PROC1_INTF3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RW 0x0
22 GPIO29_EDGE_LOW RW 0x0
21 GPIO29_LEVEL_HIGH RW 0x0
20 GPIO29_LEVEL_LOW RW 0x0
19 GPIO28_EDGE_HIGH RW 0x0
18 GPIO28_EDGE_LOW RW 0x0
17 GPIO28_LEVEL_HIGH RW 0x0
16 GPIO28_LEVEL_LOW RW 0x0
15 GPIO27_EDGE_HIGH RW 0x0
14 GPIO27_EDGE_LOW RW 0x0
13 GPIO27_LEVEL_HIGH RW 0x0
12 GPIO27_LEVEL_LOW RW 0x0
11 GPIO26_EDGE_HIGH RW 0x0
10 GPIO26_EDGE_LOW RW 0x0
9 GPIO26_LEVEL_HIGH RW 0x0
8 GPIO26_LEVEL_LOW RW 0x0
7 GPIO25_EDGE_HIGH RW 0x0
6 GPIO25_EDGE_LOW RW 0x0
5 GPIO25_LEVEL_HIGH RW 0x0
4 GPIO25_LEVEL_LOW RW 0x0
3 GPIO24_EDGE_HIGH RW 0x0
2 GPIO24_EDGE_LOW RW 0x0
1 GPIO24_LEVEL_HIGH RW 0x0
0 GPIO24_LEVEL_LOW RW 0x0
Description
Interrupt status after masking & forcing for proc1
Table 320.
Bits Name Description Type Reset
PROC1_INTS0
Register
31 GPIO7_EDGE_HIGH RO 0x0
30 GPIO7_EDGE_LOW RO 0x0
29 GPIO7_LEVEL_HIGH RO 0x0
28 GPIO7_LEVEL_LOW RO 0x0
27 GPIO6_EDGE_HIGH RO 0x0
26 GPIO6_EDGE_LOW RO 0x0
25 GPIO6_LEVEL_HIGH RO 0x0
24 GPIO6_LEVEL_LOW RO 0x0
23 GPIO5_EDGE_HIGH RO 0x0
22 GPIO5_EDGE_LOW RO 0x0
21 GPIO5_LEVEL_HIGH RO 0x0
20 GPIO5_LEVEL_LOW RO 0x0
19 GPIO4_EDGE_HIGH RO 0x0
18 GPIO4_EDGE_LOW RO 0x0
17 GPIO4_LEVEL_HIGH RO 0x0
16 GPIO4_LEVEL_LOW RO 0x0
15 GPIO3_EDGE_HIGH RO 0x0
14 GPIO3_EDGE_LOW RO 0x0
13 GPIO3_LEVEL_HIGH RO 0x0
12 GPIO3_LEVEL_LOW RO 0x0
11 GPIO2_EDGE_HIGH RO 0x0
10 GPIO2_EDGE_LOW RO 0x0
9 GPIO2_LEVEL_HIGH RO 0x0
8 GPIO2_LEVEL_LOW RO 0x0
7 GPIO1_EDGE_HIGH RO 0x0
6 GPIO1_EDGE_LOW RO 0x0
5 GPIO1_LEVEL_HIGH RO 0x0
4 GPIO1_LEVEL_LOW RO 0x0
3 GPIO0_EDGE_HIGH RO 0x0
2 GPIO0_EDGE_LOW RO 0x0
1 GPIO0_LEVEL_HIGH RO 0x0
0 GPIO0_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for proc1
Table 321.
Bits Name Description Type Reset
PROC1_INTS1
Register
31 GPIO15_EDGE_HIGH RO 0x0
30 GPIO15_EDGE_LOW RO 0x0
29 GPIO15_LEVEL_HIGH RO 0x0
28 GPIO15_LEVEL_LOW RO 0x0
27 GPIO14_EDGE_HIGH RO 0x0
26 GPIO14_EDGE_LOW RO 0x0
25 GPIO14_LEVEL_HIGH RO 0x0
24 GPIO14_LEVEL_LOW RO 0x0
23 GPIO13_EDGE_HIGH RO 0x0
22 GPIO13_EDGE_LOW RO 0x0
21 GPIO13_LEVEL_HIGH RO 0x0
20 GPIO13_LEVEL_LOW RO 0x0
19 GPIO12_EDGE_HIGH RO 0x0
18 GPIO12_EDGE_LOW RO 0x0
17 GPIO12_LEVEL_HIGH RO 0x0
16 GPIO12_LEVEL_LOW RO 0x0
15 GPIO11_EDGE_HIGH RO 0x0
14 GPIO11_EDGE_LOW RO 0x0
13 GPIO11_LEVEL_HIGH RO 0x0
12 GPIO11_LEVEL_LOW RO 0x0
11 GPIO10_EDGE_HIGH RO 0x0
10 GPIO10_EDGE_LOW RO 0x0
9 GPIO10_LEVEL_HIGH RO 0x0
8 GPIO10_LEVEL_LOW RO 0x0
7 GPIO9_EDGE_HIGH RO 0x0
6 GPIO9_EDGE_LOW RO 0x0
5 GPIO9_LEVEL_HIGH RO 0x0
4 GPIO9_LEVEL_LOW RO 0x0
3 GPIO8_EDGE_HIGH RO 0x0
2 GPIO8_EDGE_LOW RO 0x0
1 GPIO8_LEVEL_HIGH RO 0x0
0 GPIO8_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for proc1
Table 322.
Bits Name Description Type Reset
PROC1_INTS2
Register
31 GPIO23_EDGE_HIGH RO 0x0
30 GPIO23_EDGE_LOW RO 0x0
29 GPIO23_LEVEL_HIGH RO 0x0
28 GPIO23_LEVEL_LOW RO 0x0
27 GPIO22_EDGE_HIGH RO 0x0
26 GPIO22_EDGE_LOW RO 0x0
25 GPIO22_LEVEL_HIGH RO 0x0
24 GPIO22_LEVEL_LOW RO 0x0
23 GPIO21_EDGE_HIGH RO 0x0
22 GPIO21_EDGE_LOW RO 0x0
21 GPIO21_LEVEL_HIGH RO 0x0
20 GPIO21_LEVEL_LOW RO 0x0
19 GPIO20_EDGE_HIGH RO 0x0
18 GPIO20_EDGE_LOW RO 0x0
17 GPIO20_LEVEL_HIGH RO 0x0
16 GPIO20_LEVEL_LOW RO 0x0
15 GPIO19_EDGE_HIGH RO 0x0
14 GPIO19_EDGE_LOW RO 0x0
13 GPIO19_LEVEL_HIGH RO 0x0
12 GPIO19_LEVEL_LOW RO 0x0
11 GPIO18_EDGE_HIGH RO 0x0
10 GPIO18_EDGE_LOW RO 0x0
9 GPIO18_LEVEL_HIGH RO 0x0
8 GPIO18_LEVEL_LOW RO 0x0
7 GPIO17_EDGE_HIGH RO 0x0
6 GPIO17_EDGE_LOW RO 0x0
5 GPIO17_LEVEL_HIGH RO 0x0
4 GPIO17_LEVEL_LOW RO 0x0
3 GPIO16_EDGE_HIGH RO 0x0
2 GPIO16_EDGE_LOW RO 0x0
1 GPIO16_LEVEL_HIGH RO 0x0
0 GPIO16_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for proc1
Table 323.
Bits Name Description Type Reset
PROC1_INTS3
Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RO 0x0
22 GPIO29_EDGE_LOW RO 0x0
21 GPIO29_LEVEL_HIGH RO 0x0
20 GPIO29_LEVEL_LOW RO 0x0
19 GPIO28_EDGE_HIGH RO 0x0
18 GPIO28_EDGE_LOW RO 0x0
17 GPIO28_LEVEL_HIGH RO 0x0
16 GPIO28_LEVEL_LOW RO 0x0
15 GPIO27_EDGE_HIGH RO 0x0
14 GPIO27_EDGE_LOW RO 0x0
13 GPIO27_LEVEL_HIGH RO 0x0
12 GPIO27_LEVEL_LOW RO 0x0
11 GPIO26_EDGE_HIGH RO 0x0
10 GPIO26_EDGE_LOW RO 0x0
9 GPIO26_LEVEL_HIGH RO 0x0
8 GPIO26_LEVEL_LOW RO 0x0
7 GPIO25_EDGE_HIGH RO 0x0
6 GPIO25_EDGE_LOW RO 0x0
5 GPIO25_LEVEL_HIGH RO 0x0
4 GPIO25_LEVEL_LOW RO 0x0
3 GPIO24_EDGE_HIGH RO 0x0
2 GPIO24_EDGE_LOW RO 0x0
1 GPIO24_LEVEL_HIGH RO 0x0
0 GPIO24_LEVEL_LOW RO 0x0
Description
Interrupt Enable for dormant_wake
Table 324.
Bits Name Description Type Reset
DORMANT_WAKE_INT
E0 Register
31 GPIO7_EDGE_HIGH RW 0x0
30 GPIO7_EDGE_LOW RW 0x0
29 GPIO7_LEVEL_HIGH RW 0x0
28 GPIO7_LEVEL_LOW RW 0x0
27 GPIO6_EDGE_HIGH RW 0x0
26 GPIO6_EDGE_LOW RW 0x0
25 GPIO6_LEVEL_HIGH RW 0x0
24 GPIO6_LEVEL_LOW RW 0x0
23 GPIO5_EDGE_HIGH RW 0x0
22 GPIO5_EDGE_LOW RW 0x0
21 GPIO5_LEVEL_HIGH RW 0x0
20 GPIO5_LEVEL_LOW RW 0x0
19 GPIO4_EDGE_HIGH RW 0x0
18 GPIO4_EDGE_LOW RW 0x0
17 GPIO4_LEVEL_HIGH RW 0x0
16 GPIO4_LEVEL_LOW RW 0x0
15 GPIO3_EDGE_HIGH RW 0x0
14 GPIO3_EDGE_LOW RW 0x0
13 GPIO3_LEVEL_HIGH RW 0x0
12 GPIO3_LEVEL_LOW RW 0x0
11 GPIO2_EDGE_HIGH RW 0x0
10 GPIO2_EDGE_LOW RW 0x0
9 GPIO2_LEVEL_HIGH RW 0x0
8 GPIO2_LEVEL_LOW RW 0x0
7 GPIO1_EDGE_HIGH RW 0x0
6 GPIO1_EDGE_LOW RW 0x0
5 GPIO1_LEVEL_HIGH RW 0x0
4 GPIO1_LEVEL_LOW RW 0x0
3 GPIO0_EDGE_HIGH RW 0x0
2 GPIO0_EDGE_LOW RW 0x0
1 GPIO0_LEVEL_HIGH RW 0x0
0 GPIO0_LEVEL_LOW RW 0x0
Description
Interrupt Enable for dormant_wake
Table 325.
Bits Name Description Type Reset
DORMANT_WAKE_INT
E1 Register
31 GPIO15_EDGE_HIGH RW 0x0
30 GPIO15_EDGE_LOW RW 0x0
29 GPIO15_LEVEL_HIGH RW 0x0
28 GPIO15_LEVEL_LOW RW 0x0
27 GPIO14_EDGE_HIGH RW 0x0
26 GPIO14_EDGE_LOW RW 0x0
25 GPIO14_LEVEL_HIGH RW 0x0
24 GPIO14_LEVEL_LOW RW 0x0
23 GPIO13_EDGE_HIGH RW 0x0
22 GPIO13_EDGE_LOW RW 0x0
21 GPIO13_LEVEL_HIGH RW 0x0
20 GPIO13_LEVEL_LOW RW 0x0
19 GPIO12_EDGE_HIGH RW 0x0
18 GPIO12_EDGE_LOW RW 0x0
17 GPIO12_LEVEL_HIGH RW 0x0
16 GPIO12_LEVEL_LOW RW 0x0
15 GPIO11_EDGE_HIGH RW 0x0
14 GPIO11_EDGE_LOW RW 0x0
13 GPIO11_LEVEL_HIGH RW 0x0
12 GPIO11_LEVEL_LOW RW 0x0
11 GPIO10_EDGE_HIGH RW 0x0
10 GPIO10_EDGE_LOW RW 0x0
9 GPIO10_LEVEL_HIGH RW 0x0
8 GPIO10_LEVEL_LOW RW 0x0
7 GPIO9_EDGE_HIGH RW 0x0
6 GPIO9_EDGE_LOW RW 0x0
5 GPIO9_LEVEL_HIGH RW 0x0
4 GPIO9_LEVEL_LOW RW 0x0
3 GPIO8_EDGE_HIGH RW 0x0
2 GPIO8_EDGE_LOW RW 0x0
1 GPIO8_LEVEL_HIGH RW 0x0
0 GPIO8_LEVEL_LOW RW 0x0
Description
Interrupt Enable for dormant_wake
Table 326.
Bits Name Description Type Reset
DORMANT_WAKE_INT
E2 Register
31 GPIO23_EDGE_HIGH RW 0x0
30 GPIO23_EDGE_LOW RW 0x0
29 GPIO23_LEVEL_HIGH RW 0x0
28 GPIO23_LEVEL_LOW RW 0x0
27 GPIO22_EDGE_HIGH RW 0x0
26 GPIO22_EDGE_LOW RW 0x0
25 GPIO22_LEVEL_HIGH RW 0x0
24 GPIO22_LEVEL_LOW RW 0x0
23 GPIO21_EDGE_HIGH RW 0x0
22 GPIO21_EDGE_LOW RW 0x0
21 GPIO21_LEVEL_HIGH RW 0x0
20 GPIO21_LEVEL_LOW RW 0x0
19 GPIO20_EDGE_HIGH RW 0x0
18 GPIO20_EDGE_LOW RW 0x0
17 GPIO20_LEVEL_HIGH RW 0x0
16 GPIO20_LEVEL_LOW RW 0x0
15 GPIO19_EDGE_HIGH RW 0x0
14 GPIO19_EDGE_LOW RW 0x0
13 GPIO19_LEVEL_HIGH RW 0x0
12 GPIO19_LEVEL_LOW RW 0x0
11 GPIO18_EDGE_HIGH RW 0x0
10 GPIO18_EDGE_LOW RW 0x0
9 GPIO18_LEVEL_HIGH RW 0x0
8 GPIO18_LEVEL_LOW RW 0x0
7 GPIO17_EDGE_HIGH RW 0x0
6 GPIO17_EDGE_LOW RW 0x0
5 GPIO17_LEVEL_HIGH RW 0x0
4 GPIO17_LEVEL_LOW RW 0x0
3 GPIO16_EDGE_HIGH RW 0x0
2 GPIO16_EDGE_LOW RW 0x0
1 GPIO16_LEVEL_HIGH RW 0x0
0 GPIO16_LEVEL_LOW RW 0x0
Description
Interrupt Enable for dormant_wake
Table 327.
Bits Name Description Type Reset
DORMANT_WAKE_INT
E3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RW 0x0
22 GPIO29_EDGE_LOW RW 0x0
21 GPIO29_LEVEL_HIGH RW 0x0
20 GPIO29_LEVEL_LOW RW 0x0
19 GPIO28_EDGE_HIGH RW 0x0
18 GPIO28_EDGE_LOW RW 0x0
17 GPIO28_LEVEL_HIGH RW 0x0
16 GPIO28_LEVEL_LOW RW 0x0
15 GPIO27_EDGE_HIGH RW 0x0
14 GPIO27_EDGE_LOW RW 0x0
13 GPIO27_LEVEL_HIGH RW 0x0
12 GPIO27_LEVEL_LOW RW 0x0
11 GPIO26_EDGE_HIGH RW 0x0
10 GPIO26_EDGE_LOW RW 0x0
9 GPIO26_LEVEL_HIGH RW 0x0
8 GPIO26_LEVEL_LOW RW 0x0
7 GPIO25_EDGE_HIGH RW 0x0
6 GPIO25_EDGE_LOW RW 0x0
5 GPIO25_LEVEL_HIGH RW 0x0
4 GPIO25_LEVEL_LOW RW 0x0
3 GPIO24_EDGE_HIGH RW 0x0
2 GPIO24_EDGE_LOW RW 0x0
1 GPIO24_LEVEL_HIGH RW 0x0
0 GPIO24_LEVEL_LOW RW 0x0
Description
Interrupt Force for dormant_wake
Table 328.
Bits Name Description Type Reset
DORMANT_WAKE_INT
F0 Register
31 GPIO7_EDGE_HIGH RW 0x0
30 GPIO7_EDGE_LOW RW 0x0
29 GPIO7_LEVEL_HIGH RW 0x0
28 GPIO7_LEVEL_LOW RW 0x0
27 GPIO6_EDGE_HIGH RW 0x0
26 GPIO6_EDGE_LOW RW 0x0
25 GPIO6_LEVEL_HIGH RW 0x0
24 GPIO6_LEVEL_LOW RW 0x0
23 GPIO5_EDGE_HIGH RW 0x0
22 GPIO5_EDGE_LOW RW 0x0
21 GPIO5_LEVEL_HIGH RW 0x0
20 GPIO5_LEVEL_LOW RW 0x0
19 GPIO4_EDGE_HIGH RW 0x0
18 GPIO4_EDGE_LOW RW 0x0
17 GPIO4_LEVEL_HIGH RW 0x0
16 GPIO4_LEVEL_LOW RW 0x0
15 GPIO3_EDGE_HIGH RW 0x0
14 GPIO3_EDGE_LOW RW 0x0
13 GPIO3_LEVEL_HIGH RW 0x0
12 GPIO3_LEVEL_LOW RW 0x0
11 GPIO2_EDGE_HIGH RW 0x0
10 GPIO2_EDGE_LOW RW 0x0
9 GPIO2_LEVEL_HIGH RW 0x0
8 GPIO2_LEVEL_LOW RW 0x0
7 GPIO1_EDGE_HIGH RW 0x0
6 GPIO1_EDGE_LOW RW 0x0
5 GPIO1_LEVEL_HIGH RW 0x0
4 GPIO1_LEVEL_LOW RW 0x0
3 GPIO0_EDGE_HIGH RW 0x0
2 GPIO0_EDGE_LOW RW 0x0
1 GPIO0_LEVEL_HIGH RW 0x0
0 GPIO0_LEVEL_LOW RW 0x0
Description
Interrupt Force for dormant_wake
Table 329.
Bits Name Description Type Reset
DORMANT_WAKE_INT
F1 Register
31 GPIO15_EDGE_HIGH RW 0x0
30 GPIO15_EDGE_LOW RW 0x0
29 GPIO15_LEVEL_HIGH RW 0x0
28 GPIO15_LEVEL_LOW RW 0x0
27 GPIO14_EDGE_HIGH RW 0x0
26 GPIO14_EDGE_LOW RW 0x0
25 GPIO14_LEVEL_HIGH RW 0x0
24 GPIO14_LEVEL_LOW RW 0x0
23 GPIO13_EDGE_HIGH RW 0x0
22 GPIO13_EDGE_LOW RW 0x0
21 GPIO13_LEVEL_HIGH RW 0x0
20 GPIO13_LEVEL_LOW RW 0x0
19 GPIO12_EDGE_HIGH RW 0x0
18 GPIO12_EDGE_LOW RW 0x0
17 GPIO12_LEVEL_HIGH RW 0x0
16 GPIO12_LEVEL_LOW RW 0x0
15 GPIO11_EDGE_HIGH RW 0x0
14 GPIO11_EDGE_LOW RW 0x0
13 GPIO11_LEVEL_HIGH RW 0x0
12 GPIO11_LEVEL_LOW RW 0x0
11 GPIO10_EDGE_HIGH RW 0x0
10 GPIO10_EDGE_LOW RW 0x0
9 GPIO10_LEVEL_HIGH RW 0x0
8 GPIO10_LEVEL_LOW RW 0x0
7 GPIO9_EDGE_HIGH RW 0x0
6 GPIO9_EDGE_LOW RW 0x0
5 GPIO9_LEVEL_HIGH RW 0x0
4 GPIO9_LEVEL_LOW RW 0x0
3 GPIO8_EDGE_HIGH RW 0x0
2 GPIO8_EDGE_LOW RW 0x0
1 GPIO8_LEVEL_HIGH RW 0x0
0 GPIO8_LEVEL_LOW RW 0x0
Description
Interrupt Force for dormant_wake
Table 330.
Bits Name Description Type Reset
DORMANT_WAKE_INT
F2 Register
31 GPIO23_EDGE_HIGH RW 0x0
30 GPIO23_EDGE_LOW RW 0x0
29 GPIO23_LEVEL_HIGH RW 0x0
28 GPIO23_LEVEL_LOW RW 0x0
27 GPIO22_EDGE_HIGH RW 0x0
26 GPIO22_EDGE_LOW RW 0x0
25 GPIO22_LEVEL_HIGH RW 0x0
24 GPIO22_LEVEL_LOW RW 0x0
23 GPIO21_EDGE_HIGH RW 0x0
22 GPIO21_EDGE_LOW RW 0x0
21 GPIO21_LEVEL_HIGH RW 0x0
20 GPIO21_LEVEL_LOW RW 0x0
19 GPIO20_EDGE_HIGH RW 0x0
18 GPIO20_EDGE_LOW RW 0x0
17 GPIO20_LEVEL_HIGH RW 0x0
16 GPIO20_LEVEL_LOW RW 0x0
15 GPIO19_EDGE_HIGH RW 0x0
14 GPIO19_EDGE_LOW RW 0x0
13 GPIO19_LEVEL_HIGH RW 0x0
12 GPIO19_LEVEL_LOW RW 0x0
11 GPIO18_EDGE_HIGH RW 0x0
10 GPIO18_EDGE_LOW RW 0x0
9 GPIO18_LEVEL_HIGH RW 0x0
8 GPIO18_LEVEL_LOW RW 0x0
7 GPIO17_EDGE_HIGH RW 0x0
6 GPIO17_EDGE_LOW RW 0x0
5 GPIO17_LEVEL_HIGH RW 0x0
4 GPIO17_LEVEL_LOW RW 0x0
3 GPIO16_EDGE_HIGH RW 0x0
2 GPIO16_EDGE_LOW RW 0x0
1 GPIO16_LEVEL_HIGH RW 0x0
0 GPIO16_LEVEL_LOW RW 0x0
Description
Interrupt Force for dormant_wake
Table 331.
Bits Name Description Type Reset
DORMANT_WAKE_INT
F3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RW 0x0
22 GPIO29_EDGE_LOW RW 0x0
21 GPIO29_LEVEL_HIGH RW 0x0
20 GPIO29_LEVEL_LOW RW 0x0
19 GPIO28_EDGE_HIGH RW 0x0
18 GPIO28_EDGE_LOW RW 0x0
17 GPIO28_LEVEL_HIGH RW 0x0
16 GPIO28_LEVEL_LOW RW 0x0
15 GPIO27_EDGE_HIGH RW 0x0
14 GPIO27_EDGE_LOW RW 0x0
13 GPIO27_LEVEL_HIGH RW 0x0
12 GPIO27_LEVEL_LOW RW 0x0
11 GPIO26_EDGE_HIGH RW 0x0
10 GPIO26_EDGE_LOW RW 0x0
9 GPIO26_LEVEL_HIGH RW 0x0
8 GPIO26_LEVEL_LOW RW 0x0
7 GPIO25_EDGE_HIGH RW 0x0
6 GPIO25_EDGE_LOW RW 0x0
5 GPIO25_LEVEL_HIGH RW 0x0
4 GPIO25_LEVEL_LOW RW 0x0
3 GPIO24_EDGE_HIGH RW 0x0
2 GPIO24_EDGE_LOW RW 0x0
1 GPIO24_LEVEL_HIGH RW 0x0
0 GPIO24_LEVEL_LOW RW 0x0
Description
Interrupt status after masking & forcing for dormant_wake
Table 332.
Bits Name Description Type Reset
DORMANT_WAKE_INT
S0 Register
31 GPIO7_EDGE_HIGH RO 0x0
30 GPIO7_EDGE_LOW RO 0x0
29 GPIO7_LEVEL_HIGH RO 0x0
28 GPIO7_LEVEL_LOW RO 0x0
27 GPIO6_EDGE_HIGH RO 0x0
26 GPIO6_EDGE_LOW RO 0x0
25 GPIO6_LEVEL_HIGH RO 0x0
24 GPIO6_LEVEL_LOW RO 0x0
23 GPIO5_EDGE_HIGH RO 0x0
22 GPIO5_EDGE_LOW RO 0x0
21 GPIO5_LEVEL_HIGH RO 0x0
20 GPIO5_LEVEL_LOW RO 0x0
19 GPIO4_EDGE_HIGH RO 0x0
18 GPIO4_EDGE_LOW RO 0x0
17 GPIO4_LEVEL_HIGH RO 0x0
16 GPIO4_LEVEL_LOW RO 0x0
15 GPIO3_EDGE_HIGH RO 0x0
14 GPIO3_EDGE_LOW RO 0x0
13 GPIO3_LEVEL_HIGH RO 0x0
12 GPIO3_LEVEL_LOW RO 0x0
11 GPIO2_EDGE_HIGH RO 0x0
10 GPIO2_EDGE_LOW RO 0x0
9 GPIO2_LEVEL_HIGH RO 0x0
8 GPIO2_LEVEL_LOW RO 0x0
7 GPIO1_EDGE_HIGH RO 0x0
6 GPIO1_EDGE_LOW RO 0x0
5 GPIO1_LEVEL_HIGH RO 0x0
4 GPIO1_LEVEL_LOW RO 0x0
3 GPIO0_EDGE_HIGH RO 0x0
2 GPIO0_EDGE_LOW RO 0x0
1 GPIO0_LEVEL_HIGH RO 0x0
0 GPIO0_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for dormant_wake
Table 333.
Bits Name Description Type Reset
DORMANT_WAKE_INT
S1 Register
31 GPIO15_EDGE_HIGH RO 0x0
30 GPIO15_EDGE_LOW RO 0x0
29 GPIO15_LEVEL_HIGH RO 0x0
28 GPIO15_LEVEL_LOW RO 0x0
27 GPIO14_EDGE_HIGH RO 0x0
26 GPIO14_EDGE_LOW RO 0x0
25 GPIO14_LEVEL_HIGH RO 0x0
24 GPIO14_LEVEL_LOW RO 0x0
23 GPIO13_EDGE_HIGH RO 0x0
22 GPIO13_EDGE_LOW RO 0x0
21 GPIO13_LEVEL_HIGH RO 0x0
20 GPIO13_LEVEL_LOW RO 0x0
19 GPIO12_EDGE_HIGH RO 0x0
18 GPIO12_EDGE_LOW RO 0x0
17 GPIO12_LEVEL_HIGH RO 0x0
16 GPIO12_LEVEL_LOW RO 0x0
15 GPIO11_EDGE_HIGH RO 0x0
14 GPIO11_EDGE_LOW RO 0x0
13 GPIO11_LEVEL_HIGH RO 0x0
12 GPIO11_LEVEL_LOW RO 0x0
11 GPIO10_EDGE_HIGH RO 0x0
10 GPIO10_EDGE_LOW RO 0x0
9 GPIO10_LEVEL_HIGH RO 0x0
8 GPIO10_LEVEL_LOW RO 0x0
7 GPIO9_EDGE_HIGH RO 0x0
6 GPIO9_EDGE_LOW RO 0x0
5 GPIO9_LEVEL_HIGH RO 0x0
4 GPIO9_LEVEL_LOW RO 0x0
3 GPIO8_EDGE_HIGH RO 0x0
2 GPIO8_EDGE_LOW RO 0x0
1 GPIO8_LEVEL_HIGH RO 0x0
0 GPIO8_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for dormant_wake
Table 334.
Bits Name Description Type Reset
DORMANT_WAKE_INT
S2 Register
31 GPIO23_EDGE_HIGH RO 0x0
30 GPIO23_EDGE_LOW RO 0x0
29 GPIO23_LEVEL_HIGH RO 0x0
28 GPIO23_LEVEL_LOW RO 0x0
27 GPIO22_EDGE_HIGH RO 0x0
26 GPIO22_EDGE_LOW RO 0x0
25 GPIO22_LEVEL_HIGH RO 0x0
24 GPIO22_LEVEL_LOW RO 0x0
23 GPIO21_EDGE_HIGH RO 0x0
22 GPIO21_EDGE_LOW RO 0x0
21 GPIO21_LEVEL_HIGH RO 0x0
20 GPIO21_LEVEL_LOW RO 0x0
19 GPIO20_EDGE_HIGH RO 0x0
18 GPIO20_EDGE_LOW RO 0x0
17 GPIO20_LEVEL_HIGH RO 0x0
16 GPIO20_LEVEL_LOW RO 0x0
15 GPIO19_EDGE_HIGH RO 0x0
14 GPIO19_EDGE_LOW RO 0x0
13 GPIO19_LEVEL_HIGH RO 0x0
12 GPIO19_LEVEL_LOW RO 0x0
11 GPIO18_EDGE_HIGH RO 0x0
10 GPIO18_EDGE_LOW RO 0x0
9 GPIO18_LEVEL_HIGH RO 0x0
8 GPIO18_LEVEL_LOW RO 0x0
7 GPIO17_EDGE_HIGH RO 0x0
6 GPIO17_EDGE_LOW RO 0x0
5 GPIO17_LEVEL_HIGH RO 0x0
4 GPIO17_LEVEL_LOW RO 0x0
3 GPIO16_EDGE_HIGH RO 0x0
2 GPIO16_EDGE_LOW RO 0x0
1 GPIO16_LEVEL_HIGH RO 0x0
0 GPIO16_LEVEL_LOW RO 0x0
Description
Interrupt status after masking & forcing for dormant_wake
Table 335.
Bits Name Description Type Reset
DORMANT_WAKE_INT
S3 Register
31:24 Reserved. - - -
23 GPIO29_EDGE_HIGH RO 0x0
22 GPIO29_EDGE_LOW RO 0x0
21 GPIO29_LEVEL_HIGH RO 0x0
20 GPIO29_LEVEL_LOW RO 0x0
19 GPIO28_EDGE_HIGH RO 0x0
18 GPIO28_EDGE_LOW RO 0x0
17 GPIO28_LEVEL_HIGH RO 0x0
16 GPIO28_LEVEL_LOW RO 0x0
15 GPIO27_EDGE_HIGH RO 0x0
14 GPIO27_EDGE_LOW RO 0x0
13 GPIO27_LEVEL_HIGH RO 0x0
12 GPIO27_LEVEL_LOW RO 0x0
11 GPIO26_EDGE_HIGH RO 0x0
10 GPIO26_EDGE_LOW RO 0x0
9 GPIO26_LEVEL_HIGH RO 0x0
8 GPIO26_LEVEL_LOW RO 0x0
7 GPIO25_EDGE_HIGH RO 0x0
6 GPIO25_EDGE_LOW RO 0x0
5 GPIO25_LEVEL_HIGH RO 0x0
4 GPIO25_LEVEL_LOW RO 0x0
3 GPIO24_EDGE_HIGH RO 0x0
2 GPIO24_EDGE_LOW RO 0x0
1 GPIO24_LEVEL_HIGH RO 0x0
0 GPIO24_LEVEL_LOW RO 0x0
The QSPI Bank IO registers start at a base address of 0x40018000 (defined as IO_QSPI_BASE in SDK).
0x3c PROC0_INTS Interrupt status after masking & forcing for proc0
0x48 PROC1_INTS Interrupt status after masking & forcing for proc1
0x54 DORMANT_WAKE_INTS Interrupt status after masking & forcing for dormant_wake
Description
GPIO status
Table 337.
Bits Name Description Type Reset
GPIO_QSPI_SCLK_STA
TUS,
31:27 Reserved. - - -
GPIO_QSPI_SS_STATU
S, …,
26 IRQTOPROC interrupt to processors, after override is applied RO 0x0
GPIO_QSPI_SD2_STAT
US,
25 Reserved. - - -
GPIO_QSPI_SD3_STAT
US Registers
24 IRQFROMPAD interrupt from pad before override is applied RO 0x0
23:20 Reserved. - - -
18 Reserved. - - -
16:14 Reserved. - - -
11:10 Reserved. - - -
7:0 Reserved. - - -
Description
GPIO control including function select and overrides.
Table 338.
Bits Name Description Type Reset
GPIO_QSPI_SCLK_CTR
L,
31:30 Reserved. - - -
GPIO_QSPI_SS_CTRL,
…,
29:28 IRQOVER 0x0 → don’t invert the interrupt RW 0x0
GPIO_QSPI_SD2_CTRL,
GPIO_QSPI_SD3_CTRL 0x1 → invert the interrupt
Registers 0x2 → drive interrupt low
0x3 → drive interrupt high
27:18 Reserved. - - -
15:14 Reserved. - - -
13:12 OEOVER 0x0 → drive output enable from peripheral signal selected RW 0x0
by funcsel
0x1 → drive output enable from inverse of peripheral
signal selected by funcsel
0x2 → disable output
0x3 → enable output
11:10 Reserved. - - -
9:8 OUTOVER 0x0 → drive output from peripheral signal selected by RW 0x0
funcsel
0x1 → drive output from inverse of peripheral signal
selected by funcsel
0x2 → drive output low
0x3 → drive output high
7:5 Reserved. - - -
4:0 FUNCSEL Function select. 31 == NULL. See GPIO function table for RW 0x1f
available functions.
Description
Raw Interrupts
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH WC 0x0
22 GPIO_QSPI_SD3_EDGE_LOW WC 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RO 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RO 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH WC 0x0
18 GPIO_QSPI_SD2_EDGE_LOW WC 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RO 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RO 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH WC 0x0
14 GPIO_QSPI_SD1_EDGE_LOW WC 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RO 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RO 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH WC 0x0
10 GPIO_QSPI_SD0_EDGE_LOW WC 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RO 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RO 0x0
7 GPIO_QSPI_SS_EDGE_HIGH WC 0x0
6 GPIO_QSPI_SS_EDGE_LOW WC 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RO 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RO 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH WC 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW WC 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RO 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RO 0x0
Description
Interrupt Enable for proc0
Table 340.
Bits Name Description Type Reset
PROC0_INTE Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RW 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RW 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RW 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RW 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RW 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RW 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RW 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RW 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RW 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RW 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RW 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RW 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RW 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RW 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RW 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RW 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RW 0x0
6 GPIO_QSPI_SS_EDGE_LOW RW 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RW 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RW 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RW 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RW 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RW 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc0
Table 341.
Bits Name Description Type Reset
PROC0_INTF Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RW 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RW 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RW 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RW 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RW 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RW 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RW 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RW 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RW 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RW 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RW 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RW 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RW 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RW 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RW 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RW 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RW 0x0
6 GPIO_QSPI_SS_EDGE_LOW RW 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RW 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RW 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RW 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RW 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RW 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RW 0x0
Description
Interrupt status after masking & forcing for proc0
Table 342.
Bits Name Description Type Reset
PROC0_INTS Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RO 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RO 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RO 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RO 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RO 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RO 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RO 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RO 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RO 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RO 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RO 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RO 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RO 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RO 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RO 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RO 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RO 0x0
6 GPIO_QSPI_SS_EDGE_LOW RO 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RO 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RO 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RO 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RO 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RO 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RO 0x0
Description
Interrupt Enable for proc1
Table 343.
Bits Name Description Type Reset
PROC1_INTE Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RW 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RW 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RW 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RW 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RW 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RW 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RW 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RW 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RW 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RW 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RW 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RW 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RW 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RW 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RW 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RW 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RW 0x0
6 GPIO_QSPI_SS_EDGE_LOW RW 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RW 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RW 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RW 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RW 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RW 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RW 0x0
Description
Interrupt Force for proc1
Table 344.
Bits Name Description Type Reset
PROC1_INTF Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RW 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RW 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RW 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RW 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RW 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RW 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RW 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RW 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RW 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RW 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RW 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RW 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RW 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RW 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RW 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RW 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RW 0x0
6 GPIO_QSPI_SS_EDGE_LOW RW 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RW 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RW 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RW 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RW 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RW 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RW 0x0
Description
Interrupt status after masking & forcing for proc1
Table 345.
Bits Name Description Type Reset
PROC1_INTS Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RO 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RO 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RO 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RO 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RO 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RO 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RO 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RO 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RO 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RO 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RO 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RO 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RO 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RO 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RO 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RO 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RO 0x0
6 GPIO_QSPI_SS_EDGE_LOW RO 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RO 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RO 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RO 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RO 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RO 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RO 0x0
Description
Interrupt Enable for dormant_wake
Table 346.
Bits Name Description Type Reset
DORMANT_WAKE_INT
E Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RW 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RW 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RW 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RW 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RW 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RW 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RW 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RW 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RW 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RW 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RW 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RW 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RW 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RW 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RW 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RW 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RW 0x0
6 GPIO_QSPI_SS_EDGE_LOW RW 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RW 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RW 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RW 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RW 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RW 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RW 0x0
Description
Interrupt Force for dormant_wake
Table 347.
Bits Name Description Type Reset
DORMANT_WAKE_INT
F Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RW 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RW 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RW 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RW 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RW 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RW 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RW 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RW 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RW 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RW 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RW 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RW 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RW 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RW 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RW 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RW 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RW 0x0
6 GPIO_QSPI_SS_EDGE_LOW RW 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RW 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RW 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RW 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RW 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RW 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RW 0x0
Description
Interrupt status after masking & forcing for dormant_wake
Table 348.
Bits Name Description Type Reset
DORMANT_WAKE_INT
S Register
31:24 Reserved. - - -
23 GPIO_QSPI_SD3_EDGE_HIGH RO 0x0
22 GPIO_QSPI_SD3_EDGE_LOW RO 0x0
21 GPIO_QSPI_SD3_LEVEL_HIGH RO 0x0
20 GPIO_QSPI_SD3_LEVEL_LOW RO 0x0
19 GPIO_QSPI_SD2_EDGE_HIGH RO 0x0
18 GPIO_QSPI_SD2_EDGE_LOW RO 0x0
17 GPIO_QSPI_SD2_LEVEL_HIGH RO 0x0
16 GPIO_QSPI_SD2_LEVEL_LOW RO 0x0
15 GPIO_QSPI_SD1_EDGE_HIGH RO 0x0
14 GPIO_QSPI_SD1_EDGE_LOW RO 0x0
13 GPIO_QSPI_SD1_LEVEL_HIGH RO 0x0
12 GPIO_QSPI_SD1_LEVEL_LOW RO 0x0
11 GPIO_QSPI_SD0_EDGE_HIGH RO 0x0
10 GPIO_QSPI_SD0_EDGE_LOW RO 0x0
9 GPIO_QSPI_SD0_LEVEL_HIGH RO 0x0
8 GPIO_QSPI_SD0_LEVEL_LOW RO 0x0
7 GPIO_QSPI_SS_EDGE_HIGH RO 0x0
6 GPIO_QSPI_SS_EDGE_LOW RO 0x0
5 GPIO_QSPI_SS_LEVEL_HIGH RO 0x0
4 GPIO_QSPI_SS_LEVEL_LOW RO 0x0
3 GPIO_QSPI_SCLK_EDGE_HIGH RO 0x0
2 GPIO_QSPI_SCLK_EDGE_LOW RO 0x0
1 GPIO_QSPI_SCLK_LEVEL_HIGH RO 0x0
0 GPIO_QSPI_SCLK_LEVEL_LOW RO 0x0
The User Bank Pad Control registers start at a base address of 0x4001c000 (defined as PADS_BANK0_BASE in SDK).
Table 350.
Bits Description Type Reset
VOLTAGE_SELECT
Register
31:1 Reserved. - -
Description
Pad control register
Description
Pad control register
31:8 Reserved. - - -
Description
Pad control register
31:8 Reserved. - - -
The QSPI Bank Pad Control registers start at a base address of 0x40020000 (defined as PADS_QSPI_BASE in SDK).
Table 355.
Bits Description Type Reset
VOLTAGE_SELECT
Register
31:1 Reserved. - -
Description
Pad control register
Table 356.
Bits Name Description Type Reset
GPIO_QSPI_SCLK
Register
31:8 Reserved. - - -
Description
Pad control register
Table 357.
Bits Name Description Type Reset
GPIO_QSPI_SD0,
GPIO_QSPI_SD1,
31:8 Reserved. - - -
GPIO_QSPI_SD2,
GPIO_QSPI_SD3
7 OD Output disable. Has priority over output enable from RW 0x0
Registers
peripherals
Description
Pad control register
Table 358.
Bits Name Description Type Reset
GPIO_QSPI_SS
Register
31:8 Reserved. - - -
2.20. Sysinfo
2.20.1. Overview
The sysinfo block contains system information. The first register contains the Chip ID, which allows the programmer to
know which version of the chip software is running on. The second register will always read as 1 on the device.
0x40 GITREF_RP2040 Git hash of the chip source. Used to identify chip version.
Description
JEDEC JEP-106 compliant chip identifier.
31:28 REVISION RO -
27:12 PART RO -
11:0 MANUFACTURER RO -
Description
Platform register. Allows software to know what environment it is running in.
31:2 Reserved. - - -
1 ASIC RO 0x0
0 FPGA RO 0x0
Table 362.
Bits Description Type Reset
GITREF_RP2040
Register
31:0 Git hash of the chip source. Used to identify chip version. RO -
2.21. Syscfg
2.21.1. Overview
The system config block controls miscellaneous chip settings including:
◦ DAP Instance ID (to change the address that the SWD uses to communicate with the core in debug)
◦ Processor status (If the processor is halted, which may be useful in debug)
• Processor IO config
◦ Input synchroniser control (to allow input synchronisers to be bypassed to reduce latency where clocks are
synchronous)
• Debug control
◦ Provides the ability to control the SWD interface from inside the chip. This means Core 0 could debug Core 1,
which may make debug connectivity easier.
• Memory power down (each memory can be powered down if not being used to save a small amount of extra
power).
0x0c PROC_IN_SYNC_BYPASS For each bit, if 1, bypass the input synchronizer between that
GPIO
and the GPIO input register in the SIO. The input synchronizers
should
generally be unbypassed, to avoid injecting metastabilities into
processors.
If you’re feeling brave, you can bypass to save two cycles of
input
latency. This register applies to GPIO 0…29.
0x10 PROC_IN_SYNC_BYPASS_HI For each bit, if 1, bypass the input synchronizer between that
GPIO
and the GPIO input register in the SIO. The input synchronizers
should
generally be unbypassed, to avoid injecting metastabilities into
processors.
If you’re feeling brave, you can bypass to save two cycles of
input
latency. This register applies to GPIO 30…35 (the QSPI IOs).
0x14 DBGFORCE Directly control the SWD debug port of either processor
0x18 MEMPOWERDOWN Control power downs to memories. Set high to power down
memories.
Use with extreme caution
Description
Processor core 0 NMI source mask
Table 364.
Bits Description Type Reset
PROC0_NMI_MASK
Register
31:0 Set a bit high to enable NMI from that IRQ RW 0x00000000
Description
Processor core 1 NMI source mask
Table 365.
Bits Description Type Reset
PROC1_NMI_MASK
Register
31:0 Set a bit high to enable NMI from that IRQ RW 0x00000000
Description
Configuration for processors
Table 366.
Bits Name Description Type Reset
PROC_CONFIG
Register
31:28 PROC1_DAP_INST Configure proc1 DAP instance ID. RW 0x1
ID Recommend that this is NOT changed until you require
debug access in multi-chip environment
WARNING: do not set to 15 as this is reserved for
RescueDP
23:2 Reserved. - - -
Table 367.
Bits Description Type Reset
PROC_IN_SYNC_BYPA
SS Register
31:30 Reserved. - -
29:0 For each bit, if 1, bypass the input synchronizer between that GPIO RW 0x00000000
and the GPIO input register in the SIO. The input synchronizers should
generally be unbypassed, to avoid injecting metastabilities into processors.
If you’re feeling brave, you can bypass to save two cycles of input
latency. This register applies to GPIO 0…29.
Table 368.
Bits Description Type Reset
PROC_IN_SYNC_BYPA
SS_HI Register
31:6 Reserved. - -
5:0 For each bit, if 1, bypass the input synchronizer between that GPIO RW 0x00
and the GPIO input register in the SIO. The input synchronizers should
generally be unbypassed, to avoid injecting metastabilities into processors.
If you’re feeling brave, you can bypass to save two cycles of input
latency. This register applies to GPIO 30…35 (the QSPI IOs).
Description
Directly control the SWD debug port of either processor
31:8 Reserved. - - -
Description
Control power downs to memories. Set high to power down memories.
Use with extreme caution
Table 370.
Bits Name Description Type Reset
MEMPOWERDOWN
Register
31:8 Reserved. - - -
7 ROM RW 0x0
6 USB RW 0x0
5 SRAM5 RW 0x0
4 SRAM4 RW 0x0
3 SRAM3 RW 0x0
2 SRAM2 RW 0x0
1 SRAM1 RW 0x0
0 SRAM0 RW 0x0
2.22. TBMAN
TBMAN refers to the testbench manager, which is used during chip development simulations to verify the design.
During these simulations TBMAN allows software running on RP2040 to control the testbench and simulation
environment. On the real chip it has no effect other than providing a single PLATFORM register to indicate that this is the
real chip. This PLATFORM functionality is duplicated in the sysinfo (Section 2.20) registers.
Description
Indicates the type of platform in use
31:2 Reserved. - - -
Chapter 3. PIO
3.1. Overview
There are 2 identical PIO blocks in RP2040. Each PIO block has dedicated connections to the bus fabric, GPIO and
interrupt controller. The diagram for a single PIO block is show in Figure 38.
The programmable input/output block (PIO) is a versatile hardware interface. It can support a variety of IO standards,
including:
Making state machines programmable in a software-like manner, rather than a fully configurable logic fabric like a
CPLD, allows more hardware interfaces to be offered in the same cost and power envelope. This also presents a more
familiar programming model, and simpler tool flow, to those who wish to exploit PIO’s full flexibility by programming it
directly, rather than using a premade interface from the PIO library.
PIO is highly performant as well as flexible, thanks to a carefully selected set of fixed-function hardware inside each
state machine. When outputting DPI, PIO can sustain 360 Mb/s during the active scanline period when running from a
48 MHz system clock. In this example, one state machine is handling frame/scanline timing and generating the pixel
clock, while another is handling the pixel data, and unpacking run-length-encoded scanlines.
State machines' inputs and outputs are mapped to up to 32 GPIOs (limited to 30 GPIOs for RP2040), and all state
machines have independent, simultaneous access to any GPIO. For example, the standard UART code allows TX, RX,
CTS and RTS to be any four arbitrary GPIOs, and I2C permits the same for SDA and SCL. The amount of freedom
available depends on how exactly a given PIO program chooses to use PIO’s pin mapping resources, but at the
minimum, an interface can be freely shifted up or down by some number of GPIOs.
From this point on, state machines are generally autonomous, and system software interacts through DMA, interrupts
and control registers, as with other peripherals on RP2040. For more complex interfaces, PIO provides a small but
flexible set of primitives which allow system software to be more hands-on with state machine control flow.
Programs for common interfaces, such as UART, SPI, or I2C, are available in the PIO library, so in many cases, it is not
necessary to write PIO programs. However, the PIO is much more flexible when programmed directly, supporting a wide
variety of interfaces which may not have been foreseen by its designers.
The PIO has a total of nine instructions: JMP, WAIT, IN, OUT, PUSH, PULL, MOV, IRQ, and SET. See Section 3.4 for details on these
instructions.
Though the PIO only has a total of nine instructions, it would be difficult to edit PIO program binaries by hand. PIO
assembly is a textual format, describing a PIO program, where each command corresponds to one instruction in the
output binary. Below is an example program in PIO assembly:
7 .program squarewave
8 set pindirs, 1 ; Set pin to output
9 again:
10 set pins, 1 [1] ; Drive pin high and then delay for one cycle
11 set pins, 0 ; Drive pin low
12 jmp again ; Set PC to label `again`
The PIO assembler is included with the SDK, and is called pioasm. This program processes a PIO assembly input text file,
which may contain multiple programs, and writes out the assembled programs ready for use. For the SDK these
assembled programs are emitted in form of C headers, containing constant arrays: For more information see Section
3.3
The program counter, or PC, points to the location in the instruction memory being executed on this cycle. Generally, PC
increments by one each cycle, wrapping at the end of the instruction memory. Jump instructions are an exception and
explicitly provide the next value that PC will take.
Our example assembly program (listed as .program squarewave above) shows both of these concepts in practice. It drives
a 50/50 duty cycle square wave onto a GPIO, with a period of four cycles. Using some other features (e.g. side-set) this
can be made as low as two cycles.
NOTE
Side-set is where a state machine drives a small number of GPIOs in addition to the main side effects of the
instruction it executes. It’s described fully in Section 3.5.1.
The system has write-only access to the instruction memory, which is used to load programs:
34 // Load the assembled program directly into the PIO's instruction memory.
35 // Each PIO instance has a 32-slot instruction memory, which all 4 state
36 // machines can see. The system has write-only access.
37 for (int i = 0; i < count_of(squarewave_program_instructions); ++i)
38 pio->instr_mem[i] = squarewave_program_instructions[i];
The clock divider slows the state machine’s execution by a constant factor, represented as a 16.8 fixed-point fractional
number. Using the above example, if a clock division of 2.5 were programmed, the square wave would have a period of
cycles. This is useful for setting a precise baud rate for a serial interface, such as a UART.
The above code fragments are part of a complete code example which drives a 12.5 MHz square wave out of GPIO 0 (or
any other pins we might choose to map). We can also use pins WAIT PIN instruction to stall a state machine’s execution
for some amount of time, or a JMP PIN instruction to branch on the state of a pin, so control flow can vary based on pin
state.
51 // There are five pin mapping groups (out, in, set, side-set, jmp pin)
52 // which are used by different instructions or in different circumstances.
53 // Here we're just using SET instructions. Configure state machine 0 SETs
54 // to affect GPIO 0 only; then configure GPIO0 to be controlled by PIO0,
55 // as opposed to e.g. the processors.
56 pio->sm[0].pinctrl =
57 (1 << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
58 (0 << PIO_SM0_PINCTRL_SET_BASE_LSB);
59 gpio_set_function(0, GPIO_FUNC_PIO0);
The system can start and stop each state machine at any time, via the CTRL register. Multiple state machines can be
started simultaneously, and the deterministic nature of PIO means they can stay perfectly synchronised.
63 // Set the state machine running. The PIO CTRL register is global within a
64 // PIO instance, so you can start/stop multiple state machines
65 // simultaneously. We're using the register's hardware atomic set alias to
66 // make one bit high without doing a read-modify-write on the register.
67 hw_set_bits(&pio->ctrl, 1 << (PIO_CTRL_SM_ENABLE_LSB + 0));
Most instructions are executed from the instruction memory, but there are other sources, which can be freely mixed:
• Instructions written to a special configuration register (SMx INSTR) are immediately executed, momentarily
interrupting other execution. For example, a JMP instruction written to SMx INSTR will cause the state machine to start
executing from a different location.
• Instructions can be executed from a register, using the MOV EXEC instruction.
• Instructions can be executed from the output shifter, using the OUT EXEC instruction
The last of these is particularly versatile: instructions can be embedded in the stream of data passing through the FIFO.
The I2C example uses this to embed e.g. STOP and RESTART line conditions alongside normal data. In the case of MOV and
OUT EXEC, the MOV/OUT itself executes in one cycle, and the executee on the next.
3.2.3. Registers
Each state machine possesses a small number of internal registers. These hold input or output data, and temporary
values such as loop counter variables.
• PULL instructions: remove a 32-bit word from the TX FIFO and place into the OSR.
• OUT instructions shift data from the OSR to other destinations, 1…32 bits at a time.
• The OSR fills with zeroes as data is shifted out
• The state machine will automatically refill the OSR from the FIFO on an OUT instruction, once some total shift count
threshold is reached, if autopull is enabled
• Shift direction can be left/right, configurable by the processor via configuration registers
For example, to stream data through the FIFO and output to the pins at a rate of one byte per two clocks:
1 .program pull_example1
2 loop:
3 out pins, 8
4 public entry_point:
5 pull
6 out pins, 8 [1]
7 out pins, 8 [1]
8 out pins, 8
9 jmp loop
Autopull (see Section 3.5.4) allows the hardware to automatically refill the OSR in the majority of cases, with the state
machine stalling if it tries to OUT from an empty OSR. This has two benefits:
1 .program pull_example2
2
3 loop:
4 out pins, 8
5 public entry_point:
6 jmp loop
Program wrapping (Section 3.5.2) allows further simplification and, if desired, an output of 1 byte every system clock
cycle.
1 .program pull_example3
2
3 public entry_point:
4 .wrap_target
5 out pins, 8 [1]
6 .wrap
State machines remember how many bits, in total, have been shifted out of the OSR via OUT instructions, and into the ISR
via IN instructions. This information is tracked at all times by a pair of hardware counters — the output shift counter and
the input shift counter — each capable of holding values from 0 to 32 inclusive. With each shift operation, the relevant
counter is incremented by the shift count, up to the maximum value of 32 (equal to the width of the shift register). The
state machine can be configured to perform certain actions when a counter reaches a configurable threshold:
• The OSR can be automatically refilled once some number of bits have been shifted out. See Section 3.5.4
• The ISR can be automatically emptied once some number of bits have been shifted in. See Section 3.5.4
• PUSH or PULL instructions can be conditioned on the input or output shift counter, respectively
On PIO reset, or the assertion of CTRL_SM_RESTART, the input shift counter is cleared to 0 (nothing yet shifted in), and the
output shift counter is initialised to 32 (nothing remaining to be shifted out; fully exhausted). Some other instructions
affect the shift counters:
Each state machine has two 32-bit internal scratch registers, called X and Y.
For example, suppose we wanted to produce a long pulse for "1" data bits, and a short pulse for "0" data bits:
1 .program ws2812_led
2
3 public entry_point:
4 pull
5 set x, 23 ; Loop over 24 bits
6 bitloop:
7 set pins, 1 ; Drive pin high
8 out y, 1 [5] ; Shift 1 bit out, and write it to y
9 jmp !y skip ; Skip the extra delay if the bit was 0
10 nop [5]
11 skip:
12 set pins, 0 [5]
13 jmp x-- bitloop ; Jump if x nonzero, and decrement x
14 jmp entry_point
Here X is used as a loop counter, and Y is used as a temporary variable for branching on single bits from the OSR. This
program can be used to drive a WS2812 LED interface, although more compact implementations are possible (as few
as 3 instructions).
MOV allows the use of the scratch registers to save/restore the shift registers if, for example, you would like to repeatedly
shift out the same sequence.
NOTE
A much more compact WS2812 example (4 instructions total) is shown in Section 3.6.2
3.2.3.5. FIFOs
Each state machine has a pair of 4-word deep FIFOs, one for data transfer from system to state machine (TX), and the
other for state machine to system (RX). The TX FIFO is written to by system busmasters, such as a processor or DMA
controller, and the RX FIFO is written to by the state machine. FIFOs decouple the timing of the PIO state machines and
the system bus, allowing state machines to go for longer periods without processor intervention.
FIFOs also generate data request (DREQ) signals, which allow a system DMA controller to pace its reads/writes based
on the presence of data in an RX FIFO, or space for new data in a TX FIFO. This allows a processor to set up a long
transaction, potentially involving many kilobytes of data, which will proceed with no further processor intervention.
Often, a state machine is only transferring data in one direction. In this case the SHIFTCTRL_FJOIN option can merge the
two FIFOs into a single 8-entry FIFO going in one direction only. This is useful for high-bandwidth interfaces such as DPI.
3.2.4. Stalling
State machines may momentarily pause execution for a number of reasons:
NOTE
Side-set (Section 3.5.1) is not affected by stalls, and always takes place on the first cycle of the attached instruction.
• Change the level or direction of some GPIOs via an OUT or SET instruction, or read some GPIOs via an IN instruction
• Change the level or direction of some GPIOs via a side-set operation
Each of these operations is on one of four contiguous ranges of GPIOs, with the base and count of each range
configured via each state machine’s PINCTRL register. There is a range for each of OUT, SET, IN and side-set operations.
Each range can cover any of the GPIOs accessible to a given PIO block (on RP2040 this is the 30 user GPIOs), and the
ranges can overlap.
For each individual GPIO output (level and direction separately), PIO considers all 8 writes that may have occurred on
that cycle, and applies the write from the highest-numbered state machine. If the same state machine performs a SET
/OUT and a side-set on the same GPIO simultaneously, the side-set is used. If no state machine writes to this GPIO
output, its value does not change from the previous cycle.
Generally each state machine’s outputs are mapped to a distinct group of GPIOs, implementing some peripheral
interface.
• Asserting system level interrupts from a state machine program, and optionally waiting for the interrupt to be
acknowledged
State machines can not communicate data, but they can synchronise with one another by using the IRQ flags. There are
8 flags total (the lower four of which can be masked for use as system IRQs), and each state machine can set or clear
any flag using the IRQ instruction, and can wait for a flag to go high or low using the WAIT IRQ instruction. This allows
cycle-accurate synchronisation between state machines.
This section briefly introduces the directives and instructions that can be used in pioasm input. A deeper discussion of
how to use pioasm, how it is integrated into the SDK build system, extended features such as code pass through, and the
various output formats it can produce, is given in the Raspberry Pi Pico C/C++ SDK book.
3.3.1. Directives
The following directives control the assembly of PIO programs:
.program <name> Start a new program with the name <name>. Note that that name is used in
code so should be alphanumeric/underscore not starting with a digit. The
program lasts until another .program directive or the end of the source file. PIO
instructions are only allowed within a program
.origin <offset> Optional directive to specify the PIO instruction memory offset at which the
program must load. Most commonly this is used for programs that must load
at offset 0, because they use data based JMPs with the (absolute) jmp target
being stored in only a few bits. This directive is invalid outside of a program
.side_set <count> (opt) (pindirs) If this directive is present, <count> indicates the number of side-set bits to be
used. Additionally opt may be specified to indicate that a side <value> is
optional for instructions (not using this requires stealing an extra bit - in
addition to the <count> bits - from those available for the instruction delay).
Finally, pindirs may be specified to indicate that the side set values should be
applied to the PINDIRs and not the PINs. This directive is only valid within a
program before the first instruction
.wrap_target Place prior to an instruction, this directive specifies the instruction where
execution continues due to program wrapping. This directive is invalid outside
of a program, may only be used once within a program, and if not specified
defaults to the start of the program
.wrap Placed after an instruction, this directive specifies the instruction after which,
in normal control flow (i.e. jmp with false condition, or no jmp), the program
wraps (to .wrap_target instruction). This directive is invalid outside of a
program, may only be used once within a program, and if not specified
defaults to after the last program instruction.
.lang_opt <lang> <name> <option> Specifies an option for the program related to a particular language generator.
(See Language generators). This directive is invalid outside of a program
.word <value> Stores a raw 16-bit value as an instruction in the program. This directive is
invalid outside of a program.
3.3.2. Values
The following types of values can be used to define integer numbers or branch targets
<label> The instruction offset of the label within the program. This makes most sense when used with
a JMP instruction (see Section 3.4.2)
( <expression> ) An expression to be evaluated; see expressions. Note that the parentheses are necessary.
3.3.3. Expressions
Expressions may be freely used within pioasm values.
Table 375.
<expression> + <expression> The sum of two expressions
Expressions in pioasm
i.e. <expression>
<expression> - <expression> The difference of two expressions
3.3.4. Comments
Line comments are supported with // or ;
3.3.5. Labels
Labels are of the form:
<symbol>:
or
PUBLIC <symbol>:
TIP
A label is really just an automatic .define with a value set to the current program instruction offset. A PUBLIC label is
exposed to the user code in the same way as a PUBLIC .define.
3.3.6. Instructions
All pioasm instructions follow a common pattern:
where:
<instruction> Is an assembly instruction detailed in the following sections. (See Section 3.4)
<side_set_value> Is a value (see Section 3.3.2) to apply to the side_set pins at the start of the instruction. Note that
the rules for a side-set value via side <side_set_value> are dependent on the .side_set (see
[pioasm_side_set]) directive for the program. If no .side_set is specified then the side
<side_set_value> is invalid, if an optional number of sideset pins is specified then side
<side_set_value> may be present, and if a non-optional number of sideset pins is specified, then
side <side_set_value> is required. The <side_set_value> must fit within the number of side-set bits
specified in the .side_set directive.
<delay_value> Specifies the number of cycles to delay after the instruction completes. The delay_value is
specified as a value (see Section 3.3.2), and in general is between 0 and 31 inclusive (a 5-bit
value), however the number of bits is reduced when sideset is enabled via the .side_set (see
[pioasm_side_set]) directive. If the <delay_value> is not present, then the instruction has no delay
NOTE
pioasm instruction names, keywords and directives are case insensitive; lower case is used in the Assembly Syntax
sections below as this is the style used in the SDK.
NOTE
Commas appear in some Assembly Syntax sections below, but are entirely optional, e.g. out pins, 3 may be written
out pins 3, and jmp x-- label may be written as jmp x--, label. The Assembly Syntax sections below uses the first
style in each case as this is the style used in the SDK.
3.3.7. Pseudoinstructions
Currently pioasm provides one pseudoinstruction, as a convenience:
nop Assembles to mov y, y. "No operation", has no particular side effect, but a useful vehicle for a side-set
operation or an extra delay.
3.4.1. Summary
PIO instructions are 16 bits long, and have the following encoding:
The function of the 5-bit Delay/side-set field depends on the state machine’s SIDESET_COUNT configuration:
• Up to 5 LSBs (5 minus SIDESET_COUNT) encode a number of idle cycles inserted between this instruction and the next.
• Up to 5 MSBs, set by SIDESET_COUNT, encode a side-set (Section 3.5.1), which can assert a constant onto some
GPIOs, concurrently with main instruction execution.
3.4.2. JMP
3.4.2.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.2.2. Operation
Delay cycles on a JMP always take effect, whether Condition is true or false, and they take place after Condition is
evaluated and the program counter is updated.
• Condition:
◦ 000: (no condition): Always
◦ 001: !X: scratch X zero
◦ 010: X--: scratch X non-zero, post-decrement
◦ 011: !Y: scratch Y zero
◦ 100: Y--: scratch Y non-zero, post-decrement
◦ 101: X!=Y: scratch X not equal scratch Y
◦ 110: PIN: branch on input pin
◦ 111: !OSRE: output shift register not empty
• Address: Instruction address to jump to. In the instruction encoding this is an absolute address within the PIO
instruction memory.
JMP PIN branches on the GPIO selected by EXECCTRL_JMP_PIN, a configuration field which selects one out of the maximum
of 32 GPIO inputs visible to a state machine, independently of the state machine’s other input mapping. The branch is
taken if the GPIO is high.
!OSRE compares the bits shifted out since the last PULL with the shift count threshold configured by SHIFTCTRL_PULL_THRESH.
This is the same threshold used by autopull (Section 3.5.4).
where:
<cond> Is an optional condition listed above (e.g. !x for scratch X zero). If a condition code is not specified,
the branch is always taken
<target> Is a program label or value (see Section 3.3.2) representing instruction offset within the program (the
first instruction being offset 0). Note that because the PIO JMP instruction uses absolute addresses
in the PIO instruction memory, JMPs need to be adjusted based on the program load offset at
runtime. This is handled for you when loading a program with the SDK, but care should be taken when
encoding JMP instructions for use by OUT EXEC
3.4.3. WAIT
3.4.3.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.3.2. Operation
Like all stalling instructions (Section 3.2.4), delay cycles begin after the instruction completes. That is, if any delay
cycles are present, they do not begin counting until after the wait condition is met.
• Polarity:
◦ 1: wait for a 1.
◦ 0: wait for a 0.
• Source: what to wait on. Values are:
◦ 00: GPIO: System GPIO input selected by Index. This is an absolute GPIO index, and is not affected by the state
machine’s input IO mapping.
◦ 01: PIN: Input pin selected by Index. This state machine’s input IO mapping is applied first, and then Index
selects which of the mapped bits to wait on. In other words, the pin is selected by adding Index to the
PINCTRL_IN_BASE configuration, modulo 32.
• If Polarity is 1, the selected IRQ flag is cleared by the state machine upon the wait condition being met.
• The flag index is decoded in the same way as the IRQ index field: if the MSB is set, the state machine ID (0…3) is
added to the IRQ index, by way of modulo-4 addition on the two LSBs. For example, state machine 2 with a flag
value of '0x11' will wait on flag 3, and a flag value of '0x13' will wait on flag 1. This allows multiple state machines
running the same program to synchronise with each other.
CAUTION
WAIT 1 IRQ x should not be used with IRQ flags presented to the interrupt controller, to avoid a race condition with a
system interrupt handler
where:
<pin_num> Is a value (see Section 3.3.2) specifying the input pin number (as mapped by the SM input pin
mapping)
<gpio_num> Is a value (see Section 3.3.2) specifying the actual GPIO pin number
<irq_num> ( rel ) Is a value (see Section 3.3.2) specifying The irq number to wait on (0-7). If rel is present, then the
actual irq number used is calculating by replacing the low two bits of the irq number (irq_num10)
with the low two bits of the sum (irq_num10 + sm_num10) where sm_num10 is the state machine
number
3.4.4. IN
3.4.4.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.4.2. Operation
Shift Bit count bits from Source into the Input Shift Register (ISR). Shift direction is configured for each state machine by
SHIFTCTRL_IN_SHIFTDIR. Additionally, increase the input shift count by Bit count, saturating at 32.
• Source:
◦ 000: PINS
◦ 001: X (scratch register X)
◦ 010: Y (scratch register Y)
◦ 011: NULL (all zeroes)
◦ 100: Reserved
◦ 101: Reserved
◦ 110: ISR
◦ 111: OSR
• Bit count: How many bits to shift into the ISR. 1…32 bits, 32 is encoded as 00000.
If automatic push is enabled, IN will also push the ISR contents to the RX FIFO if the push threshold is reached
(SHIFTCTRL_PUSH_THRESH). IN still executes in one cycle, whether an automatic push takes place or not. The state machine
will stall if the RX FIFO is full when an automatic push occurs. An automatic push clears the ISR contents to all-zeroes,
and clears the input shift count. See Section 3.5.4.
IN always uses the least significant Bit count bits of the source data. For example, if PINCTRL_IN_BASE is set to 5, the
instruction IN 3, PINS will take the values of pins 5, 6 and 7, and shift these into the ISR. First the ISR is shifted to the left
or right to make room for the new input data, then the input data is copied into the gap this leaves. The bit order of the
input data is not dependent on the shift direction.
NULL can be used for shifting the ISR’s contents. For example, UARTs receive the LSB first, so must shift to the right.
After 8 IN PINS, 1 instructions, the input serial data will occupy bits 31…24 of the ISR. An IN NULL, 24 instruction will shift
in 24 zero bits, aligning the input data at ISR bits 7…0. Alternatively, the processor or DMA could perform a byte read
from FIFO address + 3, which would take bits 31…24 of the FIFO contents.
in <source>, <bit_count>
where:
<bit_count> Is a value (see Section 3.3.2) specifying the number of bits to shift (valid range 1-32)
3.4.5. OUT
3.4.5.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.5.2. Operation
Shift Bit count bits out of the Output Shift Register (OSR), and write those bits to Destination. Additionally, increase the
output shift count by Bit count, saturating at 32.
• Destination:
◦ 000: PINS
◦ 001: X (scratch register X)
◦ 010: Y (scratch register Y)
◦ 011: NULL (discard data)
◦ 100: PINDIRS
◦ 101: PC
◦ 110: ISR (also sets ISR shift counter to Bit count)
◦ 111: EXEC (Execute OSR shift data as instruction)
• Bit count: how many bits to shift out of the OSR. 1…32 bits, 32 is encoded as 00000.
A 32-bit value is written to Destination: the lower Bit count bits come from the OSR, and the remainder are zeroes. This
value is the least significant Bit count bits of the OSR if SHIFTCTRL_OUT_SHIFTDIR is to the right, otherwise it is the most
significant bits.
PINS and PINDIRS use the OUT pin mapping, as described in Section 3.5.6.
If automatic pull is enabled, the OSR is automatically refilled from the TX FIFO if the pull threshold, SHIFTCTRL_PULL_THRESH,
is reached. The output shift count is simultaneously cleared to 0. In this case, the OUT will stall if the TX FIFO is empty,
but otherwise still executes in one cycle. The specifics are given in Section 3.5.4.
OUT EXEC allows instructions to be included inline in the FIFO datastream. The OUT itself executes on one cycle, and the
instruction from the OSR is executed on the next cycle. There are no restrictions on the types of instructions which can
be executed by this mechanism. Delay cycles on the initial OUT are ignored, but the executee may insert delay cycles as
normal.
OUT PC behaves as an unconditional jump to an address shifted out from the OSR.
where:
<bit_count> Is a value (see Section 3.3.2) specifying the number of bits to shift (valid range 1-32)
3.4.6. PUSH
3.4.6.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.6.2. Operation
Push the contents of the ISR into the RX FIFO, as a single 32-bit word. Clear ISR to all-zeroes.
• IfFull: If 1, do nothing unless the total input shift count has reached its threshold, SHIFTCTRL_PUSH_THRESH (the same
as for autopush; see Section 3.5.4).
The PIO assembler sets the Block bit by default. If the Block bit is not set, the PUSH does not stall on a full RX FIFO, instead
continuing immediately to the next instruction. The FIFO state and contents are unchanged when this happens. The ISR
is still cleared to all-zeroes, and the FDEBUG_RXSTALL flag is set (the same as a blocking PUSH or autopush to a full RX FIFO)
push ( iffull )
where:
iffull Is equivalent to IfFull == 1 above. i.e. the default if this is not specified is IfFull == 0
block Is equivalent to Block == 1 above. This is the default if neither block nor noblock are specified
3.4.7. PULL
3.4.7.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.7.2. Operation
• IfEmpty: If 1, do nothing unless the total output shift count has reached its threshold, SHIFTCTRL_PULL_THRESH (the
same as for autopull; see Section 3.5.4).
• Block: If 1, stall if TX FIFO is empty. If 0, pulling from an empty FIFO copies scratch X to OSR.
Some peripherals (UART, SPI…) should halt when no data is available, and pick it up as it comes in; others (I2S) should
clock continuously, and it is better to output placeholder or repeated data than to stop clocking. This can be achieved
with the Block parameter.
A nonblocking PULL on an empty FIFO has the same effect as MOV OSR, X. The program can either preload scratch register
X with a suitable default, or execute a MOV X, OSR after each PULL NOBLOCK, so that the last valid FIFO word will be recycled
until new data is available.
PULL IFEMPTY is useful if an OUT with autopull would stall in an inappropriate location when the TX FIFO is empty. IfEmpty
permits some of the same program simplifications as autopull — for example, the elimination of an outer loop
counter — but the stall occurs at a controlled point in the program.
NOTE
When autopull is enabled, any PULL instruction is a no-op when the OSR is full, so that the PULL instruction behaves as
a barrier. OUT NULL, 32 can be used to explicitly discard the OSR contents. See Section 3.5.4.2 for more detail.
pull ( ifempty )
where:
ifempty Is equivalent to IfEmpty == 1 above. i.e. the default if this is not specified is IfEmpty == 0
block Is equivalent to Block == 1 above. This is the default if neither block nor noblock are specified
3.4.8. MOV
3.4.8.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.8.2. Operation
• Destination:
◦ 000: PINS (Uses same pin mapping as OUT)
◦ 001: X (Scratch register X)
◦ 010: Y (Scratch register Y)
◦ 011: Reserved
◦ 100: EXEC (Execute data as instruction)
◦ 101: PC
◦ 110: ISR (Input shift counter is reset to 0 by this operation, i.e. empty)
◦ 111: OSR (Output shift counter is reset to 0 by this operation, i.e. full)
• Operation:
◦ 00: None
◦ 01: Invert (bitwise complement)
◦ 10: Bit-reverse
◦ 11: Reserved
• Source:
◦ 000: PINS (Uses same pin mapping as IN)
◦ 001: X
◦ 010: Y
◦ 011: NULL
◦ 100: Reserved
◦ 101: STATUS
◦ 110: ISR
◦ 111: OSR
MOV PC causes an unconditional jump. MOV EXEC has the same behaviour as OUT EXEC (Section 3.4.5), and allows register
contents to be executed as an instruction. The MOV itself executes in 1 cycle, and the instruction in Source on the next
cycle. Delay cycles on MOV EXEC are ignored, but the executee may insert delay cycles as normal.
The STATUS source has a value of all-ones or all-zeroes, depending on some state machine status such as FIFO
full/empty, configured by EXECCTRL_STATUS_SEL.
MOV can manipulate the transferred data in limited ways, specified by the Operation argument. Invert sets each bit in
Destination to the logical NOT of the corresponding bit in Source, i.e. 1 bits become 0 bits, and vice versa. Bit reverse sets
each bit n in Destination to bit 31 - n in Source, assuming the bits are numbered 0 to 31.
where:
3.4.9. IRQ
3.4.9.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.9.2. Operation
• Clear: if 1, clear the flag selected by Index, instead of raising it. If Clear is set, the Wait bit has no effect.
• Wait: if 1, halt until the raised flag is lowered again, e.g. if a system interrupt handler has acknowledged the flag.
• Index:
◦ The 3 LSBs specify an IRQ index from 0-7. This IRQ flag will be set/cleared depending on the Clear bit.
◦ If the MSB is set, the state machine ID (0…3) is added to the IRQ index, by way of modulo-4 addition on the
two LSBs. For example, state machine 2 with a flag value of 0x11 will raise flag 3, and a flag value of 0x13 will
raise flag 1.
IRQ flags 4-7 are visible only to the state machines; IRQ flags 0-3 can be routed out to system level interrupts, on either
of the PIO’s two external interrupt request lines, configured by IRQ0_INTE and IRQ1_INTE.
The modulo addition bit allows relative addressing of 'IRQ' and 'WAIT' instructions, for synchronising state machines
which are running the same program. Bit 2 (the third LSB) is unaffected by this addition.
If Wait is set, Delay cycles do not begin until after the wait period elapses.
where:
<irq_num> ( rel ) Is a value (see Section 3.3.2) specifying The irq number to wait on (0-7). If rel is present, then the
actual irq number used is calculating by replacing the low two bits of the irq number (irq_num10)
with the low two bits of the sum (irq_num10 + sm_num10) where sm_num10 is the state machine
number
irq wait Means set the IRQ and wait for it to be cleared before proceeding
3.4.10. SET
3.4.10.1. Encoding
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
3.4.10.2. Operation
• Destination:
• 000: PINS
• 001: X (scratch register X) 5 LSBs are set to Data, all others cleared to 0.
• 010: Y (scratch register Y) 5 LSBs are set to Data, all others cleared to 0.
• 011: Reserved
• 100: PINDIRS
• 101: Reserved
• 110: Reserved
• 111: Reserved
• Data: 5-bit immediate value to drive to pins or register.
This can be used to assert control signals such as a clock or chip select, or to initialise loop counters. As Data is 5 bits in
size, scratch registers can be SET to values from 0-31, which is sufficient for a 32-iteration loop.
The mapping of SET and OUT onto pins is configured independently. They may be mapped to distinct locations, for
example if one pin is to be used as a clock signal, and another for data. They may also be overlapping ranges of pins: a
UART transmitter might use SET to assert start and stop bits, and OUT instructions to shift out FIFO data to the same pins.
where:
<value> The value (see Section 3.3.2) to set (valid range 0-31)
3.5.1. Side-set
Side-set is a feature that allows state machines to change the level or direction of up to 5 pins, concurrently with the
main execution of the instruction.
One example where this is necessary is a fast SPI interface: here a clock transition (toggling 1→0 or 0→1) must be
simultaneous with a data transition, where a new data bit is shifted from the OSR to a GPIO. In this case an OUT with a
side-set would achieve both of these at once.
This makes the timing of the interface more precise, reduces the overall program size (as a separate SET instruction is
not needed to toggle the clock pin), and also increases the maximum frequency the SPI can run at.
Side-set also makes GPIO mapping much more flexible, as its mapping is independent from SET. The example I2C code
allows SDA and SCL to be mapped to any two arbitrary pins, if clock stretching is disabled. Normally, SCL toggles to
synchronise data transfer, and SDA contains the data bits being shifted out. However, some particular I2C sequences
such as Start and Stop line conditions, need a fixed pattern to be driven on SDA as well as SCL. The mapping I2C uses to
achieve this is:
• Side-set → SCL
• OUT → SDA
• SET → SDA
This lets the state machine serve the two use cases of data on SDA and clock on SCL, or fixed transitions on both SDA
and SCL, while still allowing SDA and SCL to be mapped to any two GPIOs of choice.
The side-set data is encoded in the Delay/side-set field of each instruction. Any instruction can be combined with side-
set, including instructions which write to the pins, such as OUT PINS or SET PINS. Side-set’s pin mapping is independent
from OUT and SET mappings, though it may overlap. If side-set and an OUT or SET write to the same pin simultaneously, the
side-set data is used.
NOTE
1 .program spi_tx_fast
2 .side_set 1
3
4 loop:
5 out pins, 1 side 0
6 jmp loop side 1
The spi_tx_fast example shows two benefits of this: data and clock transitions can be more precisely co-aligned, and
programs can be made faster overall, with an output of one bit per two system clock cycles in this case. Programs can
also be made smaller.
1. The number of MSBs of the Delay/side-set field to use for side-set rather than delay. This is configured by
PINCTRL_SIDESET_COUNT. If this is set to 5, delay cycles are not available. If set to 0, no side-set will take place.
2. Whether to use the most significant of these bits as an enable. Side-set takes place on instructions where the
enable is high. If there is no enable bit, every instruction on that state machine will perform a side-set, if
SIDESET_COUNT is nonzero. This is configured by EXECCTRL_SIDE_EN.
3. The GPIO number to map the least-significant side-set bit to. Configured by PINCTRL_SIDESET_BASE.
In the above example, we have only one side-set data bit, and every instruction performs a side-set, so no enable bit is
required. SIDESET_COUNT would be 1, SIDE_EN would be false. SIDE_PINDIR would also be false, as we want to drive the clock
high and low, not high- and low-impedance. SIDESET_BASE would select the GPIO the clock is driven from.
7 .program squarewave
8 set pindirs, 1 ; Set pin to output
9 again:
10 set pins, 1 [1] ; Drive pin high and then delay for one cycle
11 set pins, 0 ; Drive pin low
12 jmp again ; Set PC to label `again`
The main body of the program drives a pin high, and then low, producing one period of a square wave. The entire
program then loops, driving a periodic output. The jump itself takes one cycle, as does each set instruction, so to keep
the high and low periods of the same duration, the set pins, 1 has a single delay cycle added, which makes the state
machine idle for one cycle before executing the set pins, 0 instruction. In total, each loop takes four cycles. There are
two frustrations here:
• The JMP takes up space in the instruction memory that could be used for other programs
• The extra cycle taken to execute the JMP ends up halving the maximum output rate
As the Program Counter (PC) naturally wraps to 0 when incremented past 31, we could solve the second of these by
filling the entire instruction memory with a repeating pattern of set pins, 1 and set pins, 0, but this is wasteful. State
machines have a hardware feature, configured via their EXECCTRL control register, which solves this common case.
11 .program squarewave_wrap
12 ; Like squarewave, but use the state machine's .wrap hardware instead of an
13 ; explicit jmp. This is a free (0-cycle) unconditional jump.
14
15 set pindirs, 1 ; Set pin to output
16 .wrap_target
17 set pins, 1 [1] ; Drive pin high and then delay for one cycle
18 set pins, 0 [1] ; Drive pin low and then delay for one cycle
19 .wrap
After executing an instruction from the program memory, state machines use the following logic to update PC:
1. If the current instruction is a JMP, and the Condition is true, set PC to the Target
The .wrap_target and .wrap assembly directives in pioasm are essentially labels. They export constants which can be
written to the WRAP_BOTTOM and WRAP_TOP control fields, respectively:
1 // -------------------------------------------------- //
2 // This file is autogenerated by pioasm; do not edit! //
3 // -------------------------------------------------- //
4
5 #if !PICO_NO_HARDWARE
6 #include "hardware/pio.h"
7 #endif
8
9 // --------------- //
10 // squarewave_wrap //
11 // --------------- //
12
13 #define squarewave_wrap_wrap_target 1
14 #define squarewave_wrap_wrap 2
15
16 static const uint16_t squarewave_wrap_program_instructions[] = {
17 0xe081, // 0: set pindirs, 1
18 // .wrap_target
19 0xe101, // 1: set pins, 1 [1]
20 0xe100, // 2: set pins, 0 [1]
21 // .wrap
22 };
23
24 #if !PICO_NO_HARDWARE
25 static const struct pio_program squarewave_wrap_program = {
26 .instructions = squarewave_wrap_program_instructions,
27 .length = 3,
28 .origin = -1,
29 };
30
31 static inline pio_sm_config squarewave_wrap_program_get_default_config(uint offset) {
32 pio_sm_config c = pio_get_default_sm_config();
33 sm_config_set_wrap(&c, offset + squarewave_wrap_wrap_target, offset +
squarewave_wrap_wrap);
34 return c;
35 }
36 #endif
This is raw output from the PIO assembler, pioasm, which has created a default pio_sm_config object containing the WRAP
register values from the program listing. The control register fields could also be initialised directly.
NOTE
WRAP_BOTTOM and WRAP_TOP are absolute addresses in the PIO instruction memory. If a program is loaded at an offset,
the wrap addresses must be adjusted accordingly.
The squarewave_wrap example has delay cycles inserted, so that it behaves identically to the original squarewave program.
Thanks to program wrapping, these can now be removed, so that the output toggles twice as fast, while maintaining an
even balance of high and low periods.
12 .program squarewave_fast
13 ; Like squarewave_wrap, but remove the delay cycles so we can run twice as fast.
14 set pindirs, 1 ; Set pin to output
15 .wrap_target
16 set pins, 1 ; Drive pin high
17 set pins, 0 ; Drive pin low
18 .wrap
Another example is a UART: because the TX/CTS and RX/RTS parts a of a UART are asynchronous, they are
implemented on two separate state machines. It would be wasteful to leave half of each state machine’s FIFO
resources idle. The ability to join the two halves into just a TX FIFO for the TX/CTS state machine, or just an RX FIFO in
the case of the RX/RTS state machine, allows full utilisation. A UART equipped with an 8-deep FIFO can be left alone for
When one FIFO is increased in size (from 4 to 8), the other FIFO on that state machine is reduced to zero. For example, if
joining to TX, the RX FIFO is unavailable, and any PUSH instruction will stall. The RX FIFO will appear both RXFULL and
RXEMPTY in the FSTAT register. The converse is true if joining to RX: the TX FIFO is unavailable, and the TXFULL and TXEMPTY
bits for this state machine will both be set in FSTAT.
8 FIFO entries is sufficient for 1 word per clock through the RP2040 system DMA, provided the DMA is not slowed by
contention with other masters.
CAUTION
Changing FJOIN discards any data present in the state machine’s FIFOs. If this data is irreplaceable, it must be
drained beforehand.
1 .program manual_pull
2 .side_set 1 opt
3
4 .wrap_target
5 set x, 2 ; X = bit count - 2
6 pull side 1 [1] ; Stall here if no TX data
7 bitloop:
8 out pins, 1 side 0 [1] ; Shift out data bit and toggle clock low
9 jmp x-- bitloop side 1 [1] ; Loop runs 3 times
10 out pins, 1 side 0 ; Shift out last bit before reloading X
11 .wrap
This program shifts out 4 bits from each FIFO word, with an accompanying bit clock, at a constant rate of 1 bit per 4
cycles. When the TX FIFO is empty, it stalls with the clock high (noting that side-set still takes place on cycles where the
instruction stalls). Figure 43 shows how a state machine would execute this program.
• On an OUT instruction which reaches or exceeds the pull threshold, the state machine can simultaneously refill the
OSR from the TX FIFO, if data is available.
• On an IN instruction which reaches or exceeds the push threshold, the state machine can write the shift result
directly to the RX FIFO, and clear the ISR.
The manual_pull example can be rewritten to take advantage of automatic pull (autopull):
1 .program autopull
2 .side_set 1
3
4 .wrap_target
5 out pins, 1 side 0 [1]
6 nop side 1 [1]
7 .wrap
This is shorter and simpler than the original, and can run twice as fast, if the delay cycles are removed, since the
hardware refills the OSR "for free". Note that the program does not determine the total number of bits to be shifted
before the next pull; the hardware automatically pulls once the programmable threshold, SHIFCTRL_PULL_THRESH, is
reached, so the same program could also shift out e.g. 16 or 32 bits from each FIFO word.
Finally, note that the above program is not exactly the same as the original, since it stalls with the clock output low,
rather than high. We can change the location of the stall, using the PULL IFEMPTY instruction, which uses the same
configurable threshold as autopull:
1 .program somewhat_manual_pull
2 .side_set 1
3
4 .wrap_target
5 out pins, 1 side 0 [1]
6 pull ifempty side 1 [1]
7 .wrap
Below is a complete example (PIO program, plus a C program to load and run it) which illustrates autopull and autopush
both enabled on the same state machine. It programs state machine 0 to loopback data from the TX FIFO to the RX
FIFO, with a throughput of one word per two clocks. It also demonstrates how the state machine will stall if it tries to OUT
when both the OSR and TX FIFO are empty.
1 .program auto_push_pull
2
3 .wrap_target
4 out x, 32
5 in x, 32
6 .wrap
1 #include "tb.h" // TODO this is built against existing sw tree, so that we get printf etc
2
3 #include "platform.h"
4 #include "pio_regs.h"
5 #include "system.h"
6 #include "hardware.h"
7
8 #include "auto_push_pull.pio.h"
9
10 int main()
11 {
12 tb_init();
13
14 // Load program and configure state machine 0 for autopush/pull with
15 // threshold of 32, and wrapping on program boundary. A threshold of 32 is
16 // encoded by a register value of 00000.
17 for (int i = 0; i < count_of(auto_push_pull_program); ++i)
18 mm_pio->instr_mem[i] = auto_push_pull_program[i];
19 mm_pio->sm[0].shiftctrl =
20 (1u << PIO_SM0_SHIFTCTRL_AUTOPUSH_LSB) |
21 (1u << PIO_SM0_SHIFTCTRL_AUTOPULL_LSB) |
22 (0u << PIO_SM0_SHIFTCTRL_PUSH_THRESH_LSB) |
23 (0u << PIO_SM0_SHIFTCTRL_PULL_THRESH_LSB);
24 mm_pio->sm[0].execctrl =
25 (auto_push_pull_wrap_target << PIO_SM0_EXECCTRL_WRAP_BOTTOM_LSB) |
26 (auto_push_pull_wrap << PIO_SM0_EXECCTRL_WRAP_TOP_LSB);
27
28 // Start state machine 0
29 hw_set_bits(&mm_pio->ctrl, 1u << (PIO_CTRL_SM_ENABLE_LSB + 0));
30
31 // Push data into TX FIFO, and pop from RX FIFO
32 for (int i = 0; i < 5; ++i)
33 mm_pio->txf[0] = i;
34 for (int i = 0; i < 5; ++i)
35 printf("%d\n", mm_pio->rxf[0]);
36
37 return 0;
38 }
Figure 44 shows how the state machine executes the example program. Initially the OSR is empty, so the state machine
stalls on the first OUT instruction. Once data is available in the TX FIFO, the state machine transfers this into the OSR. On
the next cycle, the OUT can execute using the data in the OSR (in this case, transferring this data to the X scratch
register), and the state machine simultaneously refills the OSR with fresh data from the FIFO. Since every IN instruction
immediately fills the ISR, the ISR remains empty, and IN transfers data directly from scratch X to the RX FIFO.
• At reset, or upon CTRL_SM_RESTART assertion, ISR shift counter is set to 0 (nothing shifted in), and OSR to 32 (nothing
left to be shifted out)
Note that the hardware performs the above steps in a single machine clock cycle (unless there is a stall).
On non-'OUT' cycles, the hardware performs the equivalent of the following pseudocode:
1 if MOV or PULL:
2 osr count = 0
3
4 if osr count >= threshold:
5 if tx fifo not empty:
6 osr = pull()
7 osr count = 0
An autopull can therefore occur at any point between two 'OUT' s, depending on when the data arrives in the FIFO.
The hardware is capable of refilling the OSR simultaneously with shifting out the last of the shift data, as these two
operations can proceed in parallel. However, it cannot fill an empty OSR and 'OUT' it on the same cycle, due to the long
logic path this would create.
The refill is somewhat asynchronous to your program, but an 'OUT' behaves as a data fence, and the state machine will
never 'OUT' data which you didn’t write into the FIFO.
Note that a 'MOV' from the OSR is undefined whilst autopull is enabled; you will read either any residual data that has
not been shifted out, or a fresh word from the FIFO, depending on a race against system DMA. Likewise, a 'MOV' to the
OSR may overwrite data which has just been autopulled. However, data which you 'MOV' into the OSR will never be
overwritten, since 'MOV' updates the shift counter.
If you do need to read the OSR contents, you should perform an explicit 'PULL' of some kind. The nondeterminism
described above is the cost of the hardware managing pulls automatically. When autopull is enabled, the behaviour of
'PULL' is altered: it becomes a no-op if the OSR is full. This is to avoid a race condition against the system DMA. It
behaves as a fence: either an autopull has already taken place, in which case the 'PULL' has no effect, or the program
will stall on the 'PULL' until data becomes available in the FIFO.
'PUSH' does not need a similar behaviour, because autopush does not have the same nondeterminism.
Rather than slowing the system clock itself, the clock divider redefines how many system clock periods are considered
to be "one cycle", for execution purposes. It does this by generating a clock enable signal, which can pause and resume
execution on a per-system-clock-cycle basis. The clock divider generates clock enable pulses at regular intervals, so
that the state machine runs at some steady pace, potentially much slower than the system clock.
Implementing the clock dividers in this way allows interfacing between the state machines and the system to be
simpler, lower-latency, and with a smaller footprint. The state machine is completely idle on cycles where clock enable
is low, though the system can still access the state machine’s FIFOs and change its configuration.
The clock dividers are 16-bit integer, 8-bit fractional, with first-order delta-sigma for the fractional divider. The clock
divisor can vary between 1 and 65536, in increments of .
If the clock divisor is set to 1, the state machine runs on every cycle, i.e. full speed:
Fractional division will maintain a steady state division rate of , where n and f are the integer and fractional
fields of this state machine’s CLKDIV register. It does this by selectively extending some division periods from cycles to
.
For fast asynchronous serial, it is recommended to use even divisions or multiples of 1 Mbaud where possible,
rather than the traditional multiples of 300, to avoid unnecessary jitter.
The write data and write masks for the output level and output enable registers come from the following sources:
• An OUT instruction writes to up to 32 bits. Depending on the instruction’s Destination field, this is applied to either
pins or pindirs. The least-significant bit of OUT data is mapped to PINCTRL_OUT_BASE, and this mapping continues for
PINCTRL_OUT_COUNT bits, wrapping after GPIO31.
• A SET instruction writes up to 5 bits. Depending on the instruction’s Destination field, this is applied to either pins or
pindirs. The least-significant bit of SET data is mapped to PINCTRL_SET_BASE, and this mapping continues for
PINCTRL_SET_COUNT bits, wrapping after GPIO31.
• A side-set operation writes up to 5 bits. Depending on the register field EXECCTRL_SIDE_PINDIR, this is applied to either
pins or pindirs. The least-significant bit of side-set data is mapped to PINCTRL_SIDESET_BASE, continuing for
PINCTRL_SIDESET_COUNT pins, minus one if EXECCTRL_SIDE_EN is set.
Each OUT/SET/side-set operation writes to a contiguous range of pins, but each of these ranges is independently sized
and positioned in the 32-bit GPIO space. This is sufficiently flexible for many applications. For example, if one state
machine is implementing some interface such as an SPI on a group of pins, another state machine can run the same
program, mapped to a different group of pins, and provide a second SPI interface.
On any given clock cycle, the state machine may perform an OUT or a SET, and may simultaneously perform a side-set.
The pin mapping logic generates a 32-bit write mask and write data bus for the output level and output enable registers,
based on this request, and the pin mapping configuration.
If a side-set overlaps with an OUT/SET performed by that state machine on the same cycle, the side-set takes precedence
in the overlapping region.
Each state machine may assert an OUT/SET and a side-set through its pin mapping hardware on each cycle. This
generates 32 bits of write data and write mask for the GPIO output level and output enable registers, from each state
machine.
For each GPIO, PIO collates the writes from all four state machines, and applies the write from the highest-numbered
state machine. This occurs separately for output levels and output values — it is possible for a state machine to change
both the level and direction of the same pin on the same cycle (e.g. via simultaneous SET and side-set), or for one state
machine to change a GPIO’s direction while another changes that GPIO’s level. If no state machine asserts a write to a
GPIO’s level or direction, the value does not change.
The data observed by IN instructions is mapped such that the LSB is the GPIO selected by PINCTRL_IN_BASE, and
successively more-significant bits come from successively higher-numbered GPIOs, wrapping after 31.
In other words, the IN bus is a right-rotate of the GPIO input values, by PINCTRL_IN_BASE. If fewer than 32 GPIOs are
present, the PIO input is padded with zeroes up to 32 bits.
Some instructions, such as WAIT GPIO, use an absolute GPIO number, rather than an index into the IN data bus. In this
case, the right-rotate is not applied.
To protect PIO from metastabilities, each GPIO input is equipped with a standard 2-flipflop synchroniser. This adds two
cycles of latency to input sampling, but the benefit is that state machines can perform an IN PINS at any point, and will
see only a clean high or low level, not some intermediate value that could disturb the state machine circuitry. This is
absolutely necessary for asynchronous interfaces such as UART RX.
It is possible to bypass these synchronisers, on a per-GPIO basis. This reduces input latency, but it is then up to the user
to guarantee that the state machine does not sample its inputs at inappropriate times. Generally this is only possible for
synchronous interfaces such as SPI. Synchronisers are bypassed by setting the corresponding bit in INPUT_SYNC_BYPASS.
WARNING
Sampling a metastable input can lead to unpredictable state machine behaviour. This should be avoided.
1 .program exec_example
2
3 hang:
4 jmp hang
5 execute:
6 out exec, 32
7 jmp execute
8
9 .program instructions_to_push
10
11 out x, 32
12 in x, 32
13 push
1 #include "tb.h" // TODO this is built against existing sw tree, so that we get printf etc
2
3 #include "platform.h"
4 #include "pio_regs.h"
5 #include "system.h"
6 #include "hardware.h"
7
8 #include "exec_example.pio.h"
9
10 int main()
11 {
12 tb_init();
13
14 for (int i = 0; i < count_of(exec_example_program); ++i)
15 mm_pio->instr_mem[i] = exec_example_program[i];
16
17 // Enable autopull, threshold of 32
18 mm_pio->sm[0].shiftctrl = (1u << PIO_SM0_SHIFTCTRL_AUTOPULL_LSB);
19
20 // Start state machine 0 -- will sit in "hang" loop
21 hw_set_bits(&mm_pio->ctrl, 1u << (PIO_CTRL_SM_ENABLE_LSB + 0));
22
23 // Force a jump to program location 1
24 mm_pio->sm[0].instr = 0x0000 | 0x1; // jmp execute
25
26 // Feed a mixture of instructions and data into FIFO
27 mm_pio->txf[0] = instructions_to_push_program[0]; // out x, 32
28 mm_pio->txf[0] = 12345678; // data to be OUTed
29 mm_pio->txf[0] = instructions_to_push_program[1]; // in x, 32
30 mm_pio->txf[0] = instructions_to_push_program[2]; // push
31
32 // The program pushed into TX FIFO will return some data in RX FIFO
33 while (mm_pio->fstat & (1u << PIO_FSTAT_RXEMPTY_LSB))
34 ;
35
36 printf("%d\n", mm_pio->rxf[0]);
37
38 return 0;
39 }
Here we load an example program into the state machine, which does two things:
The C program sets the state machine running, at which point it enters the hang loop. While the state machine is still
running, the C program forces in a jmp instruction, which causes the state machine to break out of the loop.
When an instruction is written to the INSTR register, the state machine immediately decodes and executes that
instruction, rather than the instruction it would have fetched from the PIO’s instruction memory. The program counter
does not advance, so on the next cycle (assuming the instruction forced into the INSTR interface did not stall) the state
machine continues to execute its current program from the point where it left off, unless the written instruction itself
manipulated PC.
Delay cycles are ignored on instructions written to the INSTR register, and execute immediately, ignoring the state
machine clock divider. This interface is provided for performing initial setup and effecting control flow changes, so it
executes instructions in a timely manner, no matter how the state machine is configured.
Instructions written to the INSTR register are permitted to stall, in which case the state machine will latch this instruction
internally until it completes. This is signified by the EXECCTRL_EXEC_STALLED flag. This can be cleared by restarting the state
machine, or writing a NOP to INSTR.
In the second phase of the example state machine program, the OUT EXEC instruction is used. The OUT itself occupies one
execution cycle, and the instruction which the OUT executes is on the next execution cycle. Note that one of the
instructions we execute is also an OUT — the state machine is only capable of executing one OUT instruction on any given
cycle.
OUT EXEC works by writing the OUT shift data to an internal instruction latch. On the next cycle, the state machine
remembers it must execute from this latch rather than the instruction memory, and also knows to not advance PC on this
second cycle.
CAUTION
If an instruction written to INSTR stalls, it is stored in the same instruction latch used by OUT EXEC and MOV EXEC, and will
overwrite an in-progress instruction there. If EXEC instructions are used, instructions written to INSTR must not stall.
3.6. Examples
These examples illustrate some of PIO’s hardware features, by implementing common I/O interfaces.
The Raspberry Pi Pico C/C++ SDK book has a comprehensive PIO chapter, which walks through writing
and building a first PIO application, and goes on to walk through some programs line-by-line. It also
covers broader topics such as using PIO with DMA, and goes into much more depth on how PIO can be
integrated into your software.
This code uses autopush and autopull to continuously stream data from the FIFOs. The entire program runs once for
every bit that is transferred, and then loops. The state machine tracks how many bits have been shifted in/out, and
automatically pushes/pulls the FIFOs at the correct point. A similar program handles the CPHA=1 case:
34 .program spi_cpha1
35 .side_set 1
36
37 ; Clock phase = 1: data transitions on the leading edge of each SCK pulse, and
38 ; is captured on the trailing edge.
39
40 out x, 1 side 0 ; Stall here on empty (keep SCK deasserted)
41 mov pins, x side 1 [1] ; Output data, assert SCK (mov pins uses OUT mapping)
42 in pins, 1 side 0 ; Input data, deassert SCK
NOTE
These programs do not control the chip select line; chip select is often implemented as a software-controlled GPIO,
due to wildly different behaviour between different SPI hardware. The full spi.pio source linked above contains some
examples how PIO can implement a hardware chip select line.
A C helper function configures the state machine, connects the GPIOs, and sets the state machine running. Note that
the SPI frame size — that is, the number of bits transferred for each FIFO record — can be programmed to any value
from 1 to 32, without modifying the program. Once configured, the state machine is set running.
46 static inline void pio_spi_init(PIO pio, uint sm, uint prog_offs, uint n_bits,
47 float clkdiv, bool cpha, bool cpol, uint pin_sck, uint pin_mosi, uint pin_miso) {
48 pio_sm_config c = cpha ? spi_cpha1_program_get_default_config(prog_offs) :
spi_cpha0_program_get_default_config(prog_offs);
49 sm_config_set_out_pins(&c, pin_mosi, 1);
50 sm_config_set_in_pins(&c, pin_miso);
51 sm_config_set_sideset_pins(&c, pin_sck);
52 // Only support MSB-first in this example code (shift to left, auto push/pull,
threshold=nbits)
53 sm_config_set_out_shift(&c, false, true, n_bits);
54 sm_config_set_in_shift(&c, false, true, n_bits);
55 sm_config_set_clkdiv(&c, clkdiv);
56
57 // MOSI, SCK output are low, MISO is input
58 pio_sm_set_pins_with_mask(pio, sm, 0, (1u << pin_sck) | (1u << pin_mosi));
59 pio_sm_set_pindirs_with_mask(pio, sm, (1u << pin_sck) | (1u << pin_mosi), (1u <<
pin_sck) | (1u << pin_mosi) | (1u << pin_miso));
60 pio_gpio_init(pio, pin_mosi);
61 pio_gpio_init(pio, pin_miso);
62 pio_gpio_init(pio, pin_sck);
63
64 // The pin muxes can be configured to invert the output (among other things
65 // and this is a cheesy way to get CPOL=1
66 gpio_set_outover(pin_sck, cpol ? GPIO_OVERRIDE_INVERT : GPIO_OVERRIDE_NORMAL);
67 // SPI is synchronous, so bypass input synchroniser to reduce input delay.
68 hw_set_bits(&pio->input_sync_bypass, 1u << pin_miso);
69
70 pio_sm_init(pio, sm, prog_offs, &c);
71 pio_sm_set_enabled(pio, sm, true);
72 }
The state machine will now immediately begin to shift out any data appearing in the TX FIFO, and push received data
into the RX FIFO.
28 }
29 if (rx_remain && !pio_sm_is_rx_fifo_empty(spi->pio, spi->sm)) {
30 (void) *rxfifo;
31 --rx_remain;
32 }
33 }
34 }
Putting this all together, this complete C program will loop back some data through a PIO SPI at 1 MHz, with all four
CPOL/CPHA combinations:
1 /**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9
10 #include "pico/stdlib.h"
11 #include "pio_spi.h"
12
13 // This program instantiates a PIO SPI with each of the four possible
14 // CPOL/CPHA combinations, with the serial input and output pin mapped to the
15 // same GPIO. Any data written into the state machine's TX FIFO should then be
16 // serialised, deserialised, and reappear in the state machine's RX FIFO.
17
18 #define PIN_SCK 18
19 #define PIN_MOSI 16
20 #define PIN_MISO 16 // same as MOSI, so we get loopback
21
22 #define BUF_SIZE 20
23
24 void test(const pio_spi_inst_t *spi) {
25 static uint8_t txbuf[BUF_SIZE];
26 static uint8_t rxbuf[BUF_SIZE];
27 printf("TX:");
28 for (int i = 0; i < BUF_SIZE; ++i) {
29 txbuf[i] = rand() >> 16;
30 rxbuf[i] = 0;
31 printf(" %02x", (int) txbuf[i]);
32 }
33 printf("\n");
34
35 pio_spi_write8_read8_blocking(spi, txbuf, rxbuf, BUF_SIZE);
36
37 printf("RX:");
38 bool mismatch = false;
39 for (int i = 0; i < BUF_SIZE; ++i) {
40 printf(" %02x", (int) rxbuf[i]);
41 mismatch = mismatch || rxbuf[i] != txbuf[i];
42 }
43 if (mismatch)
44 printf("\nNope\n");
45 else
46 printf("\nOK\n");
47 }
48
49 int main() {
50 stdio_init_all();
51
52 pio_spi_inst_t spi = {
53 .pio = pio0,
54 .sm = 0
55 };
56 float clkdiv = 31.25f; // 1 MHz @ 125 clk_sys
57 uint cpha0_prog_offs = pio_add_program(spi.pio, &spi_cpha0_program);
58 uint cpha1_prog_offs = pio_add_program(spi.pio, &spi_cpha1_program);
59
60 for (int cpha = 0; cpha <= 1; ++cpha) {
61 for (int cpol = 0; cpol <= 1; ++cpol) {
62 printf("CPHA = %d, CPOL = %d\n", cpha, cpol);
63 pio_spi_init(spi.pio, spi.sm,
64 cpha ? cpha1_prog_offs : cpha0_prog_offs,
65 8, // 8 bits per SPI frame
66 clkdiv,
67 cpha,
68 cpol,
69 PIN_SCK,
70 PIN_MOSI,
71 PIN_MISO
72 );
73 test(&spi);
74 sleep_ms(10);
75 }
76 }
77 }
7 .program ws2812
8 .side_set 1
9
10 .define public T1 2
11 .define public T2 5
12 .define public T3 3
13
14 .lang_opt python sideset_init = pico.PIO.OUT_HIGH
15 .lang_opt python out_init = pico.PIO.OUT_HIGH
16 .lang_opt python out_shiftdir = 1
17
18 .wrap_target
19 bitloop:
20 out x, 1 side 0 [T3 - 1] ; Side-set still takes place when instruction stalls
21 jmp !x do_zero side 1 [T1 - 1] ; Branch on the bit we shifted out. Positive pulse
22 do_one:
23 jmp bitloop side 1 [T2 - 1] ; Continue driving high, for a long pulse
24 do_zero:
25 nop side 0 [T2 - 1] ; Or drive low, for a short pulse
26 .wrap
This program shifts bits from the OSR into X, and produces a wide or narrow pulse on side-set pin 0, based on the value
of each data bit. Autopull must be configured, with a threshold of 24. Software can then write 24-bit pixel values into the
FIFO, and these will be serialised to a chain of WS2812 LEDs. The .pio file contains a C helper function to set this up:
31 static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq,
bool rgbw) {
32
33 pio_gpio_init(pio, pin);
34 pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
35
36 pio_sm_config c = ws2812_program_get_default_config(offset);
37 sm_config_set_sideset_pins(&c, pin);
38 sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
39 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
40
41 int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
42 float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
43 sm_config_set_clkdiv(&c, div);
44
45 pio_sm_init(pio, sm, offset, &c);
46 pio_sm_set_enabled(pio, sm, true);
47 }
Because the shift is MSB-first, and our pixels aren’t a power of two size (so we can’t rely on the narrow write replication
behaviour on RP2040 to fan out the bits for us), we need to preshift the values written to the TX FIFO.
To DMA the pixels, we could instead set the autopull threshold to 8 bits, set the DMA transfer size to 8 bits, and write a
byte at a time into the FIFO. Each pixel would be 3 one-byte transfers. Because of how the bus fabric and DMA on
RP2040 work, each byte the DMA transfers will appear replicated four times when written to a 32-bit IO register, so
effectively your data is at both ends of the shift register, and you can shift in either direction without worry.
More detail?
The WS2812 example is the subject of a tutorial in the Raspberry Pi Pico C/C++ SDK document, in the
PIO chapter. The tutorial dissects the ws2812 program line by line, traces through how the program
executes, and shows wave diagrams of the GPIO output at every point in the program.
3.6.3. UART TX
As written, it will:
• Stall with the pin driven high until data appears (noting that side-set takes effect even when the state machine is
stalled)
The .pio file in the SDK also contains this function, for configuring the pins and the state machine, once the program
has been loaded into the PIO instruction memory:
23 static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint
baud) {
24 // Tell PIO to initially drive output-high on the selected pin, then map PIO
25 // onto that pin with the IO muxes.
26 pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
27 pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
28 pio_gpio_init(pio, pin_tx);
29
30 pio_sm_config c = uart_tx_program_get_default_config(offset);
31
32 // OUT shifts to right, no autopull
33 sm_config_set_out_shift(&c, true, false, 32);
34
35 // We are mapping both OUT and side-set to the same pin, because sometimes
36 // we need to assert user data onto the pin (with OUT) and sometimes
37 // assert constant values (start/stop bit)
38 sm_config_set_out_pins(&c, pin_tx, 1);
39 sm_config_set_sideset_pins(&c, pin_tx);
40
41 // We only need TX, so get an 8-deep FIFO!
42 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
43
44 // SM transmits 1 bit per 8 execution cycles.
45 float div = (float)clock_get_hz(clk_sys) / (8 * baud);
46 sm_config_set_clkdiv(&c, div);
47
48 pio_sm_init(pio, sm, offset, &c);
49 pio_sm_set_enabled(pio, sm, true);
50 }
The state machine is configured to shift right in out instructions, because UARTs typically send data LSB-first. Once
configured, the state machine will print any characters pushed to the TX FIFO.
56 static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) {
57 while (*s)
58 uart_tx_program_putc(pio, sm, *s++);
59 }
The example program in the SDK will configure one PIO state machine as a UART TX peripheral, and use it to print a
message on GPIO 0 at 115200 baud once per second.
1 /**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "pico/stdlib.h"
8 #include "hardware/pio.h"
9 #include "uart_tx.pio.h"
10
11 int main() {
12 // We're going to use PIO to print "Hello, world!" on the same GPIO which we
13 // normally attach UART0 to.
14 const uint PIN_TX = 0;
15 // This is the same as the default UART baud rate on Pico
16 const uint SERIAL_BAUD = 115200;
17
18 PIO pio = pio0;
19 uint sm = 0;
20 uint offset = pio_add_program(pio, &uart_tx_program);
21 uart_tx_program_init(pio, sm, offset, PIN_TX, SERIAL_BAUD);
22
23 while (true) {
24 uart_tx_program_puts(pio, sm, "Hello, world! (from PIO!)\n");
25 sleep_ms(1000);
26 }
27 }
With the two PIO instances on RP2040, this could be extended to 8 additional UART TX interfaces, on 8 different pins,
with 8 different baud rates.
3.6.4. UART RX
Recalling figure Figure 52 showing the format of an 8n1 UART:
Bit Clock
TX 0 1 2 3 4 5 6 7
We can recover the data by waiting for the start bit, sampling 8 times with the correct timing, and pushing the result to
the RX FIFO. Below is possibly the shortest program which can do this:
7 .program uart_rx_mini
8
9 ; Minimum viable 8n1 UART receiver. Wait for the start bit, then sample 8 bits
10 ; with the correct timing.
11 ; IN pin 0 is mapped to the GPIO used as UART RX.
12 ; Autopush must be enabled, with a threshold of 8.
13
14 wait 0 pin 0 ; Wait for start bit
15 set x, 7 [10] ; Preload bit counter, delay until eye of first data bit
16 bitloop: ; Loop 8 times
17 in pins, 1 ; Sample data
18 jmp x-- bitloop [6] ; Each iteration is 8 cycles
This works, but it has some annoying characteristics, like repeatedly outputting NUL characters if the line is stuck low.
Ideally, we would want to drop data that is not correctly framed by a start and stop bit (and set some sticky flag to
indicate this has happened), and pause receiving when the line is stuck low for long periods. We can add these to our
program, at the cost of a few more instructions.
43 .program uart_rx
44
45 ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and
46 ; break conditions more gracefully.
47 ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX.
48
49 start:
50 wait 0 pin 0 ; Stall until start bit is asserted
51 set x, 7 [10] ; Preload bit counter, then delay until halfway through
52 bitloop: ; the first data bit (12 cycles incl wait, set).
53 in pins, 1 ; Shift data bit into ISR
54 jmp x-- bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles
55 jmp pin good_stop ; Check stop bit (should be high)
56
57 irq 4 rel ; Either a framing error or a break. Set a sticky flag,
58 wait 1 pin 0 ; and wait for line to return to idle state.
59 jmp start ; Don't push data if we didn't see good framing.
60
61 good_stop: ; No delay before returning to start; a little slack is
62 push ; important in case the TX clock is slightly too fast.
The second example does not use autopush (Section 3.5.4), preferring instead to use an explicit push instruction, so that
it can condition the push on whether a correct stop bit is seen. The .pio file includes a helper function which configures
the state machine and connects it to a GPIO with the pullup enabled:
66 static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud)
{
67 pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
68 pio_gpio_init(pio, pin);
69 gpio_pull_up(pin);
70
71 pio_sm_config c = uart_rx_program_get_default_config(offset);
72 sm_config_set_in_pins(&c, pin); // for WAIT, IN
73 sm_config_set_jmp_pin(&c, pin); // for JMP
74 // Shift to right, autopull disabled
75 sm_config_set_in_shift(&c, true, false, 32);
76 // Deeper FIFO as we're not doing any TX
77 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
78 // SM transmits 1 bit per 8 execution cycles.
79 float div = (float)clock_get_hz(clk_sys) / (8 * baud);
80 sm_config_set_clkdiv(&c, div);
81
82 pio_sm_init(pio, sm, offset, &c);
83 pio_sm_set_enabled(pio, sm, true);
84 }
To correctly receive data which is sent LSB-first, the ISR is configured to shift to the right. After shifting in 8 bits, this
unfortunately leaves our 8 data bits in bits 31:24 of the ISR, with 24 zeroes in the LSBs. One option here is an in null, 24
instruction to shuffle the ISR contents down to 7:0. Another is to read from the FIFO at an offset of 3 bytes, with an 8-bit
read, so that the processor’s bus hardware (or the DMA’s) picks out the relevant byte for free:
An example program shows how this UART RX program can be used to receive characters sent by one of the hardware
UARTs on RP2040. A wire must be connected from GPIO4 to GPIO3 for this program to function. To make the wrangling
of 3 different serial ports a little easier, this program uses core 1 to print out a string on the test UART (UART 1), and the
code running on core 0 will pull out characters from the PIO state machine, and pass them along to the UART used for
the debug console (UART 0). Another approach here would be interrupt-based IO, using PIO’s FIFO IRQs. If the
SM0_RXNEMPTY bit is set in the IRQ0_INTE register, then PIO will raise its first interrupt request line whenever there is a
character in state machine 0’s RX FIFO.
1 /**
Starting from the label called start, this program shifts one data bit at a time into the X register, so that it can branch on
the value. Depending on the outcome, it uses side-set to drive either a 1-0 or 0-1 sequence onto the chosen GPIO. This
program uses autopull (Section 3.5.4.2) to automatically replenish the OSR from the TX FIFO once a certain amount of
data has been shifted out, without interrupting program control flow or timing. This feature is enabled by a helper
function in the .pio file which configures and starts the state machine:
32 static inline void manchester_tx_program_init(PIO pio, uint sm, uint offset, uint pin, float
div) {
33 pio_sm_set_pins_with_mask(pio, sm, 0, 1u << pin);
34 pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
35 pio_gpio_init(pio, pin);
36
37 pio_sm_config c = manchester_tx_program_get_default_config(offset);
38 sm_config_set_sideset_pins(&c, pin);
39 sm_config_set_out_shift(&c, true, true, 32);
40 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
41 sm_config_set_clkdiv(&c, div);
42 pio_sm_init(pio, sm, offset + manchester_tx_offset_start, &c);
43
44 pio_sm_set_enabled(pio, sm, true);
45 }
Another state machine can be programmed to recover the original data from the transmitted signal:
48 .program manchester_rx
49
50 ; Assumes line is idle low, first bit is 0
51 ; One bit is 12 cycles
52 ; a '0' is encoded as 10
53 ; a '1' is encoded as 01
54 ;
55 ; Both the IN base and the JMP pin mapping must be pointed at the GPIO used for RX.
56 ; Autopush must be enabled.
57 ; Before enabling the SM, it should be placed in a 'wait 1, pin` state, so that
58 ; it will not start sampling until the initial line idle state ends.
59
60 start_of_0: ; We are 0.25 bits into a 0 - signal is high
61 wait 0 pin 0 ; Wait for the 1->0 transition - at this point we are 0.5 into the
bit
62 in y, 1 [8] ; Emit a 0, sleep 3/4 of a bit
63 jmp pin start_of_0 ; If signal is 1 again, it's another 0 bit, otherwise it's a 1
64
65 .wrap_target
66 start_of_1: ; We are 0.25 bits into a 1 - signal is 1
67 wait 1 pin 0 ; Wait for the 0->1 transition - at this point we are 0.5 into the
bit
68 in x, 1 [8] ; Emit a 1, sleep 3/4 of a bit
69 jmp pin start_of_0 ; If signal is 0 again, it's another 1 bit otherwise it's a 0
70 .wrap
The main complication here is staying aligned to the input transitions, as the transmitter’s and receiver’s clocks may
drift relative to one another. In Manchester code there is always a transition in the centre of the symbol, and based on
the initial line state (high or low) we know the direction of this transition, so we can use a wait instruction to
resynchronise to the line transitions on every data bit.
This program expects the X and Y registers to be initialised with the values 1 and 0 respectively, so that a constant 1 or
0 can be provided to the in instruction. The code that configures the state machine initialises these registers by
executing some set instructions before setting the program running.
73 static inline void manchester_rx_program_init(PIO pio, uint sm, uint offset, uint pin, float
div) {
74 pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
75 pio_gpio_init(pio, pin);
76
77 pio_sm_config c = manchester_rx_program_get_default_config(offset);
78 sm_config_set_in_pins(&c, pin); // for WAIT
79 sm_config_set_jmp_pin(&c, pin); // for JMP
80 sm_config_set_in_shift(&c, true, true, 32);
81 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
82 sm_config_set_clkdiv(&c, div);
83 pio_sm_init(pio, sm, offset, &c);
84
85 // X and Y are set to 0 and 1, to conveniently emit these to ISR/FIFO.
86 pio_sm_exec(pio, sm, pio_encode_set(pio_x, 1));
87 pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
88 // Assume line is idle low, and first transmitted bit is 0. Put SM in a
89 // wait state before enabling. RX will begin once the first 0 symbol is
90 // detected.
91 pio_sm_exec(pio, sm, pio_encode_wait_pin(1, 0) | pio_encode_delay(2));
92 pio_sm_set_enabled(pio, sm, true);
93 }
The example C program in the SDK will transmit Manchester serial data from GPIO2 to GPIO3 at approximately 10 Mbps
(assuming a system clock of 125 MHz).
20 int main() {
21 stdio_init_all();
22
23 PIO pio = pio0;
24 uint sm_tx = 0;
25 uint sm_rx = 1;
26
27 uint offset_tx = pio_add_program(pio, &manchester_tx_program);
28 uint offset_rx = pio_add_program(pio, &manchester_rx_program);
29 printf("Transmit program loaded at %d\n", offset_tx);
30 printf("Receive program loaded at %d\n", offset_rx);
31
32 manchester_tx_program_init(pio, sm_tx, offset_tx, pin_tx, 1.f);
33 manchester_rx_program_init(pio, sm_rx, offset_rx, pin_rx, 1.f);
34
35 pio_sm_set_enabled(pio, sm_tx, false);
36 pio_sm_put_blocking(pio, sm_tx, 0);
37 pio_sm_put_blocking(pio, sm_tx, 0x0ff0a55a);
38 pio_sm_put_blocking(pio, sm_tx, 0x12345678);
39 pio_sm_set_enabled(pio, sm_tx, true);
40
41 for (int i = 0; i < 3; ++i)
42 printf("%08x\n", pio_sm_get_blocking(pio, sm_rx));
43 }
7 .program differential_manchester_tx
8 .side_set 1 opt
9
10 ; Transmit one bit every cycles. In each bit period:
11 ; - A '0' is encoded as a transition at the start of the bit period
12 ; - A '1' is encoded as a transition at the start *and* in the middle
13 ;
14 ; Side-set bit 0 must be mapped to the data output pin.
15 ; Autopull must be enabled.
16
17 public start:
18 initial_high:
The .pio file also includes a helper function to initialise a state machine for differential Manchester TX, and connect it to
a chosen GPIO. We arbitrarily choose a 32-bit frame size and LSB-first serialisation (shift_to_right is true in
sm_config_set_out_shift), but as the program operates on one bit at a time, we could change this by reconfiguring the
state machine.
• Wait until the initial transition at the start of the bit period, so we stay aligned to the transmit clock
• Then wait 3/4 of the configured bit period, so that we are centred on the second half-bit-period (see Figure 54)
• Sample the line at this point to determine whether there are one or two transitions in this bit period
• Repeat
Pico Examples: https://github.com/raspberrypi/pico-examples/tree/master/pio/differential_manchester/differential_manchester.pio Lines 52 - 82
52 .program differential_manchester_rx
53
54 ; Assumes line is idle low
55 ; One bit is 16 cycles. In each bit period:
56 ; - A '0' is encoded as a transition at time 0
57 ; - A '1' is encoded as a transition at time 0 and a transition at time T/2
58 ;
59 ; The IN mapping and the JMP pin select must both be mapped to the GPIO used for
This code assumes that X and Y have the values 1 and 0, respectively. This is arranged for by the included C helper
function:
85 static inline void differential_manchester_rx_program_init(PIO pio, uint sm, uint offset,
uint pin, float div) {
86 pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
87 pio_gpio_init(pio, pin);
88
89 pio_sm_config c = differential_manchester_rx_program_get_default_config(offset);
90 sm_config_set_in_pins(&c, pin); // for WAIT
91 sm_config_set_jmp_pin(&c, pin); // for JMP
92 sm_config_set_in_shift(&c, true, true, 32);
93 sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
94 sm_config_set_clkdiv(&c, div);
95 pio_sm_init(pio, sm, offset, &c);
96
97 // X and Y are set to 0 and 1, to conveniently emit these to ISR/FIFO.
98 pio_sm_exec(pio, sm, pio_encode_set(pio_x, 1));
99 pio_sm_exec(pio, sm, pio_encode_set(pio_y, 0));
100 pio_sm_set_enabled(pio, sm, true);
101 }
All the pieces now exist to loopback some serial data over a wire between two GPIOs.
1 /**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdio.h>
8
9 #include "pico/stdlib.h"
10 #include "hardware/pio.h"
11 #include "differential_manchester.pio.h"
12
13 // Differential serial transmit/receive example
14 // Need to connect a wire from GPIO2 -> GPIO3
15
16 const uint pin_tx = 2;
17 const uint pin_rx = 3;
18
19 int main() {
20 stdio_init_all();
21
22 PIO pio = pio0;
23 uint sm_tx = 0;
24 uint sm_rx = 1;
25
26 uint offset_tx = pio_add_program(pio, &differential_manchester_tx_program);
27 uint offset_rx = pio_add_program(pio, &differential_manchester_rx_program);
28 printf("Transmit program loaded at %d\n", offset_tx);
29 printf("Receive program loaded at %d\n", offset_rx);
30
31 // Configure state machines, set bit rate at 5 Mbps
32 differential_manchester_tx_program_init(pio, sm_tx, offset_tx, pin_tx, 125.f / (16 *
5));
33 differential_manchester_rx_program_init(pio, sm_rx, offset_rx, pin_rx, 125.f / (16 *
5));
34
35 pio_sm_set_enabled(pio, sm_tx, false);
36 pio_sm_put_blocking(pio, sm_tx, 0);
37 pio_sm_put_blocking(pio, sm_tx, 0x0ff0a55a);
38 pio_sm_put_blocking(pio, sm_tx, 0x12345678);
39 pio_sm_set_enabled(pio, sm_tx, true);
40
41 for (int i = 0; i < 3; ++i)
42 printf("%08x\n", pio_sm_get_blocking(pio, sm_rx));
43 }
3.6.7. I2C
7 .program i2c
8 .side_set 1 opt pindirs
9
10 ; TX Encoding:
11 ; | 15:10 | 9 | 8:1 | 0 |
12 ; | Instr | Final | Data | NAK |
13 ;
14 ; If Instr has a value n > 0, then this FIFO word has no
15 ; data payload, and the next n + 1 words will be executed as instructions.
16 ; Otherwise, shift out the 8 data bits, followed by the ACK bit.
17 ;
18 ; The Instr mechanism allows stop/start/repstart sequences to be programmed
19 ; by the processor, and then carried out by the state machine at defined points
20 ; in the datastream.
21 ;
22 ; The "Final" field should be set for the final byte in a transfer.
23 ; This tells the state machine to ignore a NAK: if this field is not
24 ; set, then any NAK will cause the state machine to halt and interrupt.
25 ;
26 ; Autopull should be enabled, with a threshold of 16.
27 ; Autopush should be enabled, with a threshold of 8.
28 ; The TX FIFO should be accessed with halfword writes, to ensure
29 ; the data is immediately available in the OSR.
30 ;
31 ; Pin mapping:
32 ; - Input pin 0 is SDA, 1 is SCL (if clock stretching used)
33 ; - Jump pin is SDA
34 ; - Side-set pin 0 is SCL
35 ; - Set pin 0 is SDA
36 ; - OUT pin 0 is SDA
37 ; - SCL must be SDA + 1 (for wait mapping)
38 ;
39 ; The OE outputs should be inverted in the system IO controls!
40 ; (It's possible for the inversion to be done in this program,
41 ; but costs 2 instructions: 1 for inversion, and one to cope
42 ; with the side effect of the MOV on TX shift counter.)
43
44 do_nack:
45 jmp y-- entry_point ; Continue if NAK was expected
46 irq wait 0 rel ; Otherwise stop, ask for help
47
48 do_byte:
49 set x, 7 ; Loop 8 times
50 bitloop:
51 out pindirs, 1 [7] ; Serialise write data (all-ones if reading)
52 nop side 1 [2] ; SCL rising edge
53 wait 1 pin, 1 [4] ; Allow clock to be stretched
54 in pins, 1 [7] ; Sample read data in middle of SCL pulse
55 jmp x-- bitloop side 0 [7] ; SCL falling edge
56
57 ; Handle ACK pulse
58 out pindirs, 1 [7] ; On reads, we provide the ACK.
59 nop side 1 [7] ; SCL rising edge
60 wait 1 pin, 1 [7] ; Allow clock to be stretched
61 jmp pin do_nack side 0 [2] ; Test SDA for ACK/NAK, fall through if ACK
62
63 public entry_point:
64 .wrap_target
65 out x, 6 ; Unpack Instr count
66 out y, 1 ; Unpack the NAK ignore bit
67 jmp !x do_byte ; Instr == 0, this is a data record.
68 out null, 32 ; Instr > 0, remainder of this OSR is invalid
69 do_exec:
70 out exec, 16 ; Execute one instruction per FIFO word
71 jmp x-- do_exec ; Repeat n + 1 times
72 .wrap
The IO mapping required by the I2C program is quite complex, due to the different ways that the two serial lines must be
driven and sampled. One interesting feature is that state machine must drive the output enable high when the output is
low, since the bus is open-drain, so the sense of the data is inverted. This could be handled in the PIO program (e.g. mov
osr, ~osr), but instead we can use the IO controls on RP2040 to perform this inversion in the GPIO muxes, saving an
instruction.
80 static inline void i2c_program_init(PIO pio, uint sm, uint offset, uint pin_sda, uint
pin_scl) {
81 assert(pin_scl == pin_sda + 1);
82 pio_sm_config c = i2c_program_get_default_config(offset);
83
84 // IO mapping
85 sm_config_set_out_pins(&c, pin_sda, 1);
86 sm_config_set_set_pins(&c, pin_sda, 1);
87 sm_config_set_in_pins(&c, pin_sda);
88 sm_config_set_sideset_pins(&c, pin_scl);
89 sm_config_set_jmp_pin(&c, pin_sda);
90
91 sm_config_set_out_shift(&c, false, true, 16);
92 sm_config_set_in_shift(&c, false, true, 8);
93
94 float div = (float)clock_get_hz(clk_sys) / (32 * 100000);
95 sm_config_set_clkdiv(&c, div);
96
97 // Try to avoid glitching the bus while connecting the IOs. Get things set
98 // up so that pin is driven down when PIO asserts OE low, and pulled up
99 // otherwise.
100 gpio_pull_up(pin_scl);
101 gpio_pull_up(pin_sda);
102 uint32_t both_pins = (1u << pin_sda) | (1u << pin_scl);
103 pio_sm_set_pins_with_mask(pio, sm, both_pins, both_pins);
104 pio_sm_set_pindirs_with_mask(pio, sm, both_pins, both_pins);
105 pio_gpio_init(pio, pin_sda);
106 gpio_set_oeover(pin_sda, GPIO_OVERRIDE_INVERT);
107 pio_gpio_init(pio, pin_scl);
108 gpio_set_oeover(pin_scl, GPIO_OVERRIDE_INVERT);
109 pio_sm_set_pins_with_mask(pio, sm, 0, both_pins);
110
111 // Clear IRQ flag before starting
112 hw_clear_bits(&pio->inte0, 1u << sm);
113 hw_clear_bits(&pio->inte1, 1u << sm);
114 pio->irq = 1u << sm;
115
116 // Configure and start SM
117 pio_sm_init(pio, sm, offset + i2c_offset_entry_point, &c);
118 pio_sm_set_enabled(pio, sm, true);
119 }
We can also use the PIO assembler to generate a table of instructions for passing through the FIFO, for
Start/Stop/Restart conditions.
The example code does blocking software IO on the state machine’s FIFOs, to avoid the extra complexity of setting up
the system DMA. For example, an I2C start condition is enqueued like so:
Because I2C can go wrong at so many points, we need to be able to check the error flag asserted by the state machine,
clear the halt and restart it, before asserting a Stop condition and releasing the bus.
We need some higher-level functions to pass correctly-formatted data though the FIFOs and insert Starts, Stops, NAKs
and so on at the correct points. This is enough to present a similar interface to the other hardware I2Cs on RP2040.
13 int main() {
14 stdio_init_all();
15
16 PIO pio = pio0;
17 uint sm = 0;
18 uint offset = pio_add_program(pio, &i2c_program);
19 i2c_program_init(pio, sm, offset, PIN_SDA, PIN_SCL);
20
21 printf("\nPIO I2C Bus Scan\n");
22 printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
23
24 for (int addr = 0; addr < (1 << 7); ++addr) {
25 if (addr % 16 == 0) {
26 printf("%02x ", addr);
27 }
28 // Perform a 0-byte read from the probe address. The read function
29 // returns a negative result NAK'd any time other than the last data
30 // byte. Skip over reserved addresses.
31 int result;
32 if (reserved_addr(addr))
33 result = -1;
34 else
35 result = pio_i2c_read_blocking(pio, sm, addr, NULL, 0);
36
37 printf(result < 0 ? "." : "@");
38 printf(addr % 16 == 15 ? "\n" : " ");
39 }
40 printf("Done.\n");
41 return 0;
42 }
3.6.8. PWM
Often, a PWM can be left at a particular pulse width for thousands of pulses, rather than supplying a new pulse width
each time. This example highlights how a nonblocking PULL (Section 3.4.7) can achieve this: if the TX FIFO is empty, a
nonblocking PULL will copy X to the OSR. After pulling, the program copies the OSR into X, so that it can be compared to
the count value in Y. The net effect is that, if a new duty cycle value has not been supplied through the TX FIFO at the
start of this period, the duty cycle from the previous period (which has been copied from X to OSR via the failed PULL, and
then back to X via the MOV) is reused, for as many periods as necessary.
Another useful technique shown here is using the ISR as a configuration register, if IN instructions are not required.
System software can load an arbitrary 32-bit value into the ISR (by executing instructions directly on the state machine),
and the program will copy this value into Y each time it begins counting. The ISR can be used to configure the range of
PWM counting, and the state machine’s clock divider controls the rate of counting.
To start modulating some pulses, we first need to map the state machine’s side-set pins to the GPIO we want to output
PWM on, and tell the state machine where the program is loaded in the PIO instruction memory:
24 static inline void pwm_program_init(PIO pio, uint sm, uint offset, uint pin) {
25 pio_gpio_init(pio, pin);
26 pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
27 pio_sm_config c = pwm_program_get_default_config(offset);
28 sm_config_set_sideset_pins(&c, pin);
29 pio_sm_init(pio, sm, offset, &c);
30 }
A little footwork is required to load the ISR with the desired counting range:
Once this is done, the state machine can be enabled, and PWM values written directly to its TX FIFO.
27 int main() {
28 stdio_init_all();
29 #ifndef PICO_DEFAULT_LED_PIN
30 #warning pio/pwm example requires a board with a regular LED
31 puts("Default LED pin was not defined");
32 #else
33
34 // todo get free sm
35 PIO pio = pio0;
36 int sm = 0;
37 uint offset = pio_add_program(pio, &pwm_program);
38 printf("Loaded program at %d\n", offset);
39
40 pwm_program_init(pio, sm, offset, PICO_DEFAULT_LED_PIN);
41 pio_pwm_set_period(pio, sm, (1u << 16) - 1);
42
43 int level = 0;
44 while (true) {
45 printf("Level = %d\n", level);
46 pio_pwm_set_level(pio, sm, level * level);
47 level = (level + 1) % 256;
48 sleep_ms(10);
49 }
50 #endif
51 }
If the TX FIFO is kept topped up with fresh pulse width values, this program will consume a new pulse width for each
pulse. Once the FIFO runs dry, the program will again start reusing the most recently supplied value.
3.6.9. Addition
Although not designed for computation, PIO is quite likely Turing-complete, provided a long enough piece of tape can be
found. It is conjectured that it could run DOOM, given a sufficiently high clock speed.
1 .program addition
2
3 ; Pop two 32 bit integers from the TX FIFO, add them together, and push the
4 ; result to the TX FIFO. Autopush/pull should be disabled as we're using
5 ; explicit push and pull instructions.
6 ;
7 ; This program uses the two's complement identity x + y == ~(~x - y)
8
9 pull
10 mov x, ~osr
11 pull
12 mov y, osr
13 jmp test ; this loop is equivalent to the following C code:
14 incr: ; while (y--)
15 jmp x-- test ; x--;
16 test: ; This has the effect of subtracting y from x, eventually.
17 jmp y-- incr
18 mov isr, ~x
19 push
A full 32-bit addition takes only around one minute at 125 MHz. The program pulls two numbers from the TX FIFO and
pushes their sum to the RX FIFO, which is perfect for use either with the system DMA, or directly by the processor:
1 /**
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9
10 #include "pico/stdlib.h"
11 #include "hardware/pio.h"
12 #include "addition.pio.h"
13
14 // Pop quiz: how many additions does the processor do when calling this function
15 uint32_t do_addition(PIO pio, uint sm, uint32_t a, uint32_t b) {
16 pio_sm_put_blocking(pio, sm, a);
17 pio_sm_put_blocking(pio, sm, b);
18 return pio_sm_get_blocking(pio, sm);
19 }
20
21 int main() {
22 stdio_init_all();
23
24 PIO pio = pio0;
25 uint sm = 0;
26 uint offset = pio_add_program(pio, &addition_program);
27 addition_program_init(pio, sm, offset);
28
29 printf("Doing some random additions:\n");
30 for (int i = 0; i < 10; ++i) {
31 uint a = rand() % 100;
32 uint b = rand() % 100;
33 printf("%u + %u = %u\n", a, b, do_addition(pio, sm, a, b));
34 }
35 }
There are also further examples in the pio/ directory in the Pico Examples repository.
Some of the more experimental example code, such as DPI and SD card support, is currently located in the Pico Extras
and Pico Playground repositories. The PIO parts of these are functional, but the surrounding software stacks are still in
an experimental state.
0x010 TXF0 Direct write access to the TX FIFO for this state machine. Each
write pushes one word to the FIFO. Attempting to write to a full
FIFO has no effect on the FIFO state or contents, and sets the
sticky FDEBUG_TXOVER error flag for this FIFO.
0x014 TXF1 Direct write access to the TX FIFO for this state machine. Each
write pushes one word to the FIFO. Attempting to write to a full
FIFO has no effect on the FIFO state or contents, and sets the
sticky FDEBUG_TXOVER error flag for this FIFO.
0x018 TXF2 Direct write access to the TX FIFO for this state machine. Each
write pushes one word to the FIFO. Attempting to write to a full
FIFO has no effect on the FIFO state or contents, and sets the
sticky FDEBUG_TXOVER error flag for this FIFO.
0x01c TXF3 Direct write access to the TX FIFO for this state machine. Each
write pushes one word to the FIFO. Attempting to write to a full
FIFO has no effect on the FIFO state or contents, and sets the
sticky FDEBUG_TXOVER error flag for this FIFO.
0x020 RXF0 Direct read access to the RX FIFO for this state machine. Each
read pops one word from the FIFO. Attempting to read from an
empty FIFO has no effect on the FIFO state, and sets the sticky
FDEBUG_RXUNDER error flag for this FIFO. The data returned to
the system on a read from an empty FIFO is undefined.
0x024 RXF1 Direct read access to the RX FIFO for this state machine. Each
read pops one word from the FIFO. Attempting to read from an
empty FIFO has no effect on the FIFO state, and sets the sticky
FDEBUG_RXUNDER error flag for this FIFO. The data returned to
the system on a read from an empty FIFO is undefined.
0x028 RXF2 Direct read access to the RX FIFO for this state machine. Each
read pops one word from the FIFO. Attempting to read from an
empty FIFO has no effect on the FIFO state, and sets the sticky
FDEBUG_RXUNDER error flag for this FIFO. The data returned to
the system on a read from an empty FIFO is undefined.
0x02c RXF3 Direct read access to the RX FIFO for this state machine. Each
read pops one word from the FIFO. Attempting to read from an
empty FIFO has no effect on the FIFO state, and sets the sticky
FDEBUG_RXUNDER error flag for this FIFO. The data returned to
the system on a read from an empty FIFO is undefined.
0x030 IRQ State machine IRQ flags register. Write 1 to clear. There are 8
state machine IRQ flags, which can be set, cleared, and waited on
by the state machines. There’s no fixed association between
flags and state machines — any state machine can use any flag.
0x034 IRQ_FORCE Writing a 1 to each of these bits will forcibly assert the
corresponding IRQ. Note this is different to the INTF register:
writing here affects PIO internal state. INTF just asserts the
processor-facing IRQ signal for testing ISRs, and is not visible to
the state machines.
0x03c DBG_PADOUT Read to sample the pad output values PIO is currently driving to
the GPIOs.
0x040 DBG_PADOE Read to sample the pad output enables (direction) PIO is
currently driving to the GPIOs.
0x044 DBG_CFGINFO The PIO hardware has some free parameters that may vary
between chip products.
These should be provided in the chip datasheet, but are also
exposed here.
0x0d0 SM0_SHIFTCTRL Control behaviour of the input/output shift registers for state
machine 0
0x0d8 SM0_INSTR Read to see the instruction currently addressed by state machine
0’s program counter
Write to execute an instruction immediately (including jumps)
and then resume execution.
0x0e8 SM1_SHIFTCTRL Control behaviour of the input/output shift registers for state
machine 1
0x0f0 SM1_INSTR Read to see the instruction currently addressed by state machine
1’s program counter
Write to execute an instruction immediately (including jumps)
and then resume execution.
0x100 SM2_SHIFTCTRL Control behaviour of the input/output shift registers for state
machine 2
0x108 SM2_INSTR Read to see the instruction currently addressed by state machine
2’s program counter
Write to execute an instruction immediately (including jumps)
and then resume execution.
0x118 SM3_SHIFTCTRL Control behaviour of the input/output shift registers for state
machine 3
0x120 SM3_INSTR Read to see the instruction currently addressed by state machine
3’s program counter
Write to execute an instruction immediately (including jumps)
and then resume execution.
0x134 IRQ0_INTS Interrupt status after masking & forcing for irq0
0x140 IRQ1_INTS Interrupt status after masking & forcing for irq1
Description
PIO control register
31:12 Reserved. - - -
11:8 CLKDIV_RESTART Restart a state machine’s clock divider from an initial SC 0x0
phase of 0. Clock dividers are free-running, so once
started, their output (including fractional jitter) is
completely determined by the integer/fractional divisor
configured in SMx_CLKDIV. This means that, if multiple
clock dividers with the same divisor are restarted
simultaneously, by writing multiple 1 bits to this field, the
execution clocks of those state machines will run in
precise lockstep.
7:4 SM_RESTART Write 1 to instantly clear internal SM state which may be SC 0x0
otherwise difficult to access and will affect future
execution.
3:0 SM_ENABLE Enable/disable each of the four state machines by writing RW 0x0
1/0 to each of these four bits. When disabled, a state
machine will cease executing instructions, except those
written directly to SMx_INSTR by the system. Multiple bits
can be set/cleared at once to run/halt multiple state
machines simultaneously.
Description
FIFO status register
31:28 Reserved. - - -
23:20 Reserved. - - -
15:12 Reserved. - - -
7:4 Reserved. - - -
Description
FIFO debug register
31:28 Reserved. - - -
27:24 TXSTALL State machine has stalled on empty TX FIFO during a WC 0x0
blocking PULL, or an OUT with autopull enabled. Write 1 to
clear.
23:20 Reserved. - - -
19:16 TXOVER TX FIFO overflow (i.e. write-on-full by the system) has WC 0x0
occurred. Write 1 to clear. Note that write-on-full does not
alter the state or contents of the FIFO in any way, but the
data that the system attempted to write is dropped, so if
this flag is set, your software has quite likely dropped
some data on the floor.
15:12 Reserved. - - -
11:8 RXUNDER RX FIFO underflow (i.e. read-on-empty by the system) has WC 0x0
occurred. Write 1 to clear. Note that read-on-empty does
not perturb the state of the FIFO in any way, but the data
returned by reading from an empty FIFO is undefined, so
this flag generally only becomes set due to some kind of
software error.
7:4 Reserved. - - -
3:0 RXSTALL State machine has stalled on full RX FIFO during a WC 0x0
blocking PUSH, or an IN with autopush enabled. This flag
is also set when a nonblocking PUSH to a full FIFO took
place, in which case the state machine has dropped data.
Write 1 to clear.
Description
FIFO levels
31:8 Reserved. - -
7:0 State machine IRQ flags register. Write 1 to clear. There are 8 state machine WC 0x00
IRQ flags, which can be set, cleared, and waited on by the state machines.
There’s no fixed association between flags and state machines — any state
machine can use any flag.
Any of the 8 flags can be used for timing synchronisation between state
machines, using IRQ and WAIT instructions. The lower four of these flags are
also routed out to system-level interrupt requests, alongside FIFO status
interrupts — see e.g. IRQ0_INTE.
31:8 Reserved. - -
7:0 Writing a 1 to each of these bits will forcibly assert the corresponding IRQ. WF 0x00
Note this is different to the INTF register: writing here affects PIO internal
state. INTF just asserts the processor-facing IRQ signal for testing ISRs, and is
not visible to the state machines.
Table 386.
Bits Description Type Reset
INPUT_SYNC_BYPASS
Register
31:0 There is a 2-flipflop synchronizer on each GPIO input, which protects PIO logic RW 0x00000000
from metastabilities. This increases input delay, and for fast synchronous IO
(e.g. SPI) these synchronizers may need to be bypassed. Each bit in this
register corresponds to one GPIO.
0 → input is synchronized (default)
1 → synchronizer is bypassed
If in doubt, leave this register as all zeroes.
Table 387.
Bits Description Type Reset
DBG_PADOUT Register
31:0 Read to sample the pad output values PIO is currently driving to the GPIOs. RO 0x00000000
Table 388.
Bits Description Type Reset
DBG_PADOE Register
31:0 Read to sample the pad output enables (direction) PIO is currently driving to RO 0x00000000
the GPIOs.
Description
The PIO hardware has some free parameters that may vary between chip products.
These should be provided in the chip datasheet, but are also exposed here.
Table 389.
Bits Name Description Type Reset
DBG_CFGINFO
Register
31:22 Reserved. - - -
15:12 Reserved. - - -
7:6 Reserved. - - -
5:0 FIFO_DEPTH The depth of the state machine TX/RX FIFOs, measured in RO -
words.
Joining fifos via SHIFTCTRL_FJOIN gives one FIFO with
double
this depth.
Table 390.
Bits Description Type Reset
INSTR_MEM0,
INSTR_MEM1, …,
31:16 Reserved. - -
INSTR_MEM30,
INSTR_MEM31
15:0 Write-only access to instruction memory location N WO 0x0000
Registers
Description
Clock divisor register for state machine N
Frequency = clock freq / (CLKDIV_INT + CLKDIV_FRAC / 256)
Table 391.
Bits Name Description Type Reset
SM0_CLKDIV,
SM1_CLKDIV,
31:16 INT Effective frequency is sysclk/(int + frac/256). RW 0x0001
SM2_CLKDIV,
SM3_CLKDIV Value of 0 is interpreted as 65536. If INT is 0, FRAC must
Registers also be 0.
7:0 Reserved. - - -
Description
Execution/behavioural settings for state machine N
Table 392.
Bits Name Description Type Reset
SM0_EXECCTRL,
SM1_EXECCTRL,
31 EXEC_STALLED If 1, an instruction written to SMx_INSTR is stalled, and RO 0x0
SM2_EXECCTRL,
SM3_EXECCTRL latched by the state machine. Will clear to 0 once this
Registers instruction completes.
28:24 JMP_PIN The GPIO number to use as condition for JMP PIN. RW 0x00
Unaffected by input mapping.
23:19 OUT_EN_SEL Which data bit to use for inline OUT enable RW 0x00
17 OUT_STICKY Continuously assert the most recent OUT/SET to the pins RW 0x0
6:5 Reserved. - - -
3:0 STATUS_N Comparison level for the MOV x, STATUS instruction RW 0x0
Description
Control behaviour of the input/output shift registers for state machine N
Table 393.
Bits Name Description Type Reset
SM0_SHIFTCTRL,
SM1_SHIFTCTRL,
31 FJOIN_RX When 1, RX FIFO steals the TX FIFO’s storage, and RW 0x0
SM2_SHIFTCTRL,
SM3_SHIFTCTRL becomes twice as deep.
Registers TX FIFO is disabled as a result (always reads as both full
and empty).
FIFOs are flushed when this bit is changed.
29:25 PULL_THRESH Number of bits shifted out of OSR before autopull, or RW 0x00
conditional pull (PULL IFEMPTY), will take place.
Write 0 for value of 32.
24:20 PUSH_THRESH Number of bits shifted into ISR before autopush, or RW 0x00
conditional push (PUSH IFFULL), will take place.
Write 0 for value of 32.
18 IN_SHIFTDIR 1 = shift input shift register to right (data enters from left). RW 0x1
0 = to left.
16 AUTOPUSH Push automatically when the input shift register is filled, RW 0x0
i.e. on an IN instruction which causes the input shift
counter to reach or exceed PUSH_THRESH.
15:0 Reserved. - - -
Table 395.
Bits Description Type Reset
SM0_INSTR,
SM1_INSTR,
31:16 Reserved. - -
SM2_INSTR,
SM3_INSTR Registers
15:0 Read to see the instruction currently addressed by state machine N's program RW -
counter.
Write to execute an instruction immediately (including jumps) and then
resume execution.
Description
State machine pin control
Table 396.
Bits Name Description Type Reset
SM0_PINCTRL,
SM1_PINCTRL,
31:29 SIDESET_COUNT The number of MSBs of the Delay/Side-set instruction RW 0x0
SM2_PINCTRL,
SM3_PINCTRL field which are used for side-set. Inclusive of the enable
Registers bit, if present. Minimum of 0 (all delay bits, no side-set)
and maximum of 5 (all side-set, no delay).
28:26 SET_COUNT The number of pins asserted by a SET. In the range 0 to 5 RW 0x5
inclusive.
25:20 OUT_COUNT The number of pins asserted by an OUT PINS, OUT RW 0x00
PINDIRS or MOV PINS instruction. In the range 0 to 32
inclusive.
19:15 IN_BASE The pin which is mapped to the least-significant bit of a RW 0x00
state machine’s IN data bus. Higher-numbered pins are
mapped to consecutively more-significant data bits, with a
modulo of 32 applied to pin number.
14:10 SIDESET_BASE The lowest-numbered pin that will be affected by a side- RW 0x00
set operation. The MSBs of an instruction’s side-set/delay
field (up to 5, determined by SIDESET_COUNT) are used
for side-set data, with the remaining LSBs used for delay.
The least-significant bit of the side-set portion is the bit
written to this pin, with more-significant bits written to
higher-numbered pins.
9:5 SET_BASE The lowest-numbered pin that will be affected by a SET RW 0x00
PINS or SET PINDIRS instruction. The data written to this
pin is the least-significant bit of the SET data.
4:0 OUT_BASE The lowest-numbered pin that will be affected by an OUT RW 0x00
PINS, OUT PINDIRS or MOV PINS instruction. The data
written to this pin will always be the least-significant bit of
the OUT or MOV data.
Description
Raw Interrupts
31:12 Reserved. - - -
11 SM3 RO 0x0
10 SM2 RO 0x0
9 SM1 RO 0x0
8 SM0 RO 0x0
7 SM3_TXNFULL RO 0x0
6 SM2_TXNFULL RO 0x0
5 SM1_TXNFULL RO 0x0
4 SM0_TXNFULL RO 0x0
3 SM3_RXNEMPTY RO 0x0
2 SM2_RXNEMPTY RO 0x0
1 SM1_RXNEMPTY RO 0x0
0 SM0_RXNEMPTY RO 0x0
Description
Interrupt Enable for irq0
31:12 Reserved. - - -
11 SM3 RW 0x0
10 SM2 RW 0x0
9 SM1 RW 0x0
8 SM0 RW 0x0
7 SM3_TXNFULL RW 0x0
6 SM2_TXNFULL RW 0x0
5 SM1_TXNFULL RW 0x0
4 SM0_TXNFULL RW 0x0
3 SM3_RXNEMPTY RW 0x0
2 SM2_RXNEMPTY RW 0x0
1 SM1_RXNEMPTY RW 0x0
0 SM0_RXNEMPTY RW 0x0
Description
Interrupt Force for irq0
31:12 Reserved. - - -
11 SM3 RW 0x0
10 SM2 RW 0x0
9 SM1 RW 0x0
8 SM0 RW 0x0
7 SM3_TXNFULL RW 0x0
6 SM2_TXNFULL RW 0x0
5 SM1_TXNFULL RW 0x0
4 SM0_TXNFULL RW 0x0
3 SM3_RXNEMPTY RW 0x0
2 SM2_RXNEMPTY RW 0x0
1 SM1_RXNEMPTY RW 0x0
0 SM0_RXNEMPTY RW 0x0
Description
Interrupt status after masking & forcing for irq0
31:12 Reserved. - - -
11 SM3 RO 0x0
10 SM2 RO 0x0
9 SM1 RO 0x0
8 SM0 RO 0x0
7 SM3_TXNFULL RO 0x0
6 SM2_TXNFULL RO 0x0
5 SM1_TXNFULL RO 0x0
4 SM0_TXNFULL RO 0x0
3 SM3_RXNEMPTY RO 0x0
2 SM2_RXNEMPTY RO 0x0
1 SM1_RXNEMPTY RO 0x0
0 SM0_RXNEMPTY RO 0x0
Description
Interrupt Enable for irq1
31:12 Reserved. - - -
11 SM3 RW 0x0
10 SM2 RW 0x0
9 SM1 RW 0x0
8 SM0 RW 0x0
7 SM3_TXNFULL RW 0x0
6 SM2_TXNFULL RW 0x0
5 SM1_TXNFULL RW 0x0
4 SM0_TXNFULL RW 0x0
3 SM3_RXNEMPTY RW 0x0
2 SM2_RXNEMPTY RW 0x0
1 SM1_RXNEMPTY RW 0x0
0 SM0_RXNEMPTY RW 0x0
Description
Interrupt Force for irq1
31:12 Reserved. - - -
11 SM3 RW 0x0
10 SM2 RW 0x0
9 SM1 RW 0x0
8 SM0 RW 0x0
7 SM3_TXNFULL RW 0x0
6 SM2_TXNFULL RW 0x0
5 SM1_TXNFULL RW 0x0
4 SM0_TXNFULL RW 0x0
3 SM3_RXNEMPTY RW 0x0
2 SM2_RXNEMPTY RW 0x0
1 SM1_RXNEMPTY RW 0x0
0 SM0_RXNEMPTY RW 0x0
Description
Interrupt status after masking & forcing for irq1
31:12 Reserved. - - -
11 SM3 RO 0x0
10 SM2 RO 0x0
9 SM1 RO 0x0
8 SM0 RO 0x0
7 SM3_TXNFULL RO 0x0
6 SM2_TXNFULL RO 0x0
5 SM1_TXNFULL RO 0x0
4 SM0_TXNFULL RO 0x0
3 SM3_RXNEMPTY RO 0x0
2 SM2_RXNEMPTY RO 0x0
1 SM1_RXNEMPTY RO 0x0
0 SM0_RXNEMPTY RO 0x0
Chapter 4. Peripherals
4.1. USB
4.1.1. Overview
This section requires knowledge of the USB protocol. We recommend [usbmadesimple] if you are
unclear on the terminology used in this section (see References).
There is an integrated USB 1.1 PHY which interfaces the USB controller with the DP and DM pins of the chip.
4.1.1.1. Features
The USB controller hardware handles the low level USB protocol, meaning the main job of the programmer is to
configure the controller and then provide / consume data buffers in response to events on the bus. The controller
interrupts the processor when it needs attention. The USB controller has 4K of DPSRAM which is used for configuration
and data buffers.
• Can communicate with Full Speed (12 Mbps) devices and Low Speed devices (1.5 Mbps)
• Can communicate with multiple devices via a USB hub, including Low Speed devices connected to a Full Speed
hub
• Can poll up to 15 interrupt endpoints in hardware. (Interrupt endpoints are used by hubs to notify the host of
connect/disconnect events, mice to notify the host of movement etc.)
4.1.2. Architecture
The USB controller is an area efficient design that muxes a device controller or host controller onto a common set of
components. Each component is detailed below.
The USB PHY provides the electrical interface between the USB DP and DM pins and the digital logic of the controller. The
DP and DM pins are a differential pair, meaning the values are always the inverse of each other, except to encode a
specific line state (SE0, etc). The USB PHY drives the DP and DM pins to transmit data, as well as performing a differential
receive of any incoming data. The USB PHY provides both single-ended and differential receive data to the line state
detection module.
The USB PHY has built in pull-up and pull-down resistors. If the controller is acting as a Full Speed device then the DP pin
is pulled up to indicate to the host that a Full Speed device has been connected. In host mode, a weak pull down is
applied to DP and DM so that the lines are pulled to a logical zero until the device pulls up DP for Full Speed or DM for Low
Speed.
The [usbspec] defines several line states (Bus Reset, Connected, Suspend, Resume, Data 1, Data 0, etc) that need to be
detected. The line state detection module has several state machines to detect these states and signal events to the
other hardware components. There is no shared clock signal in USB, so the RX data must be sampled by an internal
clock. The maximum data rate of USB Full Speed is 12 Mbps. The RX data is sampled at 48MHz, giving 4 clock cycles to
capture and filter the bus state. The line state detection module distributes the filtered RX data to the Serial RX Engine.
The serial receive engine decodes receive data captured by the line state detection module. It produces the following
information:
NOTE
If you disconnect the USB cable during a packet in either host or device mode you will see errors raised by the
hardware. Your software will need to take this scenario into account if you enable error interrupts.
The serial transmit engine is a mirror of the serial receive engine. It is connected to the currently active controller (either
device or host). It creates TOKEN and DATA packets, including calculating the CRC, and transmits them on the bus.
4.1.2.5. DPSRAM
The USB controller has 4K (4096 bytes) of DPSRAM (Dual Port SRAM). The DPSRAM is used to store control registers
and data buffers. From the AHB-Lite bus this is 32-bit wide memory with DWORD, WORD and BYTES accesses
supported.
Data Buffers are typically 64 bytes long as this is the max normal packet size for most FS packets. For Isochronous
endpoints a maximum buffer size of 1023 bytes is supported. For other packet types the maximum size is 64 bytes per
buffer.
4.1.2.5.1. Layout
Addresses 0x0-0xff are used for control registers containing configuration data. The remaining space, addresses 0x100-
0xfff (3840 bytes) can be used for data buffers. The controller has control registers that start at address 0x10000.
The memory layout is different depending on if the controller is in Device or Host mode. In device mode, there are
multiple endpoints a host can access so there must be endpoint control and buffer control registers for each endpoint.
In host mode, the host software running on the processor is deciding which endpoints and which devices to access, so
there only needs to be one set of endpoint control and buffer control registers. As well as software driven transfers, the
host controller can poll up to 15 interrupt endpoints and has a register for each of these interrupt endpoints.
31 Endpoint Enable
28 Enable Interrupt for every 2 transferred buffers (valid for double buffered only)
NOTE
The data buffer base address must be 64-byte aligned as bits 0-5 are ignored
The buffer control register contains information about the state of the data buffers for that endpoint. It is shared
between the processor and the controller. If the endpoint is configured to be single buffered, only the first half (bits 0-
15) of the buffer are used.
If double buffering, the buffer select starts at buffer 0. From then on, the buffer select flips between buffer 0 and 1
unless the "reset buffer select" bit is set.
For host interrupt and isochronous packets on EPx, the buffer full bit will be set on completion even if the transfer was
unsuccessful. The error bits in the SIE_STATUS register can be read to determine the error.
15 Buffer 0 full
WARNING
If running clk_sys and clk_usb at different speeds, the available and stall bits should be set after the other data in the
buffer control register. Otherwise the controller may initiate a transaction with data from a previous packet. That is
to say, the controller could see the available bit set but get the data pid or length from the previous packet.
This section details how the device controller operates when it receives various packet types from the host.
4.1.2.6.1. SETUP
The device controller MUST always accept a setup packet from the host. That is why the first 8 bytes of the DPSRAM
has dedicated space for the setup packet.
The [usbspec] states that receiving a setup packet also clears any stall bits on EP0. For this reason, the stall bits for EP0
are gated with two bits in the EP_STALL_ARM register. These bits are cleared when a setup packet is received. This
means that to send a stall on EP0, you have to set both the stall bit in the buffer control register, and the appropriate bit
in EP_STALL_ARM.
Barring any errors, the setup packet will be put into the setup packet buffer at DPSRAM offset 0x0. The device controller
will then reply with an ACK.
Finally, SIE_STATUS.SETUP_REC is set to indicate that a setup packet has been received. This will trigger an interrupt if
the programmer has enabled the SETUP_REC interrupt (see INTE).
4.1.2.6.2. IN
From the device’s point of view, an IN transfer means transferring data INTO the host. When an IN token is received from
the host the request is handled as follows:
TOKEN phase:
• If STALL is set in the buffer control register (and if EP0, the appropriate EP_STALL_ARM bit is set) then send a STALL
response and go back to idle.
• If AVAILABLE and FULL bits are set in buffer control move to the phase
• Otherwise send NAK unless this is an Isochronous endpoint, in which case go to idle.
DATA phase:
• Wait for ACK packet from host. If there is a timeout then raise a timeout error. If ACK is received then the packet is
done, so move to status phase.
STATUS phase:
• If this was the last buffer in the transfer (i.e. if the LAST_BUFFER bit in the buffer control register was set), set
SIE_STATUS.TRANS_COMPLETE.
• If the endpoint is double buffered, flip the buffer select to the other buffer.
• Set a bit in BUFF_STATUS to indicate the buffer is done. When handling this event, the programmer should read
BUFF_CPU_SHOULD_HANDLE to see if it is buffer 0 or buffer 1 that is finished. If the endpoint is double buffered it
is possible to have both buffers done. The cleared BUFF_STATUS bit will be set again, and
BUFF_CPU_SHOULD_HANDLE will change in this instance.
• Update status in the appropriate half of the buffer control register: length, pid, and last_buff are set. Everything else
is written to zero.
If a NAK gets sent to the host the host will retry again later.
4.1.2.6.3. OUT
When an OUT token is received from the host, the request is handled as follows:
TOKEN phase:
• Is the DATA pid what is specified in the buffer control register? If not raise SIE_STATUS.DATA_SEQ_ERROR. (The
data pid for an Isochronous endpoint is not checked because Isochronous data is always sent with a DATA0 pid.)
• Is the AVAILABLE bit set and the FULL bit unset. If so go to the data phase, unless the STALL bit is set in which case the
device controller will reply with a STALL.
DATA phase:
• Store received data in buffer. If Isochronous go to STATUS phase. Otherwise go to ACK phase.
ACK phase:
See status phase from Section 4.1.2.6.2. The only difference is that the FULL bit is set in the buffer control register to
indicate that data has been received whereas in the IN case the FULL bit is cleared to indicate that data has been sent.
The USB device controller supports both suspend and resume, as well as remote resume (triggered with
SIE_CTRL.RESUME), where the device initiates the resume. There is an interrupt / status bit in SIE_STATUS. It is not
necessary to enable the suspend and resume interrupts, as most devices do not need to care about suspend and
resume.
The device goes into suspend when it does not see any start of frame packets (transmitted every 1ms) from the host.
NOTE
If you enable the suspend interrupt, it is likely you will see a suspend interrupt when the device is first connected but
the bus is idle. The bus can be idle for a few ms before the host begins sending start of frame packets. You will also
see a suspend interrupt when the device is disconnected if you do not have a VBUS detect circuit connected. This is
because without VBUS detection, it is impossible to tell the difference between being disconnected and suspended.
4.1.2.6.5. Errata
There are two hardware issues with the device controller, both of which have software workarounds. See and RP2040-
E2 and RP2040-E5 for more information.
The host controller design is similar to the device controller. All transactions are started by the host, so the host is
always dealing with transactions it has started. For this reason there is only one set of endpoint control / endpoint
buffer control registers. There is also additional hardware to poll interrupt endpoints in the background when there are
no software controlled transactions taking place.
The host needs to send keep-alive packets to the device every 1ms to keep the device from suspending. In Full Speed
mode this is done by sending a SOF (start of frame) packet. In Low Speed mode, an EOP (end of packet) is sent. When
setting up the controller, SIE_CTRL.KEEP_ALIVE and SIE_CTRL.SOF_ENABLE` should be set to enable these packets.
• SEND_SETUP - Send a setup packet. This is typically used in conjunction with RECEIVE_TRANS so the setup packet will be
sent followed by the additional data transaction expected from the device.
• PREAMBLE_ENABLE - Use this to send a packet to a Low Speed device on a Full Speed hub. This will send a PRE token
packet before every packet the host sends (i.e. pre, token, pre, data, pre, ack).
• SOF_SYNC - The SOF Sync bit is used to delay the transaction until after the next SOF. This is useful for interrupt and
isochronous endpoints. The Host controller prevents a transaction of 64bytes from clashing with the SOF packets.
For longer Isochronous packet the software is responsible for preventing a collision by using the SOF Sync bit and
limiting the number of packets sent in one frame. If a transaction is set up with multiple packets the SOF Sync bit
only applies to the first packet.
4.1.2.7.1. SETUP
The SETUP packet sent from the host always comes from the dedicated 8 bytes of space at offset 0x0 of the DPSRAM.
Like the device controller, there are no control registers associated with the setup packet. The parameters are hard
coded and loaded into the hardware when you write to START_TRANS with the SEND_SETUP bit set. Once the setup packet has
been sent, the host state machine will wait for an ACK from the device. If there is a timeout then an RX_TIMEOUT error will be
raised. If the SEND_TRANS bit is set then the host state machine will move to the OUT phase. Most commonly the SEND_SETUP
packet is used in conjunction with the RECEIVE_TRANS bit and will therefore move to the IN phase after sending a setup
packet.
4.1.2.7.2. IN
An IN transfer is triggered with the RECEIVE_TRANS bit set when the START_TRANS bit is set. This may be preceded by a SETUP
packet being sent if the SEND_SETUP bit was set.
CONTROL phase:
• Read EPx control register located at 0x80 to get the endpoint information:
◦ Are we double buffered?
◦ What interrupts to enable
◦ Base address of the data buffer, or data buffers if in double buffered mode
◦ Endpoint type
• Read EPx buffer control register at 0x100 to get the endpoint buffer information such as transfer length and data
pid. The host state machine still checks for the presence of the AVAILABLE bit, so this needs to be set and FULL needs
to be unset. The transaction will not happen until this is the case.
TOKEN phase:
• Send the IN token packet to the device. The target device address and endpoint come from the ADDR_ENDP
register.
DATA phase:
• Receive the first data packet from the device. Raise RX timeout error if the device doesn’t reply. Raise DATA SEQ
ERROR if the data packet has wrong DATA PID.
ACK phase:
• Set BUFF_STATUS bit and update buffer control register. Will set FULL, LAST_BUFF if applicable, DATA_PID, WR_LEN.
TRANS_COMPLETE will be set if this is the last buffer in the transfer.
• The host state machine will keep performing IN transactions until LAST_BUFF is seen in the buffer_control register. If
the host is in double buffered mode then the host controller will toggle between BUF0 and BUF1 sections of the buffer
control register. Otherwise it will keep reading the buffer control register for buffer 0 and wait for the FULL to be
unset and AVAILABLE to be set before starting the next IN transaction (i.e. wait in the control phase). The device can
send a zero length packet to the host to indicate that it has no more data. In which case the host state machine will
stop listening for more data regardless of if the LAST_BUFF flag was set or not. The host software can tell this has
happened because BUFF_DONE will be set with a data length of 0 in the buffer control register.
WARNING
The USB host controller has a bug (RP2040-E4) that means the status written back to the buffer control register can
appear in the wrong half of the register. Bits 0-15 are for buffer 0, and bits 16-31 are for buffer 1. The host controller
has a buffer selector that is flipped after each transfer is complete. This buffer selector is incorrectly used when
writing status information back to the buffer control register even in single buffered mode. The buffer selector is not
used when reading the buffer control register. The implication of this is that host software needs to keep track of the
buffer selector and shift the buffer control register to the right by 16 bits if the buffer selector is 1.
4.1.2.7.3. OUT
An OUT transfer is triggered with the SEND_TRANS bit set when the START_TRANS bit is set. This may be preceded by a SETUP
packet being sent if the SEND_SETUP bit was set.
CONTROL phase:
• Send OUT packet to the device. The target device address and endpoint come from the ADDR_ENDP register.
DATA phase:
• Send the first data packet to the device. If the endpoint type is Isochronous then there is no ACK phase so the host
controller will go straight to status phase. If ACK received then go to status phase. Otherwise:
• Set BUFF_STATUS bit and update buffer control register. FULL will be set to 0. TRANS_COMPLETE will be set if this is the
last buffer in the transfer.
WARNING
The bug mentioned above (RP2040-E4) in the IN section also applies to the OUT section.
If this isn’t the last buffer in the transfer then wait for FULL and AVAILABLE to be set in the EPx buffer control register again.
The host controller can poll interrupt endpoints on many devices (up to a maximum of 15 endpoints). To enable these,
the programmer must:
• Pick the next free interrupt endpoint slot on the host controller (starting at 1, to a maximum of 15)
• Program the appropriate endpoint control register and buffer control register like you would with a normal IN or OUT
transfer. Note that interrupt endpoints are only single buffered so the BUF1 part of the buffer control register is
invalid.
• Set the address and endpoint of the device in the appropriate ADDR_ENDP register (ADDR_ENDP1 to ADDR_ENDP15).
The preamble bit should be set if the device is Low Speed but attached to a Full Speed hub. The endpoint direction
bit should also be set.
• Set the interrupt endpoint active bit in INT_EP_CTRL (i.e. set bit 1 to 15 of that register)
Typically an interrupt endpoint will be an IN transfer. For example, a USB hub would be polled to see if the state of any of
its ports have changed. If there is no changed the hub will reply with a NAK to the controller and nothing will happen.
Similarly, a mouse will reply with a NAK unless the mouse has been moved since the last time the interrupt endpoint was
polled.
Interrupt endpoints are polled by the controller once a SOF packet has been sent by the host controller.
The controller loops from 1 to 15 and will attempt to poll any interrupt endpoint with the EP_ACTIVE bit set to 1 in
INT_EP_CTRL. The controller will then read the endpoint control register, and buffer control register to see if there is an
available buffer (i.e. FULL + AVAILABLE if an OUT transfer and NOT FULL + AVAILABLE for an IN transfer). If not, the controller will
move onto the next interrupt endpoint slot.
If there is an available buffer, then the transfer is dealt with the same as a normal IN or OUT transfer and the BUFF_DONE flag
in BUFF_STATUS will be set when the interrupt endpoint has a valid buffer. BUFF_CPU_SHOULD_HANDLE is invalid for
interrupt endpoints as there is only a single buffer that can ever be done (RP2040-E3).
The USB controller can be connected up to GPIO pins (see Section 2.19) for the purpose of VBUS control:
• VBUS enable, used to enable VBUS in host mode. VBUS enable is set in SIE_CTRL
• VBUS detect, used to detect that VBUS is present in device mode. VBUS detect is a bit in SIE_STATUS and can also
raise a VBUS_DETECT interrupt (enabled in INTE)
• VBUS overcurrent, used to detect an overcurrent event. Applicable to both device and host. VBUS overcurrent is a
bit in SIE_STATUS.
It is not necessary to connect up any of these pins to GPIO. The host can permanently supply VBUS and detect a device
being connected when either the DP or DM pin is pulled high. VBUS detect can be forced in USB_PWR.
4.1.3.1. TinyUSB
The RP2040 TinyUSB port should be considered as the reference implementation for this USB controller. This port can
be found in:
https://github.com/raspberrypi/tinyusb/tree/pico/src/portable/raspberrypi/rp2040/dcd_rp2040.c
https://github.com/raspberrypi/tinyusb/tree/pico/src/portable/raspberrypi/rp2040/hcd_rp2040.c
https://github.com/raspberrypi/tinyusb/tree/pico/src/portable/raspberrypi/rp2040/rp2040_usb.h
A standalone USB device example, dev_lowlevel, makes it easier to understand how to interact with the USB controller
without needing to understand the TinyUSB abstractions. In addition to endpoint 0, the standalone device has two bulk
endpoints: EP1 OUT and EP2 IN. The device is designed to send whatever data it receives on EP1 to EP2. The example
comes with a small Python script that writes "Hello World" into EP1 and checks that it is correctly received on EP2.
The code included in this section will walk you through setting up to the USB device controller to receive a setup packet,
and then respond to the setup packet.
4.1.3.2.2. Configuring the endpoint control registers for EP1 and EP2
The function usb_configure_endpoints loops through each endpoint defined in the device configuration (including EP0 in
and EP0 out, which don’t have an endpoint control register defined) and calls the usb_configure_endpoint function. This
sets up the endpoint control register for that endpoint:
An interrupt is raised when a setup packet is received, so the interrupt handler must handle this event:
The setup packet gets written to the first 8 bytes of the USB ram, so the setup packet handler casts that area of memory
to struct usb_setup_packet *.
The first thing a host will request is the device descriptor, the following code handles that setup request.
The usb_start_transfer function copies the data to send into the appropriate hardware buffer, and configures the buffer
control register. Once the buffer control register has been written to, the device controller will respond to the host with
the data. Before this point, the device will reply with a NAK.
0x28 ADDR_ENDP10 Interrupt endpoint 10. Only valid for HOST mode.
0x2c ADDR_ENDP11 Interrupt endpoint 11. Only valid for HOST mode.
0x30 ADDR_ENDP12 Interrupt endpoint 12. Only valid for HOST mode.
0x34 ADDR_ENDP13 Interrupt endpoint 13. Only valid for HOST mode.
0x38 ADDR_ENDP14 Interrupt endpoint 14. Only valid for HOST mode.
0x3c ADDR_ENDP15 Interrupt endpoint 15. Only valid for HOST mode.
0x44 SOF_WR Set the SOF (Start of Frame) frame number in the host controller.
The SOF packet is sent every 1ms and the host will increment the
frame number by 1 each time.
0x48 SOF_RD Read the last SOF (Start of Frame) frame number seen. In device
mode the last SOF received from the host. In host mode the last
SOF sent by the host.
0x58 BUFF_STATUS Buffer status register. A bit set here indicates that a buffer has
completed on the endpoint (if the buffer interrupt is enabled). It
is possible for 2 buffers to be completed, so clearing the buffer
status bit may instantly re set it on the next clock cycle.
0x5c BUFF_CPU_SHOULD_HANDLE Which of the double buffers should be handled. Only valid if
using an interrupt per buffer (i.e. not per 2 buffers). Not valid for
host interrupt endpoint polling because they are only single
buffered.
0x60 EP_ABORT Device only: Can be set to ignore the buffer control register for
this endpoint in case you would like to revoke a buffer. A NAK
will be sent for every access to the endpoint until this bit is
cleared. A corresponding bit in EP_ABORT_DONE is set when it is safe
to modify the buffer control register.
0x64 EP_ABORT_DONE Device only: Used in conjunction with EP_ABORT. Set once an
endpoint is idle so the programmer knows it is safe to modify the
buffer control register.
0x68 EP_STALL_ARM Device: this bit must be set in conjunction with the STALL bit in the
buffer control register to send a STALL on EP0. The device
controller clears these bits when a SETUP packet is received
because the USB spec requires that a STALL condition is cleared
when a SETUP packet is received.
0x6c NAK_POLL Used by the host controller. Sets the wait time in microseconds
before trying again if the device replies with a NAK.
0x70 EP_STATUS_STALL_NAK Device: bits are set when the IRQ_ON_NAK or IRQ_ON_STALL bits are
set. For EP0 this comes from SIE_CTRL. For all other endpoints it
comes from the endpoint control register.
0x78 USB_PWR Overrides for the power signals in the event that the VBUS
signals are not hooked up to GPIO. Set the value of the override
and then the override enable to switch over to the override value.
0x7c USBPHY_DIRECT This register allows for direct control of the USB phy. Use in
conjunction with usbphy_direct_override register to enable each
override bit.
0x84 USBPHY_TRIM Used to adjust trim values of USB phy pull down resistors.
Description
Device address and endpoint control
Table 408.
Bits Name Description Type Reset
ADDR_ENDP Register
31:20 Reserved. - - -
19:16 ENDPOINT Device endpoint to send data to. Only valid for HOST RW 0x0
mode.
15:7 Reserved. - - -
6:0 ADDRESS In device mode, the address that the device should RW 0x00
respond to. Set in response to a SET_ADDR setup packet
from the host. In host mode set to the address of the
device to communicate with.
Description
Interrupt endpoint N. Only valid for HOST mode.
Table 409.
Bits Name Description Type Reset
ADDR_ENDP1,
ADDR_ENDP2, …,
31:27 Reserved. - - -
ADDR_ENDP14,
ADDR_ENDP15
26 INTEP_PREAMBL Interrupt EP requires preamble (is a low speed device on a RW 0x0
Registers
E full speed hub)
24:20 Reserved. - - -
15:7 Reserved. - - -
Description
Main control register
Table 410.
Bits Name Description Type Reset
MAIN_CTRL Register
30:2 Reserved. - - -
Description
Set the SOF (Start of Frame) frame number in the host controller. The SOF packet is sent every 1ms and the host
will increment the frame number by 1 each time.
31:11 Reserved. - - -
Description
Read the last SOF (Start of Frame) frame number seen. In device mode the last SOF received from the host. In host
mode the last SOF sent by the host.
31:11 Reserved. - - -
Description
SIE control register
23:19 Reserved. - - -
14 Reserved. - - -
12 RESUME Device: Remote wakeup. Device can initiate its own SC 0x0
resume after suspend.
10 KEEP_ALIVE_EN Host: Enable keep alive packet (for low speed bus) RW 0x0
9 SOF_EN Host: Enable SOF generation (for full speed bus) RW 0x0
7 Reserved. - - -
5 Reserved. - - -
Description
SIE status register
Table 414.
SIE_STATUS Register
27 RX_TIMEOUT RX timeout is raised by both the host and device if an ACK WC 0x0
is not received in the maximum time specified by the USB
spec.
23:20 Reserved. - - -
15:12 Reserved. - - -
11 RESUME Host: Device has initiated a remote resume. Device: host WC 0x0
has initiated a resume.
7:5 Reserved. - - -
4 SUSPENDED Bus in suspended state. Valid for device and host. Host RO 0x0
and device will go into suspend if neither Keep Alive / SOF
frames are enabled.
1 Reserved. - - -
Description
interrupt endpoint control register
Table 415.
Bits Name Description Type Reset
INT_EP_CTRL Register
31:16 Reserved. - - -
0 Reserved. - - -
Description
Buffer status register. A bit set here indicates that a buffer has completed on the endpoint (if the buffer interrupt is
enabled). It is possible for 2 buffers to be completed, so clearing the buffer status bit may instantly re set it on the
next clock cycle.
Table 416.
Bits Name Description Type Reset
BUFF_STATUS
Register
31 EP15_OUT WC 0x0
30 EP15_IN WC 0x0
29 EP14_OUT WC 0x0
28 EP14_IN WC 0x0
27 EP13_OUT WC 0x0
26 EP13_IN WC 0x0
25 EP12_OUT WC 0x0
24 EP12_IN WC 0x0
23 EP11_OUT WC 0x0
22 EP11_IN WC 0x0
21 EP10_OUT WC 0x0
20 EP10_IN WC 0x0
19 EP9_OUT WC 0x0
18 EP9_IN WC 0x0
17 EP8_OUT WC 0x0
16 EP8_IN WC 0x0
15 EP7_OUT WC 0x0
14 EP7_IN WC 0x0
13 EP6_OUT WC 0x0
12 EP6_IN WC 0x0
11 EP5_OUT WC 0x0
10 EP5_IN WC 0x0
9 EP4_OUT WC 0x0
8 EP4_IN WC 0x0
7 EP3_OUT WC 0x0
6 EP3_IN WC 0x0
5 EP2_OUT WC 0x0
4 EP2_IN WC 0x0
3 EP1_OUT WC 0x0
2 EP1_IN WC 0x0
1 EP0_OUT WC 0x0
0 EP0_IN WC 0x0
Description
Which of the double buffers should be handled. Only valid if using an interrupt per buffer (i.e. not per 2 buffers). Not
valid for host interrupt endpoint polling because they are only single buffered.
Table 417.
Bits Name Description Type Reset
BUFF_CPU_SHOULD_H
ANDLE Register
31 EP15_OUT RO 0x0
30 EP15_IN RO 0x0
29 EP14_OUT RO 0x0
28 EP14_IN RO 0x0
27 EP13_OUT RO 0x0
26 EP13_IN RO 0x0
25 EP12_OUT RO 0x0
24 EP12_IN RO 0x0
23 EP11_OUT RO 0x0
22 EP11_IN RO 0x0
21 EP10_OUT RO 0x0
20 EP10_IN RO 0x0
19 EP9_OUT RO 0x0
18 EP9_IN RO 0x0
17 EP8_OUT RO 0x0
16 EP8_IN RO 0x0
15 EP7_OUT RO 0x0
14 EP7_IN RO 0x0
13 EP6_OUT RO 0x0
12 EP6_IN RO 0x0
11 EP5_OUT RO 0x0
10 EP5_IN RO 0x0
9 EP4_OUT RO 0x0
8 EP4_IN RO 0x0
7 EP3_OUT RO 0x0
6 EP3_IN RO 0x0
5 EP2_OUT RO 0x0
4 EP2_IN RO 0x0
3 EP1_OUT RO 0x0
2 EP1_IN RO 0x0
1 EP0_OUT RO 0x0
0 EP0_IN RO 0x0
Description
Device only: Can be set to ignore the buffer control register for this endpoint in case you would like to revoke a
buffer. A NAK will be sent for every access to the endpoint until this bit is cleared. A corresponding bit in
EP_ABORT_DONE is set when it is safe to modify the buffer control register.
31 EP15_OUT RW 0x0
30 EP15_IN RW 0x0
29 EP14_OUT RW 0x0
28 EP14_IN RW 0x0
27 EP13_OUT RW 0x0
26 EP13_IN RW 0x0
25 EP12_OUT RW 0x0
24 EP12_IN RW 0x0
23 EP11_OUT RW 0x0
22 EP11_IN RW 0x0
21 EP10_OUT RW 0x0
20 EP10_IN RW 0x0
19 EP9_OUT RW 0x0
18 EP9_IN RW 0x0
17 EP8_OUT RW 0x0
16 EP8_IN RW 0x0
15 EP7_OUT RW 0x0
14 EP7_IN RW 0x0
13 EP6_OUT RW 0x0
12 EP6_IN RW 0x0
11 EP5_OUT RW 0x0
10 EP5_IN RW 0x0
9 EP4_OUT RW 0x0
8 EP4_IN RW 0x0
7 EP3_OUT RW 0x0
6 EP3_IN RW 0x0
5 EP2_OUT RW 0x0
4 EP2_IN RW 0x0
3 EP1_OUT RW 0x0
2 EP1_IN RW 0x0
1 EP0_OUT RW 0x0
0 EP0_IN RW 0x0
Description
Device only: Used in conjunction with EP_ABORT. Set once an endpoint is idle so the programmer knows it is safe to
modify the buffer control register.
Table 419.
Bits Name Description Type Reset
EP_ABORT_DONE
Register
31 EP15_OUT WC 0x0
30 EP15_IN WC 0x0
29 EP14_OUT WC 0x0
28 EP14_IN WC 0x0
27 EP13_OUT WC 0x0
26 EP13_IN WC 0x0
25 EP12_OUT WC 0x0
24 EP12_IN WC 0x0
23 EP11_OUT WC 0x0
22 EP11_IN WC 0x0
21 EP10_OUT WC 0x0
20 EP10_IN WC 0x0
19 EP9_OUT WC 0x0
18 EP9_IN WC 0x0
17 EP8_OUT WC 0x0
16 EP8_IN WC 0x0
15 EP7_OUT WC 0x0
14 EP7_IN WC 0x0
13 EP6_OUT WC 0x0
12 EP6_IN WC 0x0
11 EP5_OUT WC 0x0
10 EP5_IN WC 0x0
9 EP4_OUT WC 0x0
8 EP4_IN WC 0x0
7 EP3_OUT WC 0x0
6 EP3_IN WC 0x0
5 EP2_OUT WC 0x0
4 EP2_IN WC 0x0
3 EP1_OUT WC 0x0
2 EP1_IN WC 0x0
1 EP0_OUT WC 0x0
0 EP0_IN WC 0x0
Description
Device: this bit must be set in conjunction with the STALL bit in the buffer control register to send a STALL on EP0.
The device controller clears these bits when a SETUP packet is received because the USB spec requires that a
STALL condition is cleared when a SETUP packet is received.
Table 420.
Bits Name Description Type Reset
EP_STALL_ARM
Register
31:2 Reserved. - - -
1 EP0_OUT RW 0x0
0 EP0_IN RW 0x0
Description
Used by the host controller. Sets the wait time in microseconds before trying again if the device replies with a NAK.
31:26 Reserved. - - -
25:16 DELAY_FS NAK polling interval for a full speed device RW 0x010
15:10 Reserved. - - -
9:0 DELAY_LS NAK polling interval for a low speed device RW 0x010
Description
Device: bits are set when the IRQ_ON_NAK or IRQ_ON_STALL bits are set. For EP0 this comes from SIE_CTRL. For all other
endpoints it comes from the endpoint control register.
Table 422.
Bits Name Description Type Reset
EP_STATUS_STALL_N
AK Register
31 EP15_OUT WC 0x0
30 EP15_IN WC 0x0
29 EP14_OUT WC 0x0
28 EP14_IN WC 0x0
27 EP13_OUT WC 0x0
26 EP13_IN WC 0x0
25 EP12_OUT WC 0x0
24 EP12_IN WC 0x0
23 EP11_OUT WC 0x0
22 EP11_IN WC 0x0
21 EP10_OUT WC 0x0
20 EP10_IN WC 0x0
19 EP9_OUT WC 0x0
18 EP9_IN WC 0x0
17 EP8_OUT WC 0x0
16 EP8_IN WC 0x0
15 EP7_OUT WC 0x0
14 EP7_IN WC 0x0
13 EP6_OUT WC 0x0
12 EP6_IN WC 0x0
11 EP5_OUT WC 0x0
10 EP5_IN WC 0x0
9 EP4_OUT WC 0x0
8 EP4_IN WC 0x0
7 EP3_OUT WC 0x0
6 EP3_IN WC 0x0
5 EP2_OUT WC 0x0
4 EP2_IN WC 0x0
3 EP1_OUT WC 0x0
2 EP1_IN WC 0x0
1 EP0_OUT WC 0x0
0 EP0_IN WC 0x0
Description
Where to connect the USB controller. Should be to_phy by default.
Table 423.
Bits Name Description Type Reset
USB_MUXING Register
31:4 Reserved. - - -
3 SOFTCON RW 0x0
2 TO_DIGITAL_PAD RW 0x0
1 TO_EXTPHY RW 0x0
0 TO_PHY RW 0x0
Description
Overrides for the power signals in the event that the VBUS signals are not hooked up to GPIO. Set the value of the
override and then the override enable to switch over to the override value.
31:6 Reserved. - - -
5 OVERCURR_DETECT_EN RW 0x0
4 OVERCURR_DETECT RW 0x0
3 VBUS_DETECT_OVERRIDE_EN RW 0x0
2 VBUS_DETECT RW 0x0
1 VBUS_EN_OVERRIDE_EN RW 0x0
0 VBUS_EN RW 0x0
Description
This register allows for direct control of the USB phy. Use in conjunction with usbphy_direct_override register to
enable each override bit.
Table 425.
Bits Name Description Type Reset
USBPHY_DIRECT
Register
31:23 Reserved. - - -
7 Reserved. - - -
3 Reserved. - - -
Description
Override enable for each control in usbphy_direct
Table 426.
Bits Name Description Type Reset
USBPHY_DIRECT_OVE
RRIDE Register
31:16 Reserved. - - -
15 TX_DIFFMODE_OVERRIDE_EN RW 0x0
14:13 Reserved. - - -
12 DM_PULLUP_OVERRIDE_EN RW 0x0
11 TX_FSSLEW_OVERRIDE_EN RW 0x0
10 TX_PD_OVERRIDE_EN RW 0x0
9 RX_PD_OVERRIDE_EN RW 0x0
8 TX_DM_OVERRIDE_EN RW 0x0
7 TX_DP_OVERRIDE_EN RW 0x0
6 TX_DM_OE_OVERRIDE_EN RW 0x0
5 TX_DP_OE_OVERRIDE_EN RW 0x0
4 DM_PULLDN_EN_OVERRIDE_EN RW 0x0
3 DP_PULLDN_EN_OVERRIDE_EN RW 0x0
2 DP_PULLUP_EN_OVERRIDE_EN RW 0x0
1 DM_PULLUP_HISEL_OVERRIDE_EN RW 0x0
0 DP_PULLUP_HISEL_OVERRIDE_EN RW 0x0
Description
Used to adjust trim values of USB phy pull down resistors.
Table 427.
Bits Name Description Type Reset
USBPHY_TRIM
Register
31:13 Reserved. - - -
7:5 Reserved. - - -
Description
Raw Interrupts
31:20 Reserved. - - -
17 DEV_SOF Set every time the device receives a SOF (Start of Frame) RO 0x0
packet. Cleared by reading SOF_RD
15 DEV_RESUME_FR Set when the device receives a resume from the host. RO 0x0
OM_HOST Cleared by writing to SIE_STATUS.RESUME
14 DEV_SUSPEND Set when the device suspend state changes. Cleared by RO 0x0
writing to SIE_STATUS.SUSPENDED
13 DEV_CONN_DIS Set when the device connection state changes. Cleared by RO 0x0
writing to SIE_STATUS.CONNECTED
2 HOST_SOF Host: raised every time the host sends a SOF (Start of RO 0x0
Frame). Cleared by reading SOF_RD
1 HOST_RESUME Host: raised when a device wakes up the host. Cleared by RO 0x0
writing to SIE_STATUS.RESUME
Description
Interrupt Enable
31:20 Reserved. - - -
17 DEV_SOF Set every time the device receives a SOF (Start of Frame) RW 0x0
packet. Cleared by reading SOF_RD
15 DEV_RESUME_FR Set when the device receives a resume from the host. RW 0x0
OM_HOST Cleared by writing to SIE_STATUS.RESUME
14 DEV_SUSPEND Set when the device suspend state changes. Cleared by RW 0x0
writing to SIE_STATUS.SUSPENDED
13 DEV_CONN_DIS Set when the device connection state changes. Cleared by RW 0x0
writing to SIE_STATUS.CONNECTED
2 HOST_SOF Host: raised every time the host sends a SOF (Start of RW 0x0
Frame). Cleared by reading SOF_RD
1 HOST_RESUME Host: raised when a device wakes up the host. Cleared by RW 0x0
writing to SIE_STATUS.RESUME
Description
Interrupt Force
31:20 Reserved. - - -
17 DEV_SOF Set every time the device receives a SOF (Start of Frame) RW 0x0
packet. Cleared by reading SOF_RD
15 DEV_RESUME_FR Set when the device receives a resume from the host. RW 0x0
OM_HOST Cleared by writing to SIE_STATUS.RESUME
14 DEV_SUSPEND Set when the device suspend state changes. Cleared by RW 0x0
writing to SIE_STATUS.SUSPENDED
13 DEV_CONN_DIS Set when the device connection state changes. Cleared by RW 0x0
writing to SIE_STATUS.CONNECTED
2 HOST_SOF Host: raised every time the host sends a SOF (Start of RW 0x0
Frame). Cleared by reading SOF_RD
1 HOST_RESUME Host: raised when a device wakes up the host. Cleared by RW 0x0
writing to SIE_STATUS.RESUME
Description
Interrupt status after masking & forcing
31:20 Reserved. - - -
17 DEV_SOF Set every time the device receives a SOF (Start of Frame) RO 0x0
packet. Cleared by reading SOF_RD
15 DEV_RESUME_FR Set when the device receives a resume from the host. RO 0x0
OM_HOST Cleared by writing to SIE_STATUS.RESUME
14 DEV_SUSPEND Set when the device suspend state changes. Cleared by RO 0x0
writing to SIE_STATUS.SUSPENDED
13 DEV_CONN_DIS Set when the device connection state changes. Cleared by RO 0x0
writing to SIE_STATUS.CONNECTED
2 HOST_SOF Host: raised every time the host sends a SOF (Start of RO 0x0
Frame). Cleared by reading SOF_RD
1 HOST_RESUME Host: raised when a device wakes up the host. Cleared by RO 0x0
writing to SIE_STATUS.RESUME
References
▪ http://www.usbmadesimple.co.uk/
▪ https://www.usb.org/document-library/usb-20-specification
4.2. UART
ARM Documentation
Excerpted from the PrimeCell UART (PL011) Technical Reference Manual. Used with permission.
RP2040 has 2 identical instances of a UART peripheral, based on the ARM Primecell UART (PL011) (Revision r1p5).
The UARTCLK is driven from clk_peri, and PCLK is driven from the system clock clk_sys (see Section 2.15.1).
4.2.1. Overview
The UART performs:
The UART:
• includes a programmable baud rate generator that generates a common transmit and receive internal clock from
the UART internal reference clock input, UARTCLK
• individually-maskable interrupts from the receive (including timeout), transmit, modem status and error conditions
• a single combined interrupt so that the output is asserted if any of the individual interrupts are asserted, and
unmasked
• DMA request signals for interfacing with a Direct Memory Access (DMA) controller.
If a framing, parity, or break error occurs during reception, the appropriate error bit is set, and is stored in the FIFO. If an
overrun condition occurs, the overrun register bit is set immediately and FIFO data is prevented from being overwritten.
You can program the FIFOs to be 1-byte deep providing a conventional double-buffered UART interface.
There is a programmable hardware flow control feature that uses the nUARTCTS input and the nUARTRTS output to
automatically control the serial data flow.
The AMBA APB interface generates read and write decodes for accesses to status/control registers, and the transmit
and receive FIFOs.
The register block stores data written, or to be read across the AMBA APB interface.
The baud rate generator contains free-running counters that generate the internal clocks: Baud16 and IrLPBaud16
signals. Baud16 provides timing information for UART transmit and receive control. Baud16 is a stream of pulses with a
width of one UARTCLK clock period and a frequency of 16 times the baud rate.
The transmit FIFO is an 8-bit wide, 32 location deep, FIFO memory buffer. CPU data written across the APB interface is
stored in the FIFO until read out by the transmit logic. You can disable the transmit FIFO to act like a one-byte holding
register.
The receive FIFO is a 12-bit wide, 32 location deep, FIFO memory buffer. Received data and corresponding error bits, are
stored in the receive FIFO by the receive logic until read out by the CPU across the APB interface. The receive FIFO can
be disabled to act like a one-byte holding register.
The transmit logic performs parallel-to-serial conversion on the data read from the transmit FIFO. Control logic outputs
the serial bit stream beginning with a start bit, data bits with the Least Significant Bit (LSB) first, followed by the parity
bit, and then the stop bits according to the programmed configuration in control registers.
The receive logic performs serial-to-parallel conversion on the received bit stream after a valid start pulse has been
detected. Overrun, parity, frame error checking, and line break detection are also performed, and their status
accompanies the data that is written to the receive FIFO.
Individual maskable active HIGH interrupts are generated by the UART. A combined interrupt output is generated as an
OR function of the individual interrupt requests and is connected to the processor interrupt controllers.
The UART provides an interface to connect to the DMA controller as UART DMA interface in Section 4.2.5 describes.
The UART supports both asynchronous and synchronous operation of the clocks, PCLK and UARTCLK. Synchronization
registers and handshaking logic have been implemented, and are active at all times. This has a minimal impact on
performance or area. Synchronization of control signals is performed on both directions of data flow, that is from the
PCLK to the UARTCLK domain, and from the UARTCLK to the PCLK domain.
4.2.3. Operation
The frequency selected for UARTCLK must accommodate the required range of baud rates:
The frequency of UARTCLK must also be within the required error limits for all baud rates to be used.
There is also a constraint on the ratio of clock frequencies for PCLK to UARTCLK. The frequency of UARTCLK must be
no more than 5/3 times faster than the frequency of PCLK:
Control data is written to the UART Line Control Register, UARTLCR. This register is 30-bits wide internally, but is
externally accessed through the APB interface by writes to the following registers:
• transmission parameters
• word length
• buffer mode
• number of transmitted stop bits
• parity mode
• break generation.
The UARTIBRD register defines the integer baud rate divider, and the UARTFBRD register defines the fractional baud
rate divider.
The baud rate divisor is a 22-bit number consisting of a 16-bit integer and a 6-bit fractional part. This is used by the
baud rate generator to determine the bit period. The fractional baud rate divider enables the use of any clock with a
frequency >3.6864MHz to act as UARTCLK, while it is still possible to generate all the standard baud rates.
The 16-bit integer is written to the Integer Baud Rate Register, UARTIBRD. The 6-bit fractional part is written to the
Fractional Baud Rate Register, UARTFBRD. The Baud Rate Divisor has the following relationship to UARTCLK:
Baud Rate Divisor = UARTCLK/(16×Baud Rate) = where is the integer part and is the
fractional part separated by a decimal point as Figure 60.
You can calculate the 6-bit number ( ) by taking the fractional part of the required baud rate divisor and multiplying it by
64 (that is, , where is the width of the UARTFBRD Register) and adding 0.5 to account for rounding errors:
An internal clock enable signal, Baud16, is generated, and is a stream of one UARTCLK wide pulses with an average
frequency of 16 times the required baud rate. This signal is then divided by 16 to give the transmit clock. A low number
in the baud rate divisor gives a short bit period, and a high number in the baud rate divisor gives a long bit period.
Data received or transmitted is stored in two 32-byte FIFOs, though the receive FIFO has an extra four bits per character
for status information. For transmission, data is written into the transmit FIFO. If the UART is enabled, it causes a data
frame to start transmitting with the parameters indicated in the Line Control Register, UARTLCR_H. Data continues to be
transmitted until there is no data left in the transmit FIFO. The BUSY signal goes HIGH as soon as data is written to the
transmit FIFO (that is, the FIFO is non-empty) and remains asserted HIGH while data is being transmitted. BUSY is
negated only when the transmit FIFO is empty, and the last character has been transmitted from the shift register,
including the stop bits. BUSY can be asserted HIGH even though the UART might no longer be enabled.
For each sample of data, three readings are taken and the majority value is kept. In the following paragraphs the middle
sampling point is defined, and one sample is taken either side of it.
When the receiver is idle (UARTRXD continuously 1, in the marking state) and a LOW is detected on the data input (a
start bit has been received), the receive counter, with the clock enabled by Baud16, begins running and data is sampled
on the eighth cycle of that counter in UART mode, or the fourth cycle of the counter in SIR mode to allow for the shorter
The start bit is valid if UARTRXD is still LOW on the eighth cycle of Baud16, otherwise a false start bit is detected and it
is ignored.
If the start bit was valid, successive data bits are sampled on every 16th cycle of Baud16 (that is, one bit period later)
according to the programmed length of the data characters. The parity bit is then checked if parity mode was enabled.
Lastly, a valid stop bit is confirmed if UARTRXD is HIGH, otherwise a framing error has occurred. When a full word is
received, the data is stored in the receive FIFO, with any error bits associated with that word
Three error bits are stored in bits [10:8] of the receive FIFO, and are associated with a particular character. There is an
additional error that indicates an overrun error and this is stored in bit 11 of the receive FIFO.
The overrun bit is not associated with the character in the receive FIFO. The overrun error is set when the FIFO is full,
and the next character is completely received in the shift register. The data in the shift register is overwritten, but it is
not written into the FIFO. When an empty location is available in the receive FIFO, and another character is received, the
state of the overrun bit is copied into the receive FIFO along with the received character. The overrun state is then
cleared. Table 432 lists the bit functions of the receive FIFO.
11 Overrun indicator
10 Break error
9 Parity error
8 Framing error
Additionally, you can disable the FIFOs. In this case, the transmit and receive sides of the UART have 1-byte holding
registers (the bottom entry of the FIFOs). The overrun bit is set when a word has been received, and the previous one
was not yet read. In this implementation, the FIFOs are not physically disabled, but the flags are manipulated to give the
illusion of a 1-byte register. When the FIFOs are disabled, a write to the data register bypasses the holding register
unless the transmit shift register is already in use.
You can perform loopback testing for UART data by setting the Loop Back Enable (LBE) bit to 1 in the Control Register,
UARTCR.
DMASREQ
Bit period 3/16 Bit period
DMABREQ
DMACLR 0 1 0 1 0 0 1 1 0 1
When the RTS flow control is enabled, nUARTRTS is asserted until the receive FIFO is filled up to the programmed
watermark level. When the CTS flow control is enabled, the transmitter can only transmit data when nUARTCTS is
asserted.
The hardware flow control is selectable using the RTSEn and CTSEn bits in the Control Register, UARTCR. Table 433
lists how you must set the bits to enable RTS and CTS flow control both simultaneously, and independently.
NOTE
When RTS flow control is enabled, the software cannot use the RTSEn bit in the Control Register, UARTCR, to control
the status of nUARTRTS.
The RTS flow control logic is linked to the programmable receive FIFO watermark levels. When RTS flow control is
enabled, the nUARTRTS is asserted until the receive FIFO is filled up to the watermark level. When the receive FIFO
watermark level is reached, the nUARTRTS signal is deasserted, indicating that there is no more room to receive any
more data. The transmission of data is expected to cease after the current character has been transmitted.
The nUARTRTS signal is reasserted when data has been read out of the receive FIFO so that it is filled to less than the
watermark level. If RTS flow control is disabled and the UART is still enabled, then data is received until the receive FIFO
is full, or no more data is transmitted to it.
If CTS flow control is enabled, then the transmitter checks the nUARTCTS signal before transmitting the next byte. If the
nUARTCTS signal is asserted, it transmits the byte otherwise transmission does not occur.
The data continues to be transmitted while nUARTCTS is asserted, and the transmit FIFO is not empty. If the transmit
FIFO is empty and the nUARTCTS signal is asserted no data is transmitted.
If the nUARTCTS signal is deasserted and CTS flow control is enabled, then the current character transmission is
completed before stopping. If CTS flow control is disabled and the UART is enabled, then the data continues to be
transmitted until the transmit FIFO is empty.
For receive:
UARTRXDMASREQ
Single character DMA transfer request, asserted by the UART. For receive, one character consists of up to 12 bits.
This signal is asserted when the receive FIFO contains at least one character.
UARTRXDMABREQ
Burst DMA transfer request, asserted by the UART. This signal is asserted when the receive FIFO contains more
characters than the programmed watermark level. You can program the watermark level for each FIFO using the
Interrupt FIFO Level Select Register, UARTIFLS
UARTRXDMACLR
DMA request clear, asserted by a DMA controller to clear the receive request signals. If DMA burst transfer is
requested, the clear signal is asserted during the transfer of the last data in the burst.
For transmit:
UARTTXDMASREQ
Single character DMA transfer request, asserted by the UART. For transmit one character consists of up to eight
bits. This signal is asserted when there is at least one empty location in the transmit FIFO.
UARTTXDMABREQ
Burst DMA transfer request, asserted by the UART. This signal is asserted when the transmit FIFO contains less
characters than the watermark level. You can program the watermark level for each FIFO using the Interrupt FIFO
Level Select Register, UARTIFLS.
UARTTXDMACLR
DMA request clear, asserted by a DMA controller to clear the transmit request signals. If DMA burst transfer is
requested, the clear signal is asserted during the transfer of the last data in the burst.
The burst transfer and single transfer request signals are not mutually exclusive, they can both be asserted at the same
time. For example, when there is more data than the watermark level in the receive FIFO, the burst transfer request and
the single transfer request are asserted. When the amount of data left in the receive FIFO is less than the watermark
level, the single request only is asserted. This is useful for situations where the number of characters left to be received
in the stream is less than a burst.
For example, if 19 characters have to be received and the watermark level is programmed to be four. The DMA
controller then transfers four bursts of four characters and three single transfers to complete the stream.
NOTE
For the remaining three characters the UART cannot assert the burst request.
Each request signal remains asserted until the relevant DMACLR signal is asserted. After the request clear signal is
deasserted, a request signal can become active again, depending on the conditions described previously. All request
signals are deasserted if the UART is disabled or the relevant DMA enable bit, TXDMAE or RXDMAE, in the DMA Control
Register, UARTDMACR, is cleared.
If you disable the FIFOs in the UART then it operates in character mode and only the DMA single transfer mode can
operate, because only one character can be transferred to, or from the FIFOs at any time. UARTRXDMASREQ and
UARTTXDMASREQ are the only request signals that can be asserted. See the Line Control Register, UARTLCR_H, for
information about disabling the FIFOs.
When the UART is in the FIFO enabled mode, data transfers can be made by either single or burst transfers depending
on the programmed watermark level and the amount of data in the FIFO. Table 434 lists the trigger points for
UARTRXDMABREQ and UARTTXDMABREQ depending on the watermark level, for the transmit and receive FIFOs.
1/8 28 4
1/4 24 8
1/2 16 16
3/4 8 24
7/8 4 28
In addition, the DMAONERR bit in the DMA Control Register, UARTDMACR, supports the use of the receive error
interrupt, UARTEINTR. It enables the DMA receive request outputs, UARTRXDMASREQ or UARTRXDMABREQ, to be
masked out when the UART error interrupt, UARTEINTR, is asserted. The DMA receive request outputs remain inactive
until the UARTEINTR is cleared. The DMA transmit request outputs are unaffected.
Figure 63 shows the timing diagram for both a single transfer request and a burst transfer request with the appropriate
DMACLR signal. The signals are all synchronous to PCLK. For the sake of clarity it is assumed that there is no
synchronization of the request signals in the DMA controller.
4.2.6. Interrupts
There are eleven maskable interrupts generated in the UART. On RP2040, only the combined interrupt output, UARTINTR, is
connected.
You can enable or disable the individual interrupts by changing the mask bits in the Interrupt Mask Set/Clear Register,
UARTIMSC. Setting the appropriate mask bit HIGH enables the interrupt.
Provision of individual outputs and the combined interrupt output, enables you to use either a global interrupt service
routine, or modular device drivers to handle interrupts.
The transmit and receive dataflow interrupts UARTRXINTR and UARTTXINTR have been separated from the status
interrupts. This enables you to use UARTRXINTR and UARTTXINTR so that data can be read or written in response to
The error interrupt, UARTEINTR, can be triggered when there is an error in the reception of data. A number of error
conditions are possible.
The modem status interrupt, UARTMSINTR, is a combined interrupt of all the individual modem status signals.
The status of the individual interrupt sources can be read either from the Raw Interrupt Status Register, UARTRIS, or
from the Masked Interrupt Status Register, UARTMIS.
4.2.6.1. UARTMSINTR
The modem status interrupt is asserted if any of the modem status signals (nUARTCTS, nUARTDCD, nUARTDSR, and
nUARTRI) change. It is cleared by writing a 1 to the corresponding bit(s) in the Interrupt Clear Register, UARTICR,
depending on the modem status signals that generated the interrupt.
4.2.6.2. UARTRXINTR
The receive interrupt changes state when one of the following events occurs:
• If the FIFOs are enabled and the receive FIFO reaches the programmed trigger level. When this happens, the
receive interrupt is asserted HIGH. The receive interrupt is cleared by reading data from the receive FIFO until it
becomes less than the trigger level, or by clearing the interrupt.
• If the FIFOs are disabled (have a depth of one location) and data is received thereby filling the location, the receive
interrupt is asserted HIGH. The receive interrupt is cleared by performing a single read of the receive FIFO, or by
clearing the interrupt.
4.2.6.3. UARTTXINTR
The transmit interrupt changes state when one of the following events occurs:
• If the FIFOs are enabled and the transmit FIFO is equal to or lower than the programmed trigger level then the
transmit interrupt is asserted HIGH. The transmit interrupt is cleared by writing data to the transmit FIFO until it
becomes greater than the trigger level, or by clearing the interrupt.
• If the FIFOs are disabled (have a depth of one location) and there is no data present in the transmitters single
location, the transmit interrupt is asserted HIGH. It is cleared by performing a single write to the transmit FIFO, or
by clearing the interrupt.
• Write data to the transmit FIFO, either prior to enabling the UART and the interrupts, or after enabling the UART and
interrupts.
NOTE
The transmit interrupt is based on a transition through a level, rather than on the level itself. When the interrupt and
the UART is enabled before any data is written to the transmit FIFO the interrupt is not set. The interrupt is only set,
after written data leaves the single location of the transmit FIFO and it becomes empty.
4.2.6.4. UARTRTINTR
The receive timeout interrupt is asserted when the receive FIFO is not empty, and no more data is received during a 32-
bit period. The receive timeout interrupt is cleared either when the FIFO becomes empty through reading all the data (or
by reading the holding register), or when a 1 is written to the corresponding bit of the Interrupt Clear Register, UARTICR.
4.2.6.5. UARTEINTR
The error interrupt is asserted when an error occurs in the reception of data by the UART. The interrupt can be caused
by a number of different error conditions:
• framing
• parity
• break
• overrun.
You can determine the cause of the interrupt by reading the Raw Interrupt Status Register, UARTRIS, or the Masked
Interrupt Status Register, UARTMIS. It can be cleared by writing to the relevant bits of the Interrupt Clear Register,
UARTICR (bits 7 to 10 are the error clear bits).
4.2.6.6. UARTINTR
The interrupts are also combined into a single output, that is an OR function of the individual masked sources. You can
connect this output to a system interrupt controller to provide another level of masking on a individual peripheral basis.
The combined UART interrupt is asserted if any of the individual interrupts are asserted and enabled.
To initialise the UART, the uart_init function takes the following steps:
Description
Data Register, UARTDR
31:12 Reserved. - - -
7:0 DATA Receive (read) data character. Transmit (write) data RWF -
character.
Description
Receive Status Register/Error Clear Register, UARTRSR/UARTECR
31:4 Reserved. - - -
3 OE Overrun error. This bit is set to 1 if data is received and the WC 0x0
FIFO is already full. This bit is cleared to 0 by a write to
UARTECR. The FIFO contents remain valid because no
more data is written when the FIFO is full, only the
contents of the shift register are overwritten. The CPU
must now read the data, to empty the FIFO.
Description
Flag Register, UARTFR
31:9 Reserved. - - -
7 TXFE Transmit FIFO empty. The meaning of this bit depends on RO 0x1
the state of the FEN bit in the Line Control Register,
UARTLCR_H. If the FIFO is disabled, this bit is set when
the transmit holding register is empty. If the FIFO is
enabled, the TXFE bit is set when the transmit FIFO is
empty. This bit does not indicate if there is data in the
transmit shift register.
6 RXFF Receive FIFO full. The meaning of this bit depends on the RO 0x0
state of the FEN bit in the UARTLCR_H Register. If the
FIFO is disabled, this bit is set when the receive holding
register is full. If the FIFO is enabled, the RXFF bit is set
when the receive FIFO is full.
5 TXFF Transmit FIFO full. The meaning of this bit depends on the RO 0x0
state of the FEN bit in the UARTLCR_H Register. If the
FIFO is disabled, this bit is set when the transmit holding
register is full. If the FIFO is enabled, the TXFF bit is set
when the transmit FIFO is full.
4 RXFE Receive FIFO empty. The meaning of this bit depends on RO 0x1
the state of the FEN bit in the UARTLCR_H Register. If the
FIFO is disabled, this bit is set when the receive holding
register is empty. If the FIFO is enabled, the RXFE bit is set
when the receive FIFO is empty.
3 BUSY UART busy. If this bit is set to 1, the UART is busy RO 0x0
transmitting data. This bit remains set until the complete
byte, including all the stop bits, has been sent from the
shift register. This bit is set as soon as the transmit FIFO
becomes non-empty, regardless of whether the UART is
enabled or not.
1 DSR Data set ready. This bit is the complement of the UART RO -
data set ready, nUARTDSR, modem status input. That is,
the bit is 1 when nUARTDSR is LOW.
Description
IrDA Low-Power Counter Register, UARTILPR
31:8 Reserved. - - -
7:0 ILPDVSR 8-bit low-power divisor value. These bits are cleared to 0 RW 0x00
at reset.
Description
Integer Baud Rate Register, UARTIBRD
31:16 Reserved. - - -
15:0 BAUD_DIVINT The integer baud rate divisor. These bits are cleared to 0 RW 0x0000
on reset.
Description
Fractional Baud Rate Register, UARTFBRD
31:6 Reserved. - - -
5:0 BAUD_DIVFRAC The fractional baud rate divisor. These bits are cleared to RW 0x00
0 on reset.
Description
Line Control Register, UARTLCR_H
Table 442.
Bits Name Description Type Reset
UARTLCR_H Register
31:8 Reserved. - - -
6:5 WLEN Word length. These bits indicate the number of data bits RW 0x0
transmitted or received in a frame as follows: b11 = 8 bits
b10 = 7 bits b01 = 6 bits b00 = 5 bits.
3 STP2 Two stop bits select. If this bit is set to 1, two stop bits are RW 0x0
transmitted at the end of the frame. The receive logic
does not check for two stop bits being received.
2 EPS Even parity select. Controls the type of parity the UART RW 0x0
uses during transmission and reception: 0 = odd parity.
The UART generates or checks for an odd number of 1s in
the data and parity bits. 1 = even parity. The UART
generates or checks for an even number of 1s in the data
and parity bits. This bit has no effect when the PEN bit
disables parity checking and generation.
1 PEN Parity enable: 0 = parity is disabled and no parity bit added RW 0x0
to the data frame 1 = parity checking and generation is
enabled.
Description
Control Register, UARTCR
31:16 Reserved. - - -
15 CTSEN CTS hardware flow control enable. If this bit is set to 1, RW 0x0
CTS hardware flow control is enabled. Data is only
transmitted when the nUARTCTS signal is asserted.
14 RTSEN RTS hardware flow control enable. If this bit is set to 1, RW 0x0
RTS hardware flow control is enabled. Data is only
requested when there is space in the receive FIFO for it to
be received.
13 OUT2 This bit is the complement of the UART Out2 (nUARTOut2) RW 0x0
modem status output. That is, when the bit is
programmed to a 1, the output is 0. For DTE this can be
used as Ring Indicator (RI).
12 OUT1 This bit is the complement of the UART Out1 (nUARTOut1) RW 0x0
modem status output. That is, when the bit is
programmed to a 1 the output is 0. For DTE this can be
used as Data Carrier Detect (DCD).
11 RTS Request to send. This bit is the complement of the UART RW 0x0
request to send, nUARTRTS, modem status output. That
is, when the bit is programmed to a 1 then nUARTRTS is
LOW.
10 DTR Data transmit ready. This bit is the complement of the RW 0x0
UART data transmit ready, nUARTDTR, modem status
output. That is, when the bit is programmed to a 1 then
nUARTDTR is LOW.
9 RXE Receive enable. If this bit is set to 1, the receive section of RW 0x1
the UART is enabled. Data reception occurs for either
UART signals or SIR signals depending on the setting of
the SIREN bit. When the UART is disabled in the middle of
reception, it completes the current character before
stopping.
8 TXE Transmit enable. If this bit is set to 1, the transmit section RW 0x1
of the UART is enabled. Data transmission occurs for
either UART signals, or SIR signals depending on the
setting of the SIREN bit. When the UART is disabled in the
middle of transmission, it completes the current character
before stopping.
7 LBE Loopback enable. If this bit is set to 1 and the SIREN bit is RW 0x0
set to 1 and the SIRTEST bit in the Test Control Register,
UARTTCR is set to 1, then the nSIROUT path is inverted,
and fed through to the SIRIN path. The SIRTEST bit in the
test register must be set to 1 to override the normal half-
duplex SIR operation. This must be the requirement for
accessing the test registers during normal operation, and
SIRTEST must be cleared to 0 when loopback testing is
finished. This feature reduces the amount of external
coupling required during system test. If this bit is set to 1,
and the SIRTEST bit is set to 0, the UARTTXD path is fed
through to the UARTRXD path. In either SIR mode or UART
mode, when this bit is set, the modem outputs are also fed
through to the modem inputs. This bit is cleared to 0 on
reset, to disable loopback.
6:3 Reserved. - - -
2 SIRLP SIR low-power IrDA mode. This bit selects the IrDA RW 0x0
encoding mode. If this bit is cleared to 0, low-level bits are
transmitted as an active high pulse with a width of 3 /
16th of the bit period. If this bit is set to 1, low-level bits
are transmitted with a pulse width that is 3 times the
period of the IrLPBaud16 input signal, regardless of the
selected bit rate. Setting this bit uses less power, but
might reduce transmission distances.
Description
Interrupt FIFO Level Select Register, UARTIFLS
31:6 Reserved. - - -
5:3 RXIFLSEL Receive interrupt FIFO level select. The trigger points for RW 0x2
the receive interrupt are as follows: b000 = Receive FIFO
becomes >= 1 / 8 full b001 = Receive FIFO becomes >= 1 /
4 full b010 = Receive FIFO becomes >= 1 / 2 full b011 =
Receive FIFO becomes >= 3 / 4 full b100 = Receive FIFO
becomes >= 7 / 8 full b101-b111 = reserved.
2:0 TXIFLSEL Transmit interrupt FIFO level select. The trigger points for RW 0x2
the transmit interrupt are as follows: b000 = Transmit
FIFO becomes <= 1 / 8 full b001 = Transmit FIFO becomes
<= 1 / 4 full b010 = Transmit FIFO becomes <= 1 / 2 full
b011 = Transmit FIFO becomes <= 3 / 4 full b100 =
Transmit FIFO becomes <= 7 / 8 full b101-b111 =
reserved.
Description
Interrupt Mask Set/Clear Register, UARTIMSC
31:11 Reserved. - - -
10 OEIM Overrun error interrupt mask. A read returns the current RW 0x0
mask for the UARTOEINTR interrupt. On a write of 1, the
mask of the UARTOEINTR interrupt is set. A write of 0
clears the mask.
9 BEIM Break error interrupt mask. A read returns the current RW 0x0
mask for the UARTBEINTR interrupt. On a write of 1, the
mask of the UARTBEINTR interrupt is set. A write of 0
clears the mask.
8 PEIM Parity error interrupt mask. A read returns the current RW 0x0
mask for the UARTPEINTR interrupt. On a write of 1, the
mask of the UARTPEINTR interrupt is set. A write of 0
clears the mask.
7 FEIM Framing error interrupt mask. A read returns the current RW 0x0
mask for the UARTFEINTR interrupt. On a write of 1, the
mask of the UARTFEINTR interrupt is set. A write of 0
clears the mask.
6 RTIM Receive timeout interrupt mask. A read returns the current RW 0x0
mask for the UARTRTINTR interrupt. On a write of 1, the
mask of the UARTRTINTR interrupt is set. A write of 0
clears the mask.
5 TXIM Transmit interrupt mask. A read returns the current mask RW 0x0
for the UARTTXINTR interrupt. On a write of 1, the mask of
the UARTTXINTR interrupt is set. A write of 0 clears the
mask.
4 RXIM Receive interrupt mask. A read returns the current mask RW 0x0
for the UARTRXINTR interrupt. On a write of 1, the mask of
the UARTRXINTR interrupt is set. A write of 0 clears the
mask.
Description
Raw Interrupt Status Register, UARTRIS
31:11 Reserved. - - -
10 OERIS Overrun error interrupt status. Returns the raw interrupt RO 0x0
state of the UARTOEINTR interrupt.
9 BERIS Break error interrupt status. Returns the raw interrupt state RO 0x0
of the UARTBEINTR interrupt.
8 PERIS Parity error interrupt status. Returns the raw interrupt RO 0x0
state of the UARTPEINTR interrupt.
7 FERIS Framing error interrupt status. Returns the raw interrupt RO 0x0
state of the UARTFEINTR interrupt.
6 RTRIS Receive timeout interrupt status. Returns the raw interrupt RO 0x0
state of the UARTRTINTR interrupt. a
5 TXRIS Transmit interrupt status. Returns the raw interrupt state RO 0x0
of the UARTTXINTR interrupt.
4 RXRIS Receive interrupt status. Returns the raw interrupt state of RO 0x0
the UARTRXINTR interrupt.
Description
Masked Interrupt Status Register, UARTMIS
31:11 Reserved. - - -
9 BEMIS Break error masked interrupt status. Returns the masked RO 0x0
interrupt state of the UARTBEINTR interrupt.
8 PEMIS Parity error masked interrupt status. Returns the masked RO 0x0
interrupt state of the UARTPEINTR interrupt.
Description
Interrupt Clear Register, UARTICR
31:11 Reserved. - - -
Description
DMA Control Register, UARTDMACR
Table 449.
Bits Name Description Type Reset
UARTDMACR Register
31:3 Reserved. - - -
2 DMAONERR DMA on error. If this bit is set to 1, the DMA receive RW 0x0
request outputs, UARTRXDMASREQ or UARTRXDMABREQ,
are disabled when the UART error interrupt is asserted.
1 TXDMAE Transmit DMA enable. If this bit is set to 1, DMA for the RW 0x0
transmit FIFO is enabled.
0 RXDMAE Receive DMA enable. If this bit is set to 1, DMA for the RW 0x0
receive FIFO is enabled.
Description
UARTPeriphID0 Register
Table 450.
Bits Name Description Type Reset
UARTPERIPHID0
Register
31:8 Reserved. - - -
Description
UARTPeriphID1 Register
Table 451.
Bits Name Description Type Reset
UARTPERIPHID1
Register
31:8 Reserved. - - -
Description
UARTPeriphID2 Register
Table 452.
Bits Name Description Type Reset
UARTPERIPHID2
Register
31:8 Reserved. - - -
7:4 REVISION This field depends on the revision of the UART: r1p0 0x0 RO 0x3
r1p1 0x1 r1p3 0x2 r1p4 0x2 r1p5 0x3
Description
UARTPeriphID3 Register
Table 453.
Bits Name Description Type Reset
UARTPERIPHID3
Register
31:8 Reserved. - - -
Description
UARTPCellID0 Register
Table 454.
Bits Name Description Type Reset
UARTPCELLID0
Register
31:8 Reserved. - - -
Description
UARTPCellID1 Register
Table 455.
Bits Name Description Type Reset
UARTPCELLID1
Register
31:8 Reserved. - - -
Description
UARTPCellID2 Register
Table 456.
Bits Name Description Type Reset
UARTPCELLID2
Register
31:8 Reserved. - - -
Description
UARTPCellID3 Register
Table 457.
Bits Name Description Type Reset
UARTPCELLID3
Register
31:8 Reserved. - - -
4.3. I2C
Synopsys Documentation
I2C is a commonly used 2-wire interface that can be used to connect devices for low speed data transfer using clock SCL
and data SDA wires.
RP2040 has two identical instances of an I2C controller. The external pins of each controller are connected to GPIO pins
as defined in the GPIO muxing table in Section 2.19.2. The muxing options give some IO flexibility.
4.3.1. Features
Each I2C controller is based on a configuration of the Synopsys DW_apb_i2c (v2.01) IP. The following features are
supported:
4.3.1.1. Standard
The I2C controller was designed for I2C Bus specification, version 6.0, dated April 2014.
4.3.1.2. Clocking
The I2C controller is connected to clk_sys. The I2C clock is generated by dividing down this clock, controlled by registers
inside the block.
4.3.1.3. IOs
Each controller must connect its clock SCL and data SDA to one pair of GPIOs. The I2C standard requires that drivers drive
a signal low, or when not driven the signal will be pulled high. This applies to SCL and SDA. The GPIO pads should be
configured for:
• pull-up enabled
• slew rate limited
• schmitt trigger enabled
NOTE
There should also be external pull-ups on the board as the internal pad pull-ups may not be strong enough to pull up
external circuits.
4.3.2. IP Configuration
I2C configuration details (each instance is fully independent):
NOTE
The I2C block must only be programmed to operate in either master OR slave mode only. Operating as a master and
slave simultaneously is not supported.
• High-speed mode (with data rates less than or equal to 3.4 Mb/s),
• Ultra-Fast Speed Mode (with data rates less than or equal to 5 Mb/s).
NOTE
References to fast mode also apply to fast mode plus, unless specifically stated otherwise.
The I2C block can communicate with devices in one of these modes as long as they are attached to the bus.
Additionally, fast mode devices are downward compatible. For instance, fast mode devices can communicate with
standard mode devices in 0 to 100 Kb/s I2C bus system. However standard mode devices are not upward compatible
and should not be incorporated in a fast-mode I2C bus system as they cannot follow the higher transfer rate and
An example of high-speed mode devices are LCD displays, high-bit count ADCs, and high capacity EEPROMs. These
devices typically need to transfer large amounts of data. Most maintenance and control applications, the common use
for the I2C bus, typically operate at 100 kHz (in standard and fast modes). Any DW_apb_i2c device can be attached to
an I2C-bus and every device can talk with any master, passing information back and forth. There needs to be at least
one master (such as a microcontroller or DSP) on the bus but there can be multiple masters, which require them to
arbitrate for ownership. Multiple masters and arbitration are explained later in this chapter. The I2C block does not
support SMBus and PMBus protocols (for System Management and Power management).
The DW_apb_i2c is made up of an AMBA APB slave interface, an I2C interface, and FIFO logic to maintain coherency
between the two interfaces. The blocks of the component are illustrated in Figure 64.
Interrupt
Toggle Synchronizer DMA Interface
Controller
RX FIFO TX FIFO
• AMBA Bus Interface Unit — Takes the APB interface signals and translates them into a common generic interface
that allows the register file to be bus protocol-agnostic.
• Register File — Contains configuration registers and is the interface with software.
• Slave State Machine — Follows the protocol for a slave and monitors bus for address match.
• Master State Machine — Generates the I2C protocol for the master transfers.
• Clock Generator — Calculates the required timing to do the following:
◦ Generate the SCL clock when configured as a master
◦ Check for bus idle
◦ Generate a START and a STOP
◦ Setup the data and hold the data
• Rx Shift — Takes data into the design and extracts it in byte format.
• Tx Shift — Presents data supplied by CPU for transfer on the I2C bus.
• Rx Filter — Detects the events in the bus; for example, start, stop and arbitration lost.
• Toggle — Generates pulses on both sides and toggles to transfer signals across clock domains.
• Synchronizer — Transfers signals from one clock domain to another.
• DMA Interface — Generates the handshaking signals to the central DMA controller in order to automate the data
transfer without CPU intervention.
• Interrupt Controller — Generates the raw interrupt and interrupt flags, allowing them to be set and cleared.
• RX FIFO/TX FIFO — Holds the RX FIFO and TX FIFO register banks and controllers, along with their status levels.
The following terms relate to how the role of the I2C device and how it interacts with other I2C devices on the bus.
• Transmitter – the device that sends data to the bus. A transmitter can either be a device that initiates the data
transmission to the bus (a master-transmitter) or responds to a request from the master to send data to the bus (a
slave-transmitter).
• Receiver – the device that receives data from the bus. A receiver can either be a device that receives data on its
own request (a master-receiver) or in response to a request from the master (a slave-receiver).
• Master – the component that initializes a transfer (START command), generates the clock SCL signal and
terminates the transfer (STOP command). A master can be either a transmitter or a receiver.
• Slave – the device addressed by the master. A slave can be either receiver or transmitter.
• Multi-master – the ability for more than one master to co-exist on the bus at the same time without collision or
data loss.
• Arbitration – the predefined procedure that authorizes only one master at a time to take control of the bus. For
more information about this behaviour, refer to Section 4.3.8.
• Synchronization – the predefined procedure that synchronizes the clock signals provided by two or more masters.
For more information about this feature, refer to Section 4.3.9.
The following terms are specific to data transfers that occur to/from the I2C bus.
• START (RESTART) – data transfer begins with a START or RESTART condition. The level of the SDA data line
changes from high to low, while the SCL clock line remains high. When this occurs, the bus becomes busy.
NOTE
• STOP – data transfer is terminated by a STOP condition. This occurs when the level on the SDA data line passes
from the low state to the high state, while the SCL clock line remains high. When the data transfer has been
terminated, the bus is free or idle once again. The bus stays busy if a RESTART is generated instead of a STOP
condition.
either transmitting or receiving data to/from the master. The acknowledgement of data is sent by the device that is
receiving data, which can be either a master or a slave. As mentioned previously, the I2C protocol also allows multiple
masters to reside on the I2C bus and uses an arbitration procedure to determine bus ownership.
Each slave has a unique address that is determined by the system designer. When a master wants to communicate with
a slave, the master transmits a START/RESTART condition that is then followed by the slave’s address and a control bit
(R/W) to determine if the master wants to transmit data or receive data from the slave. The slave then sends an
acknowledge (ACK) pulse after the address.
If the master (master-transmitter) is writing to the slave (slave-receiver), the receiver gets one byte of data. This
transaction continues until the master terminates the transmission with a STOP condition. If the master is reading from
a slave (master-receiver), the slave transmits (slave-transmitter) a byte of data to the master, and the master then
acknowledges the transaction with the ACK pulse. This transaction continues until the master terminates the
transmission by not acknowledging (NACK) the transaction after the last byte is received, and then the master issues a
STOP condition or addresses another slave after issuing a RESTART condition. This behaviour is illustrated in Figure 65.
P
Figure 65. Data or
R
transfer on the I2C MSB LSB ACK ACK
SDA
from slave from receiver
Bus
S 1 2 7 8 9 1 2 3-8 9 R
SCL or or
R P
START or RESTART Condition Byte Complete Interrupt STOP AND RESTART Condition
within Slave
The DW_apb_i2c is a synchronous serial interface. The SDA line is a bidirectional signal and changes only while the SCL
line is low, except for STOP, START, and RESTART conditions. The output drivers are open-drain or open-collector to
perform wire-AND functions on the bus. The maximum number of devices on the bus is limited by only the maximum
capacitance specification of 400 pF. Data is transmitted in byte packages.
The I2C protocols implemented in DW_apb_i2c are described in more details in Section 4.3.6.
When operating as an I2C master, putting data into the transmit FIFO causes the DW_apb_i2c to generate a START
condition on the I2C bus. Writing a 1 to IC_DATA_CMD.STOP causes the DW_apb_i2c to generate a STOP condition on
the I2C bus; a STOP condition is not issued if this bit is not set, even if the transmit FIFO is empty.
When operating as a slave, the DW_apb_i2c does not generate START and STOP conditions, as per the protocol.
However, if a read request is made to the DW_apb_i2c, it holds the SCL line low until read data has been supplied to it.
This stalls the I2C bus until read data is provided to the slave DW_apb_i2c, or the DW_apb_i2c slave is disabled by
writing a 0 to IC_ENABLE.ENABLE.
The DW_apb_i2c supports mixed read and write combined format transactions in both 7-bit and 10-bit addressing
modes. The DW_apb_i2c does not support mixed address and mixed address format—that is, a 7-bit address
transaction followed by a 10-bit address transaction or vice versa—combined format transactions. To initiate combined
format transfers, IC_CON.IC_RESTART_EN should be set to 1. With this value set and operating as a master, when the
DW_apb_i2c completes an I2C transfer, it checks the transmit FIFO and executes the next transfer. If the direction of
this transfer differs from the previous transfer, the combined format is used to issue the transfer. If the transmit FIFO is
empty when the current I2C transfer completes:
When the bus is idle, both the SCL and SDA signals are pulled high through external pull-up resistors on the bus. When the
master wants to start a transmission on the bus, the master issues a START condition. This is defined to be a high-to-
low transition of the SDA signal while SCL is 1. When the master wants to terminate the transmission, the master issues a
STOP condition. This is defined to be a low-to-high transition of the SDA line while SCL is 1. Figure 66 shows the timing of
the START and STOP conditions. When data is being transmitted on the bus, the SDA line must be stable when SCL is 1.
SCL
S P
Start Condition Change of Data Allowed Data line Stable Data Valid Change of Data Stop Condition
Allowed
NOTE
The signal transitions for the START/STOP conditions, as depicted in Figure 66, reflect those observed at the output
signals of the Master driving the I2C bus. Care should be taken when observing the SDA/SCL signals at the input
signals of the Slave(s), because unequal line delays may result in an incorrect SDA/SCL timing relationship.
There are two address formats: the 7-bit address format and the 10-bit address format.
During the 7-bit address format, the first seven bits (bits 7:1) of the first byte set the slave address and the LSB bit (bit 0)
is the R/W bit as shown in Figure 67. When bit 0 (R/W) is set to 0, the master writes to the slave. When bit 0 (R/W) is set
to 1, the master reads from the slave.
During 10-bit addressing, two bytes are transferred to set the 10-bit address. The transfer of the first byte contains the
following bit definition. The first five bits (bits 7:3) notify the slaves that this is a 10-bit transfer followed by the next two
bits (bits 2:1), which set the slaves address bits 9:8, and the LSB bit (bit 0) is the R/W bit. The second byte transferred
sets bits 7:0 of the slave address. Figure 68 shows the 10-bit address format.
This table defines the special purpose and reserved first byte addresses.
DW_apb_i2c does not restrict you from using these reserved addresses. However, if you use these reserved addresses,
you may run into incompatibilities with other I2C components.
The master can initiate data transmission and reception to/from the bus, acting as either a master-transmitter or
master-receiver. A slave responds to requests from the master to either transmit data or receive data to/from the bus,
acting as either a slave-transmitter or slave-receiver, respectively.
All data is transmitted in byte format, with no limit on the number of bytes transferred per data transfer. After the master
sends the address and R/W bit or the master transmits a byte of data to the slave, the slave-receiver must respond with
the acknowledge signal (ACK). When a slave-receiver does not respond with an ACK pulse, the master aborts the
transfer by issuing a STOP condition. The slave must leave the SDA line high so that the master can abort the transfer. If
the master-transmitter is transmitting data as shown in Figure 69, then the slave-receiver responds to the master-
transmitter with an acknowledge pulse after every byte of data is received.
‘0’ (read)
For 10-bit Address
If the master is receiving data as shown in Figure 70, then the master responds to the slave-transmitter with an
acknowledge pulse after a byte of data has been received, except for the last byte. This is the way the master-receiver
notifies the slave-transmitter that this is the last byte. The slave-transmitter relinquishes the SDA line after detecting the
No Acknowledge (NACK) so that the master can issue a STOP condition.
‘1’ (read)
For 10-bit Address
When a master does not want to relinquish the bus with a STOP condition, the master can issue a RESTART condition.
This is identical to a START condition except it occurs after the ACK pulse. Operating in master mode, the DW_apb_i2c
can then communicate with the same slave using a transfer of a different direction. For a description of the combined
format transactions that the DW_apb_i2c supports, refer to Section 4.3.5.2.
NOTE
The DW_apb_i2c must be completely disabled before the target slave address register (IC_TAR) can be
reprogrammed.
The START BYTE transfer protocol is set up for systems that do not have an on-board dedicated I2C hardware module.
When the DW_apb_i2c is addressed as a slave, it always samples the I2C bus at the highest speed supported so that it
never requires a START BYTE transfer. However, when DW_apb_i2c is a master, it supports the generation of START
BYTE transfers at the beginning of every transfer in case a slave device requires it.
This protocol consists of seven zeros being transmitted followed by a one, as illustrated in Figure 71. This allows the
processor that is polling the bus to under-sample the address phase until zero is detected. Once the microcontroller
detects a zero, it switches from the under sampling rate to the correct rate of the master.
(HIGH)
1 2 7 8 9
SCL
S Ack Sr
start byte 00000001
3. Master transmits the ACK clock pulse. (Present only to conform with the byte handling format used on the bus)
A hardware receiver does not respond to the START BYTE because it is a reserved address and resets after the
RESTART condition is generated.
The component does not generate a STOP if the Tx FIFO becomes empty; in this situation the component holds the SCL
line low, stalling the bus until a new entry is available in the Tx FIFO. A STOP condition is generated only when the user
specifically requests it by setting bit nine (Stop bit) of the command written to IC_DATA_CMD register. Figure 72 shows
the bits in the IC_DATA_CMD register.
Figure 72.
IC_DATA_CMD
IC_DATA_CMD Restart Stop CMD DATA
Register
9 8 7 0
Figure 73 illustrates the behaviour of the DW_apb_i2c when the Tx FIFO becomes empty while operating as a master
transmitter, as well as showing the generation of a STOP condition.
Empties/STOP SCL
Generation
FIFO_
STOP bit enabled triggers
EMPTY STOP condition on bus
Figure 74 illustrates the behaviour of the DW_apb_i2c when the Tx FIFO becomes empty while operating as a master
receiver, as well as showing the generation of a STOP condition.
S S
Figure 74. Master A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Nak
SDA
Receiver - Tx FIFO
Empties/STOP SCL
Generation FIFO_
EMPTY Because STOP bit was STOP bit enabled triggers
not set on last STOP condition on bus
command popped
Command availability triggers from Tx FIFO, Master
START condition on bus holds SCL low Master releases SCL line and
resumes transmission
because new command
Tx FIFO loaded with command Last command Tx FIFO loaded became available
(read operation in this example) popped from Tx with new command
FIFO, with STOP bit
not set Last command popped from
Tx FIFO with STOP bit set
Figure 75 and Figure 76 illustrate configurations where the user can control the generation of RESTART conditions on
the I2C bus. If bit 10 (Restart) of the IC_DATA_CMD register is set and the restart capability is enabled
(IC_RESTART_EN=1), a RESTART is generated before the data byte is written to or read from the slave. If the restart
capability is not enabled a STOP followed by a START is generated in place of the RESTART. Figure 75 illustrates this
situation during operation as a master transmitter.
S SR
Figure 75. Master A6 A5 A4 A3 A2 A1 A0 W Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack A6 A5 A4 A3 A2 A1 A0 W Ack D7 D6
SDA
Transmitter — Restart
Bit of IC_DATA_CMD SCL
Is Set FIFO_
EMPTY
Figure 76 illustrates the same situation, but during operation as a master receiver.
S SR
Figure 76. Master A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Nak A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6
SDA
Receiver — Restart Bit
of IC_DATA_CMD Is SCL
Set FIFO_
EMPTY
Because next command on Tx FIFO
Command availability triggers has been tagged with RESTART bit,
START condition on bus Master issues RESTART and
initiates new transmission
Tx FIFO loaded with command Next command in Tx FIFO Master issues NOT ACK as
(read operation in this example) has RESTART bit set required before RESTART
when operating as receiver
Figure 77 illustrates operation as a master transmitter where the Stop bit of the IC_DATA_CMD register is set and the Tx
FIFO is not empty
S P S
Figure 77. Master A6 A5 A4 A3 A2 A1 A0 W Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack A6 A5 A4 A3 A2 A1 A0 W Ack D7 D6
SDA
Transmitter — Stop Bit
of IC_DATA_CMD SCL
Figure 78 illustrates operation as a master transmitter where the first byte loaded into the Tx FIFO is allowed to go
empty with the Restart bit set
Figure 79 illustrates operation as a master receiver where the Stop bit of the IC_DATA_CMD register is set and the Tx
FIFO is not empty
S P S
Figure 79. Master A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Nak A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6
SDA
Receiver — Stop Bit of
IC_DATA_CMD Set/Tx SCL
Figure 80 illustrates operation as a master receiver where the first command loaded after the Tx FIFO is allowed to
empty and the Restart bit is set
S SR
Figure 80. Master A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6 D5 D4 D3 D2 D1 D0 Ack D7 D6 D5 D4 D3 D2 D1 D0 Nak A6 A5 A4 A3 A2 A1 A0 R Ack D7 D6
SDA
Receiver — First
Command Loaded SCL
Arbitration takes place on the SDA line, while the SCL line is one. The master, which transmits a one while the other master
transmits zero, loses arbitration and turns off its data output stage. The master that lost arbitration can continue to
generate clocks until the end of the byte transfer. If both masters are addressing the same slave device, the arbitration
could go into the data phase.
Upon detecting that it has lost arbitration to another master, the DW_apb_i2c will stop generating SCL (will disable the
output driver). Figure 81 illustrates the timing of when two masters are arbitrating on the bus.
matching data
MSB ‘0’
DATA2
SDA mirrors DATA2
MSB
SDA
SCL
SDA lines up
with DATA1
START condition
Control of the bus is determined by address or master code and data sent by competing masters, so there is no central
master nor any order of priority on the bus.
All masters then count off their high time, and the master with the shortest high time transitions the SCL line to zero. The
masters then count out their low time and the one with the longest low time forces the other masters into a HIGH wait
state. Therefore, a synchronized SCL clock is generated, which is illustrated in Figure 82. Optionally, slaves may hold the
SCL line low to slow down the timing on the I2C bus.
CLKB
SCL
SCL LOW transition Resets all CLKs SCL transitions HIGH when
to start counting their LOW periods all CLKs are in HIGH state
NOTE
It is important to note that the DW_apb_i2c should only be set to operate as an I2C Master, or I2C Slave, but not both
simultaneously. This is achieved by ensuring that IC_CON.IC_SLAVE_DISABLE and IC_CON.IC_MASTER_MODE are
never set to zero and one, respectively.
2. Write to the IC_SAR register (bits 9:0) to set the slave address. This is the address to which the DW_apb_i2c
responds.
3. Write to the IC_CON register to specify which type of addressing is supported (7-bit or 10-bit by setting bit 3).
Enable the DW_apb_i2c in slave-only mode by writing a ‘0’ into bit six (IC_SLAVE_DISABLE) and a ‘0’ to bit zero
(MASTER_MODE).
NOTE
Slaves and masters do not have to be programmed with the same type of addressing 7-bit or 10-bit address. For
instance, a slave can be programmed with 7-bit addressing and a master with 10-bit addressing, and vice versa.
NOTE
Depending on the reset values chosen, steps two and three may not be necessary because the reset values can be
configured. For instance, if the device is only going to be a master, there would be no need to set the slave address
because you can configure DW_apb_i2c to have the slave disabled after reset and to enable the master after reset.
The values stored are static and do not need to be reprogrammed if the DW_apb_i2c is disabled.
WARNING
It is recommended that the DW_apb_i2c Slave be brought out of reset only when the I2C bus is IDLE. De-asserting
the reset when a transfer is ongoing on the bus causes internal synchronization flip-flops used to synchronize SDA
and SCL to toggle from a reset value of one to the actual value on the bus. This can result in SDA toggling from one to
zero while SCL is one, thereby causing a false START condition to be detected by the DW_apb_i2c Slave. This
scenario can also be avoided by configuring the DW_apb_i2c with IC_SLAVE_DISABLE = 1 and IC_MASTER_MODE =
1 so that the Slave interface is disabled after reset. It can then be enabled by programming IC_CON[0] = 0 and
IC_CON[6] = 0 after the internal SDA and SCL have synchronized to the value on the bus; this takes approximately six
ic_clk cycles after reset de-assertion.
When another I2C master device on the bus addresses the DW_apb_i2c and requests data, the DW_apb_i2c acts as a
slave-transmitter and the following steps occur:
1. The other I2C master device initiates an I2C transfer with an address that matches the slave address in the IC_SAR
register of the DW_apb_i2c.
2. The DW_apb_i2c acknowledges the sent address and recognizes the direction of the transfer to indicate that it is
acting as a slave-transmitter.
3. The DW_apb_i2c asserts the RD_REQ interrupt (bit five of the IC_RAW_INTR_STAT register) and holds the SCL line
low. It is in a wait state until software responds. If the RD_REQ interrupt has been masked, due to
IC_INTR_MASK.M_RD_REQ being set to zero, then it is recommended that a hardware and/or software timing
routine be used to instruct the CPU to perform periodic reads of the IC_RAW_INTR_STAT register.
a. Reads that indicate IC_RAW_INTR_STAT.R_RD_REQ being set to one must be treated as the equivalent of the
RD_REQ interrupt being asserted.
c. The timing interval used should be in the order of 10 times the fastest SCL clock period the DW_apb_i2c can
handle. For example, for 400 kb/s, the timing interval is 25μs.
NOTE
The value of 10 is recommended here because this is approximately the amount of time required for a single byte of
data transferred on the I2C bus.
1. If there is any data remaining in the Tx FIFO before receiving the read request, then the DW_apb_i2c asserts a
TX_ABRT interrupt (bit six of the IC_RAW_INTR_STAT register) to flush the old data from the TX FIFO. If the
TX_ABRT interrupt has been masked, due to IC_INTR_MASK.M_TX_ABRT being set to zero, then it is recommended
that re-using the timing routine (described in the previous step), or a similar one, be used to read the
IC_RAW_INTR_STAT register.
NOTE
Because the DW_apb_i2c’s Tx FIFO is forced into a flushed/reset state whenever a TX_ABRT event occurs, it is
necessary for software to release the DW_apb_i2c from this state by reading the IC_CLR_TX_ABRT register before
attempting to write into the Tx FIFO. See register IC_RAW_INTR_STAT for more details.
a. Reads that indicate bit six (R_TX_ABRT) being set to one must be treated as the equivalent of the TX_ABRT
interrupt being asserted.
c. The timing interval used should be similar to that described in the previous step for the
IC_RAW_INTR_STATRD_REQ register.
1. Software writes to the IC_DATA_CMD register with the data to be written (by writing a ‘0’ in bit 8).
2. Software must clear the RD_REQ and TX_ABRT interrupts (bits five and six, respectively) of the
IC_RAW_INTR_STAT register before proceeding. If the RD_REQ and/or TX_ABRT interrupts have been
masked, then clearing of the IC_RAW_INTR_STAT register will have already been performed when either the
R_RD_REQ or R_TX_ABRT bit has been read as one.
4. The master may hold the I2C bus by issuing a RESTART condition or release the bus by issuing a STOP
condition.
NOTE
Slave-Transmitter Operation for a Single Byte is not applicable in Ultra-Fast Mode as Read transfers are not
supported.
When another I2C master device on the bus addresses the DW_apb_i2c and is sending data, the DW_apb_i2c acts as a
slave-receiver and the following steps occur:
1. The other I2C master device initiates an I2C transfer with an address that matches the DW_apb_i2c’s slave
address in the IC_SAR register.
2. The DW_apb_i2c acknowledges the sent address and recognizes the direction of the transfer to indicate that the
DW_apb_i2c is acting as a slave-receiver.
3. DW_apb_i2c receives the transmitted byte and places it in the receive buffer.
NOTE
If the Rx FIFO is completely filled with data when a byte is pushed, then the DW_apb_i2c slave holds the I2C SCL line
low until the Rx FIFO has some space, and then continues with the next read request.
1. DW_apb_i2c asserts the RX_FULL interrupt IC_RAW_INTR_STAT.RX_FULL. If the RX_FULL interrupt has been
masked, due to setting IC_INTR_MASK.M_RX_FULL register to zero or setting IC_TX_TL to a value larger than zero,
then it is recommended that a timing routine (described in Section 4.3.10.1.2) be implemented for periodic reads
of the IC_STATUS register. Reads of the IC_STATUS register, with bit 3 (RFNE) set at one, must then be treated by
software as the equivalent of the RX_FULL interrupt being asserted.
2. Software may read the byte from the IC_DATA_CMD register (bits 7:0).
3. The other master device may hold the I2C bus by issuing a RESTART condition, or release the bus by issuing a
STOP condition.
In the standard I2C protocol, all transactions are single byte transactions and the programmer responds to a remote
master read request by writing one byte into the slave’s TX FIFO. When a slave (slave-transmitter) is issued with a read
request (RD_REQ) from the remote master (master-receiver), at a minimum there should be at least one entry placed
into the slave-transmitter’s TX FIFO. DW_apb_i2c is designed to handle more data in the TX FIFO so that subsequent
read requests can take that data without raising an interrupt to get more data. Ultimately, this eliminates the possibility
of significant latencies being incurred between raising the interrupt for data each time had there been a restriction of
having only one entry placed in the TX FIFO. This mode only occurs when DW_apb_i2c is acting as a slave-transmitter. If
the remote master acknowledges the data sent by the slave-transmitter and there is no data in the slave’s TX FIFO, the
DW_apb_i2c holds the I2C SCL line low while it raises the read request interrupt (RD_REQ) and waits for data to be
written into the TX FIFO before it can be sent to the remote master.
If the RD_REQ interrupt is masked, due to IC_INTR_STAT.M_RD_REQ set to zero, then it is recommended that a timing
routine be used to activate periodic reads of the IC_RAW_INTR_STAT register. Reads of IC_RAW_INTR_STAT that return
bit five (R_RD_REQ) set to one must be treated as the equivalent of the RD_REQ interrupt referred to in this section. This
timing routine is similar to that described in Section 4.3.10.1.2.
The RD_REQ interrupt is raised upon a read request, and like interrupts, must be cleared when exiting the interrupt
service handling routine (ISR). The ISR allows you to either write one byte or more than one byte into the Tx FIFO. During
the transmission of these bytes to the master, if the master acknowledges the last byte, then the slave must raise the
RD_REQ again because the master is requesting for more data. If the programmer knows in advance that the remote
master is requesting a packet of 'n' bytes, then when another master addresses DW_apb_i2c and requests data, the Tx
FIFO could be written with 'n' bytes and the remote master receives it as a continuous stream of data. For example, the
DW_apb_i2c slave continues to send data to the remote master as long as the remote master is acknowledging the data
sent and there is data available in the Tx FIFO. There is no need to hold the SCL line low or to issue RD_REQ again.
If the remote master is to receive 'n' bytes from the DW_apb_i2c but the programmer wrote a number of bytes larger
than 'n' to the Tx FIFO, then when the slave finishes sending the requested 'n' bytes, it clears the Tx FIFO and ignores any
excess bytes.
The DW_apb_i2c generates a transmit abort (TX_ABRT) event to indicate the clearing of the Tx FIFO in this example. At
the time an ACK/NACK is expected, if a NACK is received, then the remote master has all the data it wants. At this time,
a flag is raised within the slave’s state machine to clear the leftover data in the Tx FIFO. This flag is transferred to the
processor bus clock domain where the FIFO exists and the contents of the Tx FIFO is cleared at that time.
2. Write to the IC_CON register to set the maximum speed mode supported (bits 2:1) and the desired speed of the
DW_apb_i2c master-initiated transfers, either 7-bit or 10-bit addressing (bit 4). Ensure that bit six
(IC_SLAVE_DISABLE) is written with a ‘1’ and bit zero (MASTER_MODE) is written with a ‘1’.
Note: Slaves and masters do not have to be programmed with the same type of 7-bit or 10-bit address. For instance, a
slave can be programmed with 7-bit addressing and a master with 10-bit addressing, and vice versa.
1. Write to the IC_TAR register the address of the I2C device to be addressed (bits 9:0). This register also indicates
whether a General Call or a START BYTE command is going to be performed by I2C.
3. Now write transfer direction and data to be sent to the IC_DATA_CMD register. If the IC_DATA_CMD register is
written before the DW_apb_i2c is enabled, the data and commands are lost as the buffers are kept cleared when
DW_apb_i2c is disabled. This step generates the START condition and the address byte on the DW_apb_i2c. Once
DW_apb_i2c is enabled and there is data in the TX FIFO, DW_apb_i2c starts reading the data.
NOTE
Depending on the reset values chosen, steps two, three, four, and five may not be necessary because the reset
values can be configured. The values stored are static and do not need to be reprogrammed if the DW_apb_i2c is
disabled, with the exception of the transfer direction and data.
The DW_apb_i2c supports switching back and forth between reading and writing dynamically. To transmit data, write
the data to be written to the lower byte of the I2C Rx/Tx Data Buffer and Command Register (IC_DATA_CMD). The CMD
bit [8] should be written to zero for I2C write operations. Subsequently, a read command may be issued by writing “don’t
cares” to the lower byte of the IC_DATA_CMD register, and a one should be written to the CMD bit. The DW_apb_i2c
master continues to initiate transfers as long as there are commands present in the transmit FIFO. If the transmit FIFO
becomes empty the master either inserts a STOP condition after completing the current transfers.
• If set to one, it issues a STOP condition after completing the current transfer.
• If set to zero, it holds SCL low until next command is written to the transmit FIFO.
For more details, refer to Section 4.3.7.
The register IC_ENABLE_STATUS is added to allow software to unambiguously determine when the hardware has
completely shutdown in response to IC_ENABLE.ENABLE being set from one to zero.
Only one register is required to be monitored, as opposed to monitoring two registers (IC_STATUS and
IC_RAW_INTR_STAT) which was a requirement for earlier versions of DW_apb_i2c.
NOTE
The DW_apb_i2c Master can be disabled only if the current command being processed—when the ic_enable de-
assertion occurs—has the STOP bit set to one. When an attempt is made to disable the DW_apb_i2c Master while
processing a command without the STOP bit set, the DW_apb_i2c Master continues to remain active, holding the SCL
line low until a new command is received in the Tx FIFO. When the DW_apb_i2c Master is processing a command
without the STOP bit set, you can issue the ABORT (IC_ENABLE.ABORT) to relinquish the I2C bus and then disable
DW_apb_i2c.
4.3.10.3.1. Procedure
1. Define a timer interval (t i2c_poll ) equal to the 10 times the signalling period for the highest I2C transfer speed
used in the system and supported by DW_apb_i2c. For example, if the highest I2C transfer mode is 400 kb/s, then
this t i2c_poll is 25μs.
2. Define a maximum time-out parameter, MAX_T_POLL_COUNT, such that if any repeated polling operation exceeds
this maximum value, an error is reported.
3. Execute a blocking thread/process/function that prevents any further I2C master transactions to be started by
software, but allows any pending transfers to be completed.
NOTE
This step can be ignored if DW_apb_i2c is programmed to operate as an I2C slave only.
3. Read the IC_ENABLE_STATUS register and test the IC_EN bit (bit 0). Increment POLL_COUNT by one. If
POLL_COUNT >= MAX_T_POLL_COUNT, exit with the relevant error code.
4. If IC_ENABLE_STATUS[0] is one, then sleep for t i2c_poll and proceed to the previous step. Otherwise, exit with
a relevant success code.
The ABORT control bit of the IC_ENABLE register allows the software to relinquish the I2C bus before completing the
issued transfer commands from the Tx FIFO. In response to an ABORT request, the controller issues the STOP condition
over the I2C bus, followed by Tx FIFO flush. Aborting the transfer is allowed only in master mode of operation.
4.3.10.4.1. Procedure
2. When operating in DMA mode, disable the transmit DMA by setting TDMAE to zero.
• The input signal remains unchanged until the counter reaches its count limit value. When this happens, the internal
version of the signal is updated with the input value, and the counter is reset and stopped. The counter is not
restarted until a new change on the input signal is detected.
• The input signal changes again before the counter reaches its count limit value. When this happens, the counter is
reset and stopped, but the internal version of the signal is not updated. The counter remains stopped until a new
change on the input signal is detected.
NOTE
There is a 2-stage synchronizer on the SCL input, but for the sake of simplicity this synchronization delay was not
included in the timing diagram in Figure 83.
The I2C Bus Specification calls for different maximum spike lengths according to the operating mode—50 ns for SS and
FS, so this register is required to store the values needed:
• Register IC_FS_SPKLEN holds the maximum spike length for SS and FS modes
This register is 8 bits wide and accessible through the APB interface for read and write purposes; however, they can be
written to only when the DW_apb_i2c is disabled. The minimum value that can be programmed into these registers is
one; attempting to program a value smaller than one results in the value one being written.
The default value for these registers is based on the value of 100ns for ic_clk period, so does should be updated for the
clk_sys period in use on RP2040.
NOTE
• Because the minimum value that can be programmed into the IC_FS_SPKLEN register is one, the spike length
specification can be exceeded for low frequencies of ic_clk. Consider the simple example of a 10 MHz (100 ns
period) ic_clk; in this case, the minimum spike length that can be programmed is 100 ns, which means that
spikes up to this length are suppressed.
• Standard synchronization logic (two flip-flops in series) is implemented upstream of the spike suppression
logic and is not affected in any way by the contents of the spike length registers or the operation of the spike
suppression logic; the two operations (synchronization and spike suppression) are completely independent.
Because the SCL and SDA inputs are asynchronous to ic_clk, there is one ic_clk cycle uncertainty in the sampling
of these signals; that is, depending on when they occur relative to the rising edge of ic_clk, spikes of the same
original length might show a difference of one ic_clk cycle after being sampled.
• Spike suppression is symmetrical; that is, the behaviour is exactly the same for transitions from zero to one and
from one to zero.
1. Set ic_clk frequency greater than or equal to 32 MHz (refer to Section 4.3.14.2.1).
2. Program the IC_CON register [2:1] = 2’b10 for fast mode or fast mode plus.
3. Program IC_FS_SCL_LCNT and IC_FS_SCL_HCNT registers to meet the fast mode plus SCL (refer to Section 4.3.14).
5. Program the IC_SDA_SETUP register to meet the minimum data setup time (tSU; DAT).
In case of SDA line stuck at LOW, the master performs the following actions to recover as shown in Figure 84 and Figure
85:
1. Master sends a maximum of nine clock pulses to recover the bus LOW within those nine clocks.
◦ The number of clock pulses will vary with the number of bits that remain to be sent by the slave. As the
maximum number of bits is nine, master sends up to nine clock pluses and allows the slave to recover it.
◦ The master attempts to assert a Logic 1 on the SDA line and check whether SDA is recovered. If the SDA is not
recovered, it will continue to send a maximum of nine SCL clocks.
2. If SDA line is recovered within nine clock pulses then the master will send the STOP to release the bus.
3. If SDA line is not recovered even after the ninth clock pulse then system needs a hardware reset.
SDA
MST_SDA Master drives 9 clocks to recover SDA stuck at low
In the unlikely event (due to an electric failure of a circuit) where the clock (SCL) is stuck to LOW, there is no effective
method to overcome this problem but to reset the bus using the hardware reset signal.
• IC_SS_SCL_HCNT
• IC_SS_SCL_LCNT
• IC_FS_SCL_HCNT
• IC_FS_SCL_LCNT
NOTE
The tBUF timing and setup/hold time of START, STOP and RESTART registers uses *HCNT/*LCNT register settings
for the corresponding speed mode.
NOTE
It is not necessary to program any of the *CNT registers if the DW_apb_i2c is enabled to operate only as an I2C
slave, since these registers are used only to determine the SCL timing requirements for operation as an I2C master.
Table 459 lists the derivation of I2C timing parameters from the *CNT programming registers.
Timing Parameter Symbol Standard Speed Fast Speed / Fast Speed Plus
4.3.14.1. Minimum High and Low Counts in SS, FS, and FM+ Modes.
When the DW_apb_i2c operates as an I2C master, in both transmit and receive transfers:
• The minimum value of IC_*_SPKLEN + 7 for the *_LCNT registers is due to the time required for the DW_apb_i2c to
drive SDA after a negative edge of SCL.
• The minimum value of IC_*_SPKLEN + 5 for the *_HCNT registers is due to the time required for the DW_apb_i2c to
sample SDA during the high period of SCL.
• The DW_apb_i2c adds one cycle to the programmed *_LCNT value in order to generate the low period of the SCL
clock; this is due to the counting logic for SCL low counting to (*_LCNT + 1).
• The DW_apb_i2c adds IC_*_SPKLEN + 7 cycles to the programmed *_HCNT value in order to generate the high
period of the SCL clock; this is due to the following factors:
◦ Whenever SCL is driven one to zero by the DW_apb_i2c—that is, completing the SCL high time—an internal logic
latency of three ic_clk cycles is incurred. Consequently, the minimum SCL low time of which the DW_apb_i2c is
capable is nine ic_clk periods (7 + 1 + 1), while the minimum SCL high time is thirteen ic_clk periods (6 + 1 + 3
+ 3).
NOTE
The total high time and low time of SCL generated by the DW_apb_i2c master is also influenced by the rise time and
fall time of the SCL line, as shown in the illustration and equations in Figure 86. It should be noted that the SCL rise and
fall time parameters vary, depending on external factors such as:
• Characteristics of IO driver
• Pull-up resistor value
• Total capacitance on SCL line, and so on
These characteristics are beyond the control of the DW_apb_i2c.
ic_clk_in_a/SCL
This section describes the minimum ic_clk frequencies that the DW_apb_i2c supports for each speed mode, and the
associated high and low count values. In Slave mode, IC_SDA_HOLD (Thd;dat) and IC_SDA_SETUP (Tsu:dat) need to be
programmed to satisfy the I2C protocol timing requirements. The following examples are for the case where
IC_FS_SPKLEN is programmed to two.
4.3.14.2.1. Standard Mode (SM), Fast Mode (FM), and Fast Mode Plus (FM+)
This section details how to derive a minimum ic_clk value for standard and fast modes of the DW_apb_i2c. Although
the following method shows how to do fast mode calculations, you can also use the same method in order to do
calculations for standard mode and fast mode plus.
NOTE
Given conditions and calculations for the minimum DW_apb_i2c ic_clk value in fast mode:
• Fast mode has data rate of 400kb/s; implies SCL period of 1/400khz = 2.5μs
• Minimum hcnt value of 14 as a seed value; IC_HCNT_FS = 14
• Protocol minimum SCL high and low times:
◦ MIN_SCL_LOWtime_FS = 1300ns
◦ MIN_SCL_HIGHtime_FS = 600ns
Derived equations:
IC_LCNT_FS = roundup(15.166) = 16
These calculations produce IC_LCNT_FS = 16 and IC_HCNT_FS = 14, giving an ic_clk value of:
Table 460 lists the minimum ic_clk values for all modes with high and low count values.
Table 460. ic_clk in Speed Mode ic_clkfreq Minimum SCL Low SCL Low SCL Low SCL High SCL High SCL High
Relation to High and
(MHz) Value of Time in Program Time Time in Program Time
Low Counts
IC_*_SPKLEN `ic_clk`s Value `ic_clk`s Value
• The IC_*_SCL_LCNT and IC_*_SCL_HCNT registers are programmed using the SCL low and high program values in
Table 460, which are calculated using SCL low count minus one, and SCL high counts minus eight, respectively. The
values in Table 460 are based on IC_SDA_RX_HOLD = 0. The maximum IC_SDA_RX_HOLD value depends on the
IC_*CNT registers in Master mode.
• In order to compute the HCNT and LCNT considering RC timings, use the following equations:
◦ IC_HCNT_* = [(HCNT + IC_*_SPKLEN + 7) * ic_clk] + SCL_Fall_time
◦ IC_LCNT_* = [(LCNT + 1) * ic_clk] - SCL_Fall_time + SCL_Rise_time
The calculations below show how to calculate SCL high and low counts for each speed mode in the DW_apb_i2c. For the
calculations to work, the ic_clk frequencies used must not be less than the minimum ic_clk frequencies specified in
Table 460.
The default ic_clk period value is set to 100ns, so default SCL high and low count values are calculated for each speed
mode based on this clock. These values need updating according to the guidelines below.
The equation to calculate the proper number of ic_clk signals required for setting the proper SCL clocks high and low
times is as follows:
IC_xCNT = (ROUNDUP(MIN_SCL_xxxtime*OSCFREQ,0))
For example:
IC_xCNT = (ROUNDUP(MIN_SCL_HIGH_LOWtime*OSCFREQ,0))
To enable the DMA Controller interface on the DW_apb_i2c, you must write the DMA Control Register (IC_DMA_CR).
Writing a one into the TDMAE bit field of IC_DMA_CR register enables the DW_apb_i2c transmit handshaking interface.
Writing a one into the RDMAE bit field of the IC_DMA_CR register enables the DW_apb_i2c receive handshaking
interface.
The DMA Controller is programmed with the number of data items (transfer count) that are to be transmitted or
received by DW_apb_i2c.
The transfer is broken into single transfers on the bus, each initiated by a request from the DW_apb_i2c.
For example, where the transfer count programmed into the DMA Controller is four. The DMA transfer consists of a
series of four single transactions. If the DW_apb_i2c makes a transmit request to this channel, a single data item is
written to the DW_apb_i2c TX FIFO. Similarly, if the DW_apb_i2c makes a receive request to this channel, a single data
item is read from the DW_apb_i2c RX FIFO. Four separate requests must be made to this DMA channel before all four
data items are written or read.
In DW_apb_i2c the registers for setting watermarks to allow DMA bursts do not need be set to anything other than their
reset value. Specifically IC_DMA_TDLR and IC_DMA_RDLR can be left at reset values of zero. This is because only single
transfers are needed due to the low bandwidth of I2C relative to system bandwidth, and also the DMA controller
normally has highest priority on the system bus so will generally complete very quickly.
Table 461 lists the operation of the DW_apb_i2c interrupt registers and how they are set and cleared. Some bits are set
by hardware and cleared by software, whereas other bits are set and cleared by hardware.
RESTART_DET Y N
GEN_CALL Y N
START_DET Y N
STOP_DET Y N
ACTIVITY Y N
RX_DONE Y N
TX_ABRT Y N
RD_REQ Y N
TX_EMPTY N Y
TX_OVER Y N
RX_FULL N Y
RX_OVER Y N
RX_UNDER Y N
0x14 IC_SS_SCL_HCNT Standard Speed I2C Clock SCL High Count Register
0x18 IC_SS_SCL_LCNT Standard Speed I2C Clock SCL Low Count Register
0x1c IC_FS_SCL_HCNT Fast Mode or Fast Mode Plus I2C Clock SCL High Count Register
0x20 IC_FS_SCL_LCNT Fast Mode or Fast Mode Plus I2C Clock SCL Low Count Register
Description
I2C Control Register. This register can be written only when the DW_apb_i2c is disabled, which corresponds to the
IC_ENABLE[0] register being set to 0. Writes at other times have no effect.
Read/Write Access: - bit 10 is read only. - bit 11 is read only - bit 16 is read only - bit 17 is read only - bits 18 and 19 are
read only.
31:11 Reserved. - - -
9 RX_FIFO_FULL_HL This bit controls whether DW_apb_i2c should hold the bus RW 0x0
D_CTRL when the Rx FIFO is physically full to its
RX_BUFFER_DEPTH, as described in the
IC_RX_FULL_HLD_BUS_EN parameter.
7 STOP_DET_IFADD In slave mode: - 1’b1: issues the STOP_DET interrupt only RW 0x0
RESSED when it is addressed. - 1’b0: issues the STOP_DET
irrespective of whether it’s addressed or not. Reset value:
0x0
6 IC_SLAVE_DISABL This bit controls whether I2C has its slave disabled, which RW 0x1
E means once the presetn signal is applied, then this bit is
set and the slave is disabled.
3 IC_10BITADDR_SL When acting as a slave, this bit controls whether the RW 0x0
AVE DW_apb_i2c responds to 7- or 10-bit addresses. - 0: 7-bit
addressing. The DW_apb_i2c ignores transactions that
involve 10-bit addressing; for 7-bit addressing, only the
lower 7 bits of the IC_SAR register are compared. - 1: 10-
bit addressing. The DW_apb_i2c responds to only 10-bit
addressing transfers that match the full 10 bits of the
IC_SAR register.
0x0 → Slave 7Bit addressing
0x1 → Slave 10Bit addressing
2:1 SPEED These bits control at which speed the DW_apb_i2c RW 0x2
operates; its setting is relevant only if one is operating the
DW_apb_i2c in master mode. Hardware protects against
illegal values being programmed by software. These bits
must be programmed appropriately for slave mode also,
as it is used to capture correct value of spike filter as per
the speed mode.
Description
I2C Target Address Register
This register is 12 bits wide, and bits 31:12 are reserved. This register can be written to only when IC_ENABLE[0] is set
to 0.
Note: If the software or application is aware that the DW_apb_i2c is not using the TAR address for the pending
commands in the Tx FIFO, then it is possible to update the TAR address even while the Tx FIFO has entries
(IC_STATUS[2]= 0). - It is not necessary to perform any write to this register if DW_apb_i2c is enabled as an I2C slave
only.
31:12 Reserved. - - -
9:0 IC_TAR This is the target address for any master transaction. RW 0x055
When transmitting a General Call, these bits are ignored.
To generate a START BYTE, the CPU needs to write only
once into these bits.
Description
I2C Slave Address Register
31:10 Reserved. - - -
9:0 IC_SAR The IC_SAR holds the slave address when the I2C is RW 0x055
operating as a slave. For 7-bit addressing, only IC_SAR[6:0]
is used.
Description
I2C Rx/Tx Data Buffer and Command Register; this is the register the CPU writes to when filling the TX FIFO and the
CPU reads from when retrieving bytes from RX FIFO.
Table 466.
Bits Name Description Type Reset
IC_DATA_CMD
Register
31:12 Reserved. - - -
11 FIRST_DATA_BYT Indicates the first data byte received after the address RO 0x0
E phase for receive transfer in Master receiver or Slave
receiver mode.
10 RESTART This bit controls whether a RESTART is issued before the SC 0x0
byte is sent or received.
9 STOP This bit controls whether a STOP is issued after the byte is SC 0x0
sent or received.
Description
Standard Speed I2C Clock SCL High Count Register
Table 467.
Bits Name Description Type Reset
IC_SS_SCL_HCNT
Register
31:16 Reserved. - - -
15:0 IC_SS_SCL_HCNT This register must be set before any I2C bus transaction RW 0x0028
can take place to ensure proper I/O timing. This register
sets the SCL clock high-period count for standard speed.
For more information, refer to 'IC_CLK Frequency
Configuration'.
Description
Standard Speed I2C Clock SCL Low Count Register
Table 468.
Bits Name Description Type Reset
IC_SS_SCL_LCNT
Register
31:16 Reserved. - - -
15:0 IC_SS_SCL_LCNT This register must be set before any I2C bus transaction RW 0x002f
can take place to ensure proper I/O timing. This register
sets the SCL clock low period count for standard speed.
For more information, refer to 'IC_CLK Frequency
Configuration'
Description
Fast Mode or Fast Mode Plus I2C Clock SCL High Count Register
Table 469.
Bits Name Description Type Reset
IC_FS_SCL_HCNT
Register
31:16 Reserved. - - -
15:0 IC_FS_SCL_HCNT This register must be set before any I2C bus transaction RW 0x0006
can take place to ensure proper I/O timing. This register
sets the SCL clock high-period count for fast mode or fast
mode plus. It is used in high-speed mode to send the
Master Code and START BYTE or General CALL. For more
information, refer to 'IC_CLK Frequency Configuration'.
Description
Fast Mode or Fast Mode Plus I2C Clock SCL Low Count Register
Table 470.
Bits Name Description Type Reset
IC_FS_SCL_LCNT
Register
31:16 Reserved. - - -
15:0 IC_FS_SCL_LCNT This register must be set before any I2C bus transaction RW 0x000d
can take place to ensure proper I/O timing. This register
sets the SCL clock low period count for fast speed. It is
used in high-speed mode to send the Master Code and
START BYTE or General CALL. For more information, refer
to 'IC_CLK Frequency Configuration'.
Description
I2C Interrupt Status Register
Each bit in this register has a corresponding mask bit in the IC_INTR_MASK register. These bits are cleared by reading
the matching interrupt clear register. The unmasked raw versions of these bits are available in the IC_RAW_INTR_STAT
register.
Table 471.
Bits Name Description Type Reset
IC_INTR_STAT
Register
31:14 Reserved. - - -
Description
I2C Interrupt Mask Register.
These bits mask their corresponding interrupt status bits. This register is active low; a value of 0 masks the interrupt,
whereas a value of 1 unmasks the interrupt.
Table 472.
Bits Name Description Type Reset
IC_INTR_MASK
Register
31:14 Reserved. - - -
Description
I2C Raw Interrupt Status Register
Unlike the IC_INTR_STAT register, these bits are not masked so they always show the true status of the DW_apb_i2c.
Table 473.
Bits Name Description Type Reset
IC_RAW_INTR_STAT
Register
31:14 Reserved. - - -
13 MASTER_ON_HOL Indicates whether master is holding the bus and TX FIFO RO 0x0
D is empty. Enabled only when
I2C_DYNAMIC_TAR_UPDATE=1 and
IC_EMPTYFIFO_HOLD_MASTER_EN=1.
11 GEN_CALL Set only when a General Call address is received and it is RO 0x0
acknowledged. It stays set until it is cleared either by
disabling DW_apb_i2c or when the CPU reads bit 0 of the
IC_CLR_GEN_CALL register. DW_apb_i2c stores the
received data in the Rx buffer.
8 ACTIVITY This bit captures DW_apb_i2c activity and stays set until it RO 0x0
is cleared. There are four ways to clear it: - Disabling the
DW_apb_i2c - Reading the IC_CLR_ACTIVITY register -
Reading the IC_CLR_INTR register - System reset Once
this bit is set, it stays set unless one of the four methods
is used to clear it. Even if the DW_apb_i2c module is idle,
this bit remains set until cleared, indicating that there was
activity on the bus.
2 RX_FULL Set when the receive buffer reaches or goes above the RO 0x0
RX_TL threshold in the IC_RX_TL register. It is
automatically cleared by hardware when buffer level goes
below the threshold. If the module is disabled
(IC_ENABLE[0]=0), the RX FIFO is flushed and held in reset;
therefore the RX FIFO is not full. So this bit is cleared once
the IC_ENABLE bit 0 is programmed with a 0, regardless of
the activity that continues.
0 RX_UNDER Set if the processor attempts to read the receive buffer RO 0x0
when it is empty by reading from the IC_DATA_CMD
register. If the module is disabled (IC_ENABLE[0]=0), this
bit keeps its level until the master or slave state machines
go into idle, and when ic_en goes to 0, this interrupt is
cleared.
Offset: 0x38
Description
I2C Receive FIFO Threshold Register
31:8 Reserved. - - -
Description
I2C Transmit FIFO Threshold Register
31:8 Reserved. - - -
Description
Clear Combined and Individual Interrupt Register
Table 476.
Bits Name Description Type Reset
IC_CLR_INTR Register
31:1 Reserved. - - -
0 CLR_INTR Read this register to clear the combined interrupt, all RO 0x0
individual interrupts, and the IC_TX_ABRT_SOURCE
register. This bit does not clear hardware clearable
interrupts but software clearable interrupts. Refer to Bit 9
of the IC_TX_ABRT_SOURCE register for an exception to
clearing IC_TX_ABRT_SOURCE.
Description
Clear RX_UNDER Interrupt Register
Table 477.
Bits Name Description Type Reset
IC_CLR_RX_UNDER
Register
31:1 Reserved. - - -
0 CLR_RX_UNDER Read this register to clear the RX_UNDER interrupt (bit 0) RO 0x0
of the IC_RAW_INTR_STAT register.
Description
Clear RX_OVER Interrupt Register
Table 478.
Bits Name Description Type Reset
IC_CLR_RX_OVER
Register
31:1 Reserved. - - -
0 CLR_RX_OVER Read this register to clear the RX_OVER interrupt (bit 1) of RO 0x0
the IC_RAW_INTR_STAT register.
Description
Clear TX_OVER Interrupt Register
Table 479.
Bits Name Description Type Reset
IC_CLR_TX_OVER
Register
31:1 Reserved. - - -
0 CLR_TX_OVER Read this register to clear the TX_OVER interrupt (bit 3) of RO 0x0
the IC_RAW_INTR_STAT register.
Description
Clear RD_REQ Interrupt Register
Table 480.
Bits Name Description Type Reset
IC_CLR_RD_REQ
Register
31:1 Reserved. - - -
0 CLR_RD_REQ Read this register to clear the RD_REQ interrupt (bit 5) of RO 0x0
the IC_RAW_INTR_STAT register.
Description
Clear TX_ABRT Interrupt Register
Table 481.
Bits Name Description Type Reset
IC_CLR_TX_ABRT
Register
31:1 Reserved. - - -
0 CLR_TX_ABRT Read this register to clear the TX_ABRT interrupt (bit 6) of RO 0x0
the IC_RAW_INTR_STAT register, and the
IC_TX_ABRT_SOURCE register. This also releases the TX
FIFO from the flushed/reset state, allowing more writes to
the TX FIFO. Refer to Bit 9 of the IC_TX_ABRT_SOURCE
register for an exception to clearing
IC_TX_ABRT_SOURCE.
Description
Clear RX_DONE Interrupt Register
Table 482.
Bits Name Description Type Reset
IC_CLR_RX_DONE
Register
31:1 Reserved. - - -
0 CLR_RX_DONE Read this register to clear the RX_DONE interrupt (bit 7) of RO 0x0
the IC_RAW_INTR_STAT register.
Description
Clear ACTIVITY Interrupt Register
Table 483.
Bits Name Description Type Reset
IC_CLR_ACTIVITY
Register
31:1 Reserved. - - -
0 CLR_ACTIVITY Reading this register clears the ACTIVITY interrupt if the RO 0x0
I2C is not active anymore. If the I2C module is still active
on the bus, the ACTIVITY interrupt bit continues to be set.
It is automatically cleared by hardware if the module is
disabled and if there is no further activity on the bus. The
value read from this register to get status of the ACTIVITY
interrupt (bit 8) of the IC_RAW_INTR_STAT register.
Description
Clear STOP_DET Interrupt Register
Table 484.
Bits Name Description Type Reset
IC_CLR_STOP_DET
Register
31:1 Reserved. - - -
0 CLR_STOP_DET Read this register to clear the STOP_DET interrupt (bit 9) RO 0x0
of the IC_RAW_INTR_STAT register.
Description
Clear START_DET Interrupt Register
Table 485.
Bits Name Description Type Reset
IC_CLR_START_DET
Register
31:1 Reserved. - - -
0 CLR_START_DET Read this register to clear the START_DET interrupt (bit RO 0x0
10) of the IC_RAW_INTR_STAT register.
Description
Clear GEN_CALL Interrupt Register
Table 486.
Bits Name Description Type Reset
IC_CLR_GEN_CALL
Register
31:1 Reserved. - - -
0 CLR_GEN_CALL Read this register to clear the GEN_CALL interrupt (bit 11) RO 0x0
of IC_RAW_INTR_STAT register.
Description
I2C Enable Register
31:3 Reserved. - - -
1 ABORT When set, the controller initiates the transfer abort. - 0: RW 0x0
ABORT not initiated or ABORT done - 1: ABORT operation
in progress The software can abort the I2C transfer in
master mode by setting this bit. The software can set this
bit only when ENABLE is already set; otherwise, the
controller ignores any write to ABORT bit. The software
cannot clear the ABORT bit once set. In response to an
ABORT, the controller issues a STOP and flushes the Tx
FIFO after completing the current transfer, then sets the
TX_ABORT interrupt after the abort operation. The ABORT
bit is cleared automatically after the abort operation.
Description
I2C Status Register
This is a read-only register used to indicate the current transfer status and FIFO status. The status register may be read
at any time. None of the bits in this register request an interrupt.
When the I2C is disabled by writing 0 in bit 0 of the IC_ENABLE register: - Bits 1 and 2 are set to 1 - Bits 3 and 10 are set
to 0 When the master or slave state machines goes to idle and ic_en=0: - Bits 5 and 6 are set to 0
31:7 Reserved. - - -
6 SLV_ACTIVITY Slave FSM Activity Status. When the Slave Finite State RO 0x0
Machine (FSM) is not in the IDLE state, this bit is set. - 0:
Slave FSM is in IDLE state so the Slave part of
DW_apb_i2c is not Active - 1: Slave FSM is not in IDLE
state so the Slave part of DW_apb_i2c is Active Reset
value: 0x0
0x0 → Slave is idle
0x1 → Slave not idle
5 MST_ACTIVITY Master FSM Activity Status. When the Master Finite State RO 0x0
Machine (FSM) is not in the IDLE state, this bit is set. - 0:
Master FSM is in IDLE state so the Master part of
DW_apb_i2c is not Active - 1: Master FSM is not in IDLE
state so the Master part of DW_apb_i2c is Active Note:
IC_STATUS[0]-that is, ACTIVITY bit-is the OR of
SLV_ACTIVITY and MST_ACTIVITY bits.
4 RFF Receive FIFO Completely Full. When the receive FIFO is RO 0x0
completely full, this bit is set. When the receive FIFO
contains one or more empty location, this bit is cleared. -
0: Receive FIFO is not full - 1: Receive FIFO is full Reset
value: 0x0
0x0 → Rx FIFO not full
0x1 → Rx FIFO is full
3 RFNE Receive FIFO Not Empty. This bit is set when the receive RO 0x0
FIFO contains one or more entries; it is cleared when the
receive FIFO is empty. - 0: Receive FIFO is empty - 1:
Receive FIFO is not empty Reset value: 0x0
0x0 → Rx FIFO is empty
0x1 → Rx FIFO not empty
2 TFE Transmit FIFO Completely Empty. When the transmit FIFO RO 0x1
is completely empty, this bit is set. When it contains one
or more valid entries, this bit is cleared. This bit field does
not request an interrupt. - 0: Transmit FIFO is not empty -
1: Transmit FIFO is empty Reset value: 0x1
0x0 → Tx FIFO not empty
0x1 → Tx FIFO is empty
1 TFNF Transmit FIFO Not Full. Set when the transmit FIFO RO 0x1
contains one or more empty locations, and is cleared
when the FIFO is full. - 0: Transmit FIFO is full - 1: Transmit
FIFO is not full Reset value: 0x1
0x0 → Tx FIFO is full
0x1 → Tx FIFO not full
Description
I2C Transmit FIFO Level Register This register contains the number of valid data entries in the transmit FIFO buffer.
It is cleared whenever: - The I2C is disabled - There is a transmit abort - that is, TX_ABRT bit is set in the
IC_RAW_INTR_STAT register - The slave bulk transmit mode is aborted The register increments whenever data is
placed into the transmit FIFO and decrements when data is taken from the transmit FIFO.
31:5 Reserved. - - -
4:0 TXFLR Transmit FIFO Level. Contains the number of valid data RO 0x00
entries in the transmit FIFO.
Description
I2C Receive FIFO Level Register This register contains the number of valid data entries in the receive FIFO buffer. It
is cleared whenever: - The I2C is disabled - Whenever there is a transmit abort caused by any of the events tracked
in IC_TX_ABRT_SOURCE The register increments whenever data is placed into the receive FIFO and decrements
when data is taken from the receive FIFO.
31:5 Reserved. - - -
4:0 RXFLR Receive FIFO Level. Contains the number of valid data RO 0x00
entries in the receive FIFO.
Description
I2C SDA Hold Time Length Register
The bits [15:0] of this register are used to control the hold time of SDA during transmit in both slave and master mode
(after SCL goes from HIGH to LOW).
The bits [23:16] of this register are used to extend the SDA transition (if any) whenever SCL is HIGH in the receiver in
either master or slave mode.
The values in this register are in units of ic_clk period. The value programmed in IC_SDA_TX_HOLD must be greater than
the minimum hold time in each mode one cycle in master mode, seven cycles in slave mode for the value to be
implemented.
The programmed SDA hold time during transmit (IC_SDA_TX_HOLD) cannot exceed at any time the duration of the low
part of scl. Therefore the programmed value cannot be larger than N_SCL_LOW-2, where N_SCL_LOW is the duration of
the low part of the scl period measured in ic_clk cycles.
Table 491.
Bits Name Description Type Reset
IC_SDA_HOLD
Register
31:24 Reserved. - - -
23:16 IC_SDA_RX_HOLD Sets the required SDA hold time in units of ic_clk period, RW 0x00
when DW_apb_i2c acts as a receiver.
15:0 IC_SDA_TX_HOLD Sets the required SDA hold time in units of ic_clk period, RW 0x0001
when DW_apb_i2c acts as a transmitter.
Description
I2C Transmit Abort Source Register
This register has 32 bits that indicate the source of the TX_ABRT bit. Except for Bit 9, this register is cleared whenever
the IC_CLR_TX_ABRT register or the IC_CLR_INTR register is read. To clear Bit 9, the source of the
ABRT_SBYTE_NORSTRT must be fixed first; RESTART must be enabled (IC_CON[5]=1), the SPECIAL bit must be cleared
(IC_TAR[11]), or the GC_OR_START bit must be cleared (IC_TAR[10]).
Once the source of the ABRT_SBYTE_NORSTRT is fixed, then this bit can be cleared in the same manner as other bits in
this register. If the source of the ABRT_SBYTE_NORSTRT is not fixed before attempting to clear this bit, Bit 9 clears for
one cycle and is then re-asserted.
Table 492.
Bits Name Description Type Reset
IC_TX_ABRT_SOURCE
Register
31:23 TX_FLUSH_CNT This field indicates the number of Tx FIFO Data RO 0x000
Commands which are flushed due to TX_ABRT interrupt. It
is cleared whenever I2C is disabled.
22:17 Reserved. - - -
14 ABRT_SLV_ARBL This field indicates that a Slave has lost the bus while RO 0x0
OST transmitting data to a remote master.
IC_TX_ABRT_SOURCE[12] is set at the same time. Note:
Even though the slave never 'owns' the bus, something
could go wrong on the bus. This is a fail safe check. For
instance, during a data transmission at the low-to-high
transition of SCL, if what is on the data bus is not what is
supposed to be transmitted, then DW_apb_i2c no longer
own the bus.
13 ABRT_SLVFLUSH_ This field specifies that the Slave has received a read RO 0x0
TXFIFO command and some data exists in the TX FIFO, so the
slave issues a TX_ABRT interrupt to flush old data in TX
FIFO.
12 ARB_LOST This field specifies that the Master has lost arbitration, or RO 0x0
if IC_TX_ABRT_SOURCE[14] is also set, then the slave
transmitter has lost arbitration.
11 ABRT_MASTER_DI This field indicates that the User tries to initiate a Master RO 0x0
S operation with the Master mode disabled.
7 ABRT_SBYTE_AC This field indicates that the Master has sent a START Byte RO 0x0
KDET and the START Byte was acknowledged (wrong behavior).
6 ABRT_HS_ACKDE This field indicates that the Master is in High Speed mode RO 0x0
T and the High Speed Master code was acknowledged
(wrong behavior).
5 ABRT_GCALL_RE This field indicates that DW_apb_i2c in the master mode RO 0x0
AD has sent a General Call but the user programmed the byte
following the General Call to be a read from the bus
(IC_DATA_CMD[9] is set to 1).
4 ABRT_GCALL_NO This field indicates that DW_apb_i2c in master mode has RO 0x0
ACK sent a General Call and no slave on the bus acknowledged
the General Call.
3 ABRT_TXDATA_N This field indicates the master-mode only bit. When the RO 0x0
OACK master receives an acknowledgement for the address, but
when it sends data byte(s) following the address, it did not
receive an acknowledge from the remote slave(s).
2 ABRT_10ADDR2_ This field indicates that the Master is in 10-bit address RO 0x0
NOACK mode and that the second address byte of the 10-bit
address was not acknowledged by any slave.
1 ABRT_10ADDR1_ This field indicates that the Master is in 10-bit address RO 0x0
NOACK mode and the first 10-bit address byte was not
acknowledged by any slave.
0 ABRT_7B_ADDR_ This field indicates that the Master is in 7-bit addressing RO 0x0
NOACK mode and the address sent was not acknowledged by any
slave.
Description
Generate Slave Data NACK Register
The register is used to generate a NACK for the data part of a transfer when DW_apb_i2c is acting as a slave-receiver.
This register only exists when the IC_SLV_DATA_NACK_ONLY parameter is set to 1. When this parameter disabled, this
register does not exist and writing to the register’s address has no effect.
A write can occur on this register if both of the following conditions are met: - DW_apb_i2c is disabled (IC_ENABLE[0] =
0) - Slave part is inactive (IC_STATUS[6] = 0) Note: The IC_STATUS[6] is a register read-back location for the internal
slv_activity signal; the user should poll this before writing the ic_slv_data_nack_only bit.
Table 493.
Bits Name Description Type Reset
IC_SLV_DATA_NACK_
ONLY Register
31:1 Reserved. - - -
0 NACK Generate NACK. This NACK generation only occurs when RW 0x0
DW_apb_i2c is a slave-receiver. If this register is set to a
value of 1, it can only generate a NACK after a data byte is
received; hence, the data transfer is aborted and the data
received is not pushed to the receive buffer.
Description
DMA Control Register
The register is used to enable the DMA Controller interface operation. There is a separate bit for transmit and receive.
This can be programmed regardless of the state of IC_ENABLE.
Table 494.
Bits Name Description Type Reset
IC_DMA_CR Register
31:2 Reserved. - - -
0 RDMAE Receive DMA Enable. This bit enables/disables the receive RW 0x0
FIFO DMA channel. Reset value: 0x0
0x0 → Receive FIFO DMA channel disabled
0x1 → Receive FIFO DMA channel enabled
Description
DMA Transmit Data Level Register
Table 495.
Bits Name Description Type Reset
IC_DMA_TDLR
Register
31:4 Reserved. - - -
3:0 DMATDL Transmit Data Level. This bit field controls the level at RW 0x0
which a DMA request is made by the transmit logic. It is
equal to the watermark level; that is, the dma_tx_req signal
is generated when the number of valid data entries in the
transmit FIFO is equal to or below this field value, and
TDMAE = 1.
Description
I2C Receive Data Level Register
Table 496.
Bits Name Description Type Reset
IC_DMA_RDLR
Register
31:4 Reserved. - - -
3:0 DMARDL Receive Data Level. This bit field controls the level at RW 0x0
which a DMA request is made by the receive logic. The
watermark level = DMARDL+1; that is, dma_rx_req is
generated when the number of valid data entries in the
receive FIFO is equal to or more than this field value + 1,
and RDMAE =1. For instance, when DMARDL is 0, then
dma_rx_req is asserted when 1 or more data entries are
present in the receive FIFO.
Description
I2C SDA Setup Register
This register controls the amount of time delay (in terms of number of ic_clk clock periods) introduced in the rising edge
of SCL - relative to SDA changing - when DW_apb_i2c services a read request in a slave-transmitter operation. The
relevant I2C requirement is tSU:DAT (note 4) as detailed in the I2C Bus Specification. This register must be programmed
with a value equal to or greater than 2.
Note: The length of setup time is calculated using [(IC_SDA_SETUP - 1) * (ic_clk_period)], so if the user requires 10 ic_clk
periods of setup time, they should program a value of 11. The IC_SDA_SETUP register is only used by the DW_apb_i2c
when operating as a slave transmitter.
Table 497.
Bits Name Description Type Reset
IC_SDA_SETUP
Register
31:8 Reserved. - - -
7:0 SDA_SETUP SDA Setup. It is recommended that if the required delay is RW 0x64
1000ns, then for an ic_clk frequency of 10 MHz,
IC_SDA_SETUP should be programmed to a value of 11.
IC_SDA_SETUP must be programmed with a minimum
value of 2.
Description
I2C ACK General Call Register
The register controls whether DW_apb_i2c responds with a ACK or NACK when it receives an I2C General Call address.
Table 498.
Bits Name Description Type Reset
IC_ACK_GENERAL_CA
LL Register
31:1 Reserved. - - -
Description
I2C Enable Status Register
The register is used to report the DW_apb_i2c hardware status when the IC_ENABLE[0] register is set from 1 to 0; that is,
when DW_apb_i2c is disabled.
If IC_ENABLE[0] has been set to 1, bits 2:1 are forced to 0, and bit 0 is forced to 1.
If IC_ENABLE[0] has been set to 0, bits 2:1 is only be valid as soon as bit 0 is read as '0'.
Note: When IC_ENABLE[0] has been set to 0, a delay occurs for bit 0 to be read as 0 because disabling the DW_apb_i2c
depends on I2C bus activities.
Table 499.
Bits Name Description Type Reset
IC_ENABLE_STATUS
Register
31:3 Reserved. - - -
2 SLV_RX_DATA_LO Slave Received Data Lost. This bit indicates if a Slave- RO 0x0
ST Receiver operation has been aborted with at least one
data byte received from an I2C transfer due to the setting
bit 0 of IC_ENABLE from 1 to 0. When read as 1,
DW_apb_i2c is deemed to have been actively engaged in
an aborted I2C transfer (with matching address) and the
data phase of the I2C transfer has been entered, even
though a data byte has been responded with a NACK.
Note: The CPU can safely read this bit when IC_EN (bit 0)
is read as 0.
1 SLV_DISABLED_W Slave Disabled While Busy (Transmit, Receive). This bit RO 0x0
HILE_BUSY indicates if a potential or active Slave operation has been
aborted due to the setting bit 0 of the IC_ENABLE register
from 1 to 0. This bit is set when the CPU writes a 0 to the
IC_ENABLE register while:
OR,
Note: The CPU can safely read this bit when IC_EN (bit 0)
is read as 0.
0 IC_EN ic_en Status. This bit always reflects the value driven on RO 0x0
the output port ic_en. - When read as 1, DW_apb_i2c is
deemed to be in an enabled state. - When read as 0,
DW_apb_i2c is deemed completely inactive. Note: The
CPU can safely read this bit anytime. When this bit is read
as 0, the CPU can safely read SLV_RX_DATA_LOST (bit 2)
and SLV_DISABLED_WHILE_BUSY (bit 1).
Description
I2C SS, FS or FM+ spike suppression limit
This register is used to store the duration, measured in ic_clk cycles, of the longest spike that is filtered out by the spike
suppression logic when the component is operating in SS, FS or FM+ modes. The relevant I2C requirement is tSP (table
4) as detailed in the I2C Bus Specification. This register must be programmed with a minimum value of 1.
Table 500.
Bits Name Description Type Reset
IC_FS_SPKLEN
Register
31:8 Reserved. - - -
7:0 IC_FS_SPKLEN This register must be set before any I2C bus transaction RW 0x07
can take place to ensure stable operation. This register
sets the duration, measured in ic_clk cycles, of the longest
spike in the SCL or SDA lines that will be filtered out by the
spike suppression logic. This register can be written only
when the I2C interface is disabled which corresponds to
the IC_ENABLE[0] register being set to 0. Writes at other
times have no effect. The minimum valid value is 1;
hardware prevents values less than this being written, and
if attempted results in 1 being set. or more information,
refer to 'Spike Suppression'.
Description
Clear RESTART_DET Interrupt Register
Table 501.
Bits Name Description Type Reset
IC_CLR_RESTART_DET
Register
31:1 Reserved. - - -
0 CLR_RESTART_DE Read this register to clear the RESTART_DET interrupt (bit RO 0x0
T 12) of IC_RAW_INTR_STAT register.
Description
Component Parameter Register 1
Note This register is not implemented and therefore reads as 0. If it was implemented it would be a constant read-only
register that contains encoded information about the component’s parameter settings. Fields shown below are the
settings for those parameters
Table 502.
Bits Name Description Type Reset
IC_COMP_PARAM_1
Register
31:24 Reserved. - - -
Description
I2C Component Version Register
Table 503.
Bits Name Description Type Reset
IC_COMP_VERSION
Register
31:0 IC_COMP_VERSION RO 0x3230312a
Description
I2C Component Type Register
Table 504.
Bits Name Description Type Reset
IC_COMP_TYPE
Register
31:0 IC_COMP_TYPE Designware Component Type number = 0x44_57_01_40. RO 0x44570140
This assigned unique hex value is constant and is derived
from the two ASCII letters 'DW' followed by a 16-bit
unsigned number.
4.4. SPI
ARM Documentation
Excerpted from the ARM PrimeCell Synchronous Serial Port (PL022) Technical Reference Manual. Used
with permission.
RP2040 has two identical SPI controllers, both based on an ARM Primecell Synchronous Serial Port (SSP) (PL022)
(Revision r1p4). Note this is NOT the same as the QSPI interface covered in Section 4.10.
• clock sclk (connects to SSPCLKOUT in the following sections when the controller is operating in master mode, or
SSPCLKIN when in slave mode)
• active low chip select or frame sync ss_n (referred to as SSPFSSOUT in the following sections)
• transmit data tx (referred to as SSPTXD in the following sections)
• receive data rd (referred to as SSPRXD in the following sections)
The SPI uses clk_peri as its reference clock for SPI timing, and is referred to as SSPCLK in the following sections.
clk_sys is used as the bus clock, and is referred to as PCLK in the following sections (also see Section 2.15.1).
4.4.1. Overview
The PrimeCell SSP is a master or slave interface for synchronous serial communication with peripheral devices that
have Motorola SPI, National Semiconductor Microwire, or Texas Instruments synchronous serial interfaces.
The PrimeCell SSP performs serial-to-parallel conversion on data received from a peripheral device. The CPU accesses
data, control, and status information through the AMBA APB interface. The transmit and receive paths are buffered with
internal FIFO memories enabling up to eight 16-bit values to be stored independently in both transmit and receive
modes. Serial data is transmitted on SSPTXD and received on SSPRXD.
The PrimeCell SSP includes a programmable bit rate clock divider and prescaler to generate the serial output clock,
SSPCLKOUT, from the input clock, SSPCLK. Bit rates are supported to 2MHz and higher, subject to choice of frequency
for SSPCLK, and the maximum bit rate is determined by peripheral devices.
You can use the control registers SSPCR0 and SSPCR1 to program the PrimeCell SSP operating mode, frame format,
and size.
In addition to the above interrupts, a set of DMA signals are provided for interfacing with a DMA controller.
Depending on the operating mode selected, the SSPFSSOUT output operates as:
• an active-HIGH frame synchronization output for Texas Instruments synchronous serial frame format
• an active-LOW slave select for SPI and Microwire.
SSPFSSOUT
Transmit and
SSPRXDMACLR
receive logic SSPCLKOUT
SSPTXDMACLR
Tx/Rx FIFO watermark levels nSSPCTLOE
SSPRXDMASREQ
SSPCLKIN
DMA
SSPRXDMABREQ interface SSPFSSIN
SSPTXDMASREQ
SSPRXD
SSPTXDMABREQ RxWrData[15:0]
The AMBA APB interface generates read and write decodes for accesses to status and control registers, and transmit
and receive FIFO memories.
The register block stores data written, or to be read, across the AMBA APB interface.
When configured as a master, an internal prescaler, comprising two free-running reloadable serially linked counters,
provides the serial output clock SSPCLKOUT.
You can program the clock prescaler, using the SSPCPSR register, to divide SSPCLK by a factor of 2-254 in steps of two.
By not utilizing the least significant bit of the SSPCPSR register, division by an odd number is not possible which
ensures that a symmetrical, equal mark space ratio, clock is generated. See SSPCPSR.
The output of the prescaler is divided again by a factor of 1-256, by programming the SSPCR0 control register, to give
the final master output clock SSPCLKOUT.
NOTE
The PCLK and SSPCLK clock inputs in Figure 87 are connected to the clk_sys and clk_peri system-level clock nets on
RP2040, respectively. By default clk_peri is attached directly to the system clock, but can be detached to maintain
constant SPI frequency if the system clock is varied dynamically. See Figure 28 for an overview of the RP2040 clock
architecture.
The common transmit FIFO is a 16-bit wide, 8-locations deep memory buffer. CPU data written across the AMBA APB
interface are stored in the buffer until read out by the transmit logic.
When configured as a master or a slave, parallel data is written into the transmit FIFO prior to serial conversion, and
transmission to the attached slave or master respectively, through the SSPTXD pin.
The common receive FIFO is a 16-bit wide, 8-locations deep memory buffer. Received data from the serial interface are
stored in the buffer until read out by the CPU across the AMBA APB interface.
When configured as a master or slave, serial data received through the SSPRXD pin is registered prior to parallel loading
into the attached slave or master receive FIFO respectively.
When configured as a master, the clock to the attached slaves is derived from a divided-down version of SSPCLK
through the previously described prescaler operations. The master transmit logic successively reads a value from its
transmit FIFO and performs parallel to serial conversion on it. Then, the serial data stream and frame control signal,
synchronized to SSPCLKOUT, are output through the SSPTXD pin to the attached slaves. The master receive logic
performs serial to parallel conversion on the incoming synchronous SSPRXD data stream, extracting and storing values
into its receive FIFO, for subsequent reading through the APB interface.
When configured as a slave, the SSPCLKIN clock is provided by an attached master and used to time its transmission
and reception sequences. The slave transmit logic, under control of the master clock, successively reads a value from
its transmit FIFO, performs parallel to serial conversion, then outputs the serial data stream and frame control signal
through the slave SSPTXD pin. The slave receive logic performs serial to parallel conversion on the incoming SSPRXD
data stream, extracting and storing values into its receive FIFO, for subsequent reading through the APB interface.
The PrimeCell SSP generates four individual maskable, active-HIGH interrupts. A combined interrupt output is generated
as an OR function of the individual interrupt requests.
The transmit and receive dynamic data-flow interrupts, SSPTXINTR and SSPRXINTR, are separated from the status
interrupts so that data can be read or written in response to the FIFO trigger levels.
The PrimeCell SSP provides an interface to connect to a DMA controller, see Section 4.4.3.16.
The PrimeCell SSP supports both asynchronous and synchronous operation of the clocks, PCLK and SSPCLK.
Synchronization registers and handshaking logic have been implemented, and are active at all times. Synchronization of
control signals is performed on both directions of data flow, that is:
4.4.3. Operation
The PrimeCell SSP is reset by the global reset signal, PRESETn, and a block-specific reset signal, nSSPRST. The device
reset controller asserts nSSPRST asynchronously and negate it synchronously to SSPCLK.
Following reset, the PrimeCell SSP logic is disabled and must be configured when in this state. It is necessary to
program control registers SSPCR0 and SSPCR1 to configure the peripheral as a master or slave operating under one of
the following protocols:
• Motorola SPI
• Texas Instruments SSI
• National Semiconductor.
The bit rate, derived from the external SSPCLK, requires the programming of the clock prescale register SSPCPSR.
You can either prime the transmit FIFO, by writing up to eight 16-bit values when the PrimeCell SSP is disabled, or permit
the transmit FIFO service request to interrupt the CPU. Once enabled, transmission or reception of data begins on the
transmit, SSPTXD, and receive, SSPRXD, pins.
There is a constraint on the ratio of the frequencies of PCLK to SSPCLK. The frequency of SSPCLK must be less than or
equal to that of PCLK. This ensures that control signals from the SSPCLK domain to the PCLK domain are guaranteed
to get synchronized before one frame duration:
In the slave mode of operation, the SSPCLKIN signal from the external master is double-synchronized and then delayed
to detect an edge. It takes three SSPCLKs to detect an edge on SSPCLKIN. SSPTXD has less setup time to the falling
edge of SSPCLKIN on which the master is sampling the line.
The setup and hold times on SSPRXD, with reference to SSPCLKIN, must be more conservative to ensure that it is at the
right value when the actual sampling occurs within the SSPMS. To ensure correct device operation, SSPCLK must be at
least 12 times faster than the maximum expected frequency of SSPCLKIN.
The frequency selected for SSPCLK must accommodate the desired range of bit clock rates. The ratio of minimum
SSPCLK frequency to SSPCLKOUT maximum frequency in the case of the slave mode is 12, and for the master mode, it
is two.
To generate a maximum bit rate of 1.8432Mbps in the master mode, the frequency of SSPCLK must be at least
3.6864MHz. With an SSPCLK frequency of 3.6864MHz, the SSPCPSR register must be programmed with a value of 2,
and the SCR[7:0] field in the SSPCR0 register must be programmed with a value of 0.
To work with a maximum bit rate of 1.8432Mbps in the slave mode, the frequency of SSPCLK must be at least
22.12MHz. With an SSPCLK frequency of 22.12MHz, the SSPCPSR register can be programmed with a value of 12, and
the SCR[7:0] field in the SSPCR0 register can be programmed with a value of 0. Similarly, the ratio of SSPCLK maximum
frequency to SSPCLKOUT minimum frequency is 254 x 256.
The minimum frequency of SSPCLK is governed by the following equations, both of which must be satisfied:
The maximum frequency of SSPCLK is governed by the following equations, both of which must be satisfied:
NOTE
Since the maximum frequency for clk_peri on RP2040 (and hence the maximum frequency for SSPCLK) is 133 MHz,
the maximum SCK output frequency is 133 / 2 = 66.5 MHz, and the maximum SCK input frequency is 133 / 12 =
~11.083 MHz.
The frame format is programmed through the FRF bits, and the data word size through the DSS bits.
Bit phase and polarity, applicable to Motorola SPI format only, are programmed through the SPH and SPO bits.
Setting the SSPCR1 register MS bit to 1 configures the PrimeCell SSP as a slave. When configured as a slave, enabling
or disabling of the PrimeCell SSP SSPTXD signal is provided through the SSPCR1 slave mode SSPTXD output disable
bit, SOD. You can use this in some multi-slave environments where masters might parallel broadcast.
To enable the operation of the PrimeCell SSP, set the Synchronous Serial Port Enable (SSE) bit to 1.
The serial bit rate is derived by dividing down the input clock, SSPCLK. The clock is first divided by an even prescale
value CPSDVSR in the range 2-254, and is programmed in SSPCPSR. The clock is divided again by a value in the range 1-
256, that is 1 + SCR, where SCR is the value programmed in SSPCR0.
The following equation defines the frequency of the output signal bit clock, SSPCLKOUT:
For example, if SSPCLK is 3.6864MHz, and CPSDVSR = 2, then SSPCLKOUT has a frequency range from 7.2kHz-
1.8432MHz.
Each data frame is between 4-16 bits long, depending on the size of data programmed, and is transmitted starting with
the MSB. You can select the following basic frame types:
For Motorola SPI and National Semiconductor Microwire frame formats, the serial frame, SSPFSSOUT, pin is active-
LOW, and is asserted, pulled-down, during the entire transmission of the frame.
For Texas Instruments synchronous serial frame format, the SSPFSSOUT pin is pulsed for one serial clock period,
starting at its rising edge, prior to the transmission of each frame. For this frame format, both the PrimeCell SSP and the
off-chip slave device drive their output data on the rising edge of SSPCLKOUT, and latch data from the other device on
the falling edge.
Unlike the full-duplex transmission of the other two frame formats, the National Semiconductor Microwire format uses a
special master-slave messaging technique that operates at half-duplex. In this mode, when a frame begins, an 8-bit
control message is transmitted to the off-chip slave. During this transmit, the SSS receives no incoming data. After the
message has been sent, the off-chip slave decodes it and, after waiting one serial clock after the last bit of the 8-bit
control message has been sent, responds with the requested data. The returned data can be 4-16 bits in length, making
the total frame length in the range 13-25 bits.
Figure 88 shows the Texas Instruments synchronous serial frame format for a single transmitted frame.
nSSPOE
In this mode, SSPCLKOUT and SSPFSSOUT are forced LOW, and the transmit data line, SSPTXD is tristated whenever
the PrimeCell SSP is idle. When the bottom entry of the transmit FIFO contains data, SSPFSSOUT is pulsed HIGH for one
SSPCLKOUT period. The value to be transmitted is also transferred from the transmit FIFO to the serial shift register of
the transmit logic. On the next rising edge of SSPCLKOUT, the MSB of the 4-bit to 16-bit data frame is shifted out on the
SSPTXD pin. In a similar way, the MSB of the received data is shifted onto the SSPRXD pin by the off-chip serial slave
device.
Both the PrimeCell SSP and the off-chip serial slave device then clock each data bit into their serial shifter on the falling
edge of each SSPCLKOUT. The received data is transferred from the serial shifter to the receive FIFO on the first rising
edge of PCLK after the LSB has been latched.
Figure 89 shows the Texas Instruments synchronous serial frame format when back-to-back frames are transmitted.
nSSPOE (=0)
The Motorola SPI interface is a four-wire interface where the SSPFSSOUT signal behaves as a slave select. The main
feature of the Motorola SPI format is that you can program the inactive state and phase of the SSPCLKOUT signal using
the SPO and SPH bits of the SSPSCR0 control register.
When the SPO clock polarity control bit is LOW, it produces a steady state LOW value on the SSPCLKOUT pin. If the SPO
clock polarity control bit is HIGH, a steady state HIGH value is placed on the SSPCLKOUT pin when data is not being
transferred.
The SPH control bit selects the clock edge that captures data and enables it to change state. It has the most impact on
the first bit transmitted by either permitting or not permitting a clock transition before the first data capture edge.
When the SPH phase control bit is LOW, data is captured on the first clock edge transition.
When the SPH clock phase control bit is HIGH, data is captured on the second clock edge transition.
Figure 90 and Figure 91 shows a continuous transmission signal sequence for Motorola SPI frame format with SPO=0,
SPH=0. Figure 90 shows a single transmission signal sequence for Motorola SPI frame format with SPO=0, SPH=0.
nSSPOE
Figure 91 shows a continuous transmission signal sequence for Motorola SPI frame format with SPO=0, SPH=0.
nSSPOE (=0)
• when the PrimeCell SSP is configured as a slave, the nSSPCTLOE line is driven HIGH, disabling the SSPCLKOUT
pad, active-LOW enable.
If the PrimeCell SSP is enable, and there is valid data within the transmit FIFO, the start of transmission is signified by
the SSPFSSOUT master signal being driven LOW. This causes slave data to be enabled onto the SSPRXD input line of
the master. The nSSPOE line is driven LOW, enabling the master SSPTXD output pad.
One-half SSPCLKOUT period later, valid master data is transferred to the SSPTXD pin. Now that both the master and
slave data have been set, the SSPCLKOUT master clock pin goes HIGH after one additional half SSPCLKOUT period.
The data is now captured on the rising and propagated on the falling edges of the SSPCLKOUT signal.
In the case of a single word transmission, after all bits of the data word have been transferred, the SSPFSSOUT line is
returned to its idle HIGH state one SSPCLKOUT period after the last bit has been captured.
However, in the case of continuous back-to-back transmissions, the SSPFSSOUT signal must be pulsed HIGH between
each data word transfer. This is because the slave select pin freezes the data in its serial peripheral register and does
not permit it to be altered if the SPH bit is logic zero. Therefore, the master device must raise the SSPFSSIN pin of the
slave device between each data transfer to enable the serial peripheral data write. On completion of the continuous
transfer, the SSPFSSOUT pin is returned to its idle state one SSPCLKOUT period after the last bit has been captured.
Figure 92 shows the transfer signal sequence for Motorola SPI format with SPO=0, SPH=1, and it covers both single and
continuous transfers.
nSSPOE
• when the PrimeCell SSP is configured as a slave, the nSSPCTLOE line is driven HIGH, disabling the SSPCLKOUT
pad, active-LOW enable.
If the PrimeCell SSP is enabled, and there is valid data within the transmit FIFO, the start of transmission is signified by
the SSPFSSOUT master signal being driven LOW. The nSSPOE line is driven LOW, enabling the master SSPTXD output
pad. After an additional one half SSPCLKOUT period, both master and slave valid data is enabled onto their respective
transmission lines. At the same time, the SSPCLKOUT is enabled with a rising edge transition.
Data is then captured on the falling edges and propagated on the rising edges of the SSPCLKOUT signal.
In the case of a single word transfer, after all bits have been transferred, the SSPFSSOUT line is returned to its idle HIGH
state one SSPCLKOUT period after the last bit has been captured. For continuous back-to-back transfers, the
SSPFSSOUT pin is held LOW between successive data words and termination is the same as that of the single word
transfer.
Figure 93 and Figure 94 show single and continuous transmission signal sequences for Motorola SPI format with
SPO=1, SPH=0.
Figure 93 shows a single transmission signal sequence for Motorola SPI format with SPO=1, SPH=0.
nSSPOE
Figure 94 shows a continuous transmission signal sequence for Motorola SPI format with SPO=1, SPH=0.
NOTE
nSSPOE (=0)
• when the PrimeCell SSP is configured as a slave, the nSSPCTLOE line is driven HIGH, disabling the SSPCLKOUT
pad, active-LOW enable.
If the PrimeCell SSP is enabled, and there is valid data within the transmit FIFO, the start of transmission is signified by
the SSPFSSOUT master signal being driven LOW, and this causes slave data to be immediately transferred onto the
SSPRXD line of the master. The nSSPOE line is driven LOW, enabling the master SSPTXD output pad.
One half period later, valid master data is transferred to the SSPTXD line. Now that both the master and slave data have
been set, the SSPCLKOUT master clock pin becomes LOW after one additional half SSPCLKOUT period. This means
that data is captured on the falling edges and be propagated on the rising edges of the SSPCLKOUT signal.
In the case of a single word transmission, after all bits of the data word are transferred, the SSPFSSOUT line is returned
to its idle HIGH state one SSPCLKOUT period after the last bit has been captured.
However, in the case of continuous back-to-back transmissions, the SSPFSSOUT signal must be pulsed HIGH between
each data word transfer. This is because the slave select pin freezes the data in its serial peripheral register and does
not permit it to be altered if the SPH bit is logic zero. Therefore, the master device must raise the SSPFSSIN pin of the
slave device between each data transfer to enable the serial peripheral data write. On completion of the continuous
transfer, the SSPFSSOUT pin is returned to its idle state one SSPCLKOUT period after the last bit has been captured.
Figure 95 shows the transfer signal sequence for Motorola SPI format with SPO=1, SPH=1, and it covers both single and
continuous transfers.
nSSPOE
NOTE
• when the PrimeCell SSP is configured as a slave, the nSSPCTLOE line is driven HIGH, disabling the SSPCLKOUT
pad, active-LOW enable.
If the PrimeCell SSP is enabled, and there is valid data within the transmit FIFO, the start of transmission is signified by
the SSPFSSOUT master signal being driven LOW. The nSSPOE line is driven LOW, enabling the master SSPTXD output
pad. After an additional one half SSPCLKOUT period, both master and slave data are enabled onto their respective
transmission lines. At the same time, the SSPCLKOUT is enabled with a falling edge transition. Data is then captured on
the rising edges and propagated on the falling edges of the SSPCLKOUT signal.
After all bits have been transferred, in the case of a single word transmission, the SSPFSSOUT line is returned to its idle
HIGH state one SSPCLKOUT period after the last bit has been captured.
For continuous back-to-back transmissions, the SSPFSSOUT pin remains in its active-LOW state, until the final bit of the
last word has been captured, and then returns to its idle state as the previous section describes.
For continuous back-to-back transfers, the SSPFSSOUT pin is held LOW between successive data words and
termination is the same as that of the single word transfer.
Figure 96 shows the National Semiconductor Microwire frame format for a single frame. Figure 97 shows the same
format when back to back frames are transmitted.
nSSPOE
Microwire format is very similar to SPI format, except that transmission is half-duplex instead of full-duplex, using a
master-slave message passing technique. Each serial transmission begins with an 8-bit control word that is transmitted
from the PrimeCell SSP to the off-chip slave device. During this transmission, the PrimeCell SSP receives no incoming
data. After the message has been sent, the off-chip slave decodes it and, after waiting one serial clock after the last bit
of the 8-bit control message has been sent, responds with the required data. The returned data is 4 to 16 bits in length,
making the total frame length in the range 13-25 bits.
The off-chip serial slave device latches each control bit into its serial shifter on the rising edge of each SSPCLKOUT.
After the last bit is latched by the slave device, the control byte is decoded during a one clock wait-state, and the slave
responds by transmitting data back to the PrimeCell SSP. Each bit is driven onto SSPRXD line on the falling edge of
SSPCLKOUT. The PrimeCell SSP in turn latches each bit on the rising edge of SSPCLKOUT. At the end of the frame, for
single transfers, the SSPFSSOUT signal is pulled HIGH one clock period after the last bit has been latched in the receive
serial shifter, that causes the data to be transferred to the receive FIFO.
NOTE
The off-chip slave device can tristate the receive line either on the falling edge of SSPCLKOUT after the LSB has
been latched by the receive shifter, or when the SSPFSSOUT pin goes HIGH.
For continuous transfers, data transmission begins and ends in the same manner as a single transfer. However, the
SSPFSSOUT line is continuously asserted, held LOW, and transmission of data occurs back-to-back. The control byte of
the next frame follows directly after the LSB of the received data from the current frame. Each of the received values is
transferred from the receive shifter on the falling edge SSPCLKOUT, after the LSB of the frame has been latched into the
PrimeCell SSP.
Figure 97 shows the National Semiconductor Microwire frame format when back-to-back frames are transmitted.
nSSPOE
In Microwire mode, the PrimeCell SSP slave samples the first bit of receive data on the rising edge of SSPCLKIN after
SSPFSSIN has gone LOW. Masters that drive a free-running SSPCKLIN must ensure that the SSPFSSIN signal has
sufficient setup and hold margins with respect to the rising edge of SSPCLKIN.
With respect to the SSPCLKIN rising edge on which the first bit of receive data is to be sampled by the PrimeCell SSP
slave, SSPFSSIN must have a setup of at least two times the period of SSPCLK on which the PrimeCell SSP operates.
With respect to the SSPCLKIN rising edge previous to this edge, SSPFSSIN must have a hold of at least one SSPCLK
period.
SSPFSSIN
SSPRXD
First RX data bit to be
sampled by SSP slave
Figure 99, Figure 100, and Figure 101 shows how you can connect the PrimeCell SSP (PL022) peripheral to other
synchronous serial peripherals, when it is configured as a master or a slave.
NOTE
The SSP (PL022) does not support dynamic switching between master and slave in a system. Each instance is
configured and connected either as a master or slave.
Figure 99 shows the PrimeCell SSP (PL022) instanced twice, as a single master and one slave. The master can
broadcast to the slave through the master SSPTXD line. In response, the slave drives its nSSPOE signal HIGH, enabling
its SSPTXD data onto the SSPRXD line of the master.
nSSPOE nSSPOE
SSPRXD SSPTXD
SSPFSSOUT SSPFSSIN
SSPFSSIN SSPFSSOUT
OV
SSPCLKOUT SSPCLKIN
nSSPCTLOE nSSPCTLOE
SSPCLKIN SSPCLKOUT
OV
Figure 100 shows how an PrimeCell SSP (PL022), configured as master, interfaces to a Motorola SPI slave. The SPI
Slave Select (SS) signal is permanently tied LOW and configures it as a slave. Similar to the above operation, the master
can broadcast to the slave through the master PrimeCell SSP SSPTXD line. In response, the slave drives its SPI MISO
port onto the SSPRXD line of the master.
nSSPOE
SSPRXD MISO
SSPFSSOUT
SSPFSSIN
OV
SSPCLKOUT SCK
nSSPCTLOE SS
SSPCLKIN
OV
Figure 101 shows a Motorola SPI configured as a master and interfaced to an instance of a PrimeCell SSP (PL022)
configured as a slave. In this case, the slave Select Signal (SS) is permanently tied HIGH to configure it as a master. The
master can broadcast to the slave through the master SPI MOSI line and in response, the slave drives its nSSPOE signal
LOW. This enables its SSPTXD data onto the MISO line of the master.
nSSPOE
MISO SSPTXD
SSPFSSIN
OV SSPFSSOUT
SCK SSPCLKIN
Vdd nSSPCTLOE
SS SSPCLKOUT
The PrimeCell SSP provides an interface to connect to the DMA controller. The PrimeCell SSP DMA control register,
SSPDMACR controls the DMA operation of the PrimeCell SSP.
SSPRXDMASREQ
Single-character DMA transfer request, asserted by the SSP. This signal is asserted when the receive FIFO contains
at least one character.
SSPRXDMABREQ
Burst DMA transfer request, asserted by the SSP. This signal is asserted when the receive FIFO contains four or
more characters.
SSPRXDMACLR
DMA request clear, asserted by the DMA controller to clear the receive request signals. If DMA burst transfer is
requested, the clear signal is asserted during the transfer of the last data in the burst.
SSPTXDMASREQ
Single-character DMA transfer request, asserted by the SSP. This signal is asserted when there is at least one
empty location in the transmit FIFO.
SSPTXDMABREQ
Burst DMA transfer request, asserted by the SSP. This signal is asserted when the transmit FIFO contains four
characters or fewer.
SSPTXDMACLR
DMA request clear, asserted by the DMA controller, to clear the transmit request signals. If a DMA burst transfer is
requested, the clear signal is asserted during the transfer of the last data in the burst.
The burst transfer and single transfer request signals are not mutually exclusive. They can both be asserted at the same
time. For example, when there is more data than the watermark level of four in the receive FIFO, the burst transfer
request, and the single transfer request, are asserted. When the amount of data left in the receive FIFO is less than the
watermark level, the single request only is asserted. This is useful for situations where the number of characters left to
be received in the stream is less than a burst.
For example, if 19 characters must be received, the DMA controller then transfers four bursts of four characters, and
three single transfers to complete the stream.
NOTE
For the remaining three characters, the PrimeCell SSP does not assert the burst request.
Each request signal remains asserted until the relevant DMA clear signal is asserted. After the request clear signal is
deasserted, a request signal can become active again, depending on the conditions that previous sections describe. All
request signals are deasserted if the PrimeCell SSP is disabled, or the DMA enable signal is cleared.
Table 505 shows the trigger points for DMABREQ, for both the transmit and receive FIFOs.
1/2 4 4
Figure 102 shows the timing diagram for both a single transfer request, and a burst transfer request, with the
appropriate DMA clear signal. The signals are all synchronous to PCLK.
0x014 SSPIMSC Interrupt mask set or clear register, SSPIMSC on page 3-9
Description
Control register 0, SSPCR0 on page 3-4
31:16 Reserved. - - -
15:8 SCR Serial clock rate. The value SCR is used to generate the RW 0x00
transmit and receive bit rate of the PrimeCell SSP. The bit
rate is: F SSPCLK CPSDVSR x (1+SCR) where CPSDVSR is
an even value from 2-254, programmed through the
SSPCPSR register and SCR is a value from 0-255.
3:0 DSS Data Size Select: 0000 Reserved, undefined operation. RW 0x0
0001 Reserved, undefined operation. 0010 Reserved,
undefined operation. 0011 4-bit data. 0100 5-bit data.
0101 6-bit data. 0110 7-bit data. 0111 8-bit data. 1000 9-
bit data. 1001 10-bit data. 1010 11-bit data. 1011 12-bit
data. 1100 13-bit data. 1101 14-bit data. 1110 15-bit data.
1111 16-bit data.
Description
Control register 1, SSPCR1 on page 3-5
31:4 Reserved. - - -
3 SOD Slave-mode output disable. This bit is relevant only in the RW 0x0
slave mode, MS=1. In multiple-slave systems, it is possible
for an PrimeCell SSP master to broadcast a message to
all slaves in the system while ensuring that only one slave
drives data onto its serial output line. In such systems the
RXD lines from multiple slaves could be tied together. To
operate in such systems, the SOD bit can be set if the
PrimeCell SSP slave is not supposed to drive the SSPTXD
line: 0 SSP can drive the SSPTXD output in slave mode. 1
SSP must not drive the SSPTXD output in slave mode.
2 MS Master or slave mode select. This bit can be modified only RW 0x0
when the PrimeCell SSP is disabled, SSE=0: 0 Device
configured as master, default. 1 Device configured as
slave.
0 LBM Loop back mode: 0 Normal serial port operation enabled. RW 0x0
1 Output of transmit serial shifter is connected to input of
receive serial shifter internally.
Description
Data register, SSPDR on page 3-6
31:16 Reserved. - - -
Description
Status register, SSPSR on page 3-7
31:5 Reserved. - - -
4 BSY PrimeCell SSP busy flag, RO: 0 SSP is idle. 1 SSP is RO 0x0
currently transmitting and/or receiving a frame or the
transmit FIFO is not empty.
3 RFF Receive FIFO full, RO: 0 Receive FIFO is not full. 1 Receive RO 0x0
FIFO is full.
2 RNE Receive FIFO not empty, RO: 0 Receive FIFO is empty. 1 RO 0x0
Receive FIFO is not empty.
1 TNF Transmit FIFO not full, RO: 0 Transmit FIFO is full. 1 RO 0x1
Transmit FIFO is not full.
0 TFE Transmit FIFO empty, RO: 0 Transmit FIFO is not empty. 1 RO 0x1
Transmit FIFO is empty.
Description
Clock prescale register, SSPCPSR on page 3-8
31:8 Reserved. - - -
7:0 CPSDVSR Clock prescale divisor. Must be an even number from 2- RW 0x00
254, depending on the frequency of SSPCLK. The least
significant bit always returns zero on reads.
Description
Interrupt mask set or clear register, SSPIMSC on page 3-9
31:4 Reserved. - - -
3 TXIM Transmit FIFO interrupt mask: 0 Transmit FIFO half empty RW 0x0
or less condition interrupt is masked. 1 Transmit FIFO half
empty or less condition interrupt is not masked.
2 RXIM Receive FIFO interrupt mask: 0 Receive FIFO half full or RW 0x0
less condition interrupt is masked. 1 Receive FIFO half full
or less condition interrupt is not masked.
1 RTIM Receive timeout interrupt mask: 0 Receive FIFO not empty RW 0x0
and no read prior to timeout period interrupt is masked. 1
Receive FIFO not empty and no read prior to timeout
period interrupt is not masked.
Offset: 0x018
Description
Raw interrupt status register, SSPRIS on page 3-10
31:4 Reserved. - - -
3 TXRIS Gives the raw interrupt state, prior to masking, of the RO 0x1
SSPTXINTR interrupt
2 RXRIS Gives the raw interrupt state, prior to masking, of the RO 0x0
SSPRXINTR interrupt
1 RTRIS Gives the raw interrupt state, prior to masking, of the RO 0x0
SSPRTINTR interrupt
0 RORRIS Gives the raw interrupt state, prior to masking, of the RO 0x0
SSPRORINTR interrupt
Description
Masked interrupt status register, SSPMIS on page 3-11
31:4 Reserved. - - -
3 TXMIS Gives the transmit FIFO masked interrupt state, after RO 0x0
masking, of the SSPTXINTR interrupt
2 RXMIS Gives the receive FIFO masked interrupt state, after RO 0x0
masking, of the SSPRXINTR interrupt
1 RTMIS Gives the receive timeout masked interrupt state, after RO 0x0
masking, of the SSPRTINTR interrupt
0 RORMIS Gives the receive over run masked interrupt status, after RO 0x0
masking, of the SSPRORINTR interrupt
Description
Interrupt clear register, SSPICR on page 3-11
31:2 Reserved. - - -
Description
DMA control register, SSPDMACR on page 3-12
31:2 Reserved. - - -
1 TXDMAE Transmit DMA Enable. If this bit is set to 1, DMA for the RW 0x0
transmit FIFO is enabled.
0 RXDMAE Receive DMA Enable. If this bit is set to 1, DMA for the RW 0x0
receive FIFO is enabled.
Description
Peripheral identification registers, SSPPeriphID0-3 on page 3-13
Table 517.
Bits Name Description Type Reset
SSPPERIPHID0
Register
31:8 Reserved. - - -
Description
Peripheral identification registers, SSPPeriphID0-3 on page 3-13
Table 518.
Bits Name Description Type Reset
SSPPERIPHID1
Register
31:8 Reserved. - - -
Description
Peripheral identification registers, SSPPeriphID0-3 on page 3-13
Table 519.
Bits Name Description Type Reset
SSPPERIPHID2
Register
31:8 Reserved. - - -
Description
Peripheral identification registers, SSPPeriphID0-3 on page 3-13
Table 520.
Bits Name Description Type Reset
SSPPERIPHID3
Register
31:8 Reserved. - - -
Description
PrimeCell identification registers, SSPPCellID0-3 on page 3-16
Table 521.
Bits Name Description Type Reset
SSPPCELLID0 Register
31:8 Reserved. - - -
Description
PrimeCell identification registers, SSPPCellID0-3 on page 3-16
Table 522.
Bits Name Description Type Reset
SSPPCELLID1 Register
31:8 Reserved. - - -
Description
PrimeCell identification registers, SSPPCellID0-3 on page 3-16
Table 523.
Bits Name Description Type Reset
SSPPCELLID2 Register
31:8 Reserved. - - -
Description
PrimeCell identification registers, SSPPCellID0-3 on page 3-16
Table 524.
Bits Name Description Type Reset
SSPPCELLID3 Register
31:8 Reserved. - - -
4.5. PWM
4.5.1. Overview
Pulse width modulation (PWM) is a scheme where a digital signal provides a smoothly varying average voltage. This is
achieved with positive pulses of some controlled width, at regular intervals. The fraction of time spent high is known as
the duty cycle. This may be used to approximate an analog output, or control switchmode power electronics.
The RP2040 PWM block has 8 identical slices. Each slice can drive two PWM output signals, or measure the frequency
or duty cycle of an input signal. This gives a total of up to 16 controllable PWM outputs. All 30 GPIO pins can be driven
by the PWM block.
• The 16 PWM channels (8 2-channel slices) appear on GPIO0 to GPIO15, in the order PWM0 A, PWM0 B, PWM1 A…
• This repeats for GPIO16 to GPIO29. GPIO16 is PWM0 A, GPIO17 is PWM0 B, so on up to PWM6 B on GPIO29
• The same PWM output can be selected on two GPIO pins; the same signal will appear on each GPIO.
• If a PWM B pin is used as an input, and is selected on multiple GPIO pins, then the PWM slice will see the logical
OR of those two GPIO inputs
The PWM hardware functions by continuously comparing the input value to a free-running counter. This produces a
toggling output where the amount of time spent at the high output level is proportional to the input value. The fraction of
time spent at the high signal level is known as the duty cycle of the signal.
The counting period is controlled by the TOP register, with a maximum possible period of 65536 cycles, as the counter
and TOP are 16 bits in size. The input values are configured via the CC register.
Figure 105 shows how the PWM hardware operates once it has been configured in this way.
from 0 to 3, which is
A
configured as the TOP
B
value. The output
waves therefore have
a period of 4. Output A
is high for 1 cycle in 4,
The default behaviour of a PWM slice is to count upward until the value of the TOP register is reached, and then
so the average output immediately wrap to 0. PWM slices also offer a phase-correct mode, enabled by setting CSR_PH_CORRECT to 1, where the
voltage is 1/4 of the
counter starts to count downward after reaching TOP, until it reaches 0 again.
IO supply voltage.
Output B is high for 3 It is called phase-correct mode because the pulse is always centred on the same point, no matter the duty cycle. In
cycles in every 4. Note
the rising edges of A
other words, its phase is not a function of duty cycle. The output frequency is halved when phase-correct mode is
and B are always enabled.
aligned.
Input (Count)
Figure 106. In phase- Count
correct mode, the TOP
counter counts back Counter compare level
Counter
down from TOP to 0
once it reaches TOP.
TOP/3
0 t
T 2T 3T
Output (Pulse)
V
IOVDD
GPIO pulse output
0 t
T 2T 3T
The RP2040 PWM can produce toggle-free 0% and 100% duty cycle output.
0 t
T 2T 3T
Output (Pulse)
V
IOVDD
GPIO pulse output
0 t
T 2T 3T
A CC value of 0 will produce a 0% output, i.e. the output signal is always low. A CC value of TOP + 1 (i.e. equal to the period,
in non-phase-correct mode) will produce a 100% output. For example, if TOP is programmed to 254, the counter will have
a period of 255 cycles, and CC values in the range of 0 to 255 inclusive will produce duty cycles in the range 0% to 100%
inclusive.
Glitch-free output at 0% and 100% is important e.g. to avoid switching losses when a MOSFET is controlled at its
minimum and maximum current levels.
Figure 108 shows how a change in input value will produce a change in output duty cycle. This can be used to
approximate some analog waveform such as a sine wave.
IOVDD
GPIO pulse output
0 t
T/3 T 5T/3 2T 3T
In Figure 108, the input value only changes at the instant where the counter wraps through 0. Figure 109 shows what
happens if the input value is allowed to change at any other time: an unwanted glitch is produced at the output.
0 t
T 2T 3T
Output (Pulse)
V
IOVDD
GPIO pulse output
0 t
T/3 T 5T/3 2T 3T
The behaviour becomes even more perplexing if the TOP register is also modified. It would be difficult for software to
write to CC or TOP with the correct timing. To solve this, each slice has two copies of the CC and TOP registers: one copy
which software can modify, and another, internal copy which is updated from the first register at the instant the counter
wraps. Software can modify its copy of the register at will, but the changes are not captured by the PWM output until the
next wrap.
Figure 110 shows the sequence of events where a software interrupt handler changes the value of CC_A each time the
counter wraps.
By allowing the slice to run for a fixed amount of time in level-sensitive or edge-sensitive mode, it’s possible to measure
the duty cycle or frequency of an input signal. Due to the type of edge-detect circuit used, the low period and high period
of the measured signal must both be strictly greater than the system clock period when taking frequency
measurements.
The clock divider is still operational in level-sensitive and edge-sensitive mode. At maximum division (writing 0 to
DIV_INT), the counter will only advance once per 256 high input cycles in level-sensitive modes, or once per 256 edges in
edge-sensitive mode. This allows longer-running measurements to be taken, although the resolution is still just 16 bits.
When free-running, the period of a PWM slice’s output (measured in system clock cycles) is controlled by three
parameters:
minimum speed of one count per cycles. The period in clock cycles can be calculated as:
The output frequency can then be determined based on the system clock frequency:
The PWM block has a single IRQ output. The interrupt status registers INTR, INTS and INTE allow software to control which
slices will assert this IRQ output, to check which slices are the cause of the IRQ’s assertion, and to clear and
acknowledge the interrupt.
A slice generates an interrupt request each time its counter wraps (or, if CSR_PH_CORRECT is enabled, each time the counter
returns to 0). This sets the flag corresponding to this slice in the raw interrupt status register, INTR. If this slice’s interrupt
is enabled in INTE, then this flag will cause the PWM block’s IRQ to be asserted, and the flag will also appear in the
masked interrupt status register INTS.
Flags are cleared by writing a mask back to INTR. This is demonstrated in the "LED fade" SDK example.
This scheme allows multiple slices to generate interrupts concurrently, and a system interrupt handler to determine
which slices caused the most recent interruption, and handle appropriately. Normally this would mean reloading those
slices' TOP or CC registers, but the PWM block can also be used as a source of regular interrupt requests for non-PWM-
related purposes.
The same pulse which sets the interrupt flag in INTR is also available as a one-cycle data request to the RP2040 system
DMA. For each cycle the DMA sees a DREQ asserted, it will make one data transfer to its programmed location, in as
timely a manner as possible. In combination with the double-buffered behaviour of CC and TOP, this allows the DMA to
efficiently stream data to a PWM slice at a rate of one transfer per counter period. Alternatively, a PWM slice could
serve as a pacing timer for DMA transfers to some other memory-mapped hardware.
For some applications it is necessary to control the phase relationship between two PWM outputs on different slices.
The global enable register EN contains an alias of the CSR_EN flag for each slice, and allows multiple slices to be started
and stopped simultaneously. If two slices with the same output frequency are started at the same time, they will run in
perfect lockstep, and have a fixed phase relationship, determined by the initial counter values.
The CSR_PH_ADV and CSR_PH_RET fields will advance or retard a slice’s output phase by one count, whilst it is running. They
do so by inserting or deleting pulses from the clock enable (the output of the clock divider), as shown in Figure 113.
DIV_INT 2
CSR_PH_ADV
Clock enable
Count 0 1 2 3 4
The counter can not count faster than once per cycle, so PH_ADV requires DIV_INT > 1 or DIV_FRAC > 0. Likewise, the counter
will not start to count backward if PH_RET is asserted when the clock enable is permanently low.
To advance or retard the phase by one count, software writes 1 to PH_ADV or PH_RET. Once an enable pulse has been
inserted or deleted, the PH_ADV or PH_RET register bit will return to 0, and software can poll the CSR until this happens. PH_ADV
will always insert a pulse into the next available gap, and PH_RET will always delete the next available pulse.
0xa0 EN This register aliases the CSR_EN bits for all channels.
Writing to this register allows multiple channels to be enabled
or disabled simultaneously, so they can run in perfect sync.
For each channel, there is only one physical EN register bit,
which can be accessed through here or CHx_CSR.
Description
Control and status register
Description
INT and FRAC form a fixed-point fractional number.
Counting rate is system clock frequency divided by this number.
Fractional division uses simple 1st-order sigma-delta.
Description
Counter compare values
15:0 A RW 0x0000
PWM: EN Register
Offset: 0xa0
Description
This register aliases the CSR_EN bits for all channels.
Writing to this register allows multiple channels to be enabled
or disabled simultaneously, so they can run in perfect sync.
For each channel, there is only one physical EN register bit,
which can be accessed through here or CHx_CSR.
31:8 Reserved. - - -
7 CH7 RW 0x0
6 CH6 RW 0x0
5 CH5 RW 0x0
4 CH4 RW 0x0
3 CH3 RW 0x0
2 CH2 RW 0x0
1 CH1 RW 0x0
0 CH0 RW 0x0
Description
Raw Interrupts
31:8 Reserved. - - -
7 CH7 WC 0x0
6 CH6 WC 0x0
5 CH5 WC 0x0
4 CH4 WC 0x0
3 CH3 WC 0x0
2 CH2 WC 0x0
1 CH1 WC 0x0
0 CH0 WC 0x0
Description
Interrupt Enable
31:8 Reserved. - - -
7 CH7 RW 0x0
6 CH6 RW 0x0
5 CH5 RW 0x0
4 CH4 RW 0x0
3 CH3 RW 0x0
2 CH2 RW 0x0
1 CH1 RW 0x0
0 CH0 RW 0x0
Description
Interrupt Force
31:8 Reserved. - - -
7 CH7 RW 0x0
6 CH6 RW 0x0
5 CH5 RW 0x0
4 CH4 RW 0x0
3 CH3 RW 0x0
2 CH2 RW 0x0
1 CH1 RW 0x0
0 CH0 RW 0x0
Description
Interrupt status after masking & forcing
31:8 Reserved. - - -
7 CH7 RO 0x0
6 CH6 RO 0x0
5 CH5 RO 0x0
4 CH4 RO 0x0
3 CH3 RO 0x0
2 CH2 RO 0x0
1 CH1 RO 0x0
0 CH0 RO 0x0
4.6. Timer
4.6.1. Overview
The system timer peripheral on RP2040 provides a global microsecond timebase for the system, and generates
interrupts based on this timebase. It supports the following features:
the reference clock (Figure 28), which itself is usually connected directly to the crystal oscillator (Section 2.16).
The 64-bit counter effectively can not overflow (thousands of years at 1 MHz), so the system timer is completely
monotonic in practice.
The system timer is intended to provide a global timebase for software. RP2040 has a number of other programmable
counter resources which can provide regular interrupts, or trigger DMA transfers.
• The PWM (Section 4.5) contains 8× 16-bit programmable counters, which run at up to system speed, can generate
interrupts, and can be continuously reprogrammed via the DMA, or trigger DMA transfers to other peripherals.
• 8× PIO state machines (Chapter 3) can count 32-bit values at system speed, and generate interrupts.
• The DMA (Section 2.5) has four internal pacing timers, which trigger transfers at regular intervals.
• Each Cortex-M0+ core (Section 2.4) has a standard 24-bit SysTick timer, counting either the microsecond tick
(Section 4.7.2) or the system clock.
4.6.2. Counter
The timer has a 64-bit counter, but RP2040 only has a 32-bit data bus. This means that the TIME value is accessed
through a pair of registers. These are:
CAUTION
While it is technically possible to force a new time value by writing to the TIMEHW and TIMELW registers,
programmers are discouraged from doing this. This is because the timer value is expected to be monotonically
increasing by the SDK which uses it for timeouts, elapsed time etc.
4.6.3. Alarms
The timer has 4 alarms, and outputs a separate interrupt for each alarm. The alarms match on the lower 32 bits of the
64-bit counter which means they can be fired at a maximum of 232 microseconds into the future. This is equivalent to:
• 2 ÷ 10 : ~4295 seconds
32 6
This timer is expected to be used for short sleeps. If you want a longer alarm see Section 4.8.
To enable an alarm:
• Enable the interrupt at the timer with a write to the appropriate alarm bit in INTE: i.e. (1 << 0) for ALARM0
• Enable the appropriate timer interrupt at the processor (see Section 2.3.2)
• Write the time you would like the interrupt to fire to ALARM0 (i.e. the current value in TIMERAWL plus your desired
alarm time in microseconds). Writing the time to the ALARM register sets the ARMED bit as a side effect.
Once the alarm has fired, the ARMED bit will be set to 0. To clear the latched interrupt, write a 1 to the appropriate bit in
INTR.
NOTE
The Watchdog tick (see Section 4.7.2) must be running for the timer to start counting. The SDK starts this tick as
part of the platform initialisation code.
NOTE
Time here refers to the number of microseconds since the timer was started, it is not a clock. For that - see Section
4.8.
The simplest form of reading the 64-bit time is to read TIMELR followed by TIMEHR. However, because RP2040 has 2
cores, it is unsafe to do this if the second core is executing code that can also access the timer, or if the timer is read
concurrently in an IRQ handler and in thread mode. This is because reading TIMELR latches the value in TIMEHR (i.e.
stops it updating) until TIMEHR is read. If one core reads TIMELR followed by another core reading TIMELR, the value in
TIMEHR isn’t necessarily accurate. The example below shows the simplest form of getting the 64-bit time.
The SDK provides a time_us_64 function that uses a more thorough method to get the 64-bit time, which makes use of
the TIMERAWH and TIMERAWL registers. The RAW registers don’t latch, and therefore make time_us_64 safe to call from
multiple cores at once.
32 uint64_t time_us_64() {
33 // Need to make sure that the upper 32 bits of the timer
34 // don't change, so read that first
35 uint32_t hi = timer_hw->timerawh;
36 uint32_t lo;
37 do {
38 // Read the lower 32 bits
39 lo = timer_hw->timerawl;
40 // Now read the upper 32 bits again and
41 // check that it hasn't incremented. If it has loop around
42 // and read the lower 32 bits again to get an accurate value
43 uint32_t next_hi = timer_hw->timerawh;
44 if (hi == next_hi) break;
45 hi = next_hi;
46 } while (true);
47 return ((uint64_t) hi << 32u) | lo;
48 }
The standalone timer example, timer_lowlevel, demonstrates how to set an alarm at a hardware level, without the
additional abstraction over the timer that the SDK provides. To use these abstractions see Section 4.6.4.4.
25 // Use alarm 0
26 #define ALARM_NUM 0
27 #define ALARM_IRQ TIMER_IRQ_0
28
29 // Alarm interrupt handler
30 static volatile bool alarm_fired;
31
32 static void alarm_irq(void) {
33 // Clear the alarm irq
34 hw_clear_bits(&timer_hw->intr, 1u << ALARM_NUM);
35
36 // Assume alarm 0 has fired
37 printf("Alarm IRQ fired\n");
38 alarm_fired = true;
39 }
40
41 static void alarm_in_us(uint32_t delay_us) {
42 // Enable the interrupt for our alarm (the timer outputs 4 alarm irqs)
43 hw_set_bits(&timer_hw->inte, 1u << ALARM_NUM);
44 // Set irq handler for alarm irq
45 irq_set_exclusive_handler(ALARM_IRQ, alarm_irq);
46 // Enable the alarm irq
47 irq_set_enabled(ALARM_IRQ, true);
48 // Enable interrupt in block and at processor
49
50 // Alarm is only 32 bits so if trying to delay more
51 // than that need to be careful and keep track of the upper
52 // bits
53 uint64_t target = timer_hw->timerawl + delay_us;
54
55 // Write the lower 32 bits of the target time to the alarm which
56 // will arm it
57 timer_hw->alarm[ALARM_NUM] = (uint32_t) target;
58 }
59
60 int main() {
61 stdio_init_all();
62 printf("Timer lowlevel!\n");
63
64 // Set alarm every 2 seconds
65 while (1) {
66 alarm_fired = false;
67 alarm_in_us(1000000 * 2);
68 // Wait for alarm to fire
69 while (!alarm_fired);
70 }
71 }
If you don’t want to use an alarm to wait for a period of time, instead use a while loop. The SDK provides various
busy_wait_ functions to do this:
0x10 ALARM0 Arm alarm 0, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM0 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x14 ALARM1 Arm alarm 1, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM1 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x18 ALARM2 Arm alarm 2, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM2 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x1c ALARM3 Arm alarm 3, and configure the time it will fire.
Once armed, the alarm fires when TIMER_ALARM3 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
0x24 TIMERAWH Raw read from bits 63:32 of time (no side effects)
0x28 TIMERAWL Raw read from bits 31:0 of time (no side effects)
0x2c DBGPAUSE Set bits high to enable pause when the corresponding debug
ports are active
31:0 Arm alarm 0, and configure the time it will fire. RW 0x00000000
Once armed, the alarm fires when TIMER_ALARM0 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
31:0 Arm alarm 1, and configure the time it will fire. RW 0x00000000
Once armed, the alarm fires when TIMER_ALARM1 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
31:0 Arm alarm 2, and configure the time it will fire. RW 0x00000000
Once armed, the alarm fires when TIMER_ALARM2 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
31:0 Arm alarm 3, and configure the time it will fire. RW 0x00000000
Once armed, the alarm fires when TIMER_ALARM3 == TIMELR.
The alarm will disarm itself once it fires, and can
be disarmed early using the ARMED status register.
31:4 Reserved. - -
31:0 Raw read from bits 63:32 of time (no side effects) RO 0x00000000
31:0 Raw read from bits 31:0 of time (no side effects) RO 0x00000000
Description
Set bits high to enable pause when the corresponding debug ports are active
31:3 Reserved. - - -
0 Reserved. - - -
31:1 Reserved. - -
Description
Raw Interrupts
31:4 Reserved. - - -
3 ALARM_3 WC 0x0
2 ALARM_2 WC 0x0
1 ALARM_1 WC 0x0
0 ALARM_0 WC 0x0
Description
Interrupt Enable
31:4 Reserved. - - -
3 ALARM_3 RW 0x0
2 ALARM_2 RW 0x0
1 ALARM_1 RW 0x0
0 ALARM_0 RW 0x0
Description
Interrupt Force
31:4 Reserved. - - -
3 ALARM_3 RW 0x0
2 ALARM_2 RW 0x0
1 ALARM_1 RW 0x0
0 ALARM_0 RW 0x0
Description
Interrupt status after masking & forcing
31:4 Reserved. - - -
3 ALARM_3 RO 0x0
2 ALARM_2 RO 0x0
1 ALARM_1 RO 0x0
0 ALARM_0 RO 0x0
4.7. Watchdog
4.7.1. Overview
The watchdog is a countdown timer that can restart parts of the chip if it reaches zero. This can be used to restart the
processor if software gets stuck in an infinite loop. The programmer must periodically write a value to the watchdog to
stop it from reaching zero.
The watchdog is reset by rst_n_run, which is deasserted as soon as the digital core supply (DVDD) is powered and
stable, and the RUN pin is high. This allows the watchdog reset to feed into the power-on state machine (see Section
2.13) and reset controller (see Section 2.14), resetting their dependants if they are selected in the WDSEL register. The
WDSEL register exists in both the power-on state machine and reset controller.
NOTE
To avoid duplicating logic, this tick is also distributed to the timer (see Section 4.6) and used as the timer reference.
WARNING
Due to a logic error, the watchdog counter is decremented twice per tick. Which means the programmer needs to
program double the intended count down value. The SDK examples take this issue into account. See RP2040-E1 for
more information.
The bootrom checks the watchdog scratch registers for a magic number on boot. This can be used to soft reset the
chip into some user specified code. See Section 2.8.1.1 for more information.
4.7.5.3. Usage
The Pico Examples repository provides a hello_watchdog example that uses the hardware_watchdog to demonstrate
use of the watchdog.
11 int main() {
12 stdio_init_all();
13
14 if (watchdog_caused_reboot()) {
15 printf("Rebooted by Watchdog!\n");
16 return 0;
17 } else {
18 printf("Clean boot\n");
19 }
20
21 // Enable the watchdog, requiring the watchdog to be updated every 100ms or the chip will
reboot
22 // second arg is pause on debug which means the watchdog will pause when stepping through
code
23 watchdog_enable(100, 1);
24
25 for (uint i = 0; i < 5; i++) {
26 printf("Updating watchdog %d\n", i);
27 watchdog_update();
28 }
29
30 // Wait in an infinite loop and don't update the watchdog so it reboots us
31 printf("Waiting to be rebooted by watchdog\n");
32 while(1);
33 }
Description
Watchdog control
The rst_wdsel register determines which subsystems are reset when the watchdog is triggered.
The watchdog can be triggered in software.
29:27 Reserved. - - -
24 PAUSE_JTAG Pause the watchdog timer when JTAG is accessing the RW 0x1
bus fabric
23:0 TIME Indicates the number of ticks / 2 (see errata RP2040-E1) RO 0x000000
before a watchdog reset will be triggered
31:24 Reserved. - -
23:0 Load the watchdog timer. The maximum setting is 0xffffff which corresponds WF 0x000000
to 0xffffff / 2 ticks before triggering a watchdog reset (see errata RP2040-E1).
Description
Logs the reason for the last reset. Both bits are zero for the case of a hardware reset.
31:2 Reserved. - - -
1 FORCE RO 0x0
0 TIMER RO 0x0
Description
Controls the tick generator
31:20 Reserved. - - -
19:11 COUNT Count down timer: the remaining number clk_tick cycles RO -
before the next tick is generated.
8:0 CYCLES Total number of clk_tick cycles before the next tick. RW 0x000
4.8. RTC
The Real-time Clock (RTC) provides time in human-readable format and can be used to generate interrupts at specific
times.
The RTC does not check that the programmed values are in range. Illegal values may cause unexpected behaviour.
Day of the week is encoded as Sun 0, Mon 1, …, Sat 6 (i.e. ISO8601 mod 7).
There is no built-in calendar function. The RTC will not compute the correct day of the week; it will only increment the
existing value.
NOTE
The leap year check is done only when needed (the second following Feb 28, 23:59:59). The software can set
FORCE_NOTLEAPYEAR anytime after 2096 Mar 1 00:00:00 as long as it arrives before 2100 Feb 28 23:59:59 (i.e. taking
into account the clock domain crossing latency)
4.8.3. Interrupts
The RTC can generate an interrupt at a configured time. There is a global bit, MATCH_ENA in IRQ_SETUP_0 to enable this
feature, and individual enables for each time field (year, month, day, day-of-the-week, hour, minute, second). The
individual enables can be used to implement repeating interrupts at specified times.
The alarm interrupt is sent to the processors and also to the ROSC and XOSC to wake them from dormant mode. See
Section 4.8.5.5 for more information on dormant mode.
The internal 1Hz reference is created by an internal clock divider which divides clk_rtc by an integer value. The divide
value minus 1 is set in CLKDIV_M1.
WARNING
While it is possible to change CLKDIV_M1 while the RTC is enabled, it is not recommended.
clk_rtc can be driven either from an internal or external clock source. Those sources can be prescaled, using a
fractional divider (see Section 2.15).
• XOSC @ 12MHz / 256 = 46875Hz. To get a 1Hz reference CLKDIV_M1 should be set to 46874.
• An external reference from a GPS, which generates one pulse per second. Configure clk_rtc to run from the GPIN0
clock source from GPIO pin 20. In this case, the clk_rtc divider is 1 and the internal RTC clock divider is also 1 (i.e.
CLKDIV_M1 = 0).
NOTE
All RTC register reads and writes are done from the processor clock domain clk_sys. All data are synchronised back
and forth between the domains. Writing to the RTC will take 2 clk_rtc clock periods to arrive, additional to the clk_sys
domain. This should be taken into account especially when the reference is slow (e.g. 1 Hz).
Select the source for clk_rtc. This is done outside the RTC registers (see Section 4.8.4).
22 void rtc_init(void) {
23 // Get clk_rtc freq and make sure it is running
24 uint rtc_freq = clock_get_hz(clk_rtc);
25 assert(rtc_freq != 0);
26
27 // Take rtc out of reset now that we know clk_rtc is running
28 reset_block(RESETS_RESET_RTC_BITS);
29 unreset_block_wait(RESETS_RESET_RTC_BITS);
30
31 // Set up the 1 second divider.
32 // If rtc_freq is 400 then clkdiv_m1 should be 399
33 rtc_freq -= 1;
34
35 // Check the freq is not too big to divide
36 assert(rtc_freq <= RTC_CLKDIV_M1_BITS);
37
38 // Write divide value
39 rtc_hw->clkdiv_m1 = rtc_freq;
40 }
84
85 return true;
86 }
NOTE
It is possible to change the current time while the RTC is running. Write the desired values, then set the LOAD bit in
the CTRL register.
The RTC time is stored across two 32-bit registers. To ensure a consistent value, RTC_0 should be read before RTC_1.
Reading RTC_0 latches the value of RTC_1.
RTC_IRQ_SETUP_1_SEC_LSB ));
155
156 // Set the match enable bits for things we care about
157 if (t->year >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_YEAR_ENA_BITS);
158 if (t->month >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_MONTH_ENA_BITS);
159 if (t->day >= 0) hw_set_bits(&rtc_hw->irq_setup_0, RTC_IRQ_SETUP_0_DAY_ENA_BITS);
160 if (t->dotw >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_DOTW_ENA_BITS);
161 if (t->hour >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_HOUR_ENA_BITS);
162 if (t->min >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_MIN_ENA_BITS);
163 if (t->sec >= 0) hw_set_bits(&rtc_hw->irq_setup_1, RTC_IRQ_SETUP_1_SEC_ENA_BITS);
164
165 // Does it repeat? I.e. do we not match on any of the bits
166 _alarm_repeats = rtc_alarm_repeats(t);
167
168 // Store function pointer we can call later
169 _callback = user_callback;
170
171 irq_set_exclusive_handler(RTC_IRQ, rtc_irq_handler);
172
173 // Enable the IRQ at the peri
174 rtc_hw->inte = RTC_INTE_RTC_BITS;
175
176 // Enable the IRQ at the proc
177 irq_set_enabled(RTC_IRQ, true);
178
179 rtc_enable_alarm();
180 }
NOTE
Recurring alarms can be created by using fewer enable bits when setting up the alarm interrupt. For example, if you
only matched on seconds and the second was configured as 54 then the alarm interrupt would fire once a minute
when the second was 54.
• Sleep mode, where the processors are asleep and the unused clocks in the chip are stopped (see Section 2.15.3.5)
• Dormant mode, where all clocks in the chip are stopped
The RTC can wake the chip up from both of these modes. In sleep mode, RP2040 can be configured such that only
clk_rtc (a slow RTC reference clock) is running, as well as a small amount of logic that allows the processor to wake
back up. The processor is woken from sleep mode when the RTC alarm interrupt fires. See Section 2.11.5.1 for more
information.
• the RTC must be configured to use an external reference clock (supplied by a GPIO pin)
• Set up the RTC to run on an external reference
• If the processor is running off the PLL, change it to run from XOSC/ROSC
• Turn off the PLLs
• Set up the RTC with the desired wake up time (one off, or recurring)
• (optionally) power down most memories
• Invoke DORMANT mode (see Section 2.16, Section 2.17, and Section 2.11.5.2 for more information)
0x00 CLKDIV_M1 Divider minus 1 for the 1 second counter. Safe to change the
value when RTC is not enabled.
31:16 Reserved. - -
15:0 Divider minus 1 for the 1 second counter. Safe to change the value when RTC RW 0x0000
is not enabled.
Description
RTC setup register 0
31:24 Reserved. - - -
7:5 Reserved. - - -
Description
RTC setup register 1
31:27 Reserved. - - -
26:24 DOTW Day of the week: 1-Monday…0-Sunday ISO 8601 mod 7 RW 0x0
23:21 Reserved. - - -
15:14 Reserved. - - -
7:6 Reserved. - - -
Description
RTC Control and status
31:9 Reserved. - - -
7:5 Reserved. - - -
3:2 Reserved. - - -
Description
Interrupt setup register 0
Table 567.
Bits Name Description Type Reset
IRQ_SETUP_0 Register
31:30 Reserved. - - -
29 MATCH_ACTIVE RO -
28 MATCH_ENA Global match enable. Don’t change any other value while RW 0x0
this one is enabled
27 Reserved. - - -
7:5 Reserved. - - -
Description
Interrupt setup register 1
Table 568.
Bits Name Description Type Reset
IRQ_SETUP_1 Register
27 Reserved. - - -
23:21 Reserved. - - -
15:14 Reserved. - - -
7:6 Reserved. - - -
Description
RTC register 1.
31:24 Reserved. - - -
7:5 Reserved. - - -
Description
RTC register 0
Read this before RTC 1!
31:27 Reserved. - - -
23:21 Reserved. - - -
15:14 Reserved. - - -
7:6 Reserved. - - -
Description
Raw Interrupts
31:1 Reserved. - - -
0 RTC RO 0x0
Description
Interrupt Enable
31:1 Reserved. - - -
0 RTC RW 0x0
Description
Interrupt Force
31:1 Reserved. - - -
0 RTC RW 0x0
Description
Interrupt status after masking & forcing
31:1 Reserved. - - -
0 RTC RO 0x0
4.9.1. Features
RP2040 has an internal analogue-digital converter (ADC) with the following features:
• SAR ADC
• 500 kS/s (Using an independent 48MHz clock)
• 12-bit (9 ENOB)
• Five input mux:
◦ Four inputs that are available on package pins shared with GPIO[29:26]
◦ One input is dedicated to the internal temperature sensor
• Four element receive sample FIFO
• Interrupt generation
• DMA interface
NOTE
When using an ADC input shared with a GPIO pin, the pin’s digital functions must be disabled by setting IE low and OD
high in the pin’s pad control register. See Section 2.19.6.3, “Pad Control - User Bank” for details. The maximum ADC
input voltage is determined by the digital IO supply voltage (IOVDD), not the ADC supply voltage (ADC_AVDD). For
example, if IOVDD is powered at 1.8V, the voltage on the ADC inputs should not exceed 1.8V even if ADC_AVDD is
powered at 3.3V. Voltages greater than IOVDD will result in leakage currents through the ESD protection diodes. See
Section 5.2.3, “Pin Specifications” for details.
The ADC requires a 48MHz clock ( clk_adc ), which could come from the USB PLL. Capturing a sample takes 96 clock
cycles (96 x 1 / 48MHz) = 2 μs per sample (500kS/s). The clock must be set up correctly before enabling the ADC.
Once the ADC block is provided with a clock, and its reset has been removed, writing a 1 to CS.EN will start a short
internal power-up sequence for the ADC’s analogue hardware. After a few clock cycles, CS.READY will go high,
indicating the ADC is ready to start its first conversion.
The ADC can be disabled again at any time by clearing CS.EN, to save power. CS.EN does not enable the temperature
sensor bias source (see Section 4.9.4). This is controlled separately.
The ADC input is capacitive, and when sampling, it places about 1pF across the input (there will be additional
capacitance from outside the ADC, such as packaging and PCB routing, to add to this). The effective impedance, even
when sampling at 500kS/s, is over 100kΩ, and for dc measurements there should be no need to buffer.
Writing a 1 to CS.START_ONCE will immediately start a new conversion. CS.READY will go low, to show that a
conversion is currently in progress. After 96 cycles of clk_adc, CS.READY will go high. The 12-bit conversion result is
available in RESULT.
The ADC input to be sampled is selected by writing to CS.AINSEL, any time before the conversion starts. An AINSEL
value of 0…3 selects the ADC input on GPIO 26…29. AINSEL of 4 selects the internal temperature sensor.
NOTE
When CS.START_MANY is set,the ADC will automatically start new conversions at regular intervals. The most recent
conversion result is always available in RESULT, but for IRQ or DMA driven streaming of samples, the ADC FIFO must be
enabled (Section 4.9.3.4).
By default (DIV = 0), new conversions start immediately upon the previous conversion finishing, so a new sample is
produced every 96 cycles. At a clock frequency of 48 MHz, this produces 500 kS/s.
Setting DIV.INT to some positive value n will trigger the ADC once per n + 1 cycles, though the ADC ignores this if a
conversion is currently in progress, so generally n will be >= 96. For example, setting DIV.INT to 47999 will run the ADC
at 1 kS/s, if running from a 48 MHz clock.
The pacing timer supports fractional-rate division (first order delta sigma). When setting DIV.FRAC to a nonzero value,
the ADC will start a new conversion once per cycles on average, by changing the sample interval
between and .
CS.RROBIN allows the ADC to sample multiple inputs, in an interleaved fashion, while performing free-running sampling.
Each bit in RROBIN corresponds to one of the five possible values of CS.AINSEL. When the ADC completes a
conversion, CS.AINSEL will automatically cycle to the next input whose corresponding bit is set in RROBIN.
For example, if AINSEL is initially 0, and RROBIN is set to 0x06 (bits 1 and 2 are set), the ADC will sample channels in the
following order:
1. Channel 0
2. Channel 1
3. Channel 2
4. Channel 1
5. Channel 2
6. Channel 1…
NOTE
The initial value of AINSEL does not need to correspond with a set bit in RROBIN.
The ADC samples can be read directly from the RESULT register, or stored in a local 4-entry FIFO and read out from
FIFO. FIFO operation is controlled by the FCS register.
If FCS.EN is set, the result of each ADC conversion is written to the FIFO. A software interrupt handler or the RP2040
DMA can read this sample from the FIFO when notified by the ADC’s IRQ or DREQ signals. Alternatively, software can
poll the status bits in FCS to wait for each sample to become available.
If the FIFO is full when a conversion completes, the sticky error flag FCS.OVER is set. The current FIFO contents is not
changed by this event, but any conversion that completes whilst the FIFO is full will be lost.
There are two flags that control the data written to the FIFO by the ADC:
• FCS.SHIFT will right-shift the FIFO data to eight bits in size (i.e. FIFO bits 7:0 are conversion result bits 11:4). This
is suitable for 8-bit DMA transfer to a byte buffer in memory, allowing deeper capture buffers, at the cost of some
precision.
• FCS.ERR will set a flag at bit 12 of each FIFO entry, showing that a conversion error took place, i.e. the SAR failed to
converge (see below)
CAUTION
Conversion errors produce undefined results, and the corresponding sample should be discarded. They indicate that
the comparison of one or more bits failed to complete in the time allowed. Normally this is caused by comparator
metastability, i.e. the closer to the comparator threshold the input signal is, the longer it will take to make a decision.
The high gain of the comparator reduces the probability that no decision is made.
4.9.3.5. DMA
The RP2040 DMA (Section 2.5) can fetch ADC samples from the sample FIFO, by performing a normal memory-mapped
read on the FIFO register, paced by the ADC_DREQ system data request signal. The following must be considered:
• The sample FIFO must be enabled (FCS.EN) so that samples are written to it; the FIFO is disabled by default so
that it does not inadvertently fill when the ADC is used for one-shot conversions.
• The ADC’s data request handshake (DREQ) must be enabled, via FCS.DREQ_EN.
• The DMA channel used for the transfer must select the DREQ_ADC data request signal (Section 2.5.3.1).
• The threshold for DREQ assertion (FCS.THRESH) should be set to 1, so that the DMA transfers as soon as a single
sample is present in the FIFO. Note this is also the threshold used for IRQ assertion, so non-DMA use cases might
prefer a higher value for less frequent interrupts.
• If the DMA transfer size is set to 8 bits, so that the DMA transfers to a byte array in memory, FCS.SHIFT must also
be set, to pre-shift the FIFO samples to 8 bits of significance.
• If multiple input channels are to be sampled, CS.RROBIN contains a 5-bit mask of those channels (4 external inputs
plus temperature sensor). Additionally CS.AINSEL must select the channel for the first sample.
• The ADC sample rate (Section 4.9.3.2) should be configured before starting the ADC.
Once the ADC is suitably configured, the DMA channel should be started first, and the ADC conversion should be started
second, via CS.START_MANY. Once the DMA completes, the ADC can be halted, or a new DMA transfer promptly
started. After clearing CS.START_MANY to halt the ADC, software should also poll CS.READY to make sure the last
conversion has finished, and then drain any stray samples from the FIFO.
4.9.3.6. Interrupts
An interrupt can be generated when the FIFO level reaches a configurable threshold FCS.THRESH. The interrupt output
must be enabled via INTE.
Status can be read from INTS. The interrupt is cleared by draining the FIFO to a level lower than FCS.THRESH.
4.9.3.7. Supply
The ADC supply is separated out on its own pin to allow noise filtering.
T = 27 - (ADC_voltage - 0.706)/0.001721
As the Vbe and the Vbe slope can vary over the temperature range, and from device to device, some user calibration
may be required if accurate measurements are required.
The temperature sensor’s bias source must be enabled before use, via CS.TS_EN. This increases current consumption
on ADC_AVDD by approximately 40 μA.
ADC: CS Register
Offset: 0x00
Description
ADC Control and Status
31:21 Reserved. - - -
20:16 RROBIN Round-robin sampling. 1 bit per channel. Set all bits to 0 to RW 0x00
disable.
Otherwise, the ADC will cycle through each enabled
channel in a round-robin fashion.
The first channel to be sampled will be the one currently
indicated by AINSEL.
AINSEL will be updated after each conversion with the
newly-selected channel.
15 Reserved. - - -
14:12 AINSEL Select analog mux input. Updated automatically in round- RW 0x0
robin mode.
11 Reserved. - - -
7:4 Reserved. - - -
31:12 Reserved. - -
Description
FIFO control and status
31:28 Reserved. - - -
23:20 Reserved. - - -
19:16 LEVEL The number of conversion results currently waiting in the RO 0x0
FIFO
15:12 Reserved. - - -
9 FULL RO 0x0
8 EMPTY RO 0x0
7:4 Reserved. - - -
2 ERR If 1: conversion error bit appears in the FIFO alongside the RW 0x0
result
Description
Conversion result FIFO
31:16 Reserved. - - -
14:12 Reserved. - - -
11:0 VAL RF -
Description
Clock divider. If non-zero, CS_START_MANY will start conversions
at regular intervals rather than back-to-back.
The divider is reset when either of these fields are written.
Total period is 1 + INT + FRAC / 256
31:24 Reserved. - - -
Description
Raw Interrupts
31:1 Reserved. - - -
0 FIFO Triggered when the sample FIFO reaches a certain level. RO 0x0
This level can be programmed via the FCS_THRESH field.
Description
Interrupt Enable
31:1 Reserved. - - -
0 FIFO Triggered when the sample FIFO reaches a certain level. RW 0x0
This level can be programmed via the FCS_THRESH field.
Description
Interrupt Force
31:1 Reserved. - - -
0 FIFO Triggered when the sample FIFO reaches a certain level. RW 0x0
This level can be programmed via the FCS_THRESH field.
Description
Interrupt status after masking & forcing
31:1 Reserved. - - -
0 FIFO Triggered when the sample FIFO reaches a certain level. RO 0x0
This level can be programmed via the FCS_THRESH field.
4.10. SSI
Synopsys Documentation
RP2040 has a Synchronous Serial Interface (SSI) controller which appears on the QSPI pins and is used to
communicate with external Flash devices. The SSI forms part of the XIP block.
4.10.1. Overview
In order for the DW_apb_ssi to connect to a serial-master or serial-slave peripheral device, the peripheral must have a
least one of the following interfaces:
You can program the FRF (frame format) bit field in the Control Register 0 (CTRLR0) to select which protocol is used.
The serial protocols supported by the DW_apb_ssi allow for serial slaves to be selected or addressed using either
hardware or software. When implemented in hardware, serial slaves are selected under the control of dedicated
hardware select lines. The number of select lines generated from the serial master is equal to the number of serial
slaves present on the bus. The serial-master device asserts the select line of the target serial slave before data transfer
When implemented in software, the input select line for all serial slave devices should originate from a single slave
select output on the serial master. In this mode it is assumed that the serial master has only a single slave select
output. If there are multiple serial masters in the system, the slave select output from all masters can be logically
ANDed to generate a single slave select input for all serial slave devices. The main program in the software domain
controls selection of the target slave device; this architecture is illustrated in Figure 116. Software would use the
SSIENR register in all slaves in order to control which slave is to respond to the serial transfer request from the master
device.
The DW_apb_ssi does not enforce hardware or software control for serial-slave device selection. You can configure the
DW_apb_ssi for either implementation, illustrated in Figure 116.
Figure 116.
Hardware/Software Master Slave Master Slave
Slave Selection. Data Bus Data Bus
ss_0 ss ss ss
ss_x
Slave Slave
ss ss
A B
ss = slave select line
4.10.2. Features
The DW_apb_ssi is a configurable and programmable component that is a full-duplex master serial interface. The host
processor accesses data, control, and status information on the DW_apb_ssi through the APB interface. The
DW_apb_ssi also interfaces with the DMA Controller for bulk data transfer.
The DW_apb_ssi is configured as a serial master. The DW_apb_ssi can connect to any serial-slave peripheral device
using one of the following interfaces:
4.10.2.1. IO connections
4.10.3. IP Modifications
The following modifications were made to the Synopsys DW_apb_ssi hardware:
1. XIP accesses are byte-swapped, such that the least-addressed byte is in the least-significant position
2. When SPI_CTRLR0_INST_L is 0, the XIP instruction field is appended to the end of the address for XIP accesses,
rather than prepended to the beginning
3. The reset value of DMARDLR is increased from 0 to 4. The SSI to DMA handshaking on RP2040 requests only single
transfers or bursts of four, depending on whether the RX FIFO level has reached DMARDLR, so DMARDLR should not be
changed from this value.
The first of these changes allows mixed-size accesses by a little-endian busmaster, such as the RP2040 DMA, or the
Cortex-M0+ configuration used on RP2040. Note that this only applies to XIP accesses (RP2040 system addresses in
the range 0x10000000 to 0x13ffffff), not to direct access to the DW_apb_ssi FIFOs. When accessing the SSI directly, it
may be necessary for software to swap bytes manually, or to use the RP2040 DMA’s byte swap feature.
The second supports issuing of continuation bits following the XIP address, so that command-prefix-free XIP modes
can be supported (e.g. EBh Quad I/O Fast Read on Winbond devices), for greater performance. For example, the
following configuration would be used to issue a standard 03h serial read command for each access to the XIP address
window:
• SPI_CTRLR0_INST_L = 8 bits
• SPI_CTRLR0_ADDR_L = 24 bits
• SPI_CTRLR0_XIP_CMD = 0x03
This will first issue eight command bits (0x03), then issue 24 address bits, then clock in the data bits. The configuration
used for EBh quad read, after the flash has entered the XIP state, would be:
• SPI_CTRLR0_INST_L = 0
• SPI_CTRLR0_ADDR_L = 32 bits
• SPI_CTRLR0_XIP_CMD = 0xa0 (continuation code on W25Qx devices)
For each XIP access, the DW_apb_ssi will issue 32 "address" bits, consisting of the 24 LSBs of the RP2040 system bus
address, followed by the 8-bit continuation code 0xa0. No command prefix is issued.
The following example is pseudo code that illustrates how to use software to select the target slave.
1 int main() {
2 disable_all_serial_devices(); ①
3 initialize_mst(ssi_mst_1); ②
4 initialize_slv(ssi_slv_1); ③
5 start_serial_xfer(ssi_mst_1); ④
6 }
① This function sets the ② This function initializes ③ This function initializes ④ This function begins the
SSI_EN bit to logic ‘0’ in the the master device for the the target slave device serial transfer by writing
SSIENR register of each serial transfer; (slave 1 in this example) transmit data into the
device on the serial bus. for the serial transfer; master’s TX FIFO. User
1. Write CTRLR0 to
can poll the busy status
match the required 1. Write CTRLR0 to
with a function or use an
transfer match the required
ISR to determine when the
transfer
2. If transfer is receive serial transfer has
only write number of 2. Write TXFTLR and completed.
frames into CTRLR1 RXFTLR to set FIFO
threshold levels
3. Write BAUDR to set
the transfer baud rate. 3. Write IMR register to
set interrupt masks
4. Write TXFTLR and
RXFTLR to set FIFO 4. Write SSIENR register
threshold levels bit[0] to logic '1' to
enable the slave.
5. Write IMR register to
set interrupt masks 5. If the slave is to
transmit data, write
6. Write SER register
data into TX FIFO Now
bit[0] to logic '1'
the slave is enabled
7. Write SSIENR register and awaiting an active
bit[0] to logic '1' to level on its ss_in_n
enable the master. input port. Note all
other serial slaves are
disabled (SSI_EN=0)
and therefore will not
respond to an active
level on their ss_in_n
port.
Figure 117 illustrates the maximum ratio between sclk_out and ssi_clk.
Figure 117. Maximum capture drive1 capture1 drive2 capture2 drive3 capture3
sclk_out/ssi_clk Ratio. ssi_clk
sclk_out
txd/rxd MSB
The sclk_out line toggles only when an active transfer is in progress. At all other times it is held in an inactive state, as
defined by the serial protocol under which it operates.
SCKDV is a bit field in the programmable register BAUDR, holding any even value in the range 0 to 65,534. If SCKDV is 0,
then sclk_out is disabled.
A summary of the frequency ratio restrictions between the bit-rate clock (sclk_out) and the DW_apb_ssi peripheral clock
(ssi_clk) are as follows:
Each data entry in the FIFO buffers contains a single data frame. It is impossible to store multiple data frames in a
single FIFO location; for example, you may not store two 8-bit data frames in a single FIFO location. If an 8-bit data
frame is required, the upper bits of the FIFO entry are ignored or unused when the serial shifter transmits the data.
NOTE
The transmit and receive FIFO buffers are cleared when the DW_apb_ssi is disabled (SSI_EN = 0) or when it is reset
(presetn).
The transmit FIFO is loaded by APB write commands to the DW_apb_ssi data register (DR). Data are popped (removed)
from the transmit FIFO by the shift control logic into the transmit shift register. The transmit FIFO generates a FIFO
empty interrupt request (ssi_txe_intr) when the number of entries in the FIFO is less than or equal to the FIFO threshold
value. The threshold value, set through the programmable register TXFTLR, determines the level of FIFO entries at which
an interrupt is generated. The threshold value allows you to provide early indication to the processor that the transmit
FIFO is nearly empty. A transmit FIFO overflow interrupt (ssi_txo_intr) is generated if you attempt to write data into an
already full transmit FIFO.
Data are popped from the receive FIFO by APB read commands to the DW_apb_ssi data register (DR). The receive FIFO
is loaded from the receive shift register by the shift control logic. The receive FIFO generates a FIFO-full interrupt
request (ssi_rxf_intr) when the number of entries in the FIFO is greater than or equal to the FIFO threshold value plus
one. The threshold value, set through programmable register RXFTLR, determines the level of FIFO entries at which an
interrupt is generated.
The threshold value allows you to provide early indication to the processor that the receive FIFO is nearly full. A receive
FIFO overrun interrupt (ssi_rxo_intr) is generated when the receive shift logic attempts to load data into a completely full
receive FIFO. However, this newly received data are lost. A receive FIFO underflow interrupt (ssi_rxu_intr) is generated if
you attempt to read from an empty receive FIFO. This alerts the processor that the read data are invalid.
Table 585 provides description for different Transmit FIFO Threshold values.
0000_0001 ssi_txe_intr is asserted when one or less data entry is present in transmit FIFO
0000_0010 ssi_txe_intr is asserted when two or less data entries are present in transmit FIFO
… …
0000_1101 ssi_txe_intr is asserted when 13 or less data entries are present in transmit FIFO
0000_1110 ssi_txe_intr is asserted when 14 or less data entries are present in transmit FIFO
0000_1111 ssi_txe_intr is asserted when 15 or less data entries are present in transmit FIFO
Table 586 provides description for different Receive FIFO Threshold values.
0000_0001 ssi_rxf_intr is asserted when two or more data entries are present in receive FIFO
0000_0010 ssi_rxf_intr is asserted when three or more data entries are present in receive FIFO
… …
0000_1101 ssi_rxf_intr is asserted when 14 or more data entries are present in receive FIFO
0000_1110 ssi_rxf_intr is asserted when 15 or more data entries are present in receive FIFO
0000_1111 ssi_rxf_intr is asserted when 16 data entries are present in receive FIFO
• dfs_32 (CTRLR0[20:16]) are valid, which contains the value of data frame size. The new register field holds the
values 0 to 31. The dfs (CTRLR0[3:0]) is invalid and writing to this register has no effect.
NOTE
The transfer mode setting does not affect the duplex of the serial transfer. TMOD is ignored for Microwire transfers,
which are controlled by the MWCR register.
When TMOD = 00b, both transmit and receive logic are valid. The data transfer occurs as normal according to the
selected frame format (serial protocol). Transmit data are popped from the transmit FIFO and sent through the txd line
to the target device, which replies with data on the rxd line. The receive data from the target device is moved from the
receive shift register into the receive FIFO at the end of each data frame.
When TMOD = 01b, the receive data are invalid and should not be stored in the receive FIFO. The data transfer occurs as
normal, according to the selected frame format (serial protocol). Transmit data are popped from the transmit FIFO and
sent through the txd line to the target device, which replies with data on the rxd line. At the end of the data frame, the
receive shift register does not load its newly received data into the receive FIFO. The data in the receive shift register is
overwritten by the next transfer. You should mask interrupts originating from the receive logic when this mode is
entered.
When TMOD = 10b, the transmit data are invalid. When configured as a slave, the transmit FIFO is never popped in
Receive Only mode. The txd output remains at a constant logic level during the transmission. The data transfer occurs
as normal according to the selected frame format (serial protocol). The receive data from the target device is moved
from the receive shift register into the receive FIFO at the end of each data frame. You should mask interrupts
NOTE
When TMOD = 11b, the transmit data is used to transmit an opcode and/or an address to the EEPROM device. Typically
this takes three data frames (8-bit opcode followed by 8-bit upper address and 8-bit lower address). During the
transmission of the opcode and address, no data is captured by the receive logic (as long as the DW_apb_ssi master is
transmitting data on its txd line, data on the rxd line is ignored). The DW_apb_ssi master continues to transmit data until
the transmit FIFO is empty. Therefore, you should ONLY have enough data frames in the transmit FIFO to supply the
opcode and address to the EEPROM. If more data frames are in the transmit FIFO than are needed, then read data is
lost.
When the transmit FIFO becomes empty (all control information has been sent), data on the receive line (rxd) is valid
and is stored in the receive FIFO; the txd output is held at a constant logic level. The serial transfer continues until the
number of data frames received by the DW_apb_ssi master matches the value of the NDF field in the CTRLR1 register +
1.
NOTE
EEPROM read mode is not supported when the DW_apb_ssi is configured to be in the SSP mode.
This mode enables serial communication with serial-slave peripheral devices. When configured as a serial-master
device, the DW_apb_ssi initiates and controls all serial transfers. Figure 118 shows an example of the DW_apb_ssi
configured as a serial master with all other devices on the serial bus configured as serial slaves.
Figure 118.
DW_apb_ssi
Configured as Master
DW_apb_ssi Slave
Device Master 1 Peripheral 1
txd DI
ssi_oe_n DO
rxd SCLK
sclk_out SS
ss_n[0]
Slave
ss_n[1]
Peripheral n
ss_in_n
DI
DO
Glue Logic
SCLK
SS
Should be driven to inactive level
(protocol-dependent) in single master
systems; may not need glue logic
The serial bit-rate clock, generated and controlled by the DW_apb_ssi, is driven out on the sclk_out line. When the
DW_apb_ssi is disabled (SSI_EN = 0), no serial transfers can occur and sclk_out is held in “inactive” state, as defined by
the serial protocol under which it operates.
When the DW_apb_ssi is configured as a master, additional logic can be included in the design in order to delay the
default sample time of the rxd signal. This additional logic can help to increase the maximum achievable frequency on
the serial bus.
Round trip routing delays on the sclk_out signal from the master and the rxd signal from the slave can mean that the
timing of the rxd signal—as seen by the master—has moved away from the normal sampling time. Figure 119 illustrates
this situation.
dly=0 dly=5
Figure 119. Effects of dly=6
Round-Trip Routing dly=7 baud-rate=4
Delays on sclk_out
ssi_clk
Signal
sclk_out
sclk_in
The Slave uses the sclk_out signal from the master as a strobe in order to drive rxd signal data onto the serial bus.
Routing and sampling delays on the sclk_out signal by the slave device can mean that the rxd bit has not stabilized to
the correct value before the master samples the rxd signal. Figure 119 shows an example of how a routing delay on the
rxd signal can result in an incorrect rxd value at the default time when the master samples the port.
Without the RXD Sample Delay logic, the user would have to increase the baud-rate for the transfer in order to ensure
that the setup times on the rxd signal are within range; this results in reducing the frequency of the serial interface.
When the RXD Sample Delay logic is included, the user can dynamically program a delay value in order to move the
sampling time of the rxd signal equal to a number of ssi_clk cycles from the default.
The sample delay logic has a resolution of one ssi_clk cycle. Software can “train” the serial bus by coding a loop that
continually reads from the slave and increments the master’s RXD Sample Delay value until the correct data is received
by the master.
Data transfers are started by the serial-master device. When the DW_apb_ssi is enabled (SSI_EN=1), at least one valid
data entry is present in the transmit FIFO and a serial-slave device is selected. When actively transferring data, the busy
flag (BUSY) in the status register (SR) is set. You must wait until the busy flag is cleared before attempting a new serial
transfer.
NOTE
The BUSY status is not set when the data are written into the transmit FIFO. This bit gets set only when the target
slave has been selected and the transfer is underway. After writing data into the transmit FIFO, the shift logic does
not begin the serial transfer until a positive edge of the sclk_out signal is present. The delay in waiting for this
positive edge depends on the baud rate of the serial transfer. Before polling the BUSY status, you should first poll the
TFE status (waiting for 1) or wait for BAUDR * ssi_clk clock cycles.
When the transfer mode is “transmit and receive” or “transmit only” (TMOD = 00b or TMOD = 01b, respectively), transfers
are terminated by the shift control logic when the transmit FIFO is empty. For continuous data transfers, you must
ensure that the transmit FIFO buffer does not become empty before all the data have been transmitted. The transmit
FIFO threshold level (TXFTLR) can be used to early interrupt (ssi_txe_intr) the processor indicating that the transmit
FIFO buffer is nearly empty. When a DMA is used for APB accesses, the transmit data level (DMATDLR) can be used to
early request (dma_tx_req) the DMA Controller, indicating that the transmit FIFO is nearly empty. The FIFO can then be
refilled with data to continue the serial transfer. The user may also write a block of data (at least two FIFO entries) into
the transmit FIFO before enabling a serial slave. This ensures that serial transmission does not begin until the number
of data-frames that make up the continuous transfer are present in the transmit FIFO.
When the transfer mode is “receive only” (TMOD = 10b), a serial transfer is started by writing one “dummy” data word
into the transmit FIFO when a serial slave is selected. The txd output from the DW_apb_ssi is held at a constant logic
level for the duration of the serial transfer. The transmit FIFO is popped only once at the beginning and may remain
empty for the duration of the serial transfer. The end of the serial transfer is controlled by the “number of data frames”
(NDF) field in control register 1 (CTRLR1).
If, for example, you want to receive 24 data frames from a serial-slave peripheral, you should program the NDF field with
the value 23; the receive logic terminates the serial transfer when the number of frames received is equal to the NDF
value + 1. This transfer mode increases the bandwidth of the APB bus as the transmit FIFO never needs to be serviced
during the transfer. The receive FIFO buffer should be read each time the receive FIFO generates a FIFO full interrupt
request to prevent an overflow.
When the transfer mode is “eeprom_read” (TMOD = 11b), a serial transfer is started by writing the opcode and/or
address into the transmit FIFO when a serial slave (EEPROM) is selected. The opcode and address are transmitted to
the EEPROM device, after which read data is received from the EEPROM device and stored in the receive FIFO. The end
of the serial transfer is controlled by the NDF field in the control register 1 (CTRLR1).
NOTE
EEPROM read mode is not supported when the DW_apb_ssi is configured to be in the SSP mode.
The receive FIFO threshold level (RXFTLR) can be used to give early indication that the receive FIFO is nearly full. When
a DMA is used for APB accesses, the receive data level (DMARDLR) can be used to early request (dma_rx_req) the DMA
Controller, indicating that the receive FIFO is nearly full.
A typical software flow for completing an SPI or SSP serial transfer from the DW_apb_ssi serial master is outlined as
follows:
1. If the DW_apb_ssi is enabled, disable it by writing 0 to the SSI Enable register (SSIENR).
2. Set up the DW_apb_ssi control registers for the transfer; these registers can be set in any order.
◦ Write Control Register 0 (CTRLR0). For SPI transfers, the serial clock polarity and serial clock phase
parameters must be set identical to target slave device.
◦ If the transfer mode is receive only, write CTRLR1 (Control Register 1) with the number of frames in the
transfer minus 1; for example, if you want to receive four data frames, if you want to receive four data frames,
write '3' into CTRLR1.
◦ Write the Baud Rate Select Register (BAUDR) to set the baud rate for the transfer.
◦ Write the Transmit and Receive FIFO Threshold Level registers (TXFTLR and RXFTLR, respectively) to set FIFO
threshold levels.
4. Write data for transmission to the target slave into the transmit FIFO (write DR). If no slaves were enabled in the
SER register at this point, enable it now to begin the transfer.
5. Poll the BUSY status to wait for completion of the transfer. The BUSY status cannot be polled immediately.
6. If a transmit FIFO empty interrupt request is made, write the transmit FIFO (write DR). If a receive FIFO full interrupt
request is made, read the receive FIFO (read DR).
7. The transfer is stopped by the shift control logic when the transmit FIFO is empty. If the transfer mode is receive
only (TMOD = 10b), the transfer is stopped by the shift control logic when the specified number of frames have
been received. When the transfer is done, the BUSY status is reset to 0.
8. If the transfer mode is not transmit only (TMOD != 01b), read the receive FIFO until it is empty.
Figure 120 shows a typical software flow for starting a DW_apb_ssi master SPI/SSP serial transfer. The diagram also
shows the hardware flow inside the serial-master component.
Figure 120.
Software Flow
DW_apb_ssi Master
SPI/SSP Transfer Flow IDLE
Disable
DW_apb_ssi DW_apb_ssi
Configure Master by
IDLE
writing CTRLR0. CTRLR1,
BAUDR, TXFTLR, RXFTLR,
IMR, SER, SPI_CTRLR0 Pop data from
(if Dual /Quad SPI) Tx FIFO into shifter
Enable
DW_apb_ssi Transfer Bit
TMOD=00
Yes Interrupt Service TMOD=01 TMOD=10
Interrupt?
Routine
Microwire serial transfers from the DW_apb_ssi serial master are controlled by the Microwire Control Register (MWCR).
The MWHS bit field enables and disables the Microwire handshaking interface. The MDD bit field controls the direction
of the data frame (the control frame is always transmitted by the master and received by the slave). The MWMOD bit
field defines whether the transfer is sequential or nonsequential.
All Microwire transfers are started by the DW_apb_ssi serial master when there is at least one control word in the
transmit FIFO and a slave is enabled. When the DW_apb_ssi master transmits the data frame (MDD = 1), the transfer is
terminated by the shift logic when the transmit FIFO is empty. When the DW_apb_ssi master receives the data frame
(MDD = 1), the termination of the transfer depends on the setting of the MWMOD bit field. If the transfer is
nonsequential (MWMOD = 0), it is terminated when the transmit FIFO is empty after shifting in the data frame from the
slave. When the transfer is sequential (MWMOD = 1), it is terminated by the shift logic when the number of data frames
received is equal to the value in the CTRLR1 register + 1.
When the handshaking interface on the DW_apb_ssi master is enabled (MWHS =1), the status of the target slave is
polled after transmission. Only when the slave reports a ready status does the DW_apb_ssi master complete the
transfer and clear its BUSY status. If the transfer is continuous, the next control/data frame is not sent until the slave
device returns a ready status.
A typical software flow for completing a Microwire serial transfer from the DW_apb_ssi serial master is outlined as
follows:
2. Set up the DW_apb_ssi control registers for the transfer. These registers can be set in any order. Write CTRLR0 to
set transfer parameters.
◦ If the transfer is sequential and the DW_apb_ssi master receives data, write CTRLR1 with the number of
frames in the transfer minus 1; for instance, if you want to receive four data frames, write '3' into CTRLR1.
You can write the SER register to enable the target slave for selection. If a slave is enabled here, the transfer
begins as soon as one valid data entry is present in the transmit FIFO. If no slaves are enabled prior to writing
to the DR register, the transfer does not begin until a slave is enabled.
4. If the DW_apb_ssi master transmits data, write the control and data words into the transmit FIFO (write DR). If the
DW_apb_ssi master receives data, write the control word(s) into the transmit FIFO.
If no slaves were enabled in the SER register at this point, enable now to begin the transfer.
5. Poll the BUSY status to wait for completion of the transfer. The BUSY status cannot be polled immediately.
6. The transfer is stopped by the shift control logic when the transmit FIFO is empty. If the transfer mode is
sequential and the DW_apb_ssi master receives data, the transfer is stopped by the shift control logic when the
specified number of data frames is received. When the transfer is done, the BUSY status is reset to 0.
7. If the DW_apb_ssi master receives data, read the receive FIFO until it is empty.
Figure 121 shows a typical software flow for starting a DW_apb_ssi master Microwire serial transfer. The diagram also
shows the hardware flow inside the serial-master component.
Microwire Transfer
IDLE
IDLE
Flow
Disable
DW_apb_ssi Pop control frame
from Tx FIFO into
shifter
Configure Master
by writing CTRLR0.
CTRLR1, BAUDR, Transfer Bit
TXFTLR, RXFTLR,
MWCR, IMR, SER
No All bits in
control frame
Enable
transmitted?
DW_apb_ssi
Yes Yes
END
With the SPI, the clock polarity (SCPOL) configuration parameter determines whether the inactive state of the serial
clock is high or low. To transmit data, both SPI peripherals must have identical serial clock phase (SCPH) and clock
polarity (SCPOL) values. The data frame can be 4 to 16/32 bits (depending upon SSI_MAX_XFER_SIZE) in length.
When the configuration parameter SCPH = 0, data transmission begins on the falling edge of the slave select signal.
The first data bit is captured by the master and slave peripherals on the first edge of the serial clock; therefore, valid
data must be present on the txd and rxd lines prior to the first serial clock edge.
Figure 122 shows a timing diagram for a single SPI data transfer with SCPH = 0. The serial clock is shown for
configuration parameters SCPOL = 0 and SCPOL = 1.
sclk_out/in 1
4 -32 bits
ss_0_n/ss_in_n
ssi_oe_n
The following signals are illustrated in the timing diagrams in this section:
sclk_out
serial clock from DW_apb_ssi master
ss_0_n
slave select signal from DW_apb_ssi master
ss_in_n
slave select input to the DW_apb_ssi slave
ss_oe_n
output enable for the DW_apb_ssi master
txd
transmit data line for the DW_apb_ssi master
rxd
receive data line for the DW_apb_ssi master
• When CTRLR0. SSTE is set to 1, the DW_apb_ssi toggles the slave select signal between frames and the serial
clock is held to its default value while the slave select signal is active; this operating mode is illustrated in Figure
123.
ss_0_n/ss_in_n
ssi_oe_n
When the configuration parameter SCPH = 1, master peripherals begin transmitting data on the first serial clock edge
after the slave select line is activated. The first data bit is captured on the second (trailing) serial clock edge. Data are
propagated by the master peripherals on the leading edge of the serial clock. During continuous data frame transfers,
the slave select line may be held active-low until the last bit of the last frame has been captured.
Figure 124 shows the timing diagram for the SPI format when the configuration parameter SCPH = 1.
sclk_out/in 1
4 -32 bits
ss_0_n/ss_in_n
ssi_oe_n
Continuous data frames are transferred in the same way as single frames, with the MSB of the next frame following
directly after the LSB of the current frame. The slave select signal is held active for the duration of the transfer.
Figure 125 shows the timing diagram for continuous SPI transfers when the configuration parameter SCPH = 1.
ss_0_n/ss_in_n
ssi_oe_n
There are four possible transfer modes on the DW_apb_ssi for performing SPI serial transactions. For transmit and
receive transfers (transfer mode field (9:8) of the Control Register 0 = 00b), data transmitted from the DW_apb_ssi to the
external serial device is written into the transmit FIFO. Data received from the external serial device into the DW_apb_ssi
is pushed into the receive FIFO.
Figure 126 shows the FIFO levels prior to the beginning of a serial transfer and the FIFO levels on completion of the
transfer. In this example, two data words are transmitted from the DW_apb_ssi to the external serial device in a
continuous transfer. The external serial device also responds with two data words for the DW_apb_ssi.
Location n NULL
Location n NULL
Location 2 NULL SHIFT LOGIC
Location 1 Tx Data(1) Location 2 NULL
Location 0 Tx Data(0) Location 1 Rx_Data(1)
Location 0 Rx_Data(0)
Rx FIFO Buffer
Rx FIFO Empty
Read DR
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
For transmit only transfers (transfer mode field (9:8) of the Control Register 0 = 01b), data transmitted from the
DW_apb_ssi to the external serial device is written into the transmit FIFO. As the data received from the external serial
device is deemed invalid, it is not stored in the DW_apb_ssi receive FIFO.
Figure 127 shows the FIFO levels prior to the beginning of a serial transfer and the FIFO levels on completion of the
transfer. In this example, two data words are transmitted from the DW_apb_ssi to the external serial device in a
continuous transfer.
Location n NULL
Location n NULL
Location 2 NULL SHIFT LOGIC
Location 1 Tx Data(1) Location 2 NULL
Location 0 Tx Data(0) Location 1 NULL
Location 0 NULL
Rx FIFO Buffer
Rx FIFO Empty
Read DR
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
For receive only transfers (transfer mode field (9:8) of the Control Register 0 = 10b), data transmitted from the
DW_apb_ssi to the external serial device is invalid, so a single dummy word is written into the transmit FIFO to begin the
serial transfer. The txd output from the DW_apb_ssi is held at a constant logic level for the duration of the serial
transfer. Data received from the external serial device into the DW_apb_ssi is pushed into the receive FIFO.
Figure 128 shows the FIFO levels prior to the beginning of a serial transfer and the FIFO levels on completion of the
transfer. In this example, two data words are received by the DW_apb_ssi from the external serial device in a continuous
transfer.
Location n NULL
Location n NULL
Location 2 NULL SHIFT LOGIC
Location 1 NULL Location 2 NULL
Location 0 Dummy Word Location 1 Rx_Data(1)
Location 0 Rx_Data(0)
Rx FIFO Buffer
Rx FIFO Empty
Read DR
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
For eeprom_read transfers (transfer mode field [9:8] of the Control Register 0 = 11b), opcode and/or EEPROM address
are written into the transmit FIFO. During transmission of these control frames, received data is not captured by the
DW_apb_ssi master. After the control frames have been transmitted, receive data from the EEPROM is stored in the
receive FIFO.
Figure 129 shows the FIFO levels prior to the beginning of a serial transfer and the FIFO levels on completion of the
transfer. In this example, one opcode and an upper and lower address are transmitted to the EEPROM, and eight data
frames are read from the EEPROM and stored in the receive FIFO of the DW_apb_ssi master.
Location n NULL
Location n NULL
Location 3 NULL SHIFT LOGIC
Location 2 Address[7:0] Location 7 Rx_Data(7)
Location 1 Address[15:8] Location 6 Rx_Data(6)
Location 0 Opcode
Location 1 Rx_Data(1)
Location 0 Rx_Data(0)
Rx FIFO Empty
Rx FIFO Buffer
FIFO Status Prior to txd
Read DR
Transfer
FIFO Status on
Completion of Transfer
Data transfers begin by asserting the frame indicator line (ss_0_n/ss_in_n) for one serial clock period. Data to be
transmitted are driven onto the txd line one serial clock cycle later; similarly data from the slave are driven onto the rxd
line. Data are propagated on the rising edge of the serial clock (sclk_out/sclk_in) and captured on the falling edge. The
length of the data frame ranges from four to 32 bits.
Figure 130 shows the timing diagram for a single SSP serial transfer.
ss_0_n/ss_in_n
ssi_oe_n
Continuous data frames are transferred in the same way as single data frames. The frame indicator is asserted for one
clock period during the same cycle as the LSB from the current transfer, indicating that another data frame follows.
ss_0_n/ss_in_n
ssi_oe_n
Data transmission begins with the falling edge of the slave-select signal (ss_0_n). One-half serial clock (sclk_out) period
later, the first bit of the control is sent out on the txd line. The length of the control word can be in the range 1 to 16 bits
and is set by writing bit field CFS (bits 15:12) in CTRLR0. The remainder of the control word is transmitted (propagated
on the falling edge of sclk_out) by the DW_apb_ssi serial master. During this transmission, no data are present (high
impedance) on the serial master’s rxd line.
The direction of the data word is controlled by the MDD bit field (bit 1) in the Microwire Control Register (MWCR). When
MDD=0, this indicates that the DW_apb_ssi serial master receives data from the external serial slave. One clock cycle
after the LSB of the control word is transmitted, the slave peripheral responds with a dummy 0 bit, followed by the data
frame, which can be four to 32 bits in length. Data are propagated on the falling edge of the serial clock and captured on
the rising edge.
The slave-select signal is held active-low during the transfer and is de-asserted one-half clock cycle later, after the data
are transferred. Figure 132 shows the timing diagram for a single DW_apb_ssi serial master read from an external serial
slave.
4 -32 bits
ss_0_n
ssi_oe_n
Figure 133 shows how the data and control frames are structured in the transmit FIFO prior to the transfer; the value
programmed into the MWCR register is also shown.
Location n NULL
Location n NULL
Location 3 NULL SHIFT LOGIC
Location 2 NULL Location 3 NULL
Location 1 NULL Location 2 NULL
Location 0 Ctrl Word(0) Location 1 NULL
Location 0 Rx_Data(0)
Rx FIFO Buffer
Rx FIFO Empty
Read DR
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
Continuous transfers for the Microwire protocol can be sequential or nonsequential, and are controlled by the MWMOD
bit field (bit 0) in the MWCR register.
Nonsequential continuous transfers occur as illustrated in Figure 134, with the control word for the next transfer
following immediately after the LSB of the current data word.
Figure 134.
sclk_out
Continuous
Control word 0 Control word 1
Nonsequential
txd MSB LSB MSB LSB
Microwire Transfer
(receiving data frame) Data Word 0 Data Word 1
ss_0_n
ssi_oe_n
The only modification needed to perform a continuous nonsequential transfer is to write more control words into the
transmit FIFO buffer; this is illustrated in Figure 135. In this example, two data words are read from the external serial-
slave device.
Nonsequential
MWCR 0 0 0
rxd
Microwire Transfer
Write DR
(receiving data frame) Tx FIFO Empty
Tx FIFO Buffer
Location n NULL
Location n NULL
Location 3 NULL SHIFT LOGIC
Location 2 NULL Location 3 NULL
Location 1 Ctrl Word(1) Location 2 NULL
Location 0 Ctrl Word(0) Location 1 Rx_Data(1)
Location 0 Rx_Data(0)
Rx FIFO Buffer
Rx FIFO Empty
Read DR
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
During sequential continuous transfers, only one control word is transmitted from the DW_apb_ssi master. The transfer
is started in the same manner as with nonsequential read operations, but the cycle is continued to read further data.
The slave device automatically increments its address pointer to the next location and continues to provide data from
that location. Any number of locations can be read in this manner; the DW_apb_ssi master terminates the transfer when
the number of words received is equal to the value in the CTRLR1 register plus one.
The timing diagram in Figure 136 and example in Figure 137 show a continuous sequential read of two data frames
from the external slave device.
Figure 136.
Continuous Sequential sclk_out
Microwire Transfer Control word
(receiving data frame)
txd MSB LSB
ss_0_n
ssi_oe_n
Location n NULL
Location n NULL
Location 3 NULL SHIFT LOGIC
Location 2 NULL Location 3 NULL
Location 1 NULL Location 2 NULL
Location 0 Ctrl Word(0) Location 1 Rx_Data(1)
Location 0 Rx_Data(0)
Rx FIFO Buffer
Rx FIFO Empty
Read DR
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
When MDD = 1, this indicates that the DW_apb_ssi serial master transmits data to the external serial slave. Immediately
after the LSB of the control word is transmitted, the DW_apb_ssi master begins transmitting the data frame to the slave
peripheral.
Figure 138 shows the timing diagram for a single DW_apb_ssi serial master write to an external serial slave.
rxd
ss_0_n
ssi_oe_n
NOTE
The DW_apb_ssi does not support continuous sequential Microwire writes, where MDD = 1 and MWMOD = 1.
Figure 139 shows how the data and control frames are structured in the transmit FIFO prior to the transfer, also shown
is the value programmed into the MWCR register.
Location n NULL
Location n NULL
Location 3 NULL SHIFT LOGIC
Location 2 NULL Location 3 NULL
Location 1 Tx Data(0) Location 2 NULL
Location 0 Ctrl Word(0) Location 1 NULL
Location 0 NULL
Rx FIFO Buffer
Rx FIFO Empty
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
Continuous transfers occur as shown in Figure 140, with the control word for the next transfer following immediately
after the LSB of the current data word.
Figure 140.
Continuous Microwire sclk_out
Transfer (transmitting Control word 0 Data word 0 Control word 1 Data word 1
data frame) txd MSB LSB MSB LSB MSB LSB MSB LSB
rxd
ss_0_n
ssi_oe_n
The only modification you need to make to perform a continuous transfer is to write more control and data words into
the transmit FIFO buffer, shown in Figure 141. This example shows two data words are written to the external serial
slave device.
Microwire Transfer
MWCR 0 1 0
rxd
(transmitting data
Write DR
frame) Tx FIFO Empty
Tx FIFO Buffer
Location n NULL
Location n NULL
Location 3 Data Word(1) SHIFT LOGIC
Location 2 Ctrl Word(1) Location 3 NULL
Location 1 Tx Data(0) Location 2 NULL
Location 0 Ctrl Word(0) Location 1 NULL
Location 0 NULL
Rx FIFO Buffer
Rx FIFO Empty
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
The Microwire handshaking interface can also be enabled for DW_apb_ssi master write operations to external serial-
slave devices. To enable the handshaking interface, you must write 1 into the MHS bit field (bit 2) on the MWCR register.
When MHS is set to 1, the DW_apb_ssi serial master checks for a ready status from the slave device before completing
the transfer, or transmitting the next control word for continuous transfers.
Figure 142 shows an example of a continuous Microwire transfer with the handshaking interface enabled.
Handshaking rxd
Busy Ready Busy Ready
After the first data word has been transmitted to the serial-slave device, the DW_apb_ssi master polls the rxd input
waiting for a ready status from the slave device. Upon reception of the ready status, the DW_apb_ssi master begins
transmission of the next control word. After transmission of the last data frame has completed, the DW_apb_ssi master
transmits a start bit to clear the ready status of the slave device before completing the transfer. The FIFO status for this
transfer is the same as in Figure 141, except that the MWHS bit field is set (1).
To transmit a control word (not followed by data) to a serial-slave device from the DW_apb_ssi master, there must be
only one entry in the transmit FIFO buffer. It is impossible to transmit two control words in a continuous transfer, as the
shift logic in the DW_apb_ssi treats the second control word as a data word. When the DW_apb_ssi master transmits
only a control word, the MDD bit field (bit 1 of MWCR register) must be set (1).
In the example shown in Figure 143 and in the timing diagram in Figure 144, the handshaking interface is enabled. If the
handshaking interface is disabled (MHS=0), the transfer is terminated by the DW_apb_ssi master one sclk_out cycle
after the LSB of the control word is captured by the slave device.
Location n NULL
Location n NULL
Location 3 NULL SHIFT LOGIC
Location 2 NULL Location 3 NULL
Location 1 NULL Location 2 NULL
Location 0 Ctrl Word(0) Location 1 NULL
Location 0 NULL
Rx FIFO Buffer
Rx FIFO Empty
FIFO Status Prior to txd FIFO Status on
Transfer Completion of Transfer
Busy Ready
rxd
ss_0_n
ssi_oe_n
DW_apb_ssi supports the dual and quad modes of SPI in RP2040; octal mode is not supported. txd, rxd and ssi_oe_n
signals are four bits wide.
Data is shifted out/in on more than one line, increasing the overall throughput. All four combinations of the serial clock’s
polarity and phase are valid in this mode and work the same as in normal SPI mode. Dual SPI, or Quad SPI modes
function similarly except for the width of txd, rxd and ssi_oe_n signals. The mode of operation (write/read) can be
selected using the CTRLR0.TMOD field.
Dual, or Quad, SPI write operations can be divided into three parts:
• Instruction phase
• Address phase
• Data phase
The following register fields are used for a write operation:
• CTRLR0.SPI_FRF - Specifies the format in which the transmission happens for the frame.
• SPI_CTRLR0 (Control Register 0 register) – Specifies length of instruction, address, and data.
• SPI_CTRLR0.INST_L – Specifies length of an instruction (possible values for an instruction are 0, 4, 8, or 16 bits.)
• SPI_CTRLR0.ADDR_L – Specifies address length (See Table 587 for decode values)
• CTRLR0.DFS or CTRLR0.DFS_32 – Specifies data length.
An instruction takes one FIFO location. An address can take more than one FIFO locations.
Both the instruction and address must be programmed in the data register (DR). DW_apb_ssi will wait until both have
been programmed to start the write operation.
The instruction, address and data can be programmed to send in dual/quad mode, which can be selected from the
SPI_CTRLR0.TRANS_TYPE and CTRLR0.SPI_FRF fields.
NOTE
• If CTRLR0.SPI_FRF is selected to be "Standard SPI Format", everything is sent in Standard SPI mode and
SPI_CTRLR0.TRANS_TYPE field is ignored.
Figure 145 shows a typical write operation in Dual, or Quad, SPI Mode. The value of N will be: 7 if SSI_SPI_MODE is set
to 3, 3 if SSI_SPI_MODE is set to 2, and 1 if SSI_SPI_MODE is set to 1. For 1-write operation, the instruction and address
are sent only once followed by data frames programmed in DR until the transmit FIFO becomes empty.
ss_oe_n
To initiate a Dual/Quad write operation, CTRLR0.SPI_FRF must be set to 01/10/11, respectively. This will set the transfer
type, and for each write command, data will be transferred in the format specified in CTLR0.SPI_FRF field.
ss_oe_n[N-1:0]
ss_oe_n
Case B: Instruction transmitted in standard and address transmitted in Enhanced SPI format
For this, SPI_CTRLR0.TRANS_TYPE field must be set to one. Figure 147 shows the timing diagram when an
instruction is transmitted in standard format and address is transmitted in dual SPI format specified in the
CTRLR0.SPI_FRF field. The value of N will be: 7 if CTRLR0.SPI_FRF is set to 11b, 3 if CTRLR0.SPI_FRF is set to 10b,
and 1 if CTRLR0.SPI_FRF is set to 01b.
ss_oe_n[N-1:0]
ss_oe_n
ss_0_n
ss_0_n
A Dual, or Quad, SPI read operation can be divided into four phases:
• Instruction phase
• Address phase
• Wait cycles
• Data phase
Wait Cycles can be programmed using SPI_CTRLR0.WAIT_CYCLES field. The value programmed into
SPI_CTRLR0.WAIT_CYCLES is mapped directly to sclk_out times. For example, WAIT_CYCLES=0 indicates no Wait,
WAIT_CYCLES=1, indicates one wait cycle and so on. The wait cycles are introduced for target slave to change their
mode from input to output and the wait cycles can vary for different devices.
For a READ operation, DW_apb_ssi sends instruction and control data once and waits until it receives NDF (CTRLR1
register) number of data frames and then de-asserts slave select signal.
Figure 150 shows a typical read operation in dual quad SPI mode. The value of N will be: 3 if SSI_SPI_MODE is set to
Quad mode, and 1 if SSI_SPI_MODE is set to Dual mode.
ss_oe_n[N:0]
ss_oe_n
To initiate a dual/quad read operation, CTRLR0.SPI_FRF must be set to 01/10/11 respectively. This will set the transfer
type, now for each read command data will be transferred in the format specified in CTLR0.SPI_FRF field.
Following are the possible cases of write operation in enhanced SPI modes:
Transmitted in txd[N-1:0]
ssi_oe_n[0]
ssi_oe_n[N-1:0]
ss_0_n
Case B: Instruction transmitted in standard and address transmitted in dual SPI format
For this, SPI_CTRLR0.TRANS_TYPE field should be set to 01b. Figure 152 shows the timing diagram in which
instruction is transmitted in standard format and address is transmitted in dual SPI format. The value of N will be 7
if CTRLR0.SPI_FRF is set to 11b, 3 if CTRLR0.SPI_FRF is set to 10b, and 1 if CTRLR0.SPI_FRF is set to 01b.
ssi_oe_n[0]
ssi_oe_n[N-1:0]
ss_0_n
ss_0_n
Figure 154 shows the timing diagram for such type of transfer. The value of N will be: 7 if CTRLR0.SPI_FRF is set to 11b,
3 if CTRLR0.SPI_FRF is set to 10b, and 1 if CTRLR0.SPI_FRF is set to 01b. To initiate this transfer, the software has to
perform a dummy write in the data register (DR), DW_apb_ssi will wait for programmed wait cycles and then fetch the
amount of data specified in NDF field.
Figure 154. No
sclk_out
Instruction and No
txd[N:0] WAIT CYCLES
Address READ
rxd[N:0] DATA
Transfer
ssi_oe_n[N:0]
ss_0_n
The Input/Output mapping for enhanced SPI modes (dual, and quad) is hardcoded inside the DW_apb_ssi. The rxd[1]
signal will be used to sample incoming data in standard SPI mode of operation.
For other protocols (such as SSP and Microwire), the I/O mapping remains the same. Therefore, it is easy for other
protocols to connect with any device that supports Dual/Quad SPI operation because other protocols do not require a
MUX logic to exist outside the design.
Figure 155 shows the I/O mapping of DW_apb_ssi in Quad mode with another SPI device that supports the Quad mode.
As illustrated in Figure 155, the IO[1] pin is used as DO in standard SPI mode of operation and it is connected to rxd[1]
pin, which will be sampling the input in the standard mode of operation.
txd[2]
IO Buffer IO[2]
rxd[2]
txd[1]
IO Buffer IO[1]/DO
rxd[1]
txd[0]
IO Buffer IO[0]/DI
rxd[0]
In standard operations, data transfer in SPI modes occur on either the positive or negative edge of the clock. For
improved throughput, the dual data-rate transfer can be used for reading or writing to the memories.
• Address and data are transmitted (or received in case of data) in DDR format, while instruction is transmitted in
standard format.
• Instruction, address, and data are all transmitted or received in DDR format.
The DDR_EN (SPI_CTRLR0[16]) bit is used to determine if the Address and data have to be transferred in DDR mode and
INST_DDR_EN (SPI_CTRLR0[17]) bit is used to determine if Instruction must be transferred in DDR format. These bits
are only valid when the CTRLR0.SPI_FRF bit is set to be in Dual, or Quad mode.
Figure 156 describes a DDR write transfer where instructions are continued to be transmitted in standard format. In
Figure 156, the value of N will be 7 if CTRLR0.SPI_FRF is set to 11b, 3 if CTRLR0.SPI_FRF is set to 10b , and 1 if
CTRLR0.SPI_FRF is set to 01b.
txd[N:0]
INST A3 A2 A1 A0 D3 D2 D1 D0
rxd[N:0]
ss_oe_n[N:0]
Figure 157 describes a DDR write transfer where instruction, address and data all are transferred in DDR format.
ssi_oe_n[N:0]
NOTE
In DDR mode, data is transmitted on both edges so that it is difficult to sample data correctly. DW_apb_ssi uses an
internal register to determine the edge on which the data should be transmitted. This will ensure that the receiver is able
to get a stable data while sampling. The internal register (DDR_DRIVE_EDGE) determines the edge on which the data is
transmitted. DW_apb_ssi sends data with respect to baud clock, which is an integral multiple of the internal clock
(ssi_clk * BAUDR). The data needs to be transmitted within half clock cycle (BAUDR/2), therefore the maximum value
for DDR_DRIVE_EDGE is equal to [(BAUDR/2)-1]. If the programmed value of DDR_DRIVE_EDGE is 0 then data is
transmitted edge-aligned with respect to sclk_out (baud clock). If the programmed value of DDR_DRIVE_EDGE is one
then the data is transmitted one ssi_clk before the edge of sclk_out.
NOTE
If the baud rate is programmed to be two, then the data will always be edge aligned.
Figure 158, Figure 159, and Figure 160 show examples of how data is transmitted using different values of the
DDR_DRIVE_EDGE register. The green arrows in these examples represent the points where data is driven. Baud rate
used in all these examples is 12. In Figure 158, transmit edge and driving edge of the data are the same. This is default
behavior in DDR mode.
txd[N:0] INST A3 A2 A1 A0 D3 D2 D1 D0
rxd[N:0]
ssi_oe_n[N:0]
Figure 158 shows the default behavior in which the transmit and driving edge of the data is the same.
DDR_DRIVE_EDGE = 1 sclk_out
ss_0_n
txd[N:0] INST A3 A2 A1 A0 D3 D2 D1 D0
rxd[N:0]
ssi_oe_n[N:0]
txd[N:0] INST A3 A2 A1 A0 D3 D2 D1 D0
rxd[N:0]
ssi_oe_n[N:0]
The eXecute In Place (XIP) mode enables transfer of SPI data directly through the APB interface without writing the data
register of DW_apb_ssi. XIP mode is enabled in DW_apb_ssi when the XIP cache is enabled. This control signal
indicates whether APB transfers are register read-write or XIP reads. When in XIP mode, DW_apb_ssi expects only read
request on the APB interface. This request is translated to SPI read on the serial interface and soon after the data is
received, the data is returned to the APB interface in the same transaction.
NOTE
The address length is derived from the SPI_CTRLR0.ADDR_L field, and relevant bits from paddr ([SPI_CTRLR0.ADDR_L-
1:0]) are transferred as address to the SPI interface. XIP address is managed by the XIP cache controller.
The XIP operation is supported only in enhanced SPI modes (Dual, Quad) of operation. Therefore, the CTRLR0.SPI_FRF
bit should not be programmed to 0. An XIP read operation is divided into two phases:
• Address phase
• Data phase
For an XIP read operation
1. Set the SPI frame format and data frame size value in CTRLR0 register. Note that the value of the maximum data
frame size is 32.
2. Set the Address length, Wait cycles, and transaction type in the SPI_CTRLR0 register. Note that the maximum
address length is 32.
After these settings, a user can initiate a read transaction through the APB interface which will transferred to SPI
peripheral using programmed values. Figure 161 shows the typical XIP transfer. The Value of N = 1, 3 and 7 for SPI
mode Dual, and Quad modes, respectively.
NOTE
When the DW_apb_ssi interfaces to the DMA controller, the DMA controller is always a flow controller; that is, it
controls the block size. This must be programmed by software in the DMA controller.
The DW_apb_ssi uses two DMA channels, one for the transmit data and one for the receive data. The DW_apb_ssi has
these DMA registers:
DMACR
Control register to enable DMA operation.
DMATDLR
Register to set the transmit the FIFO level at which a DMA request is made.
DMARDLR
Register to set the receive FIFO level at which a DMA request is made.
The DW_apb_ssi uses the following handshaking signals to interface with the DMA controller.
• dma_tx_req
• dma_tx_single
• dma_tx_ack
• dma_rx_req
• dma_tx_req
• dma_tx_single
• dma_tx_ack
• dma_rx_req
To enable the DMA Controller interface on the DW_apb_ssi, you must write the DMA Control Register (DMACR). Writing
a 1 into the TDMAE bit field of DMACR register enables the DW_apb_ssi transmit handshaking interface. Writing a 1 into
the RDMAE bit field of the DMACR register enables the DW_apb_ssi receive handshaking interface.
Table 588 provides description for different DMA transmit data level values.
0000_0001 dma_tx_req is asserted when one or less data entry is present in the transmit FIFO
0000_0010 dma_tx_req is asserted when two or less data entries are present in the transmit FIFO
… …
0000_1101 dma_tx_req is asserted when 13 or less data entries are present in the transmit FIFO
0000_1110 dma_tx_req is asserted when 14 or less data entries are present in the transmit FIFO
0000_1111 dma_tx_req is asserted when 15 or less data entries are present in the transmit FIFO
Table 589 provides description for different DMA Receive Data Level values.
0000_0001 dma_rx_req is asserted when two or more data entries are present in the receive FIFO
0000_0010 dma_rx_req is asserted when three or more data entries are present in the receive FIFO
… …
0000_1101 dma_rx_req is asserted when 14 or more data entries are present in the receive FIFO
0000_1110 dma_rx_req is asserted when 15 or more data entries are present in the receive FIFO
0000_1111 dma_rx_req is asserted when 16 data entries are present in the receive FIFO
As a block flow control device, the DMA Controller is programmed by the processor with the number of data items
(block size) that are to be transmitted or received by the DW_apb_ssi.
The block is broken into a number of transactions, each initiated by a request from the DW_apb_ssi. The DMA Controller
must also be programmed with the number of data items (in this case, DW_apb_ssi FIFO entries) to be transferred for
each DMA request. This is also known as the burst transaction length.
Figure 162 shows a single block transfer, where the block size programmed into the DMA Controller is 12 and the burst
transaction length is set to four. In this case, the block size is a multiple of the burst transaction length; therefore, the
DMA block transfer consists of a series of burst transactions.
CAUTION
On RP2040, the burst transaction length of the SSI’s DMA interface is fixed at four transfers. SSI.DMARDLR must always
be equal to 4, which is the value it takes at reset. The SSI will then request a single transfer when it has between one
and three items in its FIFO, and a 4-burst when it has four or more.
Figure 162.
Breakdown of DMA 12 Data Items
Transfer into Burst
Transactions. Block
size,
DMA
DMA.CTLx.BLOCKS Multi-block Transfer
_TS = 12. Number of Level
data items per source
burst transaction,
12 Data Items
DMA.CTLx.SRC_MS
IZE = 4. SSI receive
DMA
FIFO watermark level,
SSI.DMARDLR + 1 =
Block
DMA.CTLx.SRC_MS Level
IZE = 4
If the DW_apb_ssi makes a transmit request to this channel, four data items are written to the DW_apb_ssi transmit
FIFO. Similarly, if the DW_apb_ssi makes a receive request to this channel, four data items are read from the
DW_apb_ssi receive FIFO. Three separate requests must be made to this DMA channel before all 12 data items are
written or read.
When the block size programmed into the DMA Controller is not a multiple of the burst transaction length, as shown in
Figure 163, a series of burst transactions followed by single transactions are needed to complete the block transfer.
Control and status registers within the DW_apb_ssi are byte-addressable. The maximum width of the control or status
register in the DW_apb_ssi is 16 bits. Therefore all read and write operations to the DW_apb_ssi control and status
registers require only one APB access.
The data register (DR) within the DW_apb_ssi is 32 bits wide in order to remain consistent with the maximum serial
transfer size (data frame). An APB write operation to DR moves data from pwdata into the transmit FIFO buffer. An APB
read operation from DR moves data from the receive FIFO buffer onto prdata.
NOTE
The DR register in the DW_apb_ssi occupies sixty-four 32-bit locations of the memory map to facilitate AHB burst
transfers. There are no burst transactions on the APB bus itself, but DW_apb_ssi supports the AHB bursts that
happen on the AHB side of the AHB/APB bridge. Writing to any of these address locations has the same effect as
pushing the data from the pwdata bus into the transmit FIFO. Reading from any of these locations has the same
effect as popping data from the receive FIFO onto the prdata bus. The FIFO buffers on the DW_apb_ssi are not
addressable.
Description
Control register 0
31:25 Reserved. - - -
23 Reserved. - - -
Description
Master Control register 1
31:16 Reserved. - - -
Description
SSI Enable
31:1 Reserved. - - -
Description
Microwire Control
31:3 Reserved. - - -
Description
Slave enable
31:1 Reserved. - -
Description
Baud rate
31:16 Reserved. - - -
Description
TX FIFO threshold level
31:8 Reserved. - - -
Description
RX FIFO threshold level
31:8 Reserved. - - -
Description
TX FIFO level
31:8 Reserved. - - -
Description
RX FIFO level
31:8 Reserved. - - -
SSI: SR Register
Offset: 0x28
Description
Status register
31:7 Reserved. - - -
Description
Interrupt mask
31:6 Reserved. - - -
Description
Interrupt status
31:6 Reserved. - - -
Description
Raw interrupt status
31:6 Reserved. - - -
Description
TX FIFO overflow interrupt clear
31:1 Reserved. - -
Description
RX FIFO overflow interrupt clear
31:1 Reserved. - -
Description
RX FIFO underflow interrupt clear
31:1 Reserved. - -
Description
Multi-master interrupt clear
31:1 Reserved. - -
Description
Interrupt clear
31:1 Reserved. - -
Description
DMA control
31:2 Reserved. - - -
Description
DMA TX data level
31:8 Reserved. - - -
Description
DMA RX data level
31:8 Reserved. - - -
Description
Identification register
Description
Version ID
Table 614.
Bits Name Description Type Reset
SSI_VERSION_ID
Register
31:0 SSI_COMP_VERSI SNPS component version (format X.YY) RO 0x3430312a
ON
Description
Data Register 0 (of 36)
Description
RX sample delay
Table 616.
Bits Name Description Type Reset
RX_SAMPLE_DLY
Register
31:8 Reserved. - - -
Description
SPI control
Table 617.
Bits Name Description Type Reset
SPI_CTRLR0 Register
31:24 XIP_CMD SPI Command to send in XIP mode (INST_L = 8-bit) or to RW 0x03
append to Address (INST_L = 0-bit)
23:19 Reserved. - - -
15:11 WAIT_CYCLES Wait cycles between control frame transmit and data RW 0x00
reception (in SCLK cycles)
10 Reserved. - - -
7:6 Reserved. - - -
Description
TX drive edge
Table 618.
Bits Name Description Type Reset
TXD_DRIVE_EDGE
Register
31:8 Reserved. - - -
5.1. Package
Figure 164. Top down
view (left, top) and
side view (right, top),
along with bottom
view (left, bottom) of
the RP2040 QFN-56
package
PIN 1
NOTE
There is no standard size for the central GND pad (or ePad) with QFNs. However, the one on RP2040 is smaller than
most. This means that standard 0.4mm QFN-56 footprints provided with CAD tools may need adjusting. This gives
the opportunity to route between the central pad and the ones on the periphery, which can help with maintaining
power and ground integrity on cheaper PCBs. See Minimal Design Example for an example.
Figure 165.
Recommended PCB 7.75
Footprint for the 6.00
RP2040 QFN-56 3.20
package
0.20
7.75 6.00 3.20 5.40
0.20
0.875 1.175
0.40
5.40
Dimensions in mm
5.1.2. Compliance
RP2040 is compliant to Moisture Sensitivity Level 1.
RP2040 is compliant to the requirement of REACH Substances of Very High Concern (SVHC) that ECHA announced on
25 June 2020.
RP2040 is compliant to the requirement and standard of Controlled Environment-related Substance of RoHS directive
(EU) 2011/65/EU and directive (EU) 2015/863.
5.2. Pinout
In the following GPIO Pin table (Table 620), the pin types are defined as shown below.
Digital In Input only Standard Digital. Programmable Pull-Up, Pull-Down, Slew Rate,
Schmitt Trigger and Drive Strength. Default Drive Strength is 4mA.
Digital IO Bi-directional
Digital In (FT) Input only Fault Tolerant Digital. These pins are described as Fault Tolerant,
which in this case means that very little current flows into the pin
whilst it is below 3.63V and IOVDD is 0V. There is also enhanced ESD
Digital IO (FT) Bi-directional protection on these pins. Programmable Pull-Up, Pull-Down, Slew Rate,
Schmitt Trigger and Drive Strength. Default Drive Strength is 4mA.
Digital IO / Analogue Bi-directional (digital), Standard Digital and ADC input. Programmable Pull-Up, Pull-Down,
Input (Analogue) Slew Rate, Schmitt Trigger and Drive Strength. Default Drive Strength
is 4mA.
USB IO Bi-directional These pins are for USB use, and contain internal pull-up and pull-down
resistors, as per the USB specification. Note that external 27Ω series
resistors are required for USB operation.
Analogue (XOSC) Oscillator input pins for attaching a 12MHz crystal. Alternatively, XIN
may be driven by a square wave.
Table 624.
Name Number Type Power Domain Reset State Description
Miscellaneous pins
Case TC -20 85 °C
Temperature
Pull-Down RPD 50 80 kΩ
Resistance
See Section 2.16 for more details on the Oscillator, and Minimal Design Example for information on crystal usage.
The GPIOs on RP2040 have four different output drive strengths, which are nominally called 2, 4, 8 and 12mA modes.
These are not hard limits, nor do they mean that they will always be sourcing (or sinking) the selected amount of
milliamps. The amount of current a GPIO sources or sinks is dependant on the load attached to it. It will attempt to drive
the output to the IOVDD level (or 0V in the case of a logic 0), but the amount of current it is able to source is limited,
which will be dependant on the selected drive strength. Therefore the higher the current load is, the lower the voltage
will be at the pin. At some point, the GPIO will be sourcing so much current, that the voltage is so low, it won’t be
recognised as a logic 1 by the input of a connected device. The purpose of the output specifications in Table 630 are to
try and quantify how much lower the voltage can be expected to be, when drawing specified amounts of current from
the pin.
The Output High Voltage (VOH) is defined as the lowest voltage the output pin can be when driven to a logic 1 with a
particular selected drive strength; e.g., 4mA being sourced by the pin whilst in 4mA drive strength mode. The Output
Low Voltage is similar, but with a logic 0 being driven.
In addition to this, the sum of all the IO currents being sourced (i.e. when outputs are being driven high) from the IOVDD
bank (essentially the GPIO and QSPI pins), must not exceed IIOVDD_MAX. Similarly, the sum of all the IO currents being sunk
(i.e. when the ouputs are being driven low) must not exceed IIOVSS_MAX.
Figure 167 shows the effect on the output voltage as the current load on the pin increases. You can clearly see the
effect of the different drive strengths; the higher the drive strength, the closer the output voltage is to IOVDD (or 0V) for
a given current. The minimum VOH and maximum VOL limits are shown in red. You can see that at the specified current
for each drive strength, the voltage is well within the allowed limits, meaning that this particular device could drive a lot
more current and still be within VOH/VOL specification. This is a typical part at room temperature, there will be a spread of
other devices which will have voltages much closer to this limit. Of course, if your application doesn’t need such tightly
controlled voltages, then you can source or sink more current from the GPIO than the selected drive strength setting, but
experimentation will be required to determine if it indeed safe to do so in your application, as it will be outside the scope
of this specification.
a
If IOVDD <2.5V, GPIO VOLTAGE_SELECT registers should be adjusted accordingly. See Section 2.9 for details.
b
ADC performance will be compromised at voltages below 2.97V
NOTE
For power consumption of the Raspberry Pi Pico, please see the Raspberry Pi Pico Datasheet.
Firstly, 'Popcorn' (Media player demo) using the VGA, SD Card, and Audio board. This demo uses VGA video, I2S audio
and 4-bit SD Card access, with a system clock frequency of 48MHz.
NOTE
For more details of the VGA board see the Hardware design with RP2040 book.
Secondly, the BOOTSEL mode of RP2040. These measurements are made both with and without USB activity on the
bus, using a Raspberry Pi 4 as a host.
The third use-case uses the hello_dormant binary which puts RP2040 into a low power state, DORMANT mode.
The final use-case uses the hello_sleep binary code which puts RP2040 into a low power state, SLEEP mode.
Table 635 has two columns per power supply, 'Typical Average Current' and 'Maximum Average Current'. The former is
the current averaged over several seconds that you might expect a typical RP2040 to consume at room temperature
and nominal voltage (e.g., DVDD=1.1V, IOVDD=3.3V, etc). The 'Maximum Average Current' is the maximum current
consumption (again averaged over several seconds) you might expect to see on a worst-case RP2040 device, across
the temperature extremes, and maximum voltage (e.g., DVDD=1.21V, etc).
NOTE
The 'Popcorn' consumption measurements are heavily dependant on the video being displayed at the time. The
'Typical' values are obtained over several seconds of video, with varied colour and intensity. The 'Maximum' values
are measured during periods of white video, when the required current is at its highest.
Software Use- Typical Max. Average Typical Max. Average Typical Max. Average Units
case Average DVDD DVDD current Average IOVDD current Average USB_VDD
Current IOVDD Current USB_VDD current
Current
Standard types
RW
The processor can write to this field and read the value back.
RO
The processor can only read this field.
WO
The processor can only write to this field.
Clear types
SC
This is a single bit that is written to by the processor and then cleared on the next clock cycle. An example use of this
would be a start bit that triggers an event, and then clears again so the event doesn’t keep triggering.
WC
This is a single bit that is typically set by a piece of hardware and then written to by the processor to clear the bit. The
bit is cleared by writing a 1, using either a normal write or the clear alias. See Section 2.1.2 for more information about
the clear alias.
FIFO types
These fields are implementation specific.
RF
Implementation defined read from the hardware.
WF
Implementation defined write to the hardware.
RWF
Implementation defined read to, and write from the hardware.
Appendix B: Errata
Hardware blocks are listed alphabetically. Errata are listed numerically under the relevant block.
Bootrom
RP2040-E9
Reference RP2040-E9
Description The XIP cache can be used as an additional 16 kB SRAM bank when XIP caching is disabled (Section
2.6.3.1). The UF2 bootloader supports RAM-only UF2 binaries, which it loads directly into memory, and
enters via a watchdog reboot. A single UF2 binary can initialise both the XIP cache contents and main
system memory, and the cache is disabled by the bootloader, so that cache contents be written.
However, the watchdog reset re-enables the cache, so booting directly into the cache-as-SRAM alias
causes an immediate bus fault. The cache contents are preserved, but can not be accessed immediately
post-boot.
Workaround Add code in main SRAM to re-disable XIP caching before accessing the cache-as-SRAM alias. When
entering a RAM-only UF2 binary, the bootloader selects the lowest loaded address in either main SRAM or
cache-as-SRAM as the entry point, preferring main SRAM if both are loaded.
Additionally, if the 0x15… segment is written immediately post-boot, a dummy read of the FLUSH register
is required, so that no cache-as-SRAM writes take place during the tag memory flush triggered by the
watchdog (see Section 2.6.3.2).
Fixed by Documentation
Clocks
RP2040-E7
Reference RP2040-E7
Description The ROSC and XOSC COUNT registers are intended to be used in the configuration of components like PHYs
and PLLs where microsecond scale delays are required and NOP loops are inadequate because the
clk_sys frequency is variable. However due to a synchronisation issue the ROSC:COUNT and
XOSC:COUNT registers are unreliable.
Fixed by Not fixed, do not use. These registers are not used by the C SDK.
Bootrom 640
RP2040 Datasheet
GPIO / ADC
RP2040-E6
Reference RP2040-E6
Summary GPIO digital inputs not disabled for ADC pins by default
Description GPIO26-29 are shared with ADC inputs AIN0-3. The GPIO digital input is enabled after RUN is released. If
the pins are connected to an analogue signal to measure, there could be unexpected signal levels on
these pads. This is unlikely to cause a problem as the digital inputs have hysteresis enabled by default.
Workaround If analogue inputs are used, the digital input should be disabled as early as possible after startup.
Fixed by Software. Fixed in SDK, custom user code will need to take note.
USB
RP2040-E2
Reference RP2040-E2
Description The USB device controller (Section 4.1) has the ability to abort any pending transactions on an endpoint
by setting that endpoint’s bit in the EP_ABORT register. Due to a logic error, the USB device controller will
reply with NAKs forever on all endpoints if a transaction is initiated for any endpoint with the EP_ABORT
bit set.
RP2040-E3
Reference RP2040-E3
Summary USB host: interrupt endpoint buffer done flag can be set with incorrect buffer select.
Description The USB host has two types of transactions: normal software initiated transfer, and interrupt transfers,
where the host polls an interrupt endpoint after a specific amount of time. For example, polling a mouse
every 1ms to check for movement. Interrupt transfer are single buffered, but the controller doesn’t reset
the buffer selector to zero. This means that if a software initiated transfer happened then the interrupt
transfer can potentially raise the buffer done flag with BUF1 selected instead of BUF0. The fix is to ignore the
BUFF_CPU_SHOULD_HANDLE register for interrupt endpoints.
Workaround
Fixed by Software
RP2040-E4
Reference RP2040-E4
Summary USB host writes to upper half of buffer status in single buffered mode.
Description The USB host maintains a buffer selector which switches between BUF0 and BUF1. This should only be
toggled in double buffered mode but is toggled in single buffered mode too. For a transaction lasting
multiple packets (i.e. length more than 8 bytes in low speed mode, and length more than 64 bytes in full
speed mode), the buffer status can be written back to the BUF1 half of the status register when the buffer
select is incorrectly set to BUF1. Note this does not affect reading new buffer information from the buffer
control register, as the controller ignores the buffer selector in single buffered mode when reading the
buffer control register.
Workaround Shift endpoint control register to the right by 16 bits if the buffer selector is BUF1. You can use
BUFF_CPU_SHOULD_HANDLE find the value of the buffer selector when the buffer was marked as done.
Fixed by Software
RP2040-E5
Reference RP2040-E5
Summary USB device fails to exit RESET state on busy USB bus.
Description The USB bus RESET state is triggered by the host sending SE0 for 10ms to the device. The USB device
controller requires 800μs of idle (J-state) after a bus reset before moving to the CONNECTED state. Without
this idle time, the USB device does not connect and will not receive any packets from the host, and so
does not enumerate.
A device reset happens just after the device is plugged in. Although a host will wait before talking to a
reset device, other devices attached to the same USB hub may also be communicating with the host.
USB 2.0 and USB 3.0 hubs have one or more transaction translators, which facilitate low speed and full
speed transactions on a higher speed bus. It depends on the hub design, but a transaction translator is
usually shared between a few ports.
As the RP2040 USB device is full speed, its traffic when connected to a hub will come via a transaction
translator. This means that if you have another device plugged in next to an RP2040, the RP2040 is likely
to see some messages from the host addressed to the other device. If the device is not very active, for
example, a mouse that is polled every 8ms, this is not a problem. However some devices, such as a USB
serial port, are polled every 30-50μs. In this case the bus is very active, and will cause the RP2040 to never
exit RESET state and not connect.
There is a software workaround for this issue (see workaround section). A user can also work around this
by closing the USB serial port or any other offending devices while connecting their RP2040 and then re
opening their USB serial port.
On a larger hub, the problem may be fixed by moving the RP2040 far away (onto a different transaction
translator) from the offending device. For example, connecting the RP2040 to port 1 of a 7 port hub, and
connecting the USB serial console to port 7, may solve the issue. Connecting the RP2040 to a separate
USB hub to any busy devices will also fix the problem.
USB 642
RP2040 Datasheet
Workaround Use software to force USB device controller to see idle USB bus for 800μs to move the device from the
RESET state to the CONNECTED state. This fix uses internal debug logic that is connected to GPIO15 for a short
amount of time (~800μs). This forces the controller to see DP as a logical 1 (and DM and logical 0) to
make the USB Device controller believe there is a J-state on the USB bus. GPIO15 does not need to be tied
in any particular way for this fix to work. Instead, we can force the input path in software using the Section
2.19 input override feature. See https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/
pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c.
Fixed by Not fixed. Software workaround on RP2040B0, RP2040B1. The workaround isn’t present in the USB mass
storage code in the bootrom. The software workaround requires use of GPIO15 during USB bus reset.
Watchdog
RP2040-E1
Reference RP2040-E1
Description The watchdog (Section 4.7) has a 24-bit counter, that decrements every tick, starting from a user defined
value set in LOAD register. There is a logic error which means the counter is decremented twice per tick,
instead of once per tick. In a recommended setup where the tick occurs at 1μs intervals, this halves the
maximum time between resetting the watchdog counter from ~16.7 seconds to ~8.3 seconds.
XIP Flash
RP2040-E8
Reference RP2040-E8
Summary Race condition when aborting an XIP DMA stream and immediately starting a new stream
Description The XIP DMA streaming hardware allows a linear sequences of flash reads to proceed in the background,
and be read by the DMA, without subjecting the DMA to the bus stalls caused by a normal XIP-window
access. A stream is begun by writing to the STREAM_ADDR register, followed by STREAM_CTR, and can
be aborted midway by writing 0 to STREAM_CTR.
When a stream is aborted in this way, there is sufficient time for software to load a new address and
begin a new stream whilst the final SPI/QSPI access of the aborted stream is still in progress. This
causes the newly-loaded stream address to be incremented once before the first data transfer of the new
stream sequence, so the entire stream takes place at a 4-byte offset.
Watchdog 643
RP2040 Datasheet
Workaround After clearing STREAM_CTR, immediately perform one dummy read from the uncached XIP window, e.g.
(void)*(io_ro_32*)XIP_NOCACHE_NOALLOC_BASE;. If an XIP stream transfer is still in progress, this dummy read
will stall until that transfer completes. It is then safe to begin a new stream by writing to STREAM_ADDR
followed by STREAM_CTR.