Now, let's blink an LED using the Arduino IDE and the Xiao RP2350. I'm going to use a really handy YouTube video by Xeno Kovah: Arch1005: RISC-V Assembly 13 Writing Assembly 02 GCC Inline Assembly. This opens up the possibility of using "extended" assembler to allow for the passing of values between your C and Assembler code -- very handy when you have hybrid C/C++ and Assembler code.
Here, I'm just going to use standard inline assembler calls. Nothing fancy, nothing clever. Addresses will be written out explicitly, too. No shortcuts on those.
The result? Blinking LED.

Here is the simpleBlink_rp2350_v4_inlineASM.ino file:
/* simpleBlink_rp2350_v4_inlineASM.ino
* James Andrew Smith, Dec 10, 2025
*
* Blink the LED on the Xiao RP2350 board once every two seconds (2s period).
* Use inline assembler rather than Arduino C++ function calls.
*
* References:
* 1. Xeno Kovah, "Arch1005: RISC-V Assembly 13 Writing Assembly 02 GCC Inline Assembly", https://www.youtube.com/watch?v=5s2Do6uNBL0, Jan 28 2025.
* 2. Igor Michalak, "Bare Metal RP2350", https://github.com/igormichalak/bare-metal-rp2350, April 2, 2025
* 3. Raspberry Pi Ltd, "RP2350 Datasheet -- A microcontroller by Raspberry Pi" (version d126e9e-clean), https://pip-assets.raspberrypi.com/categories/1214-rp2350/documents/RP-008373-DS-2-rp2350-datasheet.pdf, July 29, 2025
* 4. Seeed Studio, "Seeed Studio XIAO RP2350 with Arduino", https://wiki.seeedstudio.com/xiao_rp2350_arduino/, Nov, 2024.
* */
void setup() {
// Set up LED on GPIO 25 in assembler
// C++ equivalent: pinMode(LED_BUILTIN,OUTPUT);
// Put 0x1f in address 0x40028000 + 0x0cc + 0x3000 = 0x4002B0CC
asm volatile("li t0, 0x1f");
asm volatile("li t1, 0x4002B0CC"); // IO_BANK0_GPIO25_CTRL+ATOMIC_CLEAR = 0x4002B0CC
asm volatile("sw t0, (t1)");
// Put 0x05 in address 0x40028000 + 0x0cc + 0x2000 = 0x4002A0CC
asm volatile("li t0, 0x05");
asm volatile("li t1, 0x4002A0CC"); // IO_BANK0_GPIO25_CTRL+ATOMIC_SET = 0x4002A0CC
asm volatile("sw t0, (t1)");
// Put 0b0000 0010 0000 0000 0000 0000 0000 00000 in 0xd0000000+0x038
asm volatile("li t0, (1<<25)");
asm volatile("li t1, 0xd0000038"); // SIO_GPIO_OE_SET = SIO_BASE+0x038 = 0xd0000038
asm volatile("sw t0, (t1)");
// Put 0x0000 0000 0000 0000 0000 0001 1000 0000 in 0x40038000+0x68+0x3000
asm volatile("li t0, (1<<7)|(1<<8)");
asm volatile("li t1, 0x4003B068"); // PADS_BANK0_GPIO25+ATOMIC_CLEAR
asm volatile("sw t0, (t1)");
}
void loop() {
/* Desired sequence :
* 1. digitalWrite(LED_BUILTIN,1); // Set value (LED OFF)
* 2. delay(1000); // Wait 1000 ms.
* 3. digitalWrite(LED_BUILTIN,0); // Clear value (LED ON)
* 4. delay(1000); // Wait 1000 ms.
* */
// Step 1. digitalWrite(LED_BUILTIN,1);
asm volatile("li t0, (1<<25)"); // Put 25 mask in T0 (0b0000 0010 0000 0000 0000 0000 0000 0000)
asm volatile("li t1, 0xd0000018"); // Put SIO_GPIO_OUT_SET ("set") address in T1, SIO_BASE+0x018 where SIO_BASE is 0xd0000000
asm volatile("sw t0, (t1)"); // Store mask in SIO_GPIO_OUT_SET register.
// Step 2. Delay.
delay(1000);
// Step 3. digitalWrite(LED_BUILTIN,0);
asm volatile("li t0, (1<<25)"); // Put 25 mask in T0 (0b0000 0010 0000 0000 0000 0000 0000 0000)
asm volatile("li t2, 0xd0000020"); // Put SIO_GPIO_OUT_CLR ("clear") address in T2, SIO_BASE+0x020 where SIO_BASE is 0xd0000000
asm volatile("sw t0, (t2)"); // Store mask in SIO_GPIO_OUT_CLR register.
// Step 4. Delay.
delay(1000);
}
That's it. This code shows how to initialize the GPIO and turn GPIO 25 on and off via the SIO system and it uses "atomic" operations rather than rely on the GPIO "co-processor" system.

James Andrew Smith is a Professional Engineer and Associate Professor in the Electrical Engineering and Computer Science Department of York University’s Lassonde School, with degrees in Electrical and Mechanical Engineering from the University of Alberta and McGill University. Previously a program director in biomedical engineering, his research background spans robotics, locomotion, human birth, music and engineering education. While on sabbatical in 2018-19 with his wife and kids he lived in Strasbourg, France and he taught at the INSA Strasbourg and Hochschule Karlsruhe and wrote about his personal and professional perspectives. James is a proponent of using social media to advocate for justice, equity, diversity and inclusion as well as evidence-based applications of research in the public sphere. You can find him on Twitter. You can find him on BlueSky. Originally from Québec City, he now lives in Toronto, Canada.
