Input Devices
QUOTE OF THE DAY
The way to succeed is to double your failure rate - Thomas J. Watson
Goals
I want to use a simple commercial thermistor to measure temperature. Ideally, the simplest form that includes no processing/abstraction by the manufacturer.
FabAcademy goals
- individual assignment:
- measure something: add a sensor to a microcontroller board that you have designed and read it (read a magnitude) ✅
Personal goals for this week
I want to use a raw input device to achieve various things:
- Where machines touch the real world:
- WHAT: This week, I’d like to use an input device that is a raw as possible (a device that has no processor built in). I hope this will help me understand how they work at the lowest level, without having to rely on any pre-processing done by a manufacturer/API/abstraction.
- WHY: As a software developer, we work in a “real world” that is always abstracted away from us. The machines we program (computers, mobile apps, web servers, … ) are always operating in a virtual world that is hidden behind dozens of layers of abstraction. That is, we don’t have to worry about debouncing signals when someone presses the ENTER key, we don’t even have to listen to keyboard events. This physical reality has been hidden away from us (for good reason) but this week I’d like to get a bit closer to it. I have reasonable expectations. I think that I will enjoy it, like what I did a few weeks ago, exploring the famous Interrupts. Wish me luck!
- Circuit Design: I want to understand how to design circuits to effectively extract the information I need, from the device being used.
- Circuit Optimization: I want to figure out how to design circuits to optimise the capabilities that my components
already have:
- Specifically: if the DAC has a 10-bit resolution, I want to understand how to design the circuit so that I have
the best resolution for temperatures in an arbitrary range.
- Specifically, If I know that the resistance of my probe never goes below/above a specific number, I want to design a circuit that will be able to use the full range of values that the sensors can give me. No more ( duh!), no less (the important part!)
- And use this to understand, how to pick ranges, what happens if it were to measure a value outside that range, and any safety considerations I should keep in mind in the future.
- Specifically: if the DAC has a 10-bit resolution, I want to understand how to design the circuit so that I have
the best resolution for temperatures in an arbitrary range.
The Sensor - IKEA Temperature Sensor - FANTAST
This is the sensor that I wanted to use this week.
It’s a thermal probe that you can find as part of this IKEA kitchen timer/temperature reader.
Yes, after so many weeks learning about the importance of reading the datasheet of the components we use, I decided to try to jump to the deep end and figure out what happens on ✨ the other side of the PDF ✨.
The only published material for this device is the commercial operator’s manual , written in 30 languages, but with no information about the thermal probe, its resistance, or any rated max current.
This week’s plan
This was my plan for this week:
- Figure out what the probe is, how it operates, and which of its properties change as the temperature changes.
- Figure out the relation between temperature and how to use a SAM-D11C to read this sensor.
- Figure out what the board/circuit should look like, so that the entire range of temperatures can be measured
accurately.
- and so that the 10-bit ADC precision is fully utilized.
- Figure out how to visualize this data (find exciting alternatives to the ‘Serial Monitor’ in Arduino)
- Figure out how to properly calibrate and adjust the math to get precise readings (ideally within +/- 5°C).
About the device
As I have already revealed before, the thermal probe appears to be a simple thermistor with a Negative Temperature Coefficient.
The Datasheet
High Temperature is Low Resistance
This was an easy way to set the probe to around 40+ degrees, from the comfort of my table. The only cost: 2 minutes of my life, and 3 months off of the lifespan of my CPU! Win/Win!
Low Temperature is High Resistance
This was tested by putting the probe in the Lab’s freezer for 20 minutes.
The datasheet transcript
Space | Temperature | Resistance |
---|---|---|
Laptop heat exhaust (100% CPU) | 40 °C | 50K Ohm |
Ambient Temperature | 24 °C | 150K Ohm |
Cold Water | 7 °C | 300K Ohm |
FabLab Fridge | 5 °C | 350K Ohm |
Freezer | -15 °C | 800K Ohm |
If we plot these values into a cartesian plane, we can see that the trend is clearly exponential and has a negative coefficient.
Measuring temperature by measuring resistance
The next question to answer was: “How can I measure these changes in resistance from my arduino-like board”?
The answer to this question has two parts:
- Our board (SAM-D11C) has an ADC that can be used to
measure analog voltage on a given pin (compared to ground, this is what’s known as Single Ended).
- Yes, the SAM-D11C it also supports Differential measurements (D11 datasheet Section 31.1, page 770), but we are going to keep it simple. Single Ended mode works perfectly for our use case.
- Just… listen… just pay attention, the last thing I need right now is picky questions and unnecessary distractions from tiquismiquis lecturers who want to brag about their SAM-D11C Knowledge!
- In order to measure resistance, we have to design a circuit that will result in a specific range of voltages (0 to 3.3V) in the pin that we will use for measuring.
So this section is about doing item #2 from this list. How do we design a circuit that will result in a voltage between 0 and 3.3V on the given pin.
The way we do this is with math!
We can use a voltage divider, which allows us convert a large voltage to a smaller one.
This basic equation allow us to calculate the output voltage (Vout) given a known Vin, and the resistance of both our resistors (R1 and R2)
V_{out} = V_{in} * \frac {R2} {R_1 + R_2}
We will need to apply a bit of math, since we don’t know R_2, but we do know V_{out}.
If we get our notepad out, this is the equation we need to solve.
3.3 = 5 * \frac {R_2} {50000 + R_2}
3.3 * (50000 + R_2) = 5 * R2
165000 + 3.3 * R_2 = 5 * R_2
165000 = (5-3.3) * R_2
165000 = 1.7*R_2
\frac {165000} {1.7} = R_2 = 97058 Ω
The resistance of R2 (the one after our thermistor) will have to be of 97kΩ if we want to guarantee protection of our chip, when our thermistor is at its lowest resistance (the hottest temperature).
This also solves one of the questions we wanted to answer originally: What will happen if the temperature we are measuring exceeds that maximum we calculated?
- The resistance of our thermistor will drop further
- It will consume less V than we anticipated.
- The measured Voltage on our measuring pin will exceed 3.3V, and we risk burning our SAMD chip. 😱
As bonus resources:
- this Arduino Tutorial on how to measure resistance explains why it’s important to have the value of the known resistor to be similar (orders of magnitude) to the value of the unknown resistor.
- This post was also useful to figure out how to maximise resolution when picking components for circuits
Measuring resistance by measuring voltage
Now that we know what components we will need in our circuit to protect our sensitive components, as well as to guarantee that the readings are accurate and that they provide values that our ADC can measure correctly, it’s time to jump to the next step.
How do we measure the resistance of our thermistor from our microcontroller, if it can only measure voltage?
Well, we know that the ADC of the SAM-D11C has a resolution of 10 bits. This means that it will give us a reading and convert it to a number between 0-1023 (1024 different values is (2^{10\text{ bits}})).
Designing the board
Creating a custom symbol and footprint
This week I had to create a custom KiCad Symbol and Footprint for the new component that I wanted to use.
Check out the cheatsheet on how to create custom kicad symbols and footprints
Lessons learned when designing symbols/cheatsheets.
- When you have a simple design, and you feel brave enough to do all the traces manually instead of using FreeRouting ( like in previous weeks), don’t forget to add all traces!
- When you have a new component, and you are designing its symbol, its pads/ports and its footprints, don’t forget to
validate your assumptions about the components that you do not know!
- It might be that your initial idea needs reconsidering.
- If the component is a pluggable thing, remember to plug it and replicate the measurements you will actually do when it is soldered.
Progress soldering
This week I was really happy with the process of actually soldering. I feel like I improved a lot, and it has been a lot more satisfying than the first few weeks.
I wanted to celebrate this because persistence truly is a blessing.
Programming the board
One of the issues I had while trying to program the board was this:
edu@deneb ~ cd Downloads edu@deneb ~/Downloads edbg -ebpv -t samd11 -f sam_ba_SAMD11C14A.bin Debugger: Alex Taradov Generic CMSIS-DAP Adapter 170CD3AA v0.1 (S) Clock frequency: 16.0 MHz Target: SAM D11C14A (Rev B) Erasing... done. Programming...Error: invalid response during transfer (count = 0/3, status = 7) ✘ edu@deneb ~/Downloads
Root cause: I forgot to add a trace for VDD 🤦
Fixed by adding a jumper cable to the right place.
Once this was solved, the board worked smoothly and could be programmed without issue.
Creating a simple program that reports voltage reads
The next step was to flash it with a small that could read the voltage on Pin 5, and report it to us via Serial.
The entire code for the program was this:
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(analogRead(5));
delay(100);
}
Unfortunately the reading when we inserted the probe were far from ideal:
We were getting the MAX reading, and yet the probe was far from any extreme temperature. It was sitting on the table at normal room temp.
Something was wrong.
The answer turned out to be this:
Can you see it? The two pads that near the entrance of the jack are actually shorting out because they both touch the same sleeve when you insert the connector all the way in.
For some reason, when I was designing the jack’s symbol and footprints I made an incorrect assumption: that the 2 pads at the top were the “data reading” pads, and that the pad at the opposite side must be a grounding pad (or similar). This is why I connected that bottom one to ground and those two as the “sensing” pads.
This is what happens when you don’t test your components that do not come with datasheets!
Anyway, a couple knife cuts and a short jumper cable later, my board was rocking some stylish 1990s hoop earrings.
After this, the readings were spot on:
- Consistent
- Reliable
- With values in the range we expected
- and with high resolution (or very noisy! still not sure)
These were the readings once the data started coming in.
And these are the readings once we subjected the probe to an increasing temperature.
Unexpected Problem: Using doubles in Arduino/FabSam results in enormous programs
Changing the double
type to int
somehow solves the problem… but it makes absolutely no sense!
It is, at least, very counter-intuitive, unless the double
type is not native to the board and the FabSAM library has
to somehow create a wrapper/custom type for it and all that code uses up several KB of memory.
In the end, I decided to go for floats and ignore any problems with low precision.
Using Processing to visualize the data from my board
The next thing I wanted to do was to visualize this data a bit better.
I had heard of Processing, but I had no idea what it was, or why would anyone use it.
A quick glance a some tutorials seemed to indicate that it supported reading data from Serial port, which was excellent, as it would allow me to use this to display the board’s reading in the computer screen.
Installing processing for Linux
- Download the linux installer from the Processing download page
- Unzip the contents
- Open the terminal and execute
sudo ./install.sh
from that folder. - A new desktop launcher will appear, ready to be used.
Math time - Properly calibrating the sensor to display accurate temperatures
The way I calibrated the software to perform the temperature calculation correctly was the following:
- Captured raw data (temperature-resistance) relations
- Documented those on the datasheet above, for future reference
- Use LibreOffice’s graphing tools to calculate the Logarithmic Trend line that defines the relation between these 2
variables.
- Since the relation between Temperature -to-> Resistance is exponential, we can use a logarithmic function to invert it and calculate the Resistance -to-> Temperature ration.
- Validated that the formula that LibreOffice calculated is correct using sample data points
- Encoded this calculation inside our program so that it can be visualized and rendered correctly.
Among the most important calculations, we can find:
- A function to convert the normalized reading (0 to 1024) to the real voltage (between 0 and 3.3)
- A function to convert the resistance of our thermistor from the real voltage we calculated
- A function to derive the temperature from the resistance we calculated in step 2
- A bunch of UI-centric functions used to position/draw the thermometer on the screen, so it rises/falls with the temperature we calculated.
void draw(){
drawThermometer();
if(arduinoSerial.available() > 0){
String volt = arduinoSerial.readStringUntil(lf);
float actualVolt = (3.3 / 1024) * float(volt);
float calculateResistanceOfProbe(float realVolt){
return (5 - realVolt) * 100000 / realVolt;
}
float convertResistanceToTemperature(float resistance){
return ((-19.89212 * log(resistance)) + 257.7);
}
float getYforNormalizedVoltage(float temp){
float position = map(temp, 0, 90, 600, 150);
return position;
}
Other tips used this week
- This tutorial explains how to pick resistors for your circuits.
So, if you want to keep the voltage (on your thermistor) as close to X as possible (theoretical Voltage before connecting our measuring microchip), you should only use a device where the internal resistance is a lot greater than R1 and R2. If it’s significantly greater, then the voltage won’t change as much.
- This other tutorial explains how to handle situations where our measuring device has an equivalent internal resistance
that’s very different from our known R2. This is important, as it would act as a “resistance connected in parallel”
and it will effectively create a smaller effective resistance on our circuit.
- A way to fix it is to make the internal resistance of our measuring device have a very large resistance (in series). I decided that it was probably overkill, so I skipped, but it was interesting to learn nonetheless.
So if you want to design a voltage divider circuit and you dont want your voltage to change more than 1%, you should design a circuit with an internal resistance (of your measuring equipment) x100 higher than the R2 resistance.
- Here’s a tip on how to stress test laptop (CPU) to generate high temperature on the cooling system (to test the thermal probe on a high temperature):
$ for i in $(seq $(getconf _NPROCESSORS_ONLN)); do yes > /dev/null & done
- The last tip was on how to check the datasheet that the SAM-D11C Supports ADC on Pin 1 (I/O Pin PA05):
Useful References
- Fantastic tutorial to practice electronics basic and learning step by step how to do the calc on your own
- This post seems to have done something similar with the exact same IKEA FANTAST probe.
Group Project
Assets
- thermometer-traces.png - Traces diagram
- thermometer-outline.png - Outline diagram
- thermometer-traces.png.rml - MODS output for Traces
- thermometer-outline.png.rml - MODS output for Outline
- processing_thermometer.pde - The processing application that displays the thermometer
- The Datasheet - The home-made datasheet, in premium quality
- input-devices-calc.ods - The spreadsheet used to derive the calculations and math