rlvgl 0.1.7

A modular, idiomatic Rust reimplementation of the LVGL graphics library for embedded and simulator use.
Documentation
{# HAL BSP generation template for rlvgl-creator. #}
/* Auto-generated by rlvgl-creator
 * SPDX-FileCopyrightText: 2020 STMicroelectronics
 * SPDX-FileCopyrightText: 2025 Softoboros Technology, Inc.
 * SPDX-License-Identifier: BSD-3-Clause
 * Provenance: STM32_open_pin_data (commit <hash>), build <build-hash>.
{% if meta is defined %}
 * Board: {{ meta.board }} ({{ meta.chip }})
{% endif %}
 */
{% if meta is defined %}
//! HAL BSP for {{ meta.board }}.
{% else %}
//! HAL BSP for the generated board.
{% endif %}
#![allow(non_snake_case)]
#![allow(clippy::too_many_arguments)]
{% if mod_name %}#![cfg(feature = "{{ mod_name }}")]{% endif %}

{# collect unique GPIO port letters #}
{% set ns = namespace(ports=[]) %}
{% for pin in spec.pinctrl %}
    {% if pin.pin[1] not in ns.ports %}{% set ns.ports = ns.ports + [pin.pin[1]] %}{% endif %}
{% endfor %}

{# derive HAL crate name from the MCU identifier #}
{% set crate = namespace(letters='', digits='', digits_started=false, stop=false) %}
{% for ch in spec.mcu[5:] %}
    {% if not crate.stop %}
        {% if ch >= 'A' and ch <= 'Z' %}
            {% if crate.digits_started %}
                {% set crate.stop = true %}
            {% else %}
                {% set crate.letters = crate.letters + ch %}
            {% endif %}
        {% elif ch >= '0' and ch <= '9' %}
            {% set crate.digits_started = true %}
            {% set crate.digits = crate.digits + ch %}
        {% else %}
            {% set crate.stop = true %}
        {% endif %}
    {% endif %}
{% endfor %}
{% set family = crate.letters | lower %}
{% set nums = crate.digits %}
{% if family == 'wb' %}
    {% set hal_crate = 'stm32wb_hal' %}
{% elif family == 'wl' %}
    {% set hal_crate = 'stm32wlxx_hal' %}
{% elif family == 'wba' %}
    {% set hal_crate = 'stm32wba_hal' %}
{% elif family == 'mp' %}
    {% set hal_crate = 'stm32mp1_hal' %}
{% else %}
    {% set hal_crate = 'stm32' + family + nums[0:1] + 'xx_hal' %}
{% endif %}
use {{ hal_crate }}::{gpio::Speed, pac, prelude::*{% for p in ns.ports %}, gpio{{ p|lower }}::*{% endfor %}};

{% macro gpio_bus(family) -%}
{% if family[0:7] == "STM32H7" %}ahb4enr
{% elif family[0:7] == "STM32H5" or family[0:7] == "STM32L5" or family[0:7] == "STM32L4" or family[0:7] == "STM32G4" %}ahb2enr
{% elif family[0:7] == "STM32G0" or family[0:7] == "STM32L0" %}iopenr
{% elif family[0:7] == "STM32F1" %}apb2enr
{% elif family[0:7] == "STM32F0" or family[0:7] == "STM32F3" or family[0:7] == "STM32L1" %}ahbenr
{% else %}ahb1enr{% endif %}
{%- endmacro %}
{% macro port_bit(p) -%}
{% set map = {"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25} %}
{{ map[p] }}
{%- endmacro %}
{% macro port_l(pin) -%}{{ pin.pin[1]|lower }}{%- endmacro %}
{% macro field(pin) -%}p{{ pin.pin[1:]|lower }}{%- endmacro %}
{% macro port_u(pin) -%}{{ pin.pin[1] }}{%- endmacro %}
{% macro idx(pin) -%}{{ pin.pin[2:] | int }}{%- endmacro %}
{% macro kernel_clk(name, src) -%}
{%- if name == "usart1" -%}
    dp.RCC.d2ccip2r.modify(|_, w| w.usart1sel().{{ src }}());
{%- elif name == "uart8" -%}
    dp.RCC.d3ccipr.modify(|_, w| w.uart8sel().{{ src }}());
{%- elif name in ["spi1", "spi2", "spi3"] -%}
    dp.RCC.d2ccip1r.modify(|_, w| w.spi123sel().{{ src }}());
{%- elif name in ["spi4", "spi5"] -%}
    dp.RCC.d2ccip1r.modify(|_, w| w.spi45sel().{{ src }}());
{%- elif name == "i2c4" -%}
    dp.RCC.d3ccipr.modify(|_, w| w.i2c4sel().{{ src }}());
{%- else -%}
    // TODO: set {{ name }} kernel clock source to {{ src }}
{%- endif -%}
{%- endmacro %}

{% if meta is defined %}
/// Enables GPIO clocks required by {{ meta.board }}.
{% else %}
/// Enables GPIO clocks required by the generated board.
{% endif %}
pub fn enable_gpio_clocks(dp: &pac::Peripherals) {
    {% if ns.ports|length %}
    {% if grouped_writes %}
    const MASK: u32 = {% for p in ns.ports %}(1u32 << {{ port_bit(p) }}){% if not loop.last %} |{% endif %}{% endfor %};
    dp.RCC.{{ gpio_bus(spec.mcu) }}.modify(|r, w| unsafe { w.bits(r.bits() | MASK) });
    {% else %}
    {% for p in ns.ports %}
    dp.RCC.{{ gpio_bus(spec.mcu) }}.modify(|_, w| w.gpio{{ p|lower }}en().set_bit());
    {% endfor %}
    {% endif %}
    {% endif %}
}

{% if spec.pinctrl|length %}
{% if meta is defined %}
/// Configures pins for {{ meta.board }} using the HAL API.
{% else %}
/// Configures pins using the HAL API.
{% endif %}
pub fn configure_pins_hal(dp: &pac::Peripherals) {
{% for p in ns.ports %}
    let gpio{{ p|lower }} = dp.GPIO{{ p }}.split();
{% endfor %}
{% for pin in spec.pinctrl %}
    {%- set is_gpio = pin.func[0:5] == "GPIO_" %}
    {%- set is_i2c  = pin.func[0:3] == "I2C" %}
    {%- set is_ana  = pin.func[0:3] == "ADC" or ("Analog" in pin.func) %}
    // {{ pin.pin }} {{ pin.func }} AF{{ pin.af }}
    let {{ pin.pin | lower }} =
    {%- if is_gpio %}
        {%- if "Output" in pin.func %} gpio{{ port_l(pin) }}.{{ field(pin) }}.into_push_pull_output()
        {%- elif "Input" in pin.func %}  gpio{{ port_l(pin) }}.{{ field(pin) }}.into_floating_input()
        {%- elif is_ana %}               gpio{{ port_l(pin) }}.{{ field(pin) }}.into_analog()
        {%- else %}                      gpio{{ port_l(pin) }}.{{ field(pin) }}.into_floating_input()
        {%- endif -%}
    {%- else %}
        {%- if is_i2c %}                 gpio{{ port_l(pin) }}.{{ field(pin) }}.into_alternate_open_drain::<{{ pin.af }}>()
                                            .internal_pull_up(true)
        {%- else %}                      gpio{{ port_l(pin) }}.{{ field(pin) }}.into_alternate::<{{ pin.af }}>()
        {%- endif -%}
    {%- endif %}
    {% if pin.func[0:18] == "USB_OTG_HS_ULPI_" or pin.func[0:5] == "SDMMC" or pin.func[0:3] == "SPI" %}
        .set_speed(Speed::VeryHigh)
    {% endif %};
{% endfor %}
}
{% endif %}

{% if meta is defined %}
/// Enables peripheral clocks for {{ meta.board }}.
{% else %}
/// Enables peripheral clocks for the generated board.
{% endif %}
pub fn enable_peripherals(dp: &pac::Peripherals) {
{%- set pairs = [] -%}
{%- for name, _per in spec.peripherals | dictsort %}
    {%- if spec.mcu[0:7] == "STM32H7" %}
        {%- if name == "i2c4" %}{% set reg = "apb4enr" %}{% set field = "i2c4en" %}
        {%- elif name == "spi2" %}{% set reg = "apb1lenr" %}{% set field = "spi2en" %}
        {%- elif name == "spi5" %}{% set reg = "apb2enr" %}{% set field = "spi5en" %}
        {%- elif name == "uart8" %}{% set reg = "apb1henr" %}{% set field = "uart8en" %}
        {%- elif name == "usart1" %}{% set reg = "apb2enr" %}{% set field = "usart1en" %}
        {%- else %}{% set reg = None %}{% set field = None %}{%- endif %}
    {%- elif spec.mcu[0:7] == "STM32H5" %}
        {%- if name in ["usart1", "spi1"] %}{% set reg = "apb2enr" %}{% set field = name ~ "en" %}
        {%- else %}{% set reg = "apb1enr1" %}{% set field = name ~ "en" %}{%- endif %}
    {%- elif spec.mcu[0:6] == "STM32F" or spec.mcu[0:6] == "STM32L" or spec.mcu[0:6] == "STM32G" %}
        {%- if name in ["spi1", "spi4", "spi5", "spi6", "usart1", "usart6"] %}
            {% set reg = "apb2enr" %}
        {%- elif name[0:3] == "spi" or name[0:5] == "usart" or name[0:4] == "uart" or name[0:3] == "i2c" %}
            {% set reg = "apb1enr" %}
        {%- else %}{% set reg = None %}{% endif %}
        {%- if reg %}{% set field = name ~ "en" %}{% else %}{% set field = None %}{% endif %}
    {%- else %}
        {% set reg = None %}{% set field = None %}
    {%- endif %}
    {%- if reg and field %}{% set pairs = pairs + [{"reg": reg, "field": field}] %}{% endif %}
{%- endfor %}
{% if grouped_writes %}
{%- for group in pairs | groupby("reg") %}
    dp.RCC.{{ group.grouper }}.modify(|_, w| w{% for item in group.list %}.{{ item.field }}().set_bit(){% endfor %});
{%- endfor %}
{% else %}
{%- for item in pairs %}
    dp.RCC.{{ item.reg }}.modify(|_, w| w.{{ item.field }}().set_bit());
{%- endfor %}
{% endif %}
}

{% if with_deinit %}
{% if meta is defined %}
/// De-initializes {{ meta.board }} peripherals and clocks.
{% else %}
/// De-initializes board peripherals and clocks.
{% endif %}
pub fn deinit_board_hal(dp: &pac::Peripherals) {
    // Return pins to analog and remove pulls/open-drain
{%- for pin in spec.pinctrl %}
    let shift = {{ idx(pin) }} * 2;
    dp.GPIO{{ port_u(pin) }}.moder.modify(|r, w| unsafe {
        let mut bits = r.bits() & !(0b11 << shift);
        bits |= 0b11 << shift;
        w.bits(bits)
    });
    dp.GPIO{{ port_u(pin) }}.pupdr.modify(|r, w| unsafe { w.bits(r.bits() & !(0b11 << shift)) });
    dp.GPIO{{ port_u(pin) }}.otyper.modify(|r, w| unsafe { w.bits(r.bits() & !(1 << {{ idx(pin) }})) });
{%- endfor %}

    // Gate peripheral clocks
{%- set pairs = [] -%}
{%- for name, _per in spec.peripherals | dictsort %}
    {%- if spec.mcu[0:7] == "STM32H7" %}
        {%- if name == "i2c4" %}{% set reg = "apb4enr" %}{% set field = "i2c4en" %}
        {%- elif name == "spi2" %}{% set reg = "apb1lenr" %}{% set field = "spi2en" %}
        {%- elif name == "spi5" %}{% set reg = "apb2enr" %}{% set field = "spi5en" %}
        {%- elif name == "uart8" %}{% set reg = "apb1henr" %}{% set field = "uart8en" %}
        {%- elif name == "usart1" %}{% set reg = "apb2enr" %}{% set field = "usart1en" %}
        {%- else %}{% set reg = None %}{% set field = None %}{%- endif %}
    {%- elif spec.mcu[0:7] == "STM32H5" %}
        {%- if name in ["usart1", "spi1"] %}{% set reg = "apb2enr" %}{% set field = name ~ "en" %}
        {%- else %}{% set reg = "apb1enr1" %}{% set field = name ~ "en" %}{%- endif %}
    {%- elif spec.mcu[0:6] == "STM32F" or spec.mcu[0:6] == "STM32L" or spec.mcu[0:6] == "STM32G" %}
        {%- if name in ["spi1", "spi4", "spi5", "spi6", "usart1", "usart6"] %}
            {% set reg = "apb2enr" %}
        {%- elif name[0:3] == "spi" or name[0:5] == "usart" or name[0:4] == "uart" or name[0:3] == "i2c" %}
            {% set reg = "apb1enr" %}
        {%- else %}{% set reg = None %}{% endif %}
        {%- if reg %}{% set field = name ~ "en" %}{% else %}{% set field = None %}{% endif %}
    {%- else %}
        {% set reg = None %}{% set field = None %}
    {%- endif %}
    {%- if reg and field %}{% set pairs = pairs + [{"reg": reg, "field": field}] %}{% endif %}
{%- endfor %}
{%- for group in pairs | groupby("reg") %}
    dp.RCC.{{ group.grouper }}.modify(|_, w| w{% for item in group.list %}.{{ item.field }}().clear_bit(){% endfor %});
{%- endfor %}

    {%- set dmas = [] %}
    {%- set bdmas = [] %}
    {%- set mdmas = [] %}
    {%- for name, _per in spec.peripherals | dictsort %}
        {%- if name[0:3] == "dma" %}{% set dmas = dmas + [name|upper] %}
        {%- elif name[0:4] == "bdma" %}{% set bdmas = bdmas + [name|upper] %}
        {%- elif name[0:4] == "mdma" %}{% set mdmas = mdmas + [name|upper] %}
        {%- endif %}
    {%- endfor %}
    {%- set channel_dma = spec.mcu[0:7] == "STM32F0" or spec.mcu[0:7] == "STM32F1" or spec.mcu[0:7] == "STM32F3" or spec.mcu[0:7] == "STM32L0" or spec.mcu[0:7] == "STM32L1" or spec.mcu[0:7] == "STM32G0" %}

    // Disable DMA controllers and mask their interrupts
    {%- if dmas %}
    dp.RCC.{{ "ahbenr" if channel_dma else "ahb1enr" }}.modify(|_, w| w{% for dma in dmas %}.{{ dma|lower }}en().clear_bit(){% endfor %});
    {%- for dma in dmas %}
        {%- if channel_dma %}
            {%- for i in range(1,8) %}
    unsafe { pac::NVIC::mask(pac::Interrupt::{{ dma }}_CHANNEL{{ i }}); }
            {%- endfor %}
    dp.{{ dma }}.ifcr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
            {%- for i in range(1,8) %}
    dp.{{ dma }}.ch[{{ i }}].ccr.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.ch[{{ i }}].cndtr.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.ch[{{ i }}].cpar.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.ch[{{ i }}].cmar.write(|w| unsafe { w.bits(0) });
            {%- endfor %}
        {%- else %}
            {%- for i in range(0,8) %}
    unsafe { pac::NVIC::mask(pac::Interrupt::{{ dma }}_STREAM{{ i }}); }
            {%- endfor %}
    dp.{{ dma }}.lifcr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
    dp.{{ dma }}.hifcr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
            {%- for i in range(0,8) %}
    dp.{{ dma }}.st[{{ i }}].cr.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.st[{{ i }}].ndtr.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.st[{{ i }}].par.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.st[{{ i }}].m0ar.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.st[{{ i }}].m1ar.write(|w| unsafe { w.bits(0) });
    dp.{{ dma }}.st[{{ i }}].fcr.write(|w| unsafe { w.bits(0) });
            {%- endfor %}
        {%- endif %}
    {%- endfor %}
    {%- endif %}

    {%- if bdmas %}
    dp.RCC.ahb4enr.modify(|_, w| w{% for bdma in bdmas %}.{{ bdma|lower }}en().clear_bit(){% endfor %});
    {%- for bdma in bdmas %}
        {%- for i in range(0,8) %}
    unsafe { pac::NVIC::mask(pac::Interrupt::{{ bdma }}_CHANNEL{{ i }}); }
    dp.{{ bdma }}.ifcr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
    dp.{{ bdma }}.ch[{{ i }}].cr.write(|w| unsafe { w.bits(0) });
    dp.{{ bdma }}.ch[{{ i }}].bndtr.write(|w| unsafe { w.bits(0) });
    dp.{{ bdma }}.ch[{{ i }}].sar.write(|w| unsafe { w.bits(0) });
    dp.{{ bdma }}.ch[{{ i }}].dar.write(|w| unsafe { w.bits(0) });
        {%- endfor %}
    {%- endfor %}
    {%- endif %}

    {%- if mdmas %}
    dp.RCC.ahb3enr.modify(|_, w| w{% for mdma in mdmas %}.{{ mdma|lower }}en().clear_bit(){% endfor %});
    {%- for mdma in mdmas %}
    unsafe { pac::NVIC::mask(pac::Interrupt::{{ mdma }}); }
        {%- for i in range(0,16) %}
    dp.{{ mdma }}.ch[{{ i }}].cr.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].tcr.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].bndtr.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].sar.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].dar.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].brur.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].lar.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].tbr.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].mar.write(|w| unsafe { w.bits(0) });
    dp.{{ mdma }}.ch[{{ i }}].mdr.write(|w| unsafe { w.bits(0) });
        {%- endfor %}
    {%- endfor %}
    {%- endif %}

    // Disable interrupts
    {%- set irq_map = {
        "i2c4": ["I2C4_EV", "I2C4_ER"],
        "spi2": ["SPI2"],
        "spi5": ["SPI5"],
        "uart8": ["UART8"],
        "usart1": ["USART1"],
    } -%}
    {%- for name, _per in spec.peripherals | dictsort %}
        {%- for irq in (irq_map[name] | default([])) %}
    unsafe { pac::NVIC::mask(pac::Interrupt::{{ irq }}); }
        {%- endfor %}
    {%- endfor %}
}
{% endif %}

{% if meta is defined %}
/// Initializes {{ meta.board }} using HAL drivers.
{% else %}
/// Initializes the board using HAL drivers.
{% endif %}
pub fn init_board_hal(dp: pac::Peripherals /*, clocks */) {
    enable_gpio_clocks(&dp);
    configure_pins_hal(&dp);
    enable_peripherals(&dp);
}