GPIO
Every tile pad can be plain digital I/O — and you can drive it at whichever layer suits you. core_pad addresses pads by their tile pad number, hal_pad sits on the same pad model one tier down, and ll_gpio works in raw MCU port + pin. Use the Core / HAL / LL toggle at the top of the sidebar to switch.
Overview
GPIO is digital I/O on any tile pad. How you address it depends on the layer:
The core_pad surface (in core.h) addresses a pad by the number printed on the tile, and the SDK resolves it to the right MCU port and pin. There are two ways to set a pad up:
- Declare it in
config.json(gpio.<pad>) — coregen configures it duringcore_init(), and you just call the Tier 2 verbs (write/read/toggle). This is what Studio generates. - Configure it at runtime with the Tier 1 calls (
core_pad_output,core_pad_input, …) when you want full control in C.
Digital output
Configure a pad as a push-pull output, then drive it. ON / OFF read more clearly than 1 / 0:
#include "core.h"
core_pad_output(3); // push-pull output
core_pad_write(3, ON); // drive high
core_pad_toggle(3); // flip itIf pad 3 is declared as an output in config.json, the core_pad_output(3) line is unnecessary — coregen has already configured it, and core_pad_write / toggle just work.
Digital input
Configure a pad as an input with a pull resistor, then read it (returns 0 or 1). A button to ground reads active-low with a pull-up:
core_pad_input(5, PULL_UP); // input, idles high
bool pressed = !core_pad_read(5); // pressed pulls it lowPull resistors, output type & slew
Three knobs shape how a pad drives or reads:
- Pull —
PULL_UP,PULL_DOWN, orPULL_NONEon an input, so a floating line idles at a known level. - Output type — push-pull (the default) actively drives both rails; open-drain only pulls low and floats high, for wired-AND or I²C-style buses:
core_pad_output_od(4, PULL_UP); // open-drain, internal pull-up (wired-AND)- Slew rate —
core_pad_speed(pad, SPEED_LOW … SPEED_VHIGH)trades edge sharpness against EMI. It affects outputs only.
write / read / toggle; pull, drive type, and slew are set in config.json or via the Tier 1 C calls. (Direct DSL access to those knobs is a known gap on the coverage table.)Edge events (EXTI)
Instead of polling, register an edge-triggered callback. The pad is auto-configured as an input with a sensible pull for the edge — rising → pull-down, falling → pull-up, both → no pull (external bias expected):
#include "core.h"
void on_motion(uint8_t pad, void *ctx) {
(void)pad; (void)ctx;
core_led_toggle();
}
core_pad_on_change(6, FALLING, on_motion, NULL); // fire on the falling edge
// ... core_pad_on_change_stop(6); when you're doneIn Studio, the same edges surface as the Core.Pad.rising and Core.Pad.falling events (payload: the pad number), for any pad whose config.json enables gpio.<pad>.exti.
Cross-architecture support
GPIO is the most fundamental peripheral, so it’s brought up first on every Core. The same core_pad API is the contract across architectures — only the layers beneath it are re-implemented per MCU family.
See the implementation status for the full matrix.
API reference
void core_pad_write(uint8_t pad, int state);int core_pad_read(uint8_t pad);void core_pad_toggle(uint8_t pad);void core_pad_output(uint8_t pad);void core_pad_output_od(uint8_t pad, uint32_t pull);void core_pad_input(uint8_t pad, uint32_t pull);core_pad_fast_t core_pad_resolve(uint8_t pad);void core_pad_fast_set(core_pad_fast_t h);void core_pad_fast_clear(core_pad_fast_t h);void core_pad_fast_write(core_pad_fast_t h, int state);int core_pad_fast_read(core_pad_fast_t h);void core_pad_bulk_write(GPIO_TypeDef * port, uint32_t set_mask, uint32_t clear_mask);void core_pad_analog(uint8_t pad);void core_pad_speed(uint8_t pad, uint32_t speed);hal_status_t core_pad_on_change(uint8_t pad, uint32_t edge, hal_callback_t cb, void * ctx);void core_pad_on_change_stop(uint8_t pad);Generated from core_pad.h — tiles@777be99.

