#9 Input Devices

This week I learned how to measure something with a sensors.

Assignment

Group assignment

  • Probe an input device(s)'s analog levels and digital signals

Individual assignment

  • Measure something: add a sensor to a microcontroller board that you have designed and read it

Outcomes


What did I do this week: 1. Group Assignment

The group assignment page - week09

Probe an input device(s)'s analog levels and digital signals

We used an oscilloscope to read the signal waveforms obtained from each input device board that each member had made.

For details, please see the group page: The group assignment page - week09


What did I do this week: 2. Individual assignment

Measure something: add a sensor to a microcontroller board that you have designed and read it

Procedure

I plan to use touch sensors in the final project. In class, we learned several ways to implement touch sensors.

Step Response

1pin: A method that uses electrodes from the outside world.
Some processors, such as the ESP32, have built-in touch measurement functionality, and you can use this, or some, such as the SAMD21, can be used as is by loading a library.
Also, with any processor, you can set custom peripherals to the PIO in the assembly to enable touch.

2pin: A method that creates electrodes by sending pulses from the transmitter to the receiver, and when touched, the pulse changes, which can be read.

For this week's assignment I decided to try out different touch sensors.

  1. Processor (xiao ESP32S3)
  2. 1 pin with Resistor (xiao RP2040)
  3. 2 pin (xiao RP2040)
  4. MPR121 (xiao ESP32C3)

Processor - ESP32

Last week I created a board using xiao, so I decided to first try out a method that could be implemented using the functions of the processor itself.
I decided to plug the xiaoESP32 into the board I created last week to test its reaction.
*See Week 8 for the design of the board I created last week.

1000012570.jpg

I tried it with the ESP32C3, but got an error. It seems that it can only be implemented with the S3.

image.jpg

So I borrowed an ESP32S3 from the instructor Nagano-san. The pinout for the S3 is as follows:

image.jpg

TOUCH - - — Arduino ESP32 latest documentation

I tried the following code from the above page:

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.println(touchRead(T1));  // get value using T1
  delay(1000);
}

It worked without any problems.

Next, I tried increasing the number of pins.
I tried the maximum number of touch pins for S3.

At first, I tried it with the following code.

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.println(touchRead(T1));  // get value using T1
  delay(1000);
  Serial.println(touchRead(T2));  // get value using T2
  delay(1000);
  Serial.println(touchRead(T3));  // get value using T3
  delay(1000);
  Serial.println(touchRead(T4));  // get value using T4
  delay(1000);
  Serial.println(touchRead(T5));  // get value using T5
  delay(1000);
  Serial.println(touchRead(T6));  // get value using T6
  delay(1000);
  Serial.println(touchRead(T7));  // get value using T7
  delay(1000);
  Serial.println(touchRead(T8));  // get value using T8
  delay(1000);
  Serial.println(touchRead(T9));  // get value using T9
  delay(1000);
}

Even without touching it, the following behavior occurred. I thought something was wrong, so I decided to reduce the number of pins a little.

image.jpg

I made it 5 pins.

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.println(touchRead(T1));  // get value using T1
  delay(1000);
  Serial.println(touchRead(T3));  // get value using T3
  delay(1000);
  Serial.println(touchRead(T5));  // get value using T5
  delay(1000);
  Serial.println(touchRead(T7));  // get value using T7
  delay(1000);
  Serial.println(touchRead(T9));  // get value using T9
  delay(1000);
}

It still responds without anything.

image.jpg

Even when the pin number was reduced to two, the following reactions were observed:

image.jpg

When I touched it, the numbers changed dramatically.

image.jpg

Then, I tried using a longer cord with four pins.

1000012566.jpg

There was no reaction when I touched it.

image.jpg

Debug
So I decided to add T1, T2 in that order and test.

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.println(touchRead(T1));  // get value using T1
  delay(1000);
  Serial.println(touchRead(T2));  // get value using T1
  delay(1000);
}
image.jpg

It responded well, so I made it three.

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.println(touchRead(T1));  // get value using T1
  delay(1000);
  Serial.println(touchRead(T2));  // get value using T2
  delay(1000);
  Serial.println(touchRead(T3));  // get value using T3
  delay(1000);
}
image.jpg

But when I added the T4, it stopped working…

image.jpg

When I tried adding T5, T1 to T3 responded, but only T5 did not respond…
I checked with the instructors and got the following advice from Nagano-san.

So, I modified the code as follows:

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.print(touchRead(T1));  // get value using T1
  Serial.print(",");
  Serial.print(touchRead(T2));  // get value using T2
  Serial.print(",");
  Serial.print(touchRead(T3));  // get value using T3
  Serial.print(",");
  Serial.print(touchRead(T4));  // get value using T
  Serial.print(",");
  Serial.println(touchRead(T5));  // get value using T5
  delay(1000);
}

But it didn't work.

Tsuchiya-san also gave me the following additional advice:

  • The basic rule is not to pass current through the touch sensor pins or connect them to other circuits, and it is not OK to connect LEDs or resistors directly to the touch pins.
  • Instead of using T4 and T5, it might be a good idea to use T7 to T9 on the opposite side. T5 and T6 are used for I2C, so it is probably best not to use them.
On my own board, I had already connected an LED to the T4 pin, which seems to have caused it to stop responding.
I modified the code as follows:

// ESP32 Touch Test
// Just test touch pin - Touch0 is T0 which is on GPIO 4.

void setup() {
  Serial.begin(115200);
  delay(1000);  // give me time to bring up serial monitor
  Serial.println("ESP32 Touch Test");
}

void loop() {
  Serial.print(touchRead(T1));  // get value using T1
  Serial.print(",");
  Serial.print(touchRead(T2));  // get value using T2
  Serial.print(",");
  Serial.print(touchRead(T3));  // get value using T3
  Serial.print(",");
  Serial.print(touchRead(T7));  // get value using T7
  Serial.print(",");
  Serial.println(touchRead(T8));  // get value using T8
  delay(1000);
}

It now responds nicely!
If you touch the connected pins directly, it responds as shown below.

image.jpg

I found that the value was larger when I touched both wires at the same time as GND.
Also, the value roughly doubled when I touched both wires at the same time.

image.jpg

Assuming the actual Final Project, I tested it by sticking it to a glass bottle.

1000012621.jpg

However, the values seem to vary.
Looking at the values carefully, I realized that the problem was probably that the reaction was too small, so there was no significant difference between when it was not touched and when it was touched, like when it was touched directly.
I need to research a way to get a large reaction when touched, even if it is far away from the board or through glass.

If one pin is touched

image.jpg

When covered with hand

image.jpg

Responses for each pin

image.jpg
image.jpg

Results

The results are as follows:

T1 28600
T2 27500
T3 32000
T7 30700
T8 29100


Resources:

https://docs.espressif.com/projects/arduino-esp32/en/latest/api/touch.html
https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/
https://wiki.seeedstudio.com/Seeeduino-XIAO/
https://github.com/espressif/esp-iot-solution/blob/release/v1.0/documents/touch_pad_solution/touch_sensor_design_en.md

1 pin with Resistor (xiao RP2040)

Next, I tried using a resistor even if the processor had no function for a single pin.
I used Neil's board design and circuit as is, but decided to test how different resistors would react differently depending on the resistance size by using different types of resistors.

Milling

First, I cut the circuit. I changed the mill setting: offset 4 → 6

image.jpg
image.jpg

I added three types of resistors to the circuit: 100KΩ, 1MΩ, and 2MΩ.
I realized we didn't have any 2MΩ resistors in Kamakura inventory, but I had already cut the board, so I connect two 1MΩ resistors in a tricky way…

1000012586.jpg
1000012588.jpg

Python

As the only sample code available was in Python, I started by setting up to use Python.
As this was my first time using Thonny, I struggled with setting it up and getting the RP2040 to work.
I referred to the following page.
https://wiki.seeedstudio.com/XIAO-RP2040-with-MicroPython/
https://lab.seeed.co.jp/entry/2021/12/27/120000
https://www.zep.co.jp/utaguchi/article/z-picoled_all-da1/
https://msr-r.net/raspi-picow-setting/
Also, since I got an error related to a soft reboot and didn't know how to do it, I used ChatGPT.

This is the setup on Thonny.

image.jpg

I used the following code.

image.jpg

#
# hello.steptime1.RP2040.py
#
# 1 pin step-response loading measurement with PIO
#
# Neil Gershenfeld 7/24/24
#
# This work may be reproduced, modified, distributed,
# performed, and displayed for any purpose, but must
# acknowledge this project. Copyright is retained and
# must be preserved. The work is provided as is; no
# warranty is provided, and users accept all liability.
#
# install MicroPython
#    https://micropython.org/download/RPI_PICO/
#

from machine import Pin,freq
import rp2

@rp2.asm_pio(set_init=rp2.PIO.OUT_HIGH)
def steptimer():
    #
    # initialize
    #
    pull()
    mov(y,osr) # move loop to y
    pull() # move settle to osr
    mov(x,null) # move count to x
    set(pins,1) # turn on pin
    #
    # main loop
    #
    label('main loop')
    #
    # charge up
    #
    set(pindirs,1) # set pin to output
    #
    # settle up
    #
    label('up settle')
    mov(isr,x)
    mov(x,osr)
    label('up settle loop')
    jmp(x_dec,'up settle loop')
    mov(x,isr)
    #
    # discharge
    #
    set(pindirs,0) # set pin to input
    #
    # time down
    #
    label('down loop')
    jmp(pin,'down jump')
    jmp('down continue')
    label('down jump')
    jmp(x_dec,'down loop')
    #
    # loop
    #
    label('down continue')
    jmp(y_dec,'main loop')
    #
    # push count
    #
    mov(isr,x)
    push()

class steptime:
    def __init__(self,sm_id,pin):
        self._sm = rp2.StateMachine(sm_id,steptimer,
            jmp_pin=pin,set_base=pin)
        self._sm.active(True)
        self.get = self._sm.get
        self.put = self._sm.put

freq(250000000)

step0 = steptime(0,0)
step1 = steptime(1,1)
step2 = steptime(2,2)
step3 = steptime(3,4) # these are flipped in pinout
step4 = steptime(4,3) # "

loop = 200
settle = 20000

min0 = min1 = min2 = min3 = min4 = 1e6

while True:
    step0.put(loop)
    step0.put(settle)
    result0 = 4294967296-step0.get() # +1 for init 0
    if (result0 < min0): min0 = result0
    step1.put(loop)
    step1.put(settle)
    result1 = 4294967296-step1.get()
    if (result1 < min1): min1 = result1
    step2.put(loop)
    step2.put(settle)
    result2 = 4294967296-step2.get()
    if (result2 < min2): min2 = result2
    step3.put(loop)
    step3.put(settle)
    result3 = 4294967296-step3.get()
    if (result3 < min3): min3 = result3
    step4.put(loop)
    step4.put(settle)
    result4 = 4294967296-step4.get()
    if (result4 < min4): min4 = result4
    print(f"7500,{result0-min0},{result1-min1},{result2-min2},\
       {result3-min3},{result4-min4}") # 7500 for scale

It worked fine!!

1000012616.jpg
1000012614.jpg

However, the response is too small. I looked at the code and noticed that the bottom part was the Scale specification, so I edited it.

print(f"7500,{result0-min0},{result1-min1},{result2-min2},\
{result3-min3},{result4-min4}") # 7500 for scale

I edited the above as follows:

print(f"2500,{result0-min0},{result1-min1},{result2-min2},\\
   {result3-min3},{result4-min4}") # 2500 for scale

I also decided to try it with thinner wire.

1000012618.jpg
image.jpg

Since the reaction became even smaller, I changed the scale as follows:

print(f"500,{result0-min0},{result1-min1},{result2-min2},\\
   {result3-min3},{result4-min4}") # 500 for scale
Results

The results are as follows:
Horizontal: Length of wire × Vertical: Size of resistor
*I couldn't figure out the N/A part very well.

No wire(board direct) 25cm(thick) 25cm(0.2㎜²)
1 100k 7500-15000 500 200
2 100k ~15000 1000 200
3 1M N/A N/A N/A
4 1M ~10000 6-700 400
5 2M 8000~20000 N/A 500

2 pin (xiao RP2040)

I tried a method that uses 2 pins also.
Again, I used Neil's design and code.
I created and tested two types, 1MΩ and 100KΩ.

Toolpaths

image.jpg
image.jpg

Code

image.jpg

//
// hello.txtx2.RP2040.ino
//    RP2040 XIAO two-channel transmit-receive step-response hello-world
//    overclock at 250 MHz
//
// Neil Gershenfeld 7/10/23
//

#define digitalWriteFast(pin,val) (val ? sio_hw->gpio_set = (1 << pin) : sio_hw->gpio_clr = (1 << pin))
#define digitalReadFast(pin) ((1 << pin) & sio_hw->gpio_in)

#define Rx1 27 // receive 1 pin (D1)
#define Tx1 4 // transmit 1 pin (D9)
#define Rx2 29 // receive 2 pin (D3)
#define Tx2 1 // transmit 2 pin (D7)
#define settle 20 // settle time
#define samples 2000 // number of samples to accumulate

void setup() {
   Serial.begin(115200);
   }

void loop() {
   }

void setup1() {
   pinMode(Tx1,OUTPUT);
   pinMode(Tx2,OUTPUT);
   }

void loop1() {
   int32_t up1,down1,up2,down2;
   up1 = down1 = up2 = down2 = 0;
   for (int i = 0; i < samples; ++i) {
      digitalWriteFast(Tx1,HIGH); // charge up
      up1 += analogRead(Rx1); // read
      delayMicroseconds(settle); //settle
      digitalWriteFast(Tx1,LOW); // charge down
      down1 += analogRead(Rx1); // read
      delayMicroseconds(settle); // settle
      digitalWriteFast(Tx2,HIGH); // charge up
      up2 += analogRead(Rx2); // read
      delayMicroseconds(settle); //settle
      digitalWriteFast(Tx2,LOW); // charge down
      down2 += analogRead(Rx2); // read
      delayMicroseconds(settle); // settle
      }
   Serial.print(up1-down1); // send difference
   Serial.print(',');
   Serial.println(up2-down2); // send difference
   Serial.flush(); // finish communicating before measuring
   }
Assembly
1000012593.jpg
1000012594.jpg
1000012598.jpg
1000012601.jpg

I read it as follows:
Value 1 = 1MΩ
Value 2 = 100KΩ

image.jpg

When I tap, I can see that it is responding.


image.jpg
image.jpg
image.jpg
image.jpg
image.jpg
image.jpg

This method was very instructive in learning how touch works.
However, this method requires two points to select one location.
Since I want to touch one country, I would like to implement it with one pin if possible, so this method may not be suitable for my Final Project.

MPR121 (xiao ESP32C3)

As we saw in Week 6, ChatGPT recommends using the MPR121 to implement many touches, and I was considering using it. So I conducted an experiment. This time, instructor, Tsuchiya-san, had an MPR121 breakout board, so I borrowed it.
To use this board, it needs to be connected to a microcontroller. So I decided to design a board that could be connected to the Xiao that I have.

Build a board for MPR121

The pinout for xiaoESP32-C3 is as follows:
https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/

image.jpg

The schematic design is as follows.
I've also included a circuit for an LED so that I can try out the output later.

image.jpg

The design rules are set as follows:

image.jpg
image.jpg

The PCB Design is as follows.

image.jpg
image.jpg

The key words to remember when checking milling designs are:
White: Keep
Black: Cut

image.jpg
image.jpg
image.jpg
image.jpg

The PCB board has been cut. I attached parts. This time, only for sockets.

1000012634.jpg
1000012671.jpg

Install the library

Next, to use the MPR121, you need to install the library in Arduino. I installed the following:

image.jpg

After adding the library, I found test code for MPR121, so I tried that.

image.jpg

The sample code is as follows:

/*********************************************************
This is a library for the MPR121 12-channel Capacitive touch sensor

Designed specifically to work with the MPR121 Breakout in the Adafruit shop 
  ----> https://www.adafruit.com/products/

These sensors use I2C communicate, at least 2 pins are required 
to interface

Adafruit invests time and resources providing this open source code, 
please support Adafruit and open-source hardware by purchasing 
products from Adafruit!

Written by Limor Fried/Ladyada for Adafruit Industries.  
BSD license, all text above must be included in any redistribution
**********************************************************/

#include <Wire.h>
#include "Adafruit_MPR121.h"

#ifndef _BV
#define _BV(bit) (1 << (bit)) 
#endif

// You can have up to 4 on one i2c bus but one is enough for testing!
Adafruit_MPR121 cap = Adafruit_MPR121();

// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lasttouched = 0;
uint16_t currtouched = 0;

void setup() {
  Serial.begin(9600);

  while (!Serial) { // needed to keep leonardo/micro from starting too fast!
    delay(10);
  }
  
  Serial.println("Adafruit MPR121 Capacitive Touch sensor test"); 
  
  // Default address is 0x5A, if tied to 3.3V its 0x5B
  // If tied to SDA its 0x5C and if SCL then 0x5D
  if (!cap.begin(0x5A)) {
    Serial.println("MPR121 not found, check wiring?");
    while (1);
  }
  Serial.println("MPR121 found!");
}

void loop() {
  // Get the currently touched pads
  currtouched = cap.touched();
  
  for (uint8_t i=0; i<12; i++) {
    // it if *is* touched and *wasnt* touched before, alert!
    if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {
      Serial.print(i); Serial.println(" touched");
    }
    // if it *was* touched and now *isnt*, alert!
    if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {
      Serial.print(i); Serial.println(" released");
    }
  }

  // reset our state
  lasttouched = currtouched;

  // comment out this line for detailed data from the sensor!
  return;
  
  // debugging info, what
  Serial.print("\t\t\t\t\t\t\t\t\t\t\t\t\t 0x"); Serial.println(cap.touched(), HEX);
  Serial.print("Filt: ");
  for (uint8_t i=0; i<12; i++) {
    Serial.print(cap.filteredData(i)); Serial.print("\t");
  }
  Serial.println();
  Serial.print("Base: ");
  for (uint8_t i=0; i<12; i++) {
    Serial.print(cap.baselineData(i)); Serial.print("\t");
  }
  Serial.println();
  
  // put a delay so it isn't overwhelming
  delay(100);
}

When I touched it, I was able to read the reaction well.

1000012636.jpg
image.jpg

How it works: The MPR121 performs the analog-to-digital conversion.

After that, I tried sticking it on glass, but it didn't work...
Maybe the soldering wasn't done properly.
It seems like I need to improve it if I want to actually use it for my Final Project.

1000012659.jpg


Outcomes

I was able to try out a variety of different touches!
However, I still need to refine each one a bit before I can decide which one to try in Final.
Also, in order to get the output, I need to decipher a little more about each code.

Top