BERGSONNE

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 during core_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 it

If 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 low

Pull resistors, output type & slew

Three knobs shape how a pad drives or reads:

  • PullPULL_UP, PULL_DOWN, or PULL_NONE on 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.
Studio exposes the verbs, not the knobs
The Tier 2 DSL exposes 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 done

In 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.

L0M0+L4M4W5M33H5M33WCH (RISC-V) · Nordic (nRF54) — in development

See the implementation status for the full matrix.

API reference

Default-instance · Tier 2
void core_pad_write(uint8_t pad, int state);
Set a pad high (ON) or low (OFF).
int core_pad_read(uint8_t pad);
Read a pad. Returns 0 or 1.
void core_pad_toggle(uint8_t pad);
Toggle a pad output.
Lower-level · Tier 1
void core_pad_output(uint8_t pad);
Configure a pad as push-pull output (default).
void core_pad_output_od(uint8_t pad, uint32_t pull);
Configure a pad as open-drain output with optional pull resistor. Use PULL_UP for a wired-AND / I2C-style bus, PULL_NONE for external pull.
void core_pad_input(uint8_t pad, uint32_t pull);
Configure a pad as input with pull resistor.
core_pad_fast_t core_pad_resolve(uint8_t pad);
Resolve a pad to a fast handle once, outside the hot loop.
void core_pad_fast_set(core_pad_fast_t h);
Drive the resolved pad high — single BSRR write.
void core_pad_fast_clear(core_pad_fast_t h);
Drive the resolved pad low — single BSRR write.
void core_pad_fast_write(core_pad_fast_t h, int state);
Drive the resolved pad to `state` (0/1) — single BSRR write.
int core_pad_fast_read(core_pad_fast_t h);
Read the resolved pad — single IDR load. Returns 0 or 1.
void core_pad_bulk_write(GPIO_TypeDef * port, uint32_t set_mask, uint32_t clear_mask);
Bulk update many pins on ONE port in a single atomic BSRR write: pins in `set_mask` go high, pins in `clear_mask` go low (set wins on overlap, per BSRR). Build the masks from the generated PAD_n_MASK defines. Useful for synchronized buses / LED matrices without per-pad jitter.
void core_pad_analog(uint8_t pad);
Configure a pad as analog (for ADC, DAC, comparator).
void core_pad_speed(uint8_t pad, uint32_t speed);
Set the output speed (slew rate) of a pad. Use SPEED_LOW / SPEED_MED / SPEED_HIGH / SPEED_VHIGH. Only affects outputs — input pads ignore this setting.
hal_status_t core_pad_on_change(uint8_t pad, uint32_t edge, hal_callback_t cb, void * ctx);
Register an edge-triggered callback on a pad. The pad is automatically configured as input with a sensible pull resistor based on edge direction: rising → pull-down (idle low) falling → pull-up (idle high) both → no pull (external bias expected)
void core_pad_on_change_stop(uint8_t pad);
Stop the interrupt on a pad.

Generated from core_pad.htiles@777be99.