FreeRTOS is a free, open-source real time operating system kernel targeted at embedded systems and ported to many different microcontroller architectures \cite{freertos-ports-list}. FreeRTOS provides the task scheduler, forming the central part of the RTOS, and implements queues, semaphores, and mutexes for message passing and synchronization between concurrent tasks (summarily called synchronization objects\footnote{In this chapter sometimes simply called ``objects''.}). FreeRTOS is compact and designed to be easy to understand; it's written in C, with the exception of some architecture-specific routines which use assembly. A complete overview of the system is available in the FreeRTOS reference manual \cite{freertos-rm} and its guide book \cite{freertos-book}.
GEX is designed to be modular and easy to extend. It's composed of a set of functional blocks, sometimes available in more than one instance, which can be configured by the user to fit their application needs. The firmware is built around a \textit{core framework} which provides services to the functional blocks, such as a settings storage, resource allocation, message delivery and periodic updates.
GEX is designed to be modular and easy to extend. It's composed of a set of functional blocks (also called \textit{units}), sometimes available in more than one instance, which can be configured by the user to fit their application needs. The firmware is built around a \textit{core framework} which provides services to the functional blocks, such as a settings storage, resource allocation, message delivery and periodic updates.
In this chapter, we will focus on the general function of the GEX module and will look at the services provided by the core framework. Individual functional blocks and the communication protocol will be described in chapters \ref{sec:tinyframe} and \ref{sec:units-overview}.
In this chapter we will focus on the general function of the GEX module and will look at the services provided by the core framework. Individual functional blocks and the communication protocol will be described in chapters \ref{sec:tinyframe} and \ref{sec:units-overview}.
\iffalse
This and the following parts were written after implementing and evaluating the first hardware prototype and its firmware, therefore rather than describing the development process, it tends to talk about the completed solution and the decisions taken.
@ -10,29 +10,62 @@ This and the following parts were written after implementing and evaluating the
\section{User's View of GEX}
Before going into implementation details, we'll have a look at GEX from the outside, how an end user will see it. This should give the reader some context to better orient themselves in the following sections and chapters investigating the internal structure of the firmware and the communication protocol.
Before going into implementation details, we'll have a look at GEX from the outside, how the end user will see it. This should give the reader some context to better orient themselves in the following sections and chapters investigating the internal structure of the firmware and the communication protocol.
The GEX firmware can be flashed to a STM32 Nucleo or Discovery board or a custom \gls{PCB}. It's equipped with a \gls{USB} connector to connect to the host \gls{PC}. GEX loads its configuration from the Flash memory, configures its peripherals, sets up the function blocks and enables the selected communication interface(s). When \gls{USB} is connected to the board, the \gls{PC} enumerates it and either recognizes the communication interface as \gls{CDCACM} (Virtual serial port), or leaves it without a software driver attached, to be accessed directly as raw \gls{USB} endpoints. This can be configured. The user can now access the functional blocks using the client library and the serial protocol, as well as modify the configuration files.
\begin{figure}[h]
\centering
\includegraphics[scale=.95]{img/users-view.pdf}
\caption{\label{fig:users-view-of-gex}Physical user interface of a GEX module}
\end{figure}
The GEX firmware can be flashed to a STM32 Nucleo or Discovery board or a custom \gls{PCB}. It's equipped with a \gls{USB} connector to connect to the host \gls{PC}. GEX loads its configuration from the Flash memory, configures its peripherals, sets up the function blocks and enables the selected communication interface(s).
The physical user interface of the module is shown in figure \ref{fig:users-view-of-gex}. When a \gls{USB} cable connects the board to a \gls{PC}, the \gls{PC}\gls{OS} enumerates it and either recognizes the communication interface as \gls{CDCACM} (Virtual serial port), or leaves it without a software driver attached, to be accessed directly as raw \gls{USB} endpoints, based on GEX settings.
The connection using a physical UART and a USB/UART adapter works in a very similar way, as does the wireless connection (described in more detail below).
\subsection{Updating GEX Settings}
Two ways exist in which the settings can be modified: via the virtual Mass Storage disk, and through the control interface. We'll look at the file system method here; the API for programmatic loading and updating of settings will be explained in section \ref{sec:tf-bulk-rw}.
Two ways exist in which the module's settings can be modified: via the virtual Mass Storage disk, and through the control interface. We'll look at the file system method here; the API for a programmatic loading and updating of configuration will be explained in section \ref{sec:tf-bulk-rw}.
The board is equipped with a button or a jumper labeled LOCK. When the button is pressed or the jumper removed (or inserted, the polarity is configured in the firmware), the Mass Storage \gls{USB} interface is enabled. For the user, this means that a new disk will be detected by their \gls{PC}'s operating system, which they can open in a file manager. The disk provides a read and write access to configuration INI files and other files with auxiliary information.
The board is equipped with a button or a jumper labeled Lock. When the button is pressed or the jumper removed (or inserted, the polarity is configured in the firmware), the Mass Storage \gls{USB} interface is enabled. For the user, this means that a new disk will appear on their computer which they can open in a file manager. The disk provides a read/write access to configuration files.
The user edits a configuration file and saves it back to the disk. GEX processes the new content, tries to apply the changes and generates an updated version of the file that includes any error messages or newly generated sections (when a new unit was registered). For the \gls{PC}\gls{OS} to recognize this change, the Mass Storage device momentarily reports that the media is unavailable to force the \gls{OS} to reload it. This is a similar mechanism to what happens when a memory card is removed from a reader. Now the user must reload the file in their editor, inspect the updated content and perform any changes needed. The settings, when applied successfully, should now be available to test using the communication interface. When everything is to the user's satisfaction, the updated settings are committed to the device's non-volatile memory by pressing the LOCK button again, or replacing the jumper.
The user edits a file as needed and saves it back to the disk. GEX processes the new content, tries to apply the changes and generates an updated version that includes any error messages or newly generated sections (when a new unit was registered). For the \gls{PC}\gls{OS} to recognize this change, the Mass Storage device momentarily reports that the media is unavailable to force the \gls{OS} to reload it. This is a similar mechanism to what happens when a memory card is removed from a reader. Now the user can reload the file in their editor, inspect the updated content and correct any possible mistakes. The settings, when applied successfully, should be immediately available to test using the communication interface. When everything is to the user's satisfaction, the updated settings are committed to the device's Flash memory by pressing the LOCK button again, or replacing the jumper.
\subsection{Connecting Using the Wireless Module}
In the case when a wireless module is installed on the \gls{PCB} and GEX is configured to use it, this will be used as a fallback when the \gls{USB} peripheral does not receive an address (get enumerated) within a short time after start-up. The wireless link works in the same way as any other communication interface: it can be used to read and modify the configuration files and to access the functional blocks. To use it, the user needs to connect a wireless gateway module to their host \gls{PC} and use the radio link instead of a \gls{USB} cable. The gateway may support more than once GEX board at once.
In the case when a wireless module is installed on the \gls{PCB} and GEX is configured to use it, the radio link becomes a fallback connection when the \gls{USB} peripheral does not get enumerated within a short time after start-up.
To use it, the user needs to connect a wireless gateway module to their host \gls{PC} and use the radio link instead of a \gls{USB} cable. This connection works in a way similar to the hardware UART interface: it can be used to read and modify the configuration files and to access the functional blocks; the difference lies in a slightly different protocol required to communicate with the gateway itself, e.g. to pair it with the GEX module.
\subsection{Using the Control Interface}
Now that GEX is connected and configured, the user can start using it. This involves writing a program in C or Python that uses the GEX client library, using the Python library from MATLAB, or controlling GEX using a \gls{GUI} front-end built on those libraries. The configuration can be stored in the module, but it's also possible to temporarily replace it using the control \gls{API}. This way, the settings are loaded automatically when the user's program starts and may differ for different programs.
\section{Internal Structure Block Diagram}
The data flows and other internal logic of the firmware are depicted in figure \ref{fig:gex-internal}, with more explanation following in this chapter. The interchangeable role of the three communication interfaces can be clearly seen in the diagram, as well as the central role of the message queue which decouples interrupts from the processing thread.
\begin{figure}[h]
\centering
\includegraphics[scale=1]{img/gex-internal.pdf}
\caption{\label{fig:gex-internal}Block diagram showing the internal logic in the GEX firmware}
\end{figure}
\section{FreeRTOS Synchronization Objects Usage}
The firmware is built on FreeRTOS (\ref{sec:freertos}) and a number of its synchronization objects and patterns are used to make its operation more robust.
\subsection{Message and Job Queue}
The message and job queue, seen in figure \ref{fig:gex-internal}, is used to decouple asynchronous interrupts from message transmission. All three communication interfaces use interrupts for the asynchronous handling of incoming messages. The same interrupt handler receives an event after a transmission was completed. The queue ensures that messages can be received during the transmission of a large response that demands the use of multiple transmissions.
The ``transmission complete'' interrupt signals this fact to the message processing task using a binary semaphore. The semaphore is released in the interrupt and take before a new block of data is transmitted. If more data needs to be transmitted, the queue task waits on the semaphore and enters a Blocked state until the semaphore becomes available again.
Two mutexes are used in the firmware: one that guards access to TinyFrame until the previous message was fully transmitted, and one to guard a shared memory buffer used, among other, by unit drivers during the serialization and parsing of a configuration file. The hardware resource registry (explained in \ref{sec:res-allocation}) does not need mutexes for individual resources, as a concurrent access to those fields can never happen thanks to the way the system is organized.
GEX's user-facing functions, also called functional blocks or \textit{units}, are implemented in \textit{unit drivers}. Those are independent modules in the firmware that the user can enable and configure using the GEX configuration files. In principle, there can be multiple instances of each unit type. However, we are limited by hardware constraints: there may be only one \gls{ADC} peripheral, two \gls{SPI} ports and so on. The mutually exclusive assignment of resources to units is handled by the \textit{resource registry} (\ref{sec:res-allocation}).
GEX's user-facing functions are implemented in \textit{unit drivers}. Those are mutually independent modules in the firmware that the user can enable and configure using a configuration file. There can be multiple instances of each unit type. However, we are limited by hardware constraints: e.g., there may be only one \gls{ADC} peripheral, two \gls{SPI} ports and so on. The assignment of those hardware resources to units is handled by the \textit{resource registry} (\ref{sec:res-allocation}).
Each unit is defined by a section in the configuration file \verb|UNITS.INI|. It is given a name and a \textit{callsign}, which is a number that serves as an address for message delivery. A unit is internally represented by a data object with the following structure:
@ -48,7 +81,7 @@ The unit driver handles commands sent from the host \gls{PC}, initializes and de
\section{Source Code Layout}
\begin{wrapfigure}[20]{r}{0.4\textwidth}
\begin{wrapfigure}[22]{r}{0.4\textwidth}
\scriptsize\vspace{-3em}
\begin{verbatim}
├── build
@ -83,7 +116,7 @@ The unit driver handles commands sent from the host \gls{PC}, initializes and de
\caption{\label{fig:repo-structure} The general structure of the source code repository}
\end{wrapfigure}
Looking at the source code repository (fig. \ref{fig:repo-structure}), at the root we'll find device specific driver libraries and files provided by ST Microelectronics, the FreeRTOS middleware, and a folder called \verb|User| containing the GEX application code. This division is useful when porting the firmware to a different microcontroller, as the GEX folder is mostly platform-independent and can be simply copied (of course, adjustments are needed to accompany different hardware peripheral versions etc.). The GEX core framework consists of everything in the \verb|User| folder, excluding the \verb|units| directory in which the individual units are implemented. Each unit driver must be registered in the file \verb|platform.c| to be available for the user to select. The file \verb|plat_compat.c| includes platform-specific headers and defines e.g. which pin to use for a status \gls{LED} or the LOCK button.
Looking at the source code repository (fig. \ref{fig:repo-structure}), at the root we'll find the device specific driver libraries and support files provided by ST Microelectronics, the FreeRTOS middleware, and a folder called \verb|User| containing the GEX application code. This division is useful when porting the firmware to a different microcontroller, as the GEX folder is mostly platform-independent and can be simply copied (of course, adjustments are needed to accompany different hardware peripheral versions etc.). The GEX core framework consists of everything in the \verb|User| folder, excluding the \verb|units| directory in which the individual units are implemented. Each unit driver must be registered in the file \verb|platform.c| to be available for the user to select. The file \verb|plat_compat.c| includes platform-specific headers and defines e.g. which pin to use for a status \gls{LED} or the LOCK button.
The \gls{USB} Device library, which had to be modified to support a composite class, is stored inside the \verb|User| folder too, as it is compatible with all STM32 microcontrollers that support \gls{USB}.
@ -24,6 +24,7 @@ Several units facilitate an access to a group of GPIO pins, such as the digital
For instance, we could only have the pins 0, 1, 12--15 available on a \gls{GPIO} port. GEX provides a helpful abstraction to bridge the gaps in the port: The selected pins are packed together and represented, in commands and events, as a block of six pins (0x3F) instead of their original positions in the register (0xF003). This scheme is shown in figure \ref{fig:pin-packing}. The translation is done in the unit driver and works transparently, as if the block of pins had no gaps---all the referenced pins are updated simultaneously without glitches. Where pin numbers are used, the order in the packed word should be provided---in our example, that would be 0--5, counting from the least significant bit.
\todo[inline]{Expand unit descriptions, add diagrams... (text was written before the tables and ini snippets were added)}
% here are the unit sections, all following a common pattern
@ -128,21 +128,31 @@ The TSC requires a specific topology with a sampling capacitor connected close t
The principle of capacitive touch sensing using the \gls{TSC} is well explained in the microcontroller's reference manual \cite{f072-rm}, the \gls{TSC} product training materials \cite{stm-tsc-training, stm-tsc-ppt} and application notes from ST Microelectronics \cite{stm-tsc-an1, stm-tsc-an2, stm-tsc-an3, stm-tsc-an4}. A key part of the \gls{TSC} is a set of analog switches which can be combined to form several different signal paths between external pins, Vdd, \gls{GND}, and an analog comparator. Two input pins are needed for every touch sensing channel: the sensing pad connects to one, the other is connected through a sampling capacitor (47\,nF on the Discovery board) to \gls{GND}.
\begin{figure}[h]
\centering
\includegraphics[scale=1]{img/tsc-function.pdf}
\caption{\label{fig:tsc-schem}A simplified schematic of the touch sensing circuit}
\end{figure}
\noindent
Capacitive sensing is a sequential process described in the following steps:
\begin{enumerate}
\item The sensing capacitor is discharged by connecting its free end to \gls{GND}.
\item The sensing pad is connected to Vdd and, acting as a capacitor, charged to 3.3\,V. It stores a small amount of charge, depending on its capacitance---this is the variable property we are trying to measure.
\item The sampling capacitor is discharged by connecting its free end to \gls{GND}.
\item The sensing pad is connected to +3.3\,V and, acting as a capacitor, charged to this voltage. It stores a small amount of charge, depending on its capacitance---this is the variable property we are trying to measure.
\item The free terminals of the two capacitors (the sensing pad and the sampling capacitor) are connected together and their voltages reach an equilibrium as a portion of the stored charge leaves the sensing pad and flows into the bigger capacitor.
\item The steps (2) and (3) are repeated the sampling capacitor's voltage exceeds a fixed threshold (set to a half of the supply voltage). The number of cycles needed to charge the sampling capacitor corresponds to the capacitance of the sensing pad.
\item The steps (2) and (3) are repeated until the sampling capacitor's voltage exceeds a fixed threshold (set to a half of the supply voltage). The number of cycles needed to charge the sampling capacitor corresponds to the capacitance of the sensing pad.
\end{enumerate}
\noindent
A real voltage waveform measured on the sensing pad using an oscilloscope is shown in figure \ref{fig:tsc-wfm}.
\caption[TSC operation oscilloscope screenshots]{\label{fig:tsc-wfm}A voltage waveform measured on the touch sensing pad. The bottom side of the envelope equals the sampling capacitor's voltage---this is the phase where both capacitors are connected. The detailed view (middle) shows the individual charging cycles. The bottom screenshot captures the entire waveform after the analog comparator was disabled.}
\caption[TSC operation oscilloscope screenshots]{\label{fig:tsc-wfm}A voltage waveform measured on the touch sensing pad. The bottom side of the envelope equals the sampling capacitor's voltage---this is the phase where both capacitors are connected. The detailed view (middle) shows the individual charging cycles. The bottom screenshot captures the entire waveform, left to continue until a timeout, after the analog comparator was disabled.}
@ -4,7 +4,7 @@ GEX can be controlled through a hardware \gls{UART}, the \gls{USB} or over a wir
The communication is organized in transactions. A transaction consists of one or more messages going in either direction. Messages can be stand-alone, or chained with a response or a follow-up message using the transaction ID. Both peers, GEX and the client application running on the host PC, are equal in the communication: either side can independently initiate a transaction at any time.
GEX uses a framing library \textit{TinyFrame}, developed likewise by the author but kept as a separate project for easier re-use in different applications. The library implements frame building and parsing, checksum calculation and a system of message listeners.
GEX uses a framing library \textit{TinyFrame}\cite{tinyframerepo}, developed likewise by the author, but kept as a separate project for easier re-use in different applications. The library implements frame building and parsing, checksum calculation and a system of message listeners.
Four methods of a wireless connection have been considered: Bluetooth (e.g. with CC2541), WiFi with ESP8266, a 868\,MHz long range link with SX1276, and a 2.4\,GHz link with nRF24L01+. Bluetooth was dismissed early for its complexity, and ESP8266 for its high consumption in continuous reception mode, although both solutions might be viable for certain applications and with more development time.
The Semtech SX1276 and Nordic Semiconductor nRF24L01+ transceivers have both been tested using the first GEX prototype, proving its usefulness as a hardware development tool, and it has been confirmed they could fulfill the requirements of our application.
The Semtech SX1276 \cite{semtech-manual}and Nordic Semiconductor nRF24L01+\cite{nrf-manual} transceivers have both been tested using the first GEX prototype, proving its usefulness as a hardware development tool, and it has been confirmed they could fulfill the requirements of our application.
\begin{figure}[h]
\centering
@ -63,7 +63,7 @@ The two transceivers are compared in table \ref{fig:nrf-sx-comparison}. It's app
\textbf{Price}&\$7.3 &\$1.6 \\
\bottomrule
\end{tabulary}
\caption[Comparison of the SX1276 and nRF24L01+ wireless transceivers]{\label{fig:nrf-sx-comparison}Comparison of the SX1276 and nRF24L01+ wireless transceivers (price from DigiKey @ 10 pieces, May 6th 2018)}
\caption[Comparison of the SX1276 and nRF24L01+ wireless transceivers]{\label{fig:nrf-sx-comparison}Comparison of the SX1276 and nRF24L01+ wireless transceivers, using data from their datasheets (price in USD from DigiKey in a 10\,pcs. quantity, recorded on May 6th 2018)}
\end{table}
SX1276 supports additional modulation modes, including a proprietary LoRa scheme with a frequency-hopping spread spectrum modulation that can be received at a distance up to 20\,km in ideal conditions. The long-range capability is reflected in a higher consumption during transmission. However, its consumption in receiver mode is slightly lower than that of the nRF24L01+.
@ -79,6 +79,8 @@ The nRF24L01+ was selected to be integrated into GEX thanks to its inclusion of
A separate device, the \textit{GEX wireless gateway}, was developed to provide the PC connection to a nRF24L01+ module. It is based on the STM32F103 microcontroller in its smallest package (LQFP48), selected for it's low cost and good availability.