Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MCU HAL

Flint’s MCU-facing standard library lives under micro/*.

The long-term goal is a broad, portable hardware abstraction layer that lets the same Flint source move between boards and chips with minimal rewriting. The current implementation is narrower than that vision, so this chapter only documents what is actually present in the repository today.

Implemented Today

These micro modules have real RP2040-backed APIs and working examples:

ModuleStatusWhat it provides
micro/gpioImplementedOutput GPIO setup, toggle, set high, set low, builtin LED lookup
micro/pwmImplementedPWM output setup and duty-cycle updates
micro/uartImplementedUART0 initialization and byte-by-byte TX output

micro/gpio

micro/gpio is the current foundation for board bring-up and LED examples.

Available surface today:

  • gpio.output(pin) returns an OutputPin
  • gpio.builtin_led() returns Option<OutputPin>
  • OutputPin.pin()
  • OutputPin.toggle()
  • OutputPin.set_high()
  • OutputPin.set_low()

Example:

use micro/gpio
use time/delay

fn main() {
    let builtin_led = gpio.builtin_led()
    if builtin_led.is_none() {
        return
    }

    if let Option.Some(led) = builtin_led {
        loop {
            led.toggle()
            delay.millis(500)
        }
    }
}

builtin_led() is intentionally optional because not every board has a directly usable onboard LED.

micro/pwm

micro/pwm builds on a resolved GPIO pin and configures it for PWM output.

Available surface today:

  • pwm.output(pin, top) returns a PwmPin
  • PwmPin.set_duty(duty)

Example:

use micro/gpio
use micro/pwm
use time/delay

fn main() {
    let builtin_led = gpio.builtin_led()
    if builtin_led.is_none() {
        return
    }

    if let Option.Some(pin) = builtin_led {
        let led = pwm.output(pin.pin(), 1000)

        loop {
            mut duty = 0
            while duty < 1000 {
                led.set_duty(duty)
                duty = duty + 10
                delay.millis(5)
            }

            while duty > 0 {
                led.set_duty(duty)
                duty = duty - 10
                delay.millis(5)
            }
        }
    }
}

The current implementation is tuned for RP2040 PWM slices and channels.

micro/uart

micro/uart currently exposes a small UART0 transmit path for debugging and bring-up.

Available surface today:

  • uart.init()
  • uart.write_byte(byte)

Example:

use micro/uart
use time/delay

fn write_hello() {
    uart.write_byte(72)
    uart.write_byte(105)
    uart.write_byte(10)
}

fn main() {
    uart.init()

    loop {
        write_hello()
        delay.millis(1000)
    }
}

Right now this is intentionally small and practical: enough to get serial output on RP2040 without needing an external runtime or SDK.

Present But Not Implemented Yet

These module files already exist in stdlib/micro, but they are still placeholders at the moment:

  • micro/adc
  • micro/i2c
  • micro/interrupt
  • micro/spi
  • micro/system
  • micro/timer

They are part of the intended HAL surface, but they should not be treated as available APIs yet.

Scope Today

The honest current picture is:

  • GPIO is usable.
  • PWM is usable.
  • UART TX is usable.
  • The rest of the MCU HAL surface is still being filled in.

That narrower surface is enough for real RP2040 bring-up work, and it gives the language a concrete place to prove out its embedded model before the broader HAL is expanded.