This project provides “oscilloscope-like” capabilities for the ultra low cost of £12, with near-zero soldering required. It’s not a very practical oscilloscope (and this project is really just a quick proof-of-concept written in a couple of evenings) but the information here may be reusable for analog sensing applications and for any other projects that require plotting data to a screen. It could possibly be useful as-is to demonstrate low frequency waveforms in a teaching environment where a real oscilloscope is unavailable. The oscilloscope output is viewed in a web browser, so it is possible to project the output onto a large screen for example. The 12-bit resolution helps here too. All source code is published at the end of this post.

Here is an example video, showing a real signal from a 555 based circuit (it was a sawtooth circuit, click here to download if needed). You can see that it is quite responsive, with multiple refreshes per second.


Here is another video, showing a sine wave signal being ramped up in frequency:


To construct, all that is required is an XMOS startKIT boardXMOS startKIT board (less than £12, or free if you obtained one during the XMOS giveaway at the start of the year) and some wires (and a Raspberry PiRaspberry Pi as tested here, but other boards such as the BeagleBone Black or RIoTboard would also work).



What is the XMOS startKIT?

The XMOS startKIT is a compact (slightly larger than a credit card) board that contains an XMOS multi-cored processor. It has a number of distinct advantages over other processors that make it ideal for projects that require real-time operations. The chip also contains a built-in analog-to-digital converter (ADC). Having all this on a single £10 board makes it attractive for data logging capability. Here is a photo of the setup, showing the startKIT connected up to the RPI.



The startKIT is powered and programmed using a USB cable. Information on how to do this is in an earlier post. Not shown in the photo, if desired, both the startKIT and the RPI can be powered from a single USB supply connected to the startKIT board. The RPI doesn’t need a USB supply. To achieve this, connect a wire from the startKIT connector labelled J8 pin 13 (5V) to the RPI connector pin 4.


Why is an Oscilloscope useful?

In a nutshell it allows you to graphically see electrical signals over time, at rates far higher than a multimeter could show. A multimeter may read one value, but observing the detail over time using an oscilloscope may reveal a very different picture. This project here is not really an oscilloscope, however it does attempt to implement some oscilloscope-like features such as trigger capability and sweep modes and on-screen cursors for trace measurement. It is lacking in good sample rate, any front end filter and in fact it is lacking the entire front half of a real oscilloscope which would normally include AC/DC input capabilities and gain adjustment. Since it is not really an oscilloscope, from now on it will be referred to as the XMOS Analog Examiner or XAE. It can be used to examine simple circuits at low speed. Higher sample rates require more hardware. An example project is here using a BeagleBone Black which achieved around 20 million samples per second. It is still not a complete oscilloscope though. Real oscilloscopes have come down in price, and it is possible to purchase a practical one new for £200 upward. For a new center at my workplace, we are purchasing multiple oscilloscopes. The lowest cost one we have selected is a Tektronix TBS1052BTektronix TBS1052B because it offers dual channels at 50MHz for a reasonable cost and we wanted one that can be taken home by employees. There are lower priced options, but we liked the high-resolution display on this model and the usual Tektronix reliability.


XMOS startKIT: More Information

If you’re interested in finding our more about the XMOS startKIT, the two links that follow may be useful. This is part three in a series of posts on the XMOS startKIT. The XAE 1000 here is a by-product that, while not a practical oscilloscope, was used to try out the analog capability of the XMOS board.


Part 1 entitled XMOS startKIT: Introduction, Terminology/Architecture, Getting Started and Example Programs covered the following topics:

  • Introduction/Terminology/Architecture
  • Running Tasks in Parallel
  • XMOS and IoT
  • Installing the development environment xTIMEcomposer
  • Building and running an Example Program
  • Example: Controlling a Servo
  • Example: Multi-tasking
  • Troubleshooting/Debugging


Part 2 was called XMOS startKIT: Building an XMOS and Raspberry Pi Robot XMP-1 and it covered a few different things. In particular it introduced a general-purpose framework to connect the XMOS startKIT board to the Raspberry Pi using the Serial Peripheral Interface (SPI). This capability was used to construct a robot. Part 2 covered these topics:

  • Robot introduction. Hardware and Software overview and Circuit/Wiring diagram
  • Serial Peripheral Interface (SPI) introduction
  • Connecting the Raspberry Pi to the XMOS startKIT
  • SPI implementation on the XMOS and Raspberry Pi boards
  • Implementing multiple servo control
  • Creating a Raspberry Pi web server and application using Javascript and Node.js
  • Hardware assembly of a robot


Part 2 covered methods of transferring data from the Raspberry Pi (RPI) to the XMOS board, such that servos could be controlled from a web server running on the RPI. This part 3 now covers how to use the general framework from part 2 to transfer data predominantly in the opposite direction; analog data is collected by the XMOS board, and is transferred to the RPI for display to anyone connecting to the XAE application using a web browser.


Solution Overview

The next two diagrams below shows the overall solution. The circuit diagram is extremely simple; just a few wires are used to connect up the two boards:



Analog data is collected by the startKIT board and this information is passed on demand to the Raspberry Pi (RPI) shown on the left. The RPI runs a web server and passes data to the user’s web browser. All graphical processing occurs in the browser. The major software components are shown below:


The details are discussed next, beginning with the XMOS portion.


XMOS software overview

The XMOS chip provides the capability to run multiple tasks in parallel. This capability is described in the first blog post. In summary different code can execute on different XMOS cores, and communication can occur between the XMOS cores using a concept known as ‘channels’.


The XMOS multi-cored chip also contains a built-in 4-channel analog to digital coverter (ADC). It is capable of 4096 points of resolution (12-bit) at 1 million samples per second (MSPS).  The ADC is controlled by the XMOS core using the ‘channel’ concept too. Channels were covered early on in part 1.


In this project, just three XMOS cores are used. One XMOS core runs a task called ‘spi_process’ which is used to handle serial peripheral bus (SPI) input/output between the XMOS device and the Raspberry Pi. Another XMOS core (running adc_task) is used to retrieve ADC captured data into a buffer of memory. A third XMOS core runs a task called ‘app’. It sits in the center and is used to retrieve the buffer data and pass it to the SPI core, and to handle trigger and sweep adjustments. The RPI can send specific instructions to make adjustments such as trigger type. These instructions are decoded by the app task. The diagram below shows the three tasks in purple, and some example message sequences below for retrieving ADC samples and for setting parameters such as the trigger level. This diagram makes more sense after reading part 2.


The adc_task collects 500 samples at a time (enough for one screenful) but only stores to a buffer if the trigger condition is met. A very simplistic trigger capability was implemented, and it is still buggy. It works just-about ok with most waveforms, but doesn’t maintain triggering so well with square waves. The video here shows several different types of waveforms (the view from a real oscilloscope is shown on the left for comparison). I didn’t spend much time refining the trigger capabilities.


Note that when using the attached code, the ADC needs to be enabled in the Makefile. This is done by double-clicking on ‘Makefile’ to open it, and then appending ‘-fxscope’ to the flags as shown in the screenshot below (make sure this is done for ‘Release’ and ‘Debug’) and then saving it.



Also, note that the ADC software that I used (it was found in a community tab inside the XMOS development environment) relies on an external trigger to capture data, and the trigger is hard-wired to a particular pin on the startKIT board. This means that to use SPI as well as the ADC, a different pin needs to be assigned for SPI MOSI compared to post 2 SPI wiring). The circuit diagram in this post shows that the selected pin for SPI MOSI on the XMOS board was connector J7 pin 4 which is the pin marked D12 on the startKIT silkscreen print.


Raspberry Pi software overview

Much like post 2, this project was predominantly coded using JavaScript because the same language can be used twice; in the web browser and on the Raspberry Pi server. It saves having to learn two languages. Node.js (the platform which will allow JavaScript to run on the RPI) and Socket.IO (the feature which will allow real-time communications between the RPI and the user’s web browser) were installed on the RPI (see post 2 for details on how to do this). A very simple C program called xmos_adc was written to handle the low-level communication to the XMOS board; it is responsible for transmitting values across the SPI interface to the XMOS board and dumping the result onto the command line.

So, to retrieve 500 samples of analog data (enough for one screenful), the following commands could be typed on the command line, where the parameter shown is a tag value:

./xmos_adc 3
./xmos_adc 0

The first command instructs the XMOS board that the Raspberry Pi wants to retrieve data. The second command retrieves the samples. As soon as the samples have been retrieved, the XMOS board begins to collect 500 more samples ready for subsequent collection.


To adjust the trigger or sweep settings, different parameters can be used.

As an example, to set the trigger level to a midpoint, the following command can be used, where for the second parameter, the range of 0-3.3V is represented by a number in the range 0-255:

./xmos_adc 6 127


Here is another example. This selects the trigger direction where 0 means rising, and 1 means falling:

./xmos_adc 8 0


Notice that the tags are mostly even numbers; a convention was used that even numbers would alert the XMOS board that no response was expected. An odd tag means that the RPI expects a response in the next SPI message. This convention was created in post 2.


The xmos_adc code doesn’t do anything more; all of the main logic is implemented in JavaScript. The code that is to run on the Raspberry Pi is written in a single file called index.js. It is responsible for functioning as a web server, serving up the index.html file to the user, and taking instructions from the web browser via Socket.IO and translating into xmos_adc command line instructions. Whatever xmos_adc returns is passed using Socket.IO back to the user. The code is very basic.


Most of the interesting stuff is coded in the HTML file. This code will run inside the web browser.There are many ways to improve the code, and the user interface too. The code should be considered just as a proof-of-concept. As soon as a connection is established using Socket.IO, the browser sends instructions to the web server to invoke retrieval of the ADC sample values. The HTML file then instructs the browser to display the screen and then immediately collect more samples. This repeats indefinitely. The process runs as fast as possible, so that the waveform refresh speed is dependent on the user’s computer and web browser. If any button is clicked, then temporarily this refresh scheme is paused while the instruction is sent to the Raspberry Pi for onward forwarding to the XMOS board, and then the sample retrieval is resumed. All graphical calculations are performed in the web browser. It means that very little processing is done on the Raspberry Pi. A JavaScript library called D3 was used to display the waveforms. Some interesting features were found possible to implement, such as direct placement of the trigger and cursors by just clicking on the display. If the user clicks on the left side of the waveform display, the trigger position is updated. If the user clicks at the top or the right side of the display, time or amplitude cursors will get displayed in red. You can see some time cursors and the trigger position in red in the waveform display at the end of this post.



This post completes the investigation into how to implement bidirectional information exchange between the Raspberry Pi and the XMOS startKIT board, and also examined ADC input. It was shown that JavaScript can be used to provide a very responsive user interface. Although the final XAE 1000 implementation is a novelty oscilloscope and not a true oscilloscope, it may serve some useful purpose perhaps for simple circuit demonstrations.



Source Code

See here for the source code.