Detecting User Input with Capacitive Touch and Passive Infrared (PIR) - Part 2

by <a href=""><font color="#000000"><font size="2">Ninja</font></font> </a> lynchtron on ‎03-30-2017 08:37 AM - last edited on ‎03-31-2017 10:32 AM by Administrator llooper



In part 1, we configured the capacitive sensor interface to sample touches on the Wonder Gecko touch slider.  In this section, we will get our computer ready to run Python and the freely available pyqtgraph libary, which is a cross-platform graphing tool that is easy to setup and use.


Graphing the Capacitive Touch Count

This signal to noise ratio requirement requires a way to graph the count value to observe it over time.  The easiest way to do that is to feed the data from the EFM32 to a host computer, where we can run a graphing program in real time. 



Per AN0040, we need to be able to characterize the number of pulses on a touch pad with no touch (i.e. the ambient value) and when a user is touching the pad.  The count when not touched should be 5x the count when touched to have a reliable system.


In the first example, we configured the SysTick for 1ms interrupts, then counted 100 ticks, or 100ms of time before reading the CNT register in TIMER0.  This is an easy way to get started, but is not efficient.  The SysTick interrupt brings the system out of EM1 every millisecond to add one to the counter.  Rather than rely on the SysTick interrupt and a busy while loop, we will rewrite the application to make use of TIMER1 to keep track of the sample time.  This will allow the MCU to stay in EM1 sleep state until the TIMER1 count is complete, and then fetch the TIMER0 CNT value inside the TIMER0 interrupt.


Set up the TIMER1 in the setup_capsense() function:


      // Set up TIMER0 for sampling TIMER1
      CMU_ClockEnable(cmuClock_TIMER0, true);
      /* Initialize TIMER0 - Prescaler 2^9, top value 10, interrupt on overflow */
      TIMER0->TOP  = 10;
      TIMER0->CNT  = 0;
      /* Enable TIMER0 interrupt */


The TOP value is set to 10 in this code with a prescaler set to 512.  Once again, our sample window can be any value we like.  If we set TOP to a small value or use a small prescaler, we will get a very responsive interface at the cost of higher energy consumption.  If we set the TOP value to a large value or use a large prescaler, the TIMER1 interrupt will occur less often, saving energy but creating a less responsive interface.  It is up to you to find values that work best for your application.


Now, to fetch the count, we can make the count variable global, as well as a measurement_complete flag, which is set to true in the TIMER1 interrupt handler.  The resulting main code and TIMER1 interrupt handler is shown here:



// Global variables
volatile unsigned int count = 0;
volatile bool measurement_complete = false;

int main(void)
	/* Chip errata */



	while (1)
		// Clear the count and start the timers
		measurement_complete = false;
		TIMER0->CNT = 0;
		TIMER1->CNT = 0;

		// Now, wait for TIMER0 interrupt to set the complete flag

		// Now observe the count, send it out the USART

		// Delay to not overwhelm the serial port

void TIMER0_IRQHandler(void)
	// Stop timers

	// Clear interrupt flag

	// Read out value of TIMER1
	count = TIMER1->CNT;

	measurement_complete = true;


All that is left to do is to define the print_count() function that we will use in lieu of a hardware breakpoint that we used in our earlier experiments.


We normally would use the SWO output from the Starter Kit to the host computer for simple debug print messages, but it is difficult to reroute those messages to another program for further analysis.  Therefore, we will use the USART and a USB-to-UART adapter to route the messages to a serial port on the host computer


Recall that we used the Silicon Labs USB-to-UART CP2104 MINIEK board in chapter 8.  We can reuse that board here and connect it per the following table:


Starter Kit                 CP2104 MINIEK
PC0 - USART0          TX RXD
PC1 - USART0          RX TXD
GND                          GND



Add the following to your setup_capsense() function to enable USART0:


      // Set up USART0 for graphing via PC serial port on pins
      CMU_ClockEnable(cmuClock_USART0, true);
      USART_InitAsync_TypeDef usart_settings = USART_INITASYNC_DEFAULT;
      USART_InitAsync(USART0, &usart_settings);
      // Enable TX only at location 5
      // Set the pin as push/pull in the GPIO
      GPIO_PinModeSet(gpioPortC, 0, gpioModePushPull, 0);


 Then, the following function is defined to send the count value out through USART0:


// Prints out the global count variable to the USART
void print_count()
      // Create a place to store a message
      char message[6];
      // Format the string as count, encoded in hex, with a space
      sprintf(message, "%x ", count);
      // A string pointer to the start of the message
      char * string = message;
      // While the data pointed to by the string is not null
      while (*string != 0)
            // Send the dereferenced value of the pointer to the USART
            // And then the pointer is incremented to the next address with ++
            USART_Tx(USART0, *string++);

Open a terminal emulator program as we did in chapter 8.  You can use Putty or TeraTerm, or the screen utility on Mac and Linux.  Set the baud rate to 115200.  Make sure that you select the serial port that is assigned to the MINIEK board and open it in the terminal emulator.  If all goes well, you will see a list of count values that scrolls forever.  Touch the left-most touch pad on the Starter Kit, and you will see the values change.


4a 48 48 4a 48 48 48 48 48 48 4a 48 48 4a 48 48 4a 48 
48 4a 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
4a 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
48 48 48 4a 48 48 4a 4a 48 48 48 48 48 4a 48 48 4a 48
48 48 4a 48 48 48 44 36 2c 2c 2c 2c 2c 2c 2a 2a 2c 2c
2c 2a 2c 2c 2c 2c 2c 2a 2c


The touch event can be seen at the end of this listing.


Configuring Your Computer to Run Python and pyqtgraph

We can graph the data arriving at the host computer’s serial port in real time with the help of a Python script and Python libraries called pySerial and pyqtgraph.  


The Python scripting language has many benefits over the C language that we have been using thus far in programming the EFM32.  The first thing that you need to know is that Python is dynamically typed.  What this means is that you don’t need to declare a variable as a specific type, like uint32_t.  Any variable can hold any data and can be changed at runtime; Python automatically manages this for you, as it also manages memory.  Also, Python is object oriented, which allows for each object to keep track of its own state, allowing more powerful and reusable code.


Python is interpretive, which means that we don’t compile and link during the build process.  There is no resulting executable or binary file.  Every script file is evaluated line-by-line as it runs, and you can even invoke Python by itself as an “interpreter” which allows you to write code and explore functions and return values in a live and active session.  There are plenty of Python IDE’s with breakpoint and single-stepping functionality, but they are not strictly required, as the interpreter provides some of those benefits. 

Python and the libraries are cross-platform, meaning that they will work on Windows, Mac, and Linux computers.


IMPORTANT NOTE: Python uses tabs and/or whitespace to indicate an indention block.  You don’t need to use curly braces {} after an if statement.  This is a great feature that saves keystrokes, but can be maddening if you use an editor that mixes tabs and spaces.  Therefore, make sure to use a good editor or IDE when editing Python scripts that converts tabs into spaces.  For example, Notepad++, Komodo Edit, PyCharm, or Pydev, the last of which uses Eclipse.


If you have a Mac or Linux computer, Python is likely already installed.  If not, just visit and follow the instructions to install it. 


If you have a Windows computer, download the Python2.7 “Windows x86 MSI installer” from  At the time of this writing, the sub version was 2.7.12, but any newer 2.7.x versions should work fine.  This code has not been tested on the newer Python 3.x branches.


IMPORTANT:  For Windows users, make sure that you modify the default setting “Add python.exe to Path” to “Will be installed on local hard drive” as shown in the figure below.  This is required to run the commands listed in this chapter. 


Once Python is installed, open a command window (or console) on your computer and type “python --version” at the prompt.  You should see a message that displays the python version.  If this doesn’t work for you, resolve this problem before continuing.


C:\WINDOWS\system32>python --version
Python 2.7.12


Next, install the libraries needed for the graphing script.  Type the following commands at your OS command prompt:


python -m pip install --upgrade pip
pip install pyserial
pip install -U PySide
pip install pyqtgraph

Then, at the OS command prompt, type python:

Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.


The three greater-than symbols is the Python interpreter prompt.  Type the following commands to ensure that all libraries are installed:


>>> import pyserial
>>> import pyqtgraph.examples


When you run these commands, you should not see and error messages and a window should open on your computer that looks like the following.  If so, it confirms that you are ready to run the graphing code.  This is a demo application for pyqtgraph and demonstrates all the neat things you can do with it.


In the next section, we will use our serial data port and Python GUI tool to create a program that graphs the output from the capacitive sensor in real time.