liltcp

liltcp is a demo project concerned with developing a basic glue library for connecting together smoltcp, an HAL and an async runtime. The name is sort of a pun on both smoltcp and Cliff L. Biffle's lilos, because both of these are used as a basis for the glue. The goal of the project is to be able to produce a working yet very basic alternative to embassy-net, therefore documenting how it works and how to use smoltcp's async capabilities. To avoid depdency on embassy itself, stm32h7xx-hal is used as a HAL.

The demo project is developed for the STM32H743ZI Nucleo devkit, but it should work with any other H7 board, providing pin mappings are corrected.

Getting started

Before diving into developing the networking code, let's first make an LED blinking smoke test. This is just to make sure that the environment is set up correctly and there are no broken things (devkit, cables, etc). The smoke test also makes sure that we have lilos working together with the HAL.

The code below implements such a smoke test.

#![no_main]
#![no_std]

use liltcp as _;

#[cortex_m_rt::entry]
fn main() -> ! {
    let mut cp = cortex_m::Peripherals::take().unwrap();
    let dp = stm32h7xx_hal::pac::Peripherals::take().unwrap();

    let ccdr = liltcp::initialize_clock(dp.PWR, dp.RCC, &dp.SYSCFG);

    let gpio = liltcp::init_gpio(
        dp.GPIOA,
        ccdr.peripheral.GPIOA,
        dp.GPIOB,
        ccdr.peripheral.GPIOB,
        dp.GPIOC,
        ccdr.peripheral.GPIOC,
        dp.GPIOE,
        ccdr.peripheral.GPIOE,
        dp.GPIOG,
        ccdr.peripheral.GPIOG,
    );

    lilos::time::initialize_sys_tick(&mut cp.SYST, ccdr.clocks.sysclk().to_Hz());
    lilos::exec::run_tasks(
        &mut [core::pin::pin!(liltcp::led_task(gpio.led))],
        lilos::exec::ALL_TASKS,
    )
}

First, it initializes the clock, then the GPIO. These are initialized with functions created to allow for easier code sharing, so these include more code than necessary. Next, we initialize the SYSTICK and spawn an LED blinking task.

The LED blinking task itself is pretty bare:

#![allow(unused)]
fn main() {
pub async fn led_task(mut led: ErasedPin<Output>) -> Infallible {
    let mut gate = PeriodicGate::from(lilos::time::Millis(500));
    loop {
        led.toggle();
        gate.next_time().await;
    }
}
}

If everything went well you should see a blinking LED (amber on the Nucleo devkit). We can now move to initializing the Ethernet peripheral to do some basic link state polling.