RP2350 UART Driver RISC-V

March 23, 2026 · View on GitHub

FREE Embedded Hacking Course HERE

VIDEO PROMO HERE


RP2350 UART Driver RISC-V

An RP2350 UART driver written entirely in RISC-V Assembler.


Install RISC-V Toolchain (Windows / RP2350 Hazard3)

Official Raspberry Pi guidance for RP2350 RISC-V points to pico-sdk-tools prebuilt releases.

Official References

  • RP2350 RISC-V quick start in pico-sdk: HERE
  • Tool downloads (official): HERE

Install (PowerShell)

$url = "https://github.com/raspberrypi/pico-sdk-tools/releases/download/v2.0.0-5/riscv-toolchain-14-x64-win.zip"
$zipPath = "$env:TEMP\riscv-toolchain-14-x64-win.zip"
$dest = "$HOME\riscv-toolchain-14"

Invoke-WebRequest -Uri $url -OutFile $zipPath
New-Item -ItemType Directory -Path $dest -Force | Out-Null
Expand-Archive -LiteralPath $zipPath -DestinationPath $dest -Force
Get-ChildItem -Path $dest | Select-Object Name

Add Toolchain To User PATH (PowerShell)

$toolBin = "$HOME\riscv-toolchain-14\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

riscv32-unknown-elf-as --version
riscv32-unknown-elf-ld --version
riscv32-unknown-elf-objcopy --version

Build This Project

.\build.bat

If your toolchain uses a different prefix, pass it explicitly:

.\build.bat riscv-none-elf

UART Terminal Setup (PuTTY)

  • Speed: 115200
  • Data bits: 8
  • Stop bits: 1
  • Parity: None
  • Flow control: None

UART Wiring (Pico 2 Target)

  • GP0 = UART0 TX (target output)
  • GP1 = UART0 RX (target input)
  • GND must be common between target and USB-UART adapter/debug probe
  • Cross wiring is required: adapter TX -> GP1, adapter RX -> GP0

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

Optional Toolchain Prefix Override

.\build.bat riscv-none-elf

Clean

.\clean.bat

Tutorial

A comprehensive 30-chapter technical book teaching RP2350 RISC-V assembly from absolute scratch. Every line of assembler is explained.

Foundations

Chapter 1: What Is a Computer?

Chapter 2: Number Systems — Binary, Hexadecimal, and Decimal

Chapter 3: Memory — Addresses, Bytes, Words, and Endianness

Chapter 4: What Is a Register?

Chapter 5: Load-Store Architecture — How RISC-V Accesses Memory

Chapter 6: The Fetch-Decode-Execute Cycle in Detail

RISC-V Instruction Set

Chapter 7: RISC-V ISA Overview

Chapter 8: RISC-V Immediate and Upper-Immediate Instructions

Chapter 9: RISC-V Arithmetic and Logic Instructions

Chapter 10: RISC-V Memory Access Instructions — Load and Store Deep Dive

Chapter 11: RISC-V Branch Instructions

Chapter 12: RISC-V Jumps, Calls, and Returns

Assembly Programming

Chapter 13: Pseudoinstructions — What the Assembler Does For You

Chapter 14: Assembler Directives — Controlling the Assembly Process

Chapter 15: The Calling Convention and Stack Frames

Chapter 16: Bitwise Operations for Hardware Programming

Hardware Concepts

Chapter 17: Memory-Mapped I/O — Controlling Hardware Through Addresses

Chapter 18: The RP2350 Microcontroller — Architecture and Hardware

Build System

Chapter 19: The Linker Script — Placing Code in Memory

Chapter 20: The Build Pipeline — From Assembly to UF2

Source Code Walkthroughs

Chapter 21: image_def.s — Boot Metadata Line by Line

Chapter 22: constants.s — Every Definition Explained

Chapter 23: stack.s and vector_table.s — Line by Line

Chapter 24: reset_handler.s — The Boot Sequence Line by Line

Chapter 25: xosc.s — Crystal Oscillator Initialization Line by Line

Chapter 26: reset.s — Releasing IO_BANK0 from Reset

Chapter 27: uart.s Part 1 — Release Reset and Initialization

Chapter 28: uart.s Part 2 — Transmit and Receive

Chapter 29: main.s — The Application Entry Point

Integration

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


main.s Code

/**
 * FILE: main.s
 *
 * DESCRIPTION:
 * RP2350 Bare-Metal UART Main Application (RISC-V).
 * 
 * BRIEF:
 * Main application entry point for RP2350 RISC-V UART driver. Contains the
 * main loop that echoes UART input to output.
 *
 * AUTHOR: Kevin Thomas
 * CREATION DATE: November 2, 2025
 * UPDATE DATE: November 27, 2025
 */


.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 the infinite blink loop.
 *
 * @param   None
 * @retval  None
 */
.global main                                     # export main
.type main, @function                            # mark as function
main:
.Loop:
  call  UART0_In                                 # call UART0_In
  call  UART0_Out                                # call UART0_Out
  j     .Loop                                    # loop forever
  ret                                            # 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