2014/08/26

Touch buttons with Atmel SAM4S (or similar)

I often use ATSAM4S microprocessor and one of the neat functions is capacitive sensing for touch buttons. There is a proprietary technology, QTouch, that does it. But you can make a simple touch button even easier and with half the pins. QTouch needs two pins, a capacitor and a resistor for each channel (button). I can do it with only the resistor (protection resistor, no need for a precise value) and one pin per channel.

The principle is very similar to QTouch sensing. First, you attach a button through a protection resistor (3k3 works fine) to a general purpose I/O pin. The button may be simply a piece of metal on a cable or it can be printed on the circuit board. It only has to be covered by an insulating layer. Solder mask, paper or a not very thick acrylic work well. This creates one of the plates of a capacitor and the dielectric. The second part is your finger. By approaching the button, your finger increases the capacitance and this can be measured to detect the presence of the finger thus producing a touch event.

Each pin has three possible states: high, low and high-impedance (measuring). In addition, each pin can be pulled down or high by an internal resistor, whose value is approximately 100 kOhm. We are going to use this. First, we need to discharge the capacitor. That can be easily done by pulling the pin low for sufficiently long time. A sufficiently long time is arbitrary but 5 time constants is more than enough. The RC time constant is dependent on the protection resistor and the total capacitance. A button together with parasitic capacitance can reach few tens of picofarads. So to be absolutely sure, lets use 100 pF as the capacitance value and 3k3 as the protection resistor. This translates to a time constant of 0.33 microseconds. Five time constants is 1.65 microseconds. Thus, if you rely on the built-in delay.h function delay_us(), then set two as its argument. You can see that only two microseconds are needed to prepare the button for measurement. Because you can do this in parallel for all channels, it is really fast.

Next thing is to measure the time needed to charge the capacitor. We set the pin to high-impedance mode and pull it high using the internal 100 kOhm resistor. This will form another RC series circuit, this time with a different time constant, RC = (100k + 3k3) × (button + pin capacitance). If the total capacitance is, say, 20 pF, then the time constant is 2.066 microseconds. But the internal resistor value is VERY approximate so for any accurate capacitance measurement a calibration would be needed. Having said that, we don’t need an accurate measurement at all! We only need to detect changes in capacitance. So after pulling the pin high, we simply wait until it reads 1. You can either continually poll the pin input register or set an interrupt and count the time it takes the pin to set. With 2-microsecond time constant, the pin will be high quickly so the whole measurement process is fast. One way to measure the time is to simply set a loop and wait until the pin sets. The iterator value corresponds to the charge-up time and is the result of measurement. You will need to keep a baseline time value for the untouched button. Then compare each measurement to this value to determine if the button has been (value will be higher) or hasn’t been touched. Do the measurement regularly to provide swift user interface experience. Protip: If you set the pin low after each measurement, you don't have to wait for discharge the next time.

Sample code (download here) uses touch.c and touch.h. Define the I/O port in touch.h, then call touch_init() once to setup the line and call touch_measure() to get a value proportional to port's capacitance. In the main program, watch for this value increasing, thus indicating a touch event.

touch.h:

/*
 * touch.h
 *
 * Created: 26.8.2014 19:00:00
 *  Author: Kaktus
 */

/*
 * Description:
 * Simple touch sensor demonstration.
 * Connect touch button to the defined port via approximately 3k3 resistor.
 * No other components needed.
 */

#ifndef TOUCH_H_
#define TOUCH_H_

#define TOUCH_PIOPORT PIOA
#define TOUCH_PIOLINE 0
#define TOUCH_PMC PMC_PCER0_PID11

void touch_init(void);
uint32_t touch_measure(void);

#endif /* TOUCH_H_ */


touch.c:

/*
 * touch.c
 *
 * Created: 26.8.2014 19:00:00
 *  Author: Kaktus
 */

#include <asf.h>
#include "delay.h"
#include "touch.h"

void start_discharge(void);

void touch_init()
{
    PMC->PMC_WPMR = PMC_WPMR_WPKEY_PASSWD;
    PMC->PMC_PCER0 |= TOUCH_PMC;
    TOUCH_PIOPORT -> PIO_WPMR = (0x50494F << 8); // registry unlock
    TOUCH_PIOPORT -> PIO_PER |= (1 << TOUCH_PIOLINE); // peripheral disable
    TOUCH_PIOPORT -> PIO_IFDR |= (1 << TOUCH_PIOLINE); // glitch filter disable
    TOUCH_PIOPORT -> PIO_PPDDR |= (1 << TOUCH_PIOLINE); // pull down disable
    start_discharge();
}

uint32_t touch_measure()
{
    TOUCH_PIOPORT -> PIO_ODR |= (1 << TOUCH_PIOLINE); // output disable
    TOUCH_PIOPORT -> PIO_PUER |= (1 << TOUCH_PIOLINE); // pull up enable
    uint32_t t = 0;
    while (!((TOUCH_PIOPORT -> PIO_PDSR) & (1 << TOUCH_PIOLINE)))
    {
        t++;
    }
    start_discharge();
    return t;
}

void start_discharge()
{
    TOUCH_PIOPORT -> PIO_PUDR |= (1 << TOUCH_PIOLINE); // pull up disable
    TOUCH_PIOPORT -> PIO_OER |= (1 << TOUCH_PIOLINE); // output enable   
    TOUCH_PIOPORT -> PIO_CODR |= (1 << TOUCH_PIOLINE); // output low
    delay_us(2); // set > 5 RC time constants; you can comment this line if you measure at longer intervals than the set delay
}

2014/07/23

MightyWatt revison 2: Now 50% mightier!

I've been using my MightyWatt electronic load for the last few months and I got some ideas to make it better. I am introducing the MightyWatt, revision 2. This time, you can buy it as a kit (fear not, most parts are assembled) on Tindie.

Complete schematic of the revision 2.

Four-wire connection
MightyWatt has now four input terminals. You can switch between remote (4-wire) and local (2-wire) voltage measurement. The signals are routed by a relay. This gives you the opportunity to exclude the resistance of cables from your measurement.
I have also redesigned the dual-range voltmeter from single-ended to differential.

Better DAC
I have replaced the cheap Microchip's DAC in favour of a higher-end DAC from Analog Devices with internal 2 ppm/°C voltage reference (AD5691RBRMZ). It is more expensive but the accuracy will be improved. The original DAC (MCP4726) is not a bad part, though. It only has somewhat larger inlinearity which cannot be eliminated by simple linear calibration. Feel free to use the MCP4726 if you don't need the improved accuracy.

Better gate driver
I have added additional compensation to the MOSFET gate driver so the current ripple is much reduced.

No LED
Because the temperature is monitored in software, I never experienced an overheat. I have decided to drop the red LED that was supposed to indicate overheat.

Input protection
There were occassional problems when transient voltages were present on the USB line. Some PC power supplies have problems filtering transients in the grid (e.g. motor switching) and it resulted in disconnection of the load. I have added a 5V transient voltage suppressor at the power-entry point.

New software and firmware
Because the load can do 4-wire measurement now, I also updated the software (C#) and the firmware (Arduino sketch). This means that revision 2 software is not backwards compatible with the first version. You can find all the relevant source files on my Google Drive (original revision 2). All the resources for the latest version can be found here: http://kaktuscircuits.blogspot.cz/2015/03/mightywatt-resource-page.html.
  • Eagle board and schematic
  • Bill of materials
  • Arduino sketch for firmware
  • Arduino sketch for calibration
  • Excel file to calculate calibration values
  • Windows software for MightyWatt control, as a C# Visual Studio project

2014/07/13

Reverse polarity and overvoltage protection

Circuits that are connected to outside world should be reasonably protected. Who knows when somebody just plugs in a different power adaptor (of course with twice the voltage and polarity in reverse). So how to account for this?

Protection circuits
Reverse polarity
You can use a diode in series and zener diode (or better – a transient voltage suppressor) in parallel in combination with a fuse. But you can do it better. First, the diode in series can be replaced by P-channel MOSFET (Q1). Drain connected to input and source to output. Gate is connected to ground. The transistor appears to be reversed and it is. But on purpose. Suppose the voltage is reversed. Then, gate is on V+ so the transistor is closed. Its intrinsic diode is reverse biased so no current flows. 
During normal operation, the current flows through its intrinsic diode but the gate, being grounded, has also lower voltage than the source so the transistor conducts in active mode. It is fully open and its resistance is the Rds(on) value. Which can be very low. In this way, the diode drop is eliminated and energy loss on transistor is negligible.
If you need to protect against voltages that are larger than the gate-source breakdown voltage (Vgs), then a voltage-limiting zener diode (D1) and a current-limiting resistor (R1) have to be added to the gate.

Overvoltage
It is possible to automatically disconnect a circuit when the input voltage exceeds a predefined level. This is different from parallel transient voltage suppressor and fuse. Blow fuses have the obvious problem of being a one-time devices. PTC resettable fuses tend to be slow and they can conduct significant amount of current even in tripped state (to stay tripped, the fuse needs to maintain itself hot). You can use electronic fuses for overcurrent conditons though.
With just two P-MOSFETs and a few components, it is possible to automatically limit the input voltage. The principle is this: A zener diode (D2) is chosen with value slightly lower than the maximum allowed voltage on the output. Then, when the voltage is higher than the zener voltage, D2 starts conducting and voltage drops across resistor R2. This lowers the voltage on the gate of Q2, which will open, raising the voltage drop across R4. The gate of Q3 sees higher voltage and Q3 thus closes, disconnecting the protected circuit from excess voltage. All without tripping any fuses or causing excessive current flow. Neat! Because you can get P-MOSFET with very low Rds(on), the losses can be minimal.
Resistor R3 and two zeners, D3 and D4, are there for gate protection just like D1 and R1. 

2014/06/22

BFuse – Electronic Fuse for Breadboard

Prototyping is a dangerous job. Not for a person if you keep the voltage down but for the components. On breadboard misplaced chips, loose connection and other errors can blow the components. To save them a fuse is a good idea. Having said that, standard fuses are not very suitable for breadboarding. Blow fuses have the inherent problem of being a one-time component. And during prototyping, a lot of overcurrent conditions can happen.

A better way is to use a resettable fuse, also known as PTC. After tripping, it turns into a high-impedance state and remains tripped until the overcurrent condition is removed. But they have disadvantages too. Just like the ordinary blow fuse, the tripping time depends on how much current is passed. For example, to achieve 1 millisecond breaking time a quick blow 1-amp fuse needs to pass 10 amps. For 1-amp PTC at 10 amps, the tripping time is around 100 milliseconds. That is way too long and way too much current. Moreover, resettable fuse still leaks some current in its tripped state because it has to keep being hot.

This leads me to a more advanced solution for overcurrent protection: Electronic fuses. They are devices made to sense the current and disconnect the load when an overcurrent is detected. This is usually achieved by FET switches, which are very fast compared to both blow fuses and PTCs.

You can make your own electronic fuse with only some transistors but the more advanced devices are mixed-signal. There are electronic fuses made by Texas Instruments, Linear Technology and STMicroelectronics. Usually used in final products because they are often optimized for single voltage. 

My BFuse

What I made is an adjustable and programmable electronic fuse especially designed for breadboards – a breadboard fuse, or BFuse. It is powered from the same line it protects. The trip current can be set from 50 mA to 1 A but it can measure current up to 6 A. BFuse consumes less than 10 mA and works in the voltage range from 3.3 to 12 V. It has reverse polarity protection (by P-FET), transient voltage suppressors both on its input and output and two LEDs for indication. A green one indicates power-good and red indicates tripped state. A reset button resets the fuse. Its on-state resistance is less than 100 milliohm, which is less than 1A blow fuses and comparable to 1A PTCs. But this resistance is the same in the whole range of trip currents. Shortest trip time is about 200 microseconds and the fuse has been successfully tested on a Statron 22A power supply.

Complete schematic of BFuse

The adjustable trip current is set by a trimmer but the fuse is programmable. Its core is a well-known ATTiny25 from Atmel. Set current and actual current (measured by current shunt monitor) can be compared using ATTiny's built-in comparator or sampled by the ATTiny's ADC. Then, the microprocessor controls a P-FET switch that opens or closes the power supply. The switch operates on high-side so there is no messing with the ground.

In-system programmable using SPI, the fuse can do a lot of tricks. It can emulate fast blow fuses, slow blow fuses, it can be latching or auto-restart or it can allow some inrush current at startup to charge capacitors without tripping. Because it can measure up to 6A, there is a lot of space for tailored operation. It is also small, only 18×36 mm, and takes very little space on breadboard. 

BFuse on breadboard

To be fair, there are some drawbacks too. First, it is more expensive than a simple PTC and needs some minimum voltage. Second, it is not as fast as a commercial electronic fuse, nor it can limit current in linear mode. BFuse can only switch on and off. But it is a great tool for breadboarding and it definitely saved me many components.

If you're interested, you can find source files (code, schematic and board) on my Google Drive. The code uses ADC and allows inrush current at startup. You should set the ATTiny to 1 MHz and turn on the 2.7V brown-out fuse (BODLEVEL = 0b101).

2014/05/02

Zero Resistance Ammeter

Is it sorcery to make an ammeter with zero resistance? Not really. This kind of design has been used for ammeters in corrosion science where any voltage drop would influence the experiment.

Most commonly, current is measured by passing it across a shunt resistor, then measuring the voltage drop. You can even get specialized amplifiers for that purpose (INA210-series, INA199, ZXCT1110). But such a technique creates the necessary voltage drop. What if you want not to drop any voltage and yet measure the current? There are Hall-effect probes which measure the magnetic field created by flowing current. They are good especially for larger currents. For everything else, there's Mastercard Zero Resistance Ammeter.

The ZRA is an active device; it needs a current source equal to the current being measured. For low currents, only a single op-amp is needed for maintaining equal voltages on the two input terminals. For larger currents you can boost its capabilities by a single transistor. A second op-amp (or current shunt monitor) is needed to scale the voltage drop for external measuring device or ADC.

Complete schematic of the zero resistance ammeter

My design uses a single 1.2V NiMH battery as the power source. Because the op-amp needs at least 2.2V, I put a small DC switching boost regulator to increase the voltage. A switched-capacitor type would work likewise.

The positive terminal is connected to ground. Current is sinked and for the negative terminal it is sourced from the battery. The current passes through a NPN transistor, a Schottky diode (to block reverse polarity) and a shunt resistor to the negative terminal. I used a dual op-amp, OPA2376, which has a very small input offset voltage. It would work well with a cheaper type though. One op-amp senses the voltage at the negative terminal and adjusts the current to the base of the NPN in such a way that the voltage at the negative terminal is kept zero. The NPN works in linear mode, lowering the voltage from the battery. The second op-amp only amplifies the voltage at the shunt resistor by a factor of 100 to have 1V = 1A. Capacitors C1 and C2 are needed for stability.

Assembled on breadboard

In the picture above, the shunt resistor is actually 0R02 and the gain was thus only 50.
From left: Trimmer for gain, OPA2376, shunt resistor, Schottky diode SS14 (bottom), FZT853 NPN, TLV61220 boost regulator with capacitors and inductor soldered directly to adaptor board, Sanyo Eneloop 1.2V NiMH battery.

1.003 V (= 1.003 A) and true zero voltage drop

The maximum current is mostly affected by heat sinking of the NPN. With a FZT853 in a rather small SOT-223, it is good for 1A. With beefier transistor, it would go somewhere around 4A, where both the current to base and the current from the battery will limit further expansion. On breadboard, keep it under 1A. I learned the hard way that at 2A, the board sometimes melts :-)

2014/04/19

Easter Egg the AVR way

For this Easter, I had something in my mind. A playing egg. A quick project to make an easter egg play a short tune.

To make that, I took an ATTiny10 microprocessor, a really tiny piece of programmable silicon. A small speaker I got some years ago probably from a defunct digital camera. Then, only a 3V CR2016 battery and two resistors were needed. And of course the egg.

Schematic of the Eggplayer.

I programmed the internal Timer/Counter0 on the ATTiny to change the frequency in such a way that it would play a note. To play a tune, I downloaded a midi file, a midi editor and extracted the chorus notes and put them into the ATTiny. It only has 1 kB of memory and each note takes 1 byte: 3 bits for length (1/32, to 4/1, can be changed) and 5 bits for frequency (nearly 3 octaves starting at C5 but it can be changed almost arbitrarily). Also one byte is needed for the BPM of the tune to correctly time the note duration. About half the memory is left for the notes, the other half is the program.

Circuit with CR2016 battery.

So I got a tune-playing ATTiny, powered by 3V battery. To trigger the tune, I used a phototransistor. When the light strikes the phototransistor, it conducts and changes the level at PB0 of the ATTiny. This wakes up the microprocessor from sleep mode and plays the tune. After that, it returns to sleep.
I attached the phototransistor on the top of the egg and put the circuit into an IKEA Egg cup. To block the light (and protect the circuit from NSA), I made a tinfoil hat for the egg (see the video). From cardboard, tinfoil and some hot-melt. 
Now when you remove the hat, the ambient light strikes the phototransistor, it conducts and changes level on the PB0 port. The tune plays and then stops until the next level change.

Etched face and the phototransistor, secured by some Kapton.

But to add some geekiness to this setup, I also tinkered with the egg: I am not graphically-talented but I am a chemist and do have some FeCl3 lying around. I was wondering if I could use it to etch a drawing. So I drawed a face on a hard-boiled egg with Tipp-Ex Correction Fluid and then immersed the egg in a 10 wt.% solution of FeCl3 for 10 minutes. It turned out it got etched a bit and after removing the correction fluid I got my drawing on the egg. A simple face and a simple circuit.

One egg, one cup. Circuit schematic is etched on the back of the egg.

If you are interested in the code, below is what I typed in Atmel Studio 6.2 into a single c file. The notes are only defined from C5 to C6 but this can be expanded with all 32 available notes. Watch the video before reading the code :-)



#include <avr/io.h>
#include <avr/interrupt.h>

#define CLK 1000000UL

#define C5period 478
#define C5speriod 451
#define D5period 426
#define D5speriod 402
#define E5period 379
#define F5period 358
#define F5speriod 338
#define G5period 319
#define G5speriod 301
#define A5period 284
#define A5speriod 268
#define B5period 253
#define C6period 239

#define PAUSE 0
#define C5 1
#define C5s 2
#define D5 3
#define D5s 4
#define E5 5
#define F5 6
#define F5s 7
#define G5 8
#define G5s 9
#define A5 10
#define A5s 11
#define B5 12
#define C6 13

#define BEAT32 0
#define BEAT16 32
#define BEAT8 64
#define BEAT4 96
#define BEAT2 128
#define BEAT1 160
#define BEAT0_50 192
#define BEAT0_25 224

#define BEAT32duration 66

void setup(void);
void delayms(uint16_t);
void play(uint8_t);
void setCounter(uint16_t);
void rickRoll(void);
void powerDown(void);

int main(void)
{
    setup();
    while(1)
    {
        powerDown();
        rickRoll();
    }
}

void setup(void)
{
    // enable global interrupts
    sei();
   
    // main clock
    CCP = 0xD8; // configuration change protection
    CLKMSR = 0; // internal 8 MHz oscillator
    CCP = 0xD8; // configuration change protection
    CLKPSR = 0b11; // 8x clock division
   
    // timer/counter0
    TCCR0A = (1 << COM0B0); // toggle on compare match
    TCCR0B = (1 << WGM02); // CTC mode
    TCCR0B |= (1 << CS00); // prescaler 1
   
    // i/o
    DDRB |= (1 << DDB1); // OCR0B port output
    PUEB |= (1 << PUEB2) | (1 << PUEB3); // pull-up on unused pins
   
    // interrupt
    PCICR = 1; // enable pin interrupt
    PCMSK = (1 << PCINT0); // pin 0 is active
}

void delayms(uint16_t ms)
{   
    uint16_t i;   
    uint8_t j;   
    for (i = 0; i < ms; i++)
    {
        for (j = 0; j < (CLK / 4000); j++)
        {
            asm("NOP");
        }
    }   
}

void play(uint8_t durationAndNote)
{
    switch (durationAndNote & 0x1F)
    {
    case PAUSE:
        setCounter(PAUSE);
        break;
    case C5:
        setCounter(C5period);
        break;
    case C5s:       
        setCounter(C5speriod);
        break;
    case D5:
        setCounter(D5period);
        break;       
    case D5s:
        setCounter(D5speriod);
        break;
    case E5:
        setCounter(E5period);
        break;
    case F5:
        setCounter(F5period);
        break;
    case F5s:
        setCounter(F5speriod);
        break;
    case G5:
        setCounter(G5period);
        break;
    case G5s:
        setCounter(G5speriod);
        break;       
    case A5:
        setCounter(A5period);
        break;
    case A5s:
        setCounter(A5speriod);
        break;
    case B5:
        setCounter(B5period);
        break;
    case C6:
        setCounter(C6period);
        break;
    }
    delayms(BEAT32duration << (durationAndNote >> 5));   
    setCounter(PAUSE);
    delayms(5);   
}

void setCounter(uint16_t val)
{
    OCR0AH = (val >> 8);
    OCR0AL = (val & 0xFF);
}

void rickRoll(void)
{   
    play(BEAT16 | C5);
    play(BEAT16 | D5);
    play(BEAT16 | F5);
    play(BEAT16 | D5);

    play(BEAT8 | A5);
    play(BEAT8 | A5);
    play(BEAT4 | G5);
    play(BEAT8 | PAUSE);
    play(BEAT16 | C5);
    play(BEAT16 | D5);
    play(BEAT16 | F5);
    play(BEAT16 | D5);

    play(BEAT8 | G5);
    play(BEAT8 | G5);
    play(BEAT8 | F5);
    play(BEAT16 | E5);
    play(BEAT8 | D5);
    play(BEAT16 | C5);
    play(BEAT16 | D5);
    play(BEAT16 | F5);
    play(BEAT16 | D5);
   
    play(BEAT4 | F5);
    play(BEAT8 | G5);
    play(BEAT8 | E5);
    play(BEAT16 | D5);
    play(BEAT4 | C5);
    play(BEAT8 | C5);
   
    play(BEAT8 | G5);
    play(BEAT8 | F5);
    play(BEAT4 | F5);
    play(BEAT4 | PAUSE);
    play(BEAT16 | C5);
    play(BEAT16 | D5);
    play(BEAT16 | F5);
    play(BEAT16 | D5);
   
    play(BEAT4 | A5);
    play(BEAT8 | A5);
    play(BEAT4 | G5);
    play(BEAT8 | PAUSE);
    play(BEAT16 | C5);
    play(BEAT16 | D5);
    play(BEAT16 | F5);
    play(BEAT16 | D5);
   
    play(BEAT4 | C6);
    play(BEAT8 | F5);
    play(BEAT8 | F5);
    play(BEAT16 | E5);
    play(BEAT8 | D5);
    play(BEAT16 | C5);
    play(BEAT16 | D5);
    play(BEAT16 | F5);
    play(BEAT16 | D5);
   
    play(BEAT4 | F5);
    play(BEAT8 | G5);
    play(BEAT8 | D5);
    play(BEAT8 | E5);
    play(BEAT16 | D5);
    play(BEAT4 | C5);
    play(BEAT8 | C5);
   
    play(BEAT4 | G5);
    play(BEAT4 | F5);
    play(BEAT2 | PAUSE);
}

void powerDown(void)
{
    DDRB &= !(1 << DDB1); // OCR0B port disable
    SMCR = (1 << SM1); // power-down mode
    SMCR |= (1 << SE); // sleep enable
    PRR = (1 << PRADC); // shut down adc
    asm("SLEEP");
}

ISR(PCINT0_vect)
{   
    SMCR &= !(1 << SE); // sleep disable
    DDRB |= (1 << DDB1); // OCR0B port output
}

2014/03/06

What is PIC for?

The high popularity of Arduino and ARM begs a question: What is PIC for? Is the Microchip's micro chip out of the game? Well, I don't know but I found out a great thing you can do with a PIC (or any QFP chip…):

A pair of PIC as a pair of earrings.

2014/02/25

MightyWatt: Lessons learned

Smart people learn from mistakes of others. And now you have an opportunity to learn from mine :-)
When I was developing MightyWatt, the Arduino Electronic Load, I had to change a lot of things from the first desing on breadboard.

FET
Using FET in linear mode is generally a bad idea. But these devices are so much more convenient at high currents than BJTs. During development, I learned what is FBSOA and that all datasheets are not created equal. FET experience thermal instability in linear mode at high Vds and Ids. This instability is known (now even to me) as the Spirito effect:

P.Spirito (M. IEEE), G. Breglio (M. IEEE) V. d’Alessandro, N. Rinaldi (M IEEE)
Dept. of Electronics Engineering, Universita di Napoli “Federico II”, Via
Claudio 21, 80125 Napoli, Italy. 0-7803-7318-9/02 IEEE paper 2002

But not all datasheets account for it in their FBSOA curves. Mostly International Rectifier datasheets do have this kind of information.
So during testing, I fried three FETs in linear mode before finding the correct device. Luckily, IXYS semiconductors manufactures an entire series of FETs designed to operate in linear mode. The series is designated "L2" and is the kind of FET I finally settled on. The drawback is that they are more expensive at the same Rdson/Ids/Vds combinations than the standard "switching" FETs.

Measuring the temperature
Knowing the juction temperature of a FET is very important for the "load" kind of project. It directly determines the maximum safe power you can dissipate. But how to measure it? There are some articles that use the intrinsic diode as a temperature sensor. Fine, but it would probably need calibration of every single FET. The principle is basically this: You heat the FET in linear mode, then switch the load off and immediately measure the forward drop of the diode. It is proportional to junction temperature so you should be able to estimate it. I didn't go that way.
Thermal imaging is a convenient way of measuring the surface temperature. Provided you know the emissivity of the material and you actually have access to a thermal camera. I am lucky enough to have access to Flir i7 thermal camera at the institute where I study. But such technique is of course only good for calibration of other temperature sensor. The case temperature is lower than the junction temperature but not that much. Yes, there are thermal resistances from junction to case in the datasheet but they relate to the metal pad that is connected to the heatsink and hence not visible to the thermal camera. And you won't be able to accurately calculate the heatflux from the side of the FET to the surrounding air unless you do a lot of mathematical modelling. So an educated guess and a healthy safety margin is necessary. 

Here are the techniques I tried for measuring the case temperature:
1) Mounting a TO-220 digital thermometer in the same fashion as the FET, thus measuring the heatsink temperature. This turned out to be the slowest method. The TO-220 package has high thermal capacity so its thermal impedance is high.
2) Gluing a through-hole thermistor on the side of the FET using a thermally-conductive epoxy. This turned out to be faster than the TO-220 thermometer but also quite slow. The reported temperature was also a lot lower than the actual (thermal camera) case temperature. The good thing is that this method is cheap but you have to mess with epoxy.
3) Gluing a small PT100 thermistor on the side. This was faster than the regular thermistor because the PT100 was much smaller. But then again, there is the epoxy and you need at least one precision op-amp to convert the resistance to useful voltage for the ADC. Good method but expensive.
4) Using a thermocouple. Very fast response because the thermocouple is very small and very well thermally conductive. But needs even more expensive circuitry than the PT100 and epoxy again.
5) Placing a tiny (0402) thermistor beneath the FET and coupling it using thermal grease. This turned out to be faster than the PT100 but slower than the thermocouple. It lagged behind the thermocouple by just a couple of seconds. The advantage is very low cost and no need for epoxy. This method is the one I finally settled for. Easy, cheap, and adequetely fast response. The temperature is still different from the one from thermal camera but it can be easily recalculated. In fact, when the thermal camera reported 105 °C, the themistor was at 92 °C. If you know this, you only have to adjust the thermal limits. Say, if the junction temperature is 10 °C above the case temperature, then it was 115 °C. Ambient was 22 °C so it was 93 °C more. The thermistor reported 92 °C, 70 °C above ambient. 
This means that the actual difference is 1.33 times the measured difference. Recalculating to 25 °C ambient and 150 °C junction, the thermistor would report 119 °C. I set the maximum temperature to 110 °C to give me some safety margin. This would imply 94 Watts maximum power so the 70 Watts is very conservative.

Measuring the current
I was already convinced to use INA210 series current shunt monitors but my first attempt was with a 2512 power resistor acting as the shunt. It turned out that in the recommended layout, with sense traces heading to the centre of the resistor, a part of the current being measured goes through solder. And you know what? Solder has a horrible thermal coefficient for resistance. I got extremely unstable current values, differing up to 10 % from the real values. Because the resistor is directly connected to FET, you don't have to worry about power rating very much. It is thermally coupled to the heatsink so it is cooled by it. But it is also heated by the FET. I had to replace the resistor with a more special "four terminal" model from Vishay Dale. Now no solder would be between the measuring and power "terminals". Problem solved.

Preventing oscillations
FETs have large gate capacitance and that means oscillations when driving them with op-amps. I knew that but the actual solution to prevent the oscillations was the winner of a trial and error contest. What works on breadboard does not necessarily work on PCB. I tried various models of snubber circuit (RC, R-RC, ETC, I mean, etc.) but finally, the best solution was to actually increase the gate capacitance by placing a large, 10 microfarad, capacitor from the gate to ground. Without resistor, just utilizing the op-amp's output resistance. The oscillations only occur when the load capacitance is large enough than some threshold (different for different op-amps) but they fade out when the capacitance is very large.

Boosting the voltage
Gate voltage of such a power FET is more than the 5 V (more like 4.5 V) the USB can provide. I opted for swichted capacitor voltage doubler because the op-amp does not need a very large current or precise voltage. Anything between 7 and 20 Volts is OK. The first one I tried was LM2767 but it turned out to be too noisy, with its 11 kHz switching frequency. I replaced it with LM2766 with much less switching noise but unfortunately, the pinout is different so I had to change the PCB too.

Selecting thermal grease
High-performance thermal grease is a must for such an application. Luckily, thanks to the overclockers of the world, there is a big market for performance non-conductive thermal greases. I chose Arctic Silver 5 and it is perfect. But the wide selection thinned after I tried to get the service temperature range of the greases. The PC-modding industry does not produce datasheets. They produce PR leaflets. And CPUs run at much lower temperatures than I was planning to utilize. The Arctic Silver 5 was amongst the three greases I was able to get the service temperature for.

These were the major obstacles in my design efforts. I hope the knowledge will help someone, maybe you, to save some design time, components and swearwords.

2014/02/21

MightyWatt Arduino Electronic Load

Update: Improved version now available on Tindie


Every now and then I was testing some batteries and power supplies. Usually by loading them by a BJT attached on heatsink and controlling the current by potentiometer. I read the current and voltage on two multimeters and estimated the load characteristics. But because I am naturally a lazy person, I decided to build something more automatic. An electronic load. I call it MightyWatt :-)

The basic idea is pretty simple. I connect the device under test to a FET and shunt resistor to measure current. The gate of the FET is driven by an op-amp that maintains either constant voltage across the load or constant current through it. It all attaches to Arduino Uno R3 as a shield. Simple as that. And now for some details:

FET
The main transistor is IXYS L2 series FET that is tailored for linear applications such as this. I use TO-247 package but any through-hole version will do. IXTH75N10L2 has 21 mOhms Rds on and IXTH110N10L2 has 18 mOhms but is also more expensive.

Heatsink
I chose 50x50 mm BGA-style heatsink with 5V fan because it suits the Arduino's outline. It can easily sink 70 Watts. The transistor is mounted on the board upside down so the heatsink can be attached from the top. To get a good thermal contact, the transistor sits on a 1mm silicone pad compressed to about 0.8 mm. There is also Arctic Silver 5 thermal grease, which, at these heat fluxes, is very important.

Measuring the temperature
Underneath the transistor, there is a tiny 0402 thermistor. I cut out a window in the silicone pad for the thermistor and filled it with electrically non-conductive thermal grease. In this way, I get fast response and I don't have to glue anything on the transistor. The measured temperature is, however, lower than the junction temperature so a healthy safety margin is necessary. See the thermal image at the end…

Voltmeter
A simple resistor divider between the inputs is used for voltage measurement. Its output is buffered by an op-amp before being measured with Arduino. There is also a selectable 5.7x gain for low-voltage inputs, accomplished by an analog switch. The full-scale is 30 V but the FET can actually handle 100 V.

Ammeter
Current is measured by voltage-drop method across a 4 milliohm power resistor. INA214 current shunt monitor amplifies the signal 100x for a 10 A range. The load would easily handle 20 A and probably could be extended to 30 A if needed.

DAC
To set the desired current or voltage, a 12-bit DAC is used. I chose MCP4276 from Microchip. It is cheap and reasonably accurate.

Modes of operation
The load can be operated at constant current (CC) or constant voltage (CV). At CC, the signal from ammeter goes to the inverting input and the DAC signal to the non-inverting input. At CV, the signals are switched so the DAC goes to the inverting input and voltmeter signal goes to the non-inverting input. The signals are switched using an analog DPDT switch. The same style as the voltage gain is controlled.
Because the FET's gate voltage needs to be larger than the 5 V supplied by Arduino, there is a switched capacitor voltage doubler which powers the op-amp.

Other stuff
The load also has some protection against ground loops (PTC) and voltage spikes (TVS). There is a reference voltage of 2.495 V and a single red LED that can be used for whatever is needed but it was thought as an overheat indicator. However, with good software, overheat is very unlikely.

Specifications
The load as very variable but my version has these specifications:
  • 70 W
  • 10 A
  • 30 V / 5.25 V
  • 25 milliOhms minimum resistance
  • Constant current and constant voltage modes in hardware
  • Constant power and constant resistance in software
Schematic
So here goes the schematic:



Assembled
This is the (hand) assembled PCB:

  • Top: DAC.
  • Top right: Voltage reference.
  • Bottom right: Fan connector, red LED.
  • Bottom middle: Screw-clamp terminal, PTC fuse.
  • Bottom left: Current shunt monitor.
  • Left: Switched capacitor voltage doubler.
  • Top left: Op-amp for gate driving and voltmeter buffering. Two analog switches for voltmeter gain and CC/CV switching.
  • Centre: The main FET lying on a 1mm silicone pad with thermistor underneath. Between the FET and the terminal is a 1.5kW transient voltage suppressor.

Nothing much on the bottom except the current measuring resistor and pinheads to connect the load to Arduino. The pinout is for UNO R3, the connection for I2C is different from earlier Arduino versions and it was convenient for me to put the I2C pins to the new location.

And the whole unit with heatsink & fan running:


Software
The sketch I programmed uses serial communication to send status and receive commands. The Arduino's ADC is oversampled to 12 bits for voltage and current. Temperature was left 10-bit. The ADC sampling takes the most time from all the processing.
Voltmeter, ammeter and DAC all need calibration because of some offsets and part tolerances. But a simple linear calibration curve is sufficient.
CC and CV modes are hardware so the control loop is only measuring. But there are also constant power and constant resistance modes, which are software and performed at constant current hardware mode.
There is a watchdog in case commands stop arriving, the load resets itself in few seconds. That means there has to be a constant stream of communication, which brings me to the PC side of the program:
The Windows application was made using C#. It maintains a constant monitoring of voltage, current and temperature and can send commands to set the load. It has also some datalogging capabilities. The only trick was to make it in two threads so that one is constantly communicating with the load and the other is for GUI.
If you were so brave to read up to here, you can have all the source files from my public Google Drive folder.

Some measured data
Two fresh Ikea Alkalisk AA batteries connected in series and measured with increasing current over approximately 30 second:


Single GP ReCyko+ AA accumulator discharged at 1 A. Freshly charged but been in service for 3 years. Still, it had some 80 % of its rated capacity.


The heat of the battle
I run the load at 70 Watts for 30 minutes and tried to find the hottest spot on the case. The ambient temperature was 22 °C and the thermistor reported 92 °C. The case temperature on the sides is quite close to the junction temperature so at 105 °C there is still a healthy safety margin. If the junction temperature was 10 °C higher than the case temperature, it would mean a thermal resistance of 1.33 °C/W. The maximum power dissipation at 25 °C ambient temperature would then be 94 W with the junction temperature at its maximum – 150 °C. But I wouldn't go there for a long amount of time.


2014/02/10

Connecting Kern balances to PC

So we got an idea in the lab: Let's monitor how a sample dries out by continuously measuring its weight. Because all the balances were taken, we bought two new cheap balances from Kern. They were cheap but they also had a pretty decent resolution of 1 mg. Not bad for 300 €. We thought. But you know what they say, you get what you are paying for.
The balances (series PFB) have RS-232, aka serial port connector so we bought a RS-232 to USB adaptor based on one of the FTDI chips. We connected them, used Realterm for communication and guess what: nothing happened. We tried about five different adaptors we could find lying around the lab but none of them worked. Even more strange was that our analytical Ohaus balances were working fine with the adaptors. So the problem was somewhere within the new Kerns. The manual did not help much. The company is a german one but I suspect the work has been done far more to the east. The english in the manual somehow has a dodgy feeling. The manual did not help us at all. Especially the parts of menu which were documented in the manual as "not documented". Thank you very much Kern!

Partly desperate and partly angry we decided to buy the original Kern software and cable. For a hefty 175 €. We thought that if it wouldn't work, we return it all as defective and if it would work we have to find out why.
After many weeks, a CD and a cable arrived. Earlier, I said that you get what you pay for. But sometimes, you get far, far less. The Kern original balance software is a piece of shit. Honestly, it looks horrible as if some high-school guy made that over a weekend (after getting pretty high on Friday). And the cable was a simple RS-232 to RS-232 cable. Not even a USB we asked for. But it worked with our RS-232 to USB adaptor and now it was time to do a little hacking and find out why.

Well, have you ever heard of a null modem? In the times when emails were delivered by homing pigeons, there was a machine called a teleprinter. I have no idea what that was and I don't want to know but apparently, to connect them to modems, you had to use a null modem cable. Which is a crosslinked RS-232 cable. And for some nostalgic reasons, our Kerns are using this null modem thing. So the only trick was that the TX and RX lines had to be crosslinked in the cable. Damn you, Kern! I found it after disassembling the cable, which itself costs an outrageous 45 €. Finally, for the second balances, we ordered a cable and two connectors on Conrad and assembled the second cable for about 5 €.

But that shitty day wasn't over yet. We decided not to use the Kern software (which we practically wrote off) but rather Realterm which was now working. So we set Realterm to send weight command (ASCII "w") every 10 seconds and log the response so over a few days, we would get the drying curve. But every few hours, the balances with the non-original cable tared themselves. We had no idea why. The cable was the very same that Kern uses and the connectors too. The only limitation RS-232 should have is a 2500pF capacitance which we would hardly exceed with two meters of cable. But to be sure, I salvaged a CAT5 UTP ethernet patch cable and used one of the twisted pairs for the TX/RX and one cable for ground. Also, I trimmed the cable to 30 centimeters. The situation improved, the balances stopped taring themselves but every now and then, there is a missing measurement. The balances just do not respond sometimes. After analysing the file created by balances with the original cable, I found out that they too have some missing measurements. For me, it looks like the communication feature is really shitty. These Kerns are good as budget lab balances but only if you don't need the connectivity.

2014/02/08

TMP006

Measuring temperature is a common task. Luckily, many electrical quantities change with temperature. Well, luckily… sometimes it is a big bugger. Diodes change their forward voltage, resistors change their resistance and thermocouples their voltage. There is a plenty of temperature sensors out there but not all are created equal. I was always fascinated by contactless themometers. Heck, I use IR themometer when I cook all the time. And that is why I ordered this:

TMP006
The TMP006 is a contactless temperature sensor from Texas Instruments, an infrared thermopile. Unfortunately in tiny BGA package with 8 balls and 0.5 mm pitch. It has a thermocouple inside which is heated by the radiation of the measured object. But because it has to be connected to the rest of the die somehow, it is also heated by the die/board itself. So there is another temperature sensor, this time sensing the local temperature. Then, from the difference between these temperatures, you can calculate the temperature of the measured object. It is not very straightforward but TI have provided a user guide with the necessary equations. Some specs? Well, the range is -40 to 125 °C and it is connected via I2C. It can make 4 readings per second but it is more recommended to take just one per sec (lowering the noise of course).

How to solder
For a casual diyer its BGA package is a problem. Furthermore, there is a recommended layout which I reckon would be good to follow to get the best accuracy. There are breakout boards from Sparkfun as well as from Adafruit both for 15 $. I decided to design my own breakout board and have it manufactured in a local PCB company. I followed the TI's guidelines and made a small breakout with the TMP006 and one bypass capacitor of 0603 size. And with such a board, it is actually not so hard to solder the chip.
Silkscreen is necessary to precisely align the chip. And a magnifying glass. But before doing so, you have to use a good flux because the little balls on the bottom do not have any. I used some tacky Chipquik flux. 
The bypass capacitor makes a good indicator of the reflow process. If you use a lead-free solder paste, it will reflow at about the same time as the balls on the BGA. I use a crude hotplate for reflow soldering – a 4 mm thick duralumin plate heated by a regular gas stove. I am at the reflow temperature after 3–4 minutes. It is a poor-man reflow setup but so far it worked every time. The plate is covered with Kapton tape so I can take temperature readings using an infrared themometer (the duralumin has a hard-to-determine emissivity).
Maybe i was just lucky but it reflowed correctly. Unlike larger BGAs, you can check all the connections visually because they are on the sides (you only need a microscope or magnifying glass). Finally, I soldered the pinheads and was almost ready to go.

After soldering
For the best accuracy, you have to clean the board thoroughly, preferably in ultrasonic bath. I am lucky to have one industrial ultrasonic bath in my lab so it was no problem. But you can get a cheap ultrasonic bath for less than 30 € these days. TI recommends demineralized water. The final product of my effort was ready…

TMP006 on a very basic custom breakout board.

Calibration
I used Arduino for I2C communication and it went with no problems. So I got it connected and now for calibration… yes, the chip is not factory-calibrated. You have to DIY. And it is not that easy because it measures surface temperature, which tends to be different from the bulk temperature. Calibrating it with a contact thermometer could lead to serious errors. Just make a cup of coffee/tea and measure its surface temperature and its bulk temperature. They can easily differ by 10 °C.
So it is best to calibrate it with another IR themometer. Or thermal imaging camera. I have access to both so I used Flir i7 because it is just more fun than an IR thermometer. But both will suffice.
For calibration, I used a cup of tea (65 °C) and a bottle of Becherovka from the fridge (-14 °C). And a piece of paper for the ambient temperature (22 °C).
After some math magic, you are supposed to get a linear correlation and finally calculate a single value which is then used for calculation of the temperature of measured object. However, to my surprise, the calibration values weren't on a straight line. 

The catch
It turned out the sensor had a major flaw. The object being measured does not only change the thermocouple's temperature but also the board temperature so the final calculation is inaccurate. Very inaccurate until some kind of equlibrium is established. And that can take a loooong time. It is obvious if you think about it but it is not so obvious why TI didn't account for this. And apparently, I am not the only one who noticed so TI published a workaround paper that shows how to compensate for the change in board temperature. It is done by processing 4 consecutive samples. I did that and it worked. 

The bottom line
So finally, I got a sensor that was measuring temperature with about +/- 3°C uncertainty. Which is nothing special but remember this is a (relatively) low-cost contactless sensor. So after all, it is not that bad.
There is actually a pretty cool project using the TMP006 available on Instructables – an Arduino controlled coaster which changes backlight according to the cup's temperature. So, would you use this sensor?