RP2350 Button Driver

March 23, 2026 · View on GitHub

FREE Reverse Engineering Self-Study Course HERE

VIDEO PROMO HERE


RP2350 Button Driver

An RP2350 Button driver written entirely in ARM Assembler.


Install ARM Toolchain (Windows / RP2350 Cortex-M33)

Official Raspberry Pi guidance for RP2350 ARM recommends the Arm GNU Toolchain from developer.arm.com.

Official References

  • Raspberry Pi Pico SDK quick start: HERE
  • Tool downloads (official): HERE

Install (PowerShell)

$url = "https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-mingw-w64-x86_64-arm-none-eabi.zip"
$zipPath = "$env:TEMP\arm-toolchain-15-x64-win.zip"
$extractPath = "$env:TEMP\arm-extract"
$dest = "$HOME\arm-toolchain-15"

Invoke-WebRequest -Uri $url -OutFile $zipPath
Expand-Archive -LiteralPath $zipPath -DestinationPath $extractPath -Force
Move-Item "$extractPath\arm-gnu-toolchain-*" $dest -Force
Get-ChildItem -Path $dest | Select-Object Name

Add Toolchain To User PATH (PowerShell)

$toolBin = "$HOME\arm-toolchain-15\bin"
$currentUserPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($currentUserPath -notlike "*$toolBin*") {
  [Environment]::SetEnvironmentVariable("Path", "$currentUserPath;$toolBin", "User")
}

Close and reopen your terminal after updating PATH.

Verify Toolchain

arm-none-eabi-as --version
arm-none-eabi-ld --version
arm-none-eabi-objcopy --version

Build This Project

.\build.bat

Button + LED Wiring (Pico 2 Target)

  • GP15 (Pin 20) → tactile button → GND (internal pull-up enabled)
  • GP16 (Pin 21) → 330 ohm resistor → LED anode
  • LED cathode → GND (Pin 23)

Hardware

Raspberry Pi Pico 2 w/ Header BUY

USB A-Male to USB Micro-B Cable BUY

Raspberry Pi Pico Debug Probe BUY

Complete Component Kit for Raspberry Pi BUY

10pc 25v 1000uF Capacitor BUY

10% PiShop DISCOUNT CODE - KVPE_HS320548_10PC


Build

.\build.bat

Clean

.\clean.bat

Tutorial

Part I — Foundations (Chapters 1–6)

Chapter 1: What Is a Computer?

Chapter 2: Number Systems

Chapter 3: Memory

Chapter 4: What Is a Register?

Chapter 5: Load-Store Architecture

Chapter 6: Fetch-Decode-Execute Cycle in Detail

Part II — The ARM Instruction Set (Chapters 7–12)

Chapter 7: ARM Cortex-M33 ISA Overview

Chapter 8: Immediate and Upper-Immediate Instructions

Chapter 9: Arithmetic and Logic Instructions

Chapter 10: Memory Access — Load and Store Deep Dive

Chapter 11: Branch Instructions

Chapter 12: Jumps, Calls, and Returns

Part III — Assembly Programming (Chapters 13–17)

Chapter 13: Pseudo-Instructions

Chapter 14: Assembler Directives

Chapter 15: Calling Convention and Stack Frames

Chapter 16: Bitwise Operations for Hardware Programming

Chapter 17: Memory-Mapped I/O

Part IV — RP2350 Hardware (Chapter 18)

Chapter 18: The RP2350 — Architecture and Hardware

Part V — Build System (Chapters 19–20)

Chapter 19: The Linker Script — Placing Code in Memory

Chapter 20: The Build Pipeline — From Assembly to Flashable Binary

Part VI — Source Code Walkthroughs (Chapters 21–29)

Chapter 21: Boot Metadata — image_def.s

Chapter 22: Constants File — constants.s

Chapter 23: Stack and Vector Table — stack.s and vector_table.s

Chapter 24: Boot Sequence — reset_handler.s

Chapter 25: Oscillator Init — xosc.s

Chapter 26: Reset Controller — reset.s

Chapter 27: GPIO Configuration — gpio.s

Chapter 28: Button Driver — button.s

Chapter 29: Application Entry Point — main.s

Part VII — Full Integration (Chapter 30)

Chapter 30: Full Integration — Build, Flash, Wire, and Test


main.s Code

/**
 * FILE: main.s
 *
 * DESCRIPTION:
 * RP2350 Button Driver Main Application.
 * 
 * BRIEF:
 * Main application entry point for RP2350 button driver. Monitors button
 * on GPIO15 and controls LED on GPIO16 based on button state.
 *
 * AUTHOR: Kevin Thomas
 * CREATION DATE: November 2, 2025
 * UPDATE DATE: November 28, 2025
 */

.syntax unified                                  // use unified assembly syntax
.cpu cortex-m33                                  // target Cortex-M33 core
.thumb                                           // use Thumb instruction set

.include "constants.s"

/**
 * Initialize the .text section. 
 * The .text section contains executable code.
 */
.section .text                                   // code section
.align 2                                         // align to 4-byte boundary

/**
 * @brief   Main application entry point.
 *
 * @details Implements button monitoring loop. LED on GPIO16 lights up
 *          when button on GPIO15 is pressed.
 *
 * @param   None
 * @retval  None
 */
.global main                                     // export main
.type main, %function                            // mark as function
main:
.Push_Registers:
  push  {r4-r12, lr}                             // push registers r4-r12, lr to the stack
.GPIO16_Config:
  ldr   r0, =PADS_BANK0_GPIO16_OFFSET            // load PADS_BANK0_GPIO16_OFFSET
  ldr   r1, =IO_BANK0_GPIO16_CTRL_OFFSET         // load IO_BANK0_GPIO16_CTRL_OFFSET
  ldr   r2, =16                                  // load GPIO number
  bl    GPIO_Config                              // call GPIO_Config
.Button_Init:
  bl    Button_Init                              // initialize button on GPIO15
.Loop:
  bl    Button_Read                              // read button state (0=pressed, 1=released)
  cmp   r0, #0                                   // compare with 0 (pressed)
  beq   .Button_Pressed                          // branch if button pressed (r0==0)
.Button_Released:
  ldr   r0, =16                                  // load GPIO number
  bl    GPIO_Clear                               // turn off LED
  b     .Loop_Delay                              // continue to delay
.Button_Pressed:
  ldr   r0, =16                                  // load GPIO number
  bl    GPIO_Set                                 // turn on LED
.Loop_Delay:
  ldr   r0, =10                                  // 10ms debounce delay
  bl    Delay_MS                                 // call Delay_MS
  b     .Loop                                    // loop forever
.Pop_Registers:
  pop   {r4-r12, lr}                             // pop registers r4-r12, lr from the stack
  bx    lr                                       // return to caller

/**
 * Test data and constants.
 * The .rodata section is used for constants and static data.
 */
.section .rodata                                 // read-only data section

/**
 * Initialized global data.
 * The .data section is used for initialized global or static variables.
 */
.section .data                                   // data section

/**
 * Uninitialized global data.
 * The .bss section is used for uninitialized global or static variables.
 */
.section .bss                                    // BSS section

License

Apache License 2.0