diff --git a/uart/README.md b/uart/README.md new file mode 100644 index 0000000..8550ffe --- /dev/null +++ b/uart/README.md @@ -0,0 +1,19 @@ +UART Echo Test +============== + +This is a trivial UART loopback program for the Sonata board. It configures the +pinmux to conect uart1 to PMOD0 pins 2 (TX) and 3 (RX) and then enters a loop +reading from the UART and echoing back any characters received. The baud rate is +set to 9600. + +The PMOD connector is the 15 x 2 right angled connector with holes. It is +labelled PMOD0 on the left side (when facing the holes) and PMOD1 on the other. +The pins used for the UART can be found like so: + +``` +P +-------------------------------------- +M | 3V | GD | 4 | RX | TX | 1 | ... +O +-------------------------------------- +D | 3V | GD | 8 | 7 | 6 | 5 | ... +0 +-------------------------------------- +``` diff --git a/uart/uart.cc b/uart/uart.cc new file mode 100644 index 0000000..751d979 --- /dev/null +++ b/uart/uart.cc @@ -0,0 +1,61 @@ +// Copyright Microsoft and CHERIoT Contributors. +// SPDX-License-Identifier: MIT + +#include "compartment-macros.h" +#include "platform/sunburst/platform-pinmux.hh" +#include +#include +#include +#include +#include +#include + +/* + * Await some (hardware-specified) number of bytes in the UART's RX FIFO before + * waking the core. Set to Level1 to echo byte by byte. + */ +constexpr auto RXFifoLevel = OpenTitanUart::ReceiveWatermark::Level8; + +/// Expose debugging features unconditionally for this compartment. +using Debug = ConditionalDebug; + +DECLARE_AND_DEFINE_INTERRUPT_CAPABILITY(uart1InterruptCap, Uart1Interrupt, true, true); + +/// Thread entry point. +void __cheri_compartment("uart") uart_entry() +{ + Debug::log("Configuring pinmux"); + auto pinSinks = MMIO_CAPABILITY(SonataPinmux::PinSinks, pinmux_pins_sinks); + pinSinks->get(SonataPinmux::PinSink::pmod0_2).select(4); // uart1 tx -> pmod0_2 + auto blockSinks = MMIO_CAPABILITY(SonataPinmux::BlockSinks, pinmux_block_sinks); + blockSinks->get(SonataPinmux::BlockSink::uart_1_rx).select(5); // pmod0_3 -> uart1 rx + + auto uart1 = MMIO_CAPABILITY(Uart, uart1); + uart1->init(9600); + + uart1->receive_watermark(RXFifoLevel); + uart1->interrupt_enable(OpenTitanUart::InterruptReceiveWatermark); + + auto uart1InterruptFutex = interrupt_futex_get( + STATIC_SEALED_VALUE(uart1InterruptCap)); + + while(true) + { + Timeout t {MS_TO_TICKS(60000)}; + auto irqCount = *uart1InterruptFutex; + + Debug::log("UART status {}, IRQ count {}", uart1->status, irqCount); + + while((uart1->status & OpenTitanUart::StatusReceiveEmpty) == 0) + { + char c = uart1->readData; + Debug::log("read '{}' {}", c, static_cast(c)); + uart1->blocking_write(c); + } + + interrupt_complete(STATIC_SEALED_VALUE(uart1InterruptCap)); + + auto waitRes = futex_timed_wait(&t, uart1InterruptFutex, irqCount); + Debug::log("futex_timed_wait return {}", waitRes); + } +} diff --git a/uart/xmake.lua b/uart/xmake.lua new file mode 100644 index 0000000..047b1f3 --- /dev/null +++ b/uart/xmake.lua @@ -0,0 +1,31 @@ +-- Copyright Microsoft and CHERIoT Contributors. +-- SPDX-License-Identifier: MIT + +set_project("CHERIoT UART demo") +sdkdir = os.getenv("CHERIOT_RTOS_SDK") or path.absolute("../cheriot-rtos/sdk") +includes(sdkdir) +set_toolchains("cheriot-clang") + +option("board") + set_default("sonata-1.1") + +compartment("uart") + -- memcpy + add_deps("freestanding", "debug") + add_files("uart.cc") + +-- Firmware image for the example. +firmware("uart-demo") + add_deps("uart") + on_load(function(target) + target:values_set("board", "$(board)") + target:values_set("threads", { + { + compartment = "uart", + priority = 1, + entry_point = "uart_entry", + stack_size = 0x800, + trusted_stack_frames = 4 + } + }, {expand = false}) + end)