Theory of Operation

As previously mentioned, the Rancilio Silvia model E is used for this example application. Before we will look at the electronics and modifications, we will go through the theory of operation and components of the unmodified machine. A rendered image of the espresso machine without enclosure and water tank is shown in the figure.

Figure: Hardware architecture of the electronics; red: analog electronics, purple: mains powered electronics, blue: digital or mixed-signal electronics.

Everything connected to mains power is in the power control unit. This PCB contains the power supply for mixed-signal electronics and the solid state relays to control the heating element, the solenoid valve and the pump. A zero crossing detector signals a pulse every time mains crosses zero volts. If there is a need to control the pump pressure, the pulse width modulated (PWM) signal can be synced to mains.

The processing unit contains a microcontroller and two sensor interfaces. The emSTAMP-Neon-CM7 module from emtrion is used. It contains a microcontroller (STM32F769 from STMicroelectronics), 32 MB SDRAM, 16 MB Flash memory and an ethernet PHY. The module reduces the overall complexity of the hardware design by providing an external SDRAM for the UI framebuffer and the PHY needed for the LAN connection. Not to mention that none of the components on the module were in stock at any known distributor worldwide due to the ongoing global chip shortage at the time of development (2021 and 2022). The processing unit also provides regulated power for digital and analog circuits and the display backlight.

The board provides two sockets for the sensing modules. At the moment there is a resistor temperature detector (RTD) module that can be wired up to four PT100 sensors and a thermocouple module for four sensors as well. The modular approach allows for sensing modules to be reused, optimized, or replaced without redesigning the complete board.

In the following subsections, we will take a look at each PCB and the most important design principles.

Processing Unit

The processing unit was designed simultaneously with the touch screen housing. Thus, the display size and connectors dictated the broad layout depicted in the figure.

Figure: PT100 RTD sensor used in the espresso machine.

The resistance of the sensor can be measured using a current source and a voltage measurement. For that purpose the AD7124-8 from Analog Devices is used, an external ADC shown in the figure.

Figure: Analog Devices AD7124-8 function block diagram [2].

The chip contains a 24 bit delta-sigma ADC 1 (the effective resolution varies depending on gain, filtering and output data rate [2, pp. 24]). The internal variable gain amplifiers (PGA) 2 are used to increase the signal amplitude before the ADC, so that the ADC measurement range is used optimally. The matched current sources 3 are used to supply the PT100s. The mux 4 switches different inputs to the ADC so that multiple sensors can be connected to one ADC.

Leads between the sensor and the chip introduce a resistance that must be accounted for. Otherwise, the lead resistance will be added to the PT100 resistance, resulting in a temperature offset after conversion. The solution is to use a separate lead for the current source and the voltage measurement, a four-wire measurement. The input impedance is so large that the voltage on the measurement wires is negligible. Assuming that all leads to one sensor have the same impedance, the setup can be reduced to a three-wire measurement. The circuitry in the figure and the figure implements a 3-wire setup with the AD7124.

Figure: External ADC for RTD PT100 measurement.

The sensor module has four input channels. The example in the figure shows the measurement setup for the first channel. Each channel uses four pins of the chip. Two pins at 1 are used to each source a current $I$ to the sensor (AIN0 and AIN3). The voltage is measured on the two inputs (AIN1 and AIN2). The sense and source traces are combined before the connector to the sensor 2. The current SRC_1_P is used to power the sensor and the second current SRC_2_P compensates for the lead resistance. Because both currents flow toward the sensor, the voltage drop in the second wire cancels the voltage drop of the first wire. Thus, lead resistance is compensated in hardware.

The combined current $2I$ returns via the third wire. This wire then supplies the voltage reference resistor 3 that supplies the ADC reference voltage 4. Any inaccuracy from the current sources will affect the reference voltage and so implicitly compensate the measurement. It is crucial that both currents $I$ are equal. In the case of the AD7124, matched current sources achieve this.

The circuit formed by R9, R11, C11, C12 and C14 is a differential anti-aliasing filter.

The schematic at 2 is a simplified version of the circuit shown in the figure.

Figure: Schematic extract of RTD anti-aliasing filter.

Similar to the reference voltage, this schematic also contains a anti-aliasing filter for the voltage measurement. The circuit around the AD7124 closely follows the manufacturer recommendations [3].

Figure: Galvanic isolation of the ADC for grounded thermocouples.

The red line in the figure highlights the isolation barrier. The isolated DC-DC converter module at 1 provides the power supply. SPI signals are isolated via transceivers at 2. Thus, there are no direct connections from the ADC at 3 to the board connector 4.

\warningbox{The pinout of U4 is wrong in the first revision of this module. This issue is clearly visible with multiple pins with the same index.

A handheld multimeter (Keysight U1242C) was used instead of this module to measure the temperature of the thermocouple.}

Figure: External ADC for thermocouple measurement.

The schematic of the thermocouple circuit in the figure shares some similarity with the RTD module. Most notably is the same chip used, the AD7124. There are again four sensor channels 1. To measure the temperature of the first channel, the chip uses AIN0 and AIN1 as inputs and measures the differential voltage against the internal voltage reference. The voltage from the thermocouple indicates the temperature relative to the point where the sensor material changes to copper, the cold junction. In this case, the cold junction is connector to the sense module. To calculate the temperature at the tip of the thermocouple, we must know the cold junction temperature. The familiar circuit at 2 and 3 measures the cold junction temperature with a PT100 sensor. This time two wire measurement suffices because there were no long leads. This circuit again follows the manufacturer recommendations [1].

The circuit at 1 also contains differential anti-aliasing filters.

Figure: Mains power zero crossing detector [30].

The detector takes a sine signal from mains power (230VAC) 1 and creates a pulse on every zero crossing 2. Isolation is guaranteed by an optocoupler 3. With the zero crossing signal PWMs can be synced to mains power. This could be used to control the power of the pump.

Figure: Underside of the group head with the 0.5mm thermocouple sticking out of the screw.

Cold Water Line

The sensor 1 in the figure (MIPAF1XX250PSAAX from Honeywell) measures the pressure in the cold water line. It is placed between the pump and the boiler with T-piece 2 and an adapter 3.

Figure: Espresso machine front with touch screen modification.

The touch screen assembly also contains the processing unit and is contained in a 3D printed housing. The assembly is screwed in place. For that purpose, holes were drilled in the front sheet metal and the wires to the machine go through a slot.

Figure: Opened touch screen and processing unit assembly.

The connection to the machine is detailed in the figure. The assembly has a hinge, which provides easy access to the processing unit. The board is screwed in place and all wires are attached using connectors. Thus, changing components does not require any tools.

The front panel assembly also reduces the heat issue. The inside of an espresso machine becomes hot when water is boiled. Keeping electronics outside this hot zone increases the lifespan of the components on the board.


The original wiring and power-off timer of espresso machine was removed and replaced. The actuators are now controlled by the power control unit. The on-board solid state relays shown at 1 in the figure are used for the pump and the solenoid valve. The red wires from the power control unit go to the processing unit at the front

Figure: Firmware architecture.

In this section, we take a look at the firmware in a top-down approach based on the figure. The application contains the business logic. Here, the temperature control and glue to distribute measurement data across the application. The application uses open source middleware to create a graphical user interface (LVGL) and TCP/IP stack (smoltcp). The driver layer contains software to interact with components on the board, such as the external ADC (AD7124) or the ethernet medium access controller (MAC) and physical layer (PHY). Setting microcontroller peripherals and hardware abstraction is implemented in the board support layer.

The bern-kernel runs parallel to the other packages because abstractions are internal to the kernel and RTOS only relies on the CPU core of the microcontroller.


The application is split into three loosely coupled processes in the figure.

Figure: Processes of the espresso machine firmware.

The UI process is responsible for presenting the user the measurements. The UI poses a high background load on the system, as calculating graphics is computationally expensive. Reading sensors and controlling the machine actuators is performed in the machine control process. It is critical for the espresso machine that this process is always running. Measurements and machine states are queued to the data logger process. The data is then sent via an ethernet connection to a computer.

At the time of writing the communication between processes available are message queues. The machine control process sends its data to the UI and data logger, which read the process the data asynchronically.

The UI and data logger process are straightforward. They just contain one thread waiting and then processing messages. A little more complex is the machine control process. Therefore, the data flow between threads of processes is illustrated in the figure.

Figure: Data flow inside the machine control process.

There are three threads in the machine control process. The sense thread measures water pressure with the MCU internal ADC and reads shared water volume data. But most of the time, the thread communicates with the external ADC to measure the temperatures inside the espresso machine. Measurements are then enqueued to the data logger process and shared with the temperature control thread. The temperature control thread runs periodically and creates an actuator request to control the heating element. Control signals and states are enqueued to the data logger process as well. The machine control thread forms an isolation barrier between the temperature control and the machine hardware. The goal is to enforce safety even if the temperature control fails. The thread can override the actuator requests if safety could be compromised. Also, the valve and pump are controlled by switches.

The water flow sensor triggers an interrupt for each increment. The interrupt service routing (ISR) increments the water volume data.

The interaction between the three threads is detailed in the figure.

Figure: Machine control sequence diagram.

All three threads have the same structure of receiving, processing and sending data. It is important to notice that the threads run asynchronically and can access the data at any time. Shared data protected by a mutex is sufficient in this case because the threads only need the latest value. The threads also run at different frequencies. Machine control is the fastest, as it needs to halt the pump promptly when the brew switch is released. The sense thread is mostly blocked by the external ADC. Each time a temperature is read the ADC has to be reconfigured. The temperature control thread is the slowest by choice. A boiler has a large time constant. Thus, there is no sense in running the control algorithm at a high frequency. At the moment, temperature control runs twice per second.


The middleware used in the firmware are open source and independent of the RTOS. They add a lot of functionality with little implementation effort.


Rust implementation and wrappers of graphics libraries are not as feature rich as implementations in C or C++. Thus, the light and versatile graphics library (LVGL) [37] is used. It also opens the opportunity to combine C and Rust code with foreign function interface (FFI).

the figure depicts the structure of the UI code.

Figure: Graphical user interface structure using LVGL; blue: C code, red: Rust code.

The view contains the code that draws the UI. Bindgen [49] is a Rust package that automatically creates C compatible Rust functions and structures from C header files. Although the FFI is created in the build process, there is still some manual coding needed to make use of Rusts benefits. Thus, the goal was to keep the interface between Rust and C as simple as possible. As a result there is only an initialization and an update function as well as view model. The complete UI is implemented in C based on LVGL. All the UI process must do, is update the view model and call the update function. The C code is built and linked as part of the cargo build process.

The UI is rendered in the figure. There is a visual model of the espresso machine consisting of a boiler, a portafilter, a coffee cup and a manometer. The temperatures are updated live so that the user can see the most important metrics while pulling an espresso shot.

Figure: Espresso machine graphical user interface.


In order to design and optimize the temperature controller, we need measurements from the espresso machine. The most convenient solution for the analysis is a time series database containing measurements from many espresso shots. As shown in the figure an InfluxDB is used for data storage.

Figure: Data flow in the network.

On the espresso machine, the smoltcp [53] network stack handles the TCP/IP connection to the computer. Telegraf is part of InfluxDB and collects the machine data from TCP socket and stores it in the database. Grafana is used as the front-end to visualize historical and live data.

This setup is very versatile: the computer does not need to be placed next to espresso machine, and as user the data is accessible from anywhere in the network.

The measurement data is visualized with Grafana in the web browser. An example screenshot is depicted in the figure.

Figure: Espresso machine Grafana dashboard.


The device drivers in Rust can be packaged and shared via the package manager. The drivers are generic so that they can be used on different hardware platforms. Therefore the community defines traits of communication interfaces in the embedded-hal [31]. A device driver can then run on any platform implementing the trait.

For the espresso machine, a driver for the external ADC (AD7124) had to be developed. the figure illustrates the dependencies of the driver.

Figure: Dependencies of the AD7124 external ADC driver.

The AD7124 driver only depends on the SPI trait of the embedded-hal. There is no dependency on the specific implementation of the interface itself. The SPI trait is implemented in the microcontroller HAL. The application instantiates the AD7124 drivers and provides the specific SPI to the device driver.

This structure removes any dependency on one specific hardware platform. Therefore, the driver is portable and testable. In the case of the embedded-hal there are mocks for most interface [29]. Hence, testing is simple.

Creating interfaces to abstract specific dependencies is nothing new and not limited to device drivers or Rust. Compared to other languages, Rust has the advantage that the specific implementation can replace generics at compile time. Thus, there are no function pointers or overhead at runtime.

Board Support

The board module is kept simple: it initializes the microcontroller peripherals and provides traits for hardware abstraction. The board module itself uses the community implementation of the microcontroller HAL.

Temperature Control

The original temperature controller of the espresso machine used a thermostat with a large hysteresis. Also, several PID control kits are available for the Rancilio Silvia machine. In this section a model-based state-space controller is developed. This type of controller is most probably excessive, but it makes use of all the sensors in the machine.