Signaloid C0-microSD

A programmable FPGA SoM in the tiny microSD form factor

Crowdfunding now!

View Purchasing Options
Dec 05, 2024

Project update 5 of 5

Example Commercial Use Case: Using the Signaloid C0-microSD as a Calculator for Values With Associated Uncertainty

by Signaloid Team

Dear subscribers,
Since our last update, we have been working on additional application examples using the Signaloid C0-microSD. In this technical update, we take a deep dive into the gory details and inner workings of an example we have recently released, split across two new GitHub repositories. The first example, Signaloid-C0-microSD-Demo-Calculator demonstrates a C program you can run on the Signaloid SoC which uses Signaloid’s technology for performing arithmetic operations on probability distributions to implement a calculator. The calculator allows you to perform operations on values with associated uncertainty expressed using the concise uncertainty notation with the form X.Y(Z).

The second example, Signaloid-C0-microSD-Demo-Cardputer, runs on the popular M5Stack Cardputer and interfaces with the Signaloid C0-microSD. The goal of the examples we highlight in this update is to show what you can build on top of the raw capabilities of the FPGA in the Signaloid C0-microSD and to show one of the proprietary commercial use cases for which we developed the Signaloid C0-microSD hardware.

The example we show in this update also uses the Signaloid-C0-microSD-Demo-Calculator application to demonstrate how a pre-programmed Signaloid C0-microSD can function as a co-processor for existing embedded systems that feature microSD slots. The example then builds on top of the Signaloid-C0-microSD-Demo-Calculator application to show how you can use the Signaloid C0-microSD to extend the capabilities of the popular M5Stack Cardputer, a card-sized portable computer based on the popular ESP32 microcontroller. By only modifying the host application running on the Cardputer, you can feed data to the Signaloid C0-microSD running the Signaloid-C0-microSD-Demo-Calculator application, have the Signaloid C0-microSD perform computations on probability distributions that would usually require an expensive Monte Carlo simulation to implement, get back results of the arithmetic on probability distributions, and plot the resulting probability distributions on the Cardputer. You can find this second part of the demo, which runs on the Cardputer and uses the Cardputer as an interface to the Signaloid C0-microSD, in the Signaloid-C0-microSD-Demo-Cardputer Github repository.

Providing Inputs as Probability Distributions

The Signaloid C0-microSD comes with a built-in version of the Signaloid C0 SoC, accessible when the Signaloid C0-microSD is in SoC mode. Applications running on the Signaloid SoC can take advantage of a subset of our proprietary uncertainty-tracking technology to quantify how uncertainties in the data input to programs affect the uncertainty of their outputs. In this example, we created an application that accepts two values with associated uncertainty as input. The program allows you to perform simple arithmetic operations (addition, subtraction, multiplication, or division) on the inputs you provide and to see the result of the arithmetic operation and its associated probability distribution.

The example uses the concise uncertainty notation (X.Y(Z)) to specify the uncertainty of the input values passed to the Signaloid-C0-microSD-Demo-Calculator. While this notation limits the specified uncertainty to uniform distributions and therefore does not take full advantage of the ability of the the Signaloid-C0-microSD-Demo-Calculator to perform arithmetic on arbitrarily-shaped distributions, it makes input of distributions by a human, for the purposes of the demo, much simpler. Using this notation, for example, the input value 10.0(5) represents a uniformly-distributed value between 9.5 and 10.5. The Signaloid-C0-microSD-Demo-Calculator performs the correct distribution arithmetic on these input distributions and returns the full (potentially non-uniform) result distribution. The plots below show three different examples of input distributions, the applied arithmetic operation, and their resulting output distribution. To implement this on a traditional computing platform, you would typically use a Monte Carlo simulation to sample from the input distributions, perform the arithmetic operation on the samples, and then collate the results to form a result distribution.

Inputs and Outputs for the Calculator Operation add "7.0(5)" "13.0(5)"
Inputs and Outputs for the Calculator Operation mul "10.0(10)" "3.0(10)"
Inputs and Outputs for the Calculator Operation div "3.3(6)" "12.0(60)"

Communicating with the Signaloid SoC

Typically, applications built around the Signaloid C0-microSD are divided into two components:

  1. A host application, which operates on the host machine and manages communication with the Signaloid SoC in the Signaloid C0-microSD, communicating with it using block-level I/O to the SD device and conforming to the block I/O address space map which we have detailed in the Signaloid C0-microSD documentation;
  2. The device application, which runs directly on the Signaloid SoC residing inside the Signaloid C0-microSD.

Communication between the host application (running on the system into which the Signaloid C0-microSD is plugged) and the device application (running on the Signaloid SoC inside the C0-microSD) is achieved through two registers (command and status) and two 4 KiB buffers (MOSI and MISO) which are accessed via block I/O offsets to the raw SD device which is in turn visible as, e.g., /dev/sda1 (or something similar) on Linux or /dev/disk4 (or something similar) on macOS. The Signaloid C0-microSD documentation on the Soc Communication Scheme details the block I/O offsets to which these registers are mapped. The host application has write access to the command register and MOSI buffer and it has read access to the status register and MISO buffer. The device application has read access to the command register and MOSI buffer and write access to the status register and MISO buffer.

The Device Application

In the Signaloid-C0-microSD-Demo-Calculator example, the device application expects to receive two pairs of floating-point numbers from the host application through the MOSI buffer. Each such pair defines the lower and upper bounds of a uniform distribution. Once the host application populates the MOSI buffer with the two number pairs, it writes to the command register to specify the operation (addition, subtraction, multiplication, or division) and to trigger a computation.

The device application initializes two variables as values with associated uncertainty that follow uniform distributions using the bounds provided by the host application. The device application achieves this initialization using UxHw API calls for parametric distributions (we could also have chosen to use the passed-in value pairs to construct any other parametric distribution supported by the UxHw API calls for parametric distributions or using the UxHw API calls for constructing empirical distributions from samples). The device application then performs the operation specified in the command register, encodes the resulting uncertain value as a byte array, stores it in the MISO buffer, and updates the status register to notify the host application of completion.

The Host Application

In the C0-microSD-Calculator-Demo repository, you can find the Python host application which runs on a host machine and sends calculation requests to an attached Signaloid C0-microSD. The Python application parses values with associated uncertainty expressed using the concise uncertainty notation described above, as well as parsing the desired operation (addition, subtraction, multiplication, or division) from the supplied input. It then converts the uncertain notation to two pairs of floating-point values, sends them over the SD interface to the MOSI buffer of the Signaloid SoC as described above, and triggers the Signaloid SoC inside the C0-microSD to start calculation by issuing a write to the command register. Again, this is accessed via a block I/O write to an appropriate offset of the block device, as which the C0-microSD is visible. The Python host application then polls the status register of the Signaloid SoC inside the C0-microSD (again, by reading a specific offset in the SD block device), until the operation is completed. Finally, the Python host application copies the resulting bytes from the MOSI buffer of the Signaloid SoC, again using block I/O operations to the SD device.

With the help of signaloid-python, a Python package we provide for parsing and plotting uncertainty values encoded as UX Strings or byte arrays, the host application parses the resulting bytes and plots them. For example, if you run the following:

sudo python host_application.py /dev/disk4 div "12.0(9)" "4.0(9)"

you’ll see the plot below as result:

Communicating Using SD-over-SPI

The standard “4-bit” SD communication interface supported by most microSD storage cards uses one wire for command/response transactions and four additional wires for data movement. This mode is active when the Signaloid C0-microSD is accessed from a Linux or macOS host. An alternative mode of communication also supported by most microSD storage cards, called SD-over-SPI, is also specified by the SD Association (the creators of the SD interface). This SD-over-SPI mode implements the SD interface over the simpler serial peripheral interface (SPI) physical layer and is usually preferred in embedded applications. When an embedded system such as an Arduino is interfacing with a microSD storage card, it will often be doing so using the SD-over-SPI communication mode. The Signaloid C0-microSD supports both the 4-bit communication mode provided by most microSD storage cards and the SD-over-SPI communication scheme.

Simply supporting both the 4-bit and SD-over-SPI communication schemes, however, is not enough to enable most developers to easily adopt the Signaloid C0-microSD. Why not? Well, most existing libraries for supporting SD cards in microcontrollers (e.g., ESPIDF, Arduino, etc.) assume that the SD card is formatted in either a FAT16 or FAT32 filesystem and provide an interface which builds on top of this assumption. The C0-microSD, however, presents itself as an unformatted SD block storage device.

To make it easy to communicate with the Signaloid C0-microSD from microcontroller runtime systems that don’t have the same block I/O device operating system support that makes interfacing with the C0-microSD easy from Unix-like operating systems, we developed a CircuitPython library for communicating directly with the C0-microSD using the SD-over-SPI protocol. Our CircuitPython library has many helper functions such as the ability to write to, and read from, the correct offset addresses for configuring and communicating with the built-in Signaloid SoC as described in the C0-microSD documentation. We use this CircuitPython library to make the Python host application described above available on the ESP32-based Cardputer platform, enabling a “palm-top” demonstration of the Signaloid C0-microSD with the Cardputer acting as host, sending probability distribution computation requests to the Signaloid C0-microSD plugged into the Cardputer, and with the retrieved results displayed on the Cardputer screen. The video below shows this in action.

Porting the "Host Application" to the M5Stack Cardputer

The M5Stack Cardputer is a card-sized portable computer based on the popular ESP32 microcontroller equipped with WiFi, a built-in keyboard, an LCD screen, and a microSD slot. It is officially supported by CircuitPython.

Porting the host application to work in the M5Stack Cardputer involved three main areas of work: communicating with the Signaloid C0-microSD using SD-over-SPI, supporting signaloid-python in CircuitPython, and plotting the resulting data. As mentioned above, we built our own CircuitPython infrastructure to communicate with the Signaloid C0-microSD. We also extended the existing ulab numpy library to support the required numpy functions that the signaloid-python package depends on for plotting the result distributions returned by the Signaloid C0-microSD. Finally, we created a custom plotting function based on the CircuitPython uplot library .

You can find the complete host application for the Cardputer, as well as instructions on how to run it, in the Signaloid-C0-microSD-Demo-Cardputer repository which we recently made public. For example, running the same operation as before on the M5Stack Cardputer results in the following:

In our next update, we will talk more about our post-manufacturing process for programming and testing C0-microSDs before we ship them to backers.

Best regards,
The Signaloid team


Sign up to receive future updates for Signaloid C0-microSD.

Signaloid C0-microSD is part of PCBWay Assembly Hub

Subscribe to the Crowd Supply newsletter, highlighting the latest creators and projects