Adding an MCP23017 16 port IO expander to Arduino or Esp8266 or Attiny85 or……..

After I made this expander module, a ready made module
with this chip has become available. So I actually would advice anybody needing a 16 bit expander, to buy that one rather than build it. The module will cost you abt 1.50 euro, while the individual chip may set you back a euro or so.

I am not claiming that what I am describing here is earth shattering or trailblazing, because in fact it is very simple and no doubt has been done by many already. But sometimes what is simple for the one, is still a question mark for the other, so here is quick ‘how-to’ of adding 16 I/O ports to your microprocessor. This is especially handy when working with a chip like the ESP8266 that has only limited I/O
The MCP23017 is an I2C enabled 16 I/O port chip. That means that you only need 2 pins (yes with Vcc and ground it makes 4) to control the chip and the added advantage is that you can share I2C with various other devices as well.

The 16 I/O lines are divided into an 8 I/O PORT A and an 8 I/O PORT B. Both can be used as input as well as output. The chip also has 2 configurable interrupts (that I will not be using). The physical layout of the chip makes it quite easy to use it on a piece of strip board.

The circuit (at right) is rather simple. At a last moment I decided to leave out the pull up resistors so it would be more flexible to use together with other I/O devices. The 3 Address pins A0-A2 determine the I2C address that ranges from 0x20 (all pins on ground) to 0x27 (all pins on Vcc).
The chip  can take a Vcc from 2.7V to 5V and this is perfect for 3.3 Volt devices as  the modern arduino’s and the ESP8266 range of boards.

Using the chip in a program is fairly easy. There are good libraries available, but it might help if you know how to program the chip without a library.
In my case I have all  address lines tied to ground and therefore my I2C address is 0x20. Suppose I want to use all PORT A lines as outputs. I do that  as follows:

Wire.write(0x00); // IODIRA register
Wire.write(0x00); // set entire PORT A to output

For PORT B that  is rather similar:

Wire.write(0x01); // IODIRB register
Wire.write(0x00); // set entire PORT B to output

If we then want to send a specific value ‘X’ to that PORT A, we do that as follows

Wire.write(0x12); // address port A
Wire.write(X);  // value to send

‘X’ ofcourse is a byte value that determines whether we set a specific port HIGH or LOW.
If for instance ‘X’is ‘0’ that means we write a LOW to all PORT A outputs. If it is 255 that means we write a HIGH to all PORT A outputs.
To determine what value to send, consider the 8 I/O lines of PORT A as a byte in which the individual bits determine HIGH or LOW.
So if we only want to make PORTA.0 HIGH and the rest LOW, we write a binary value of 0b00000001 =1 to the A register. If we want to make PORTA.0 and PORTA.2 HIGH and the rest LOW we write a binary value of 0b00000101 = 5.
For PORT B it is similar:

Wire.write(0x13); // address PORT B
Wire.write(X);  // value to send

If we want to use PORT B (or PORT A for that matter) as input, we do that as follows:

Wire.write(0x13); // address PORT B
Wire.requestFrom(0x20, 1); // request one byte of data
byte; // store incoming byte into "input"

The byte “input” will vary between 0 and 255, in which the individual bits determine the input on the corresponding IO line. So if ‘input’  reads ‘3’  which in binary is 0b00000011, that means that both IO line 0 and 1  were HIGH and the rest LOW

#include <Wire.h> // Wire.h
byte input=0;
void setup()
  Wire.begin(); // wake up I2C bus
  Wire.write(0x00); // IODIRA register
  Wire.write(0x00); // set entire PORT A as output
void loop()
  // read the inputs of bank B
  Wire.requestFrom(0x20, 1);;
  // now send the input data to bank A
  Wire.write(0x12); // address PORT A
  Wire.write(input);    // PORT A
  delay(100); // for debounce

That’s basically it if you want to do the adressing yourself. Using a library, such as the one from Adafruit, makes it much easier though as it has commands to write and read from individual IO lines. One of the example programs to read a single button, looks  for instance like this:

#include <Wire.h> // Wire.h
#include "Adafruit_MCP23017.h"

// Basic pin reading and pullup test for the MCP23017 I/O expander
// public domain!
// Connect pin #12 of the expander to Analog 5 (i2c clock)
// Connect pin #13 of the expander to Analog 4 (i2c data)
// Connect pins #15, 16 and 17 of the expander to ground (address selection)
// Connect pin #9 of the expander to 5V (power)
// Connect pin #10 of the expander to ground (common ground)
// Connect pin #18 through a ~10kohm resistor to 5V (reset pin, active low)
// Input #0 is on pin 21 so connect a button or switch from there to ground

Adafruit_MCP23017 mcp;

void setup() 
mcp.begin();      // use default address 0
mcp.pinMode(0, INPUT);
mcp.pullUp(0, HIGH);  // turn on a 100K pullup internally
pinMode(13, OUTPUT);  // use the p13 LED as debugging

void loop() {
// The LED will 'echo' the button
digitalWrite(13, mcp.digitalRead(0));

If you want to use more than one MCP23017 do that as follows:

#define addr1 0 //addr1 =A2 low , A1 low , A0 low =000
#define addr2 1 //addr 2 = A2 low , A1 low , A0 high =001 

Mind you that “0” is in fact 0x20 and ‘1’ is in fact 0x21


Solar powering an Attiny or Arduino with a capacitor, or just use AA? Part 1

If you have a processor in a remote location that you cannot or will not bring a psu cable to, you have several options of supplying it with energy.
Batteries come to mind and these could be rechargeable or not, or one can use a capacitor. After all, those store energy as well. To make a capacitor a viable option, obviously it needs to be a big one (in capacity, not especially in size), and one has the option of adding a solar cell to it.
As I wanted to feed an attiny that is somewhere in my garden and that is asleep most of the time and as I had some idle solar panels  (9 Volts, 2 Volts) those seemed  suitable to use, but as they do not provide much energy during the night, I needed to store that energy as well. As storage Nicads or even a LiPo came to mind. A Lipo I discarded as it takes some extra circuitry to do any decent charging. A nicad obviously needs some consideration in charging and discharging  as well, but they are more tolerant albeit that a deep discharge is usually not appreciated by them, nor is a constant charge.
Therefore I also considered using a “supercapacitor” I have a capacitor of 10.000uF but one can hardly call that a supercapacitor, but nowadays supercapacitors are readily available at modest prices. They would be easy to use in a charging circuit (basically a resistor would be enough) and they don’t mind frequent  charge and discharge. As their charge is  limited, obviously I would need a solar-cell, so the only thing I needed to see is if they would carry my application ‘through the night’

The Charge of a capacitor is expressed in Coulomb (symbol C).
this can be expressed as:

C=F * V  (where of course ‘F’ stands for the capacity in Farad)
Energy in Joule is expressed as:
Which is:
F*V*V  of F.V²
However, at a given voltage and capacity only half of the energy is available to charge the capacitor hence the energy in the capacitor will be:
J=½ * F *V²
and Joules can also be expressed as ‘Wattseconds’:
J=W *s

So if we calculate the number of Joules in the capacitor at 5.1 Volt:
J=0.5 * 1.5 * 5.1² = 19.5 J
Now obviously we will not all use those as the attiny kinda stops working at 1.8 Volt. If we calculate the number of Joules still left then we come to
J=0.5 * 1.5 * 1.8² = 2.43 J
So the amount of usable energy comes to 19.5-2.43= 17J (rounded down)

From an earlier project on  an attiny13 that was put to sleep only to awake every so many seconds, I found out that the current consumption was 5.5 uA at 5 Volt. Now obviously it will consume a bit less when the voltage drops, so lets assume 4uA at an average of 3.45 Volt (The average voltage being (5.1+1.8)/2=3.45 Volt).
We can calculate the average power consumption as V*I:
3.45 * 4*10⁻⁶ = 13.8 uWatt
as we have 17 Joules available and 17 joules being 17 Ws (Wattseconds) we can calculate the time:
s=17/(13.8 *10⁻⁶)
s=17/13.8  *10⁶
s=1.23 *10⁶
s=1230 000 sec (1,23 million seconds)
that is:
20.531 min, is
342 hrs is
14 days
Now this is just an approximation as there might be some current leakage. The processor will need to do something when awake, like flash a  led or send something, so it will probably not make the full 14 days, but that is not important as it is obviously enough to carry us through the night and probably an overcast day as well.

So how would this be if I used normal AA batteries or NiCad batteries?
As example for regular alkaline batteries  I will take the ubiquitous Philips  LR6. Fortunately someone else already calculated the energie stored in these batteries  at  1986 mAh at a discharge of 100mA. As the performance of these batteries is increasing when the discharge decreases, I will use 2000mAh for my calculations.
If one uses 3 of those to get to 4.5 Volts that will be a total of 9000mWh or 9 Wh.
Again, we will not be able to use this all as we have 1.8 Volt as lower limit, so we will be stuck with 3.6 Wh that we cant use, leaving  5.4 Watthour usable energy.
The average Voltage on the  processor will be:
(4.5+1.8)/2=3.15 Volts.
the average power consumption thus is:
3.15* 4*10⁻⁶ = 12.6uW
as we have 5.4 Wh available we can again calculate the time:
h=5.4/12.6 * 10⁶
h=0.428571 *10⁶
h=428571 hr
=17857 days
=592 months
=50 years
Wow. Why would anybody want to use anything else but LR6 batteries ?
Well for several reasons: 3 of those batteries take more space and eventhough they tend to perform well at low temperatures and low discharge rate, we all have experienced that Alkaline batteries left in a hardly used device tend to leak, even destroying that device by its corrosive leaking. Advantages and disadvantages of alkaline batteries are discussed here.
Nevertheless using alkaline batteries can be a good choice, but don’t forget to change them.

Using NiCad batteries gives a somewhat similar calculation. Suppose we use 3 cells of 1.2 Volt 2000mAh (or 2Ah).
Total energy will be 3.6*2= 7.2 Wh
useable energy will be (3.6-1.8)* 2=3.6 Wh
the average voltage we set at (3.6+1.8)/2=2.70 Volt
The average power consumption will be:
2.7* 4*10⁻⁶ = 10.8uW  (V*I)
The time will thus be:
h=(3.6/10.8) * 10⁶
=333333 hr
=38 yrs
Now if that only was true. My experience with  for instance solar garden lights (that often only have an 800mAh cell)  is that they usually dont last through the winter… and mind you, those are being recharged (which could contribute to their demise).
Nevertheless they may be a good choice.

In a following article I will discuss some practical examples


A capacitive soil humidity sensor: Part 3

Initially I imagined the probe as a sleek device with a wire coming out that one would stick in the soil, if necessary completely. This would mean that the circuit pcb would be an integral part of the PCB that  formed the plates, but as always, things go different in practice. For one thing , the piece of PCB I intended to use just wasnt long enough. Second, my PCB etching possibilites are temporarily impeded. Third, I wanted to add an LDR, meaning that I had to have some sort of  translucent cover.

I constructed the circuit on a small piece of stripboard:

IMG_20160225_163125 i2cprobe

With regard to the LDR, sure that is nonsense. If I want to add an LDR I  could just as well add it to my base station. But I am not adding it because I have to, I am adding it because I can and because I wanted to get some experience in programming an I2C slave. An LDR might not be so usefull but in future I may want another sensor, e.g.a sensor that reads if there is really water flowing from the irrigation tube.

Also I had decided on putting the capacitor plates back to back, but as I did not have double sided PCB I just used two pieces glued and  soldered(!) together.
So My BOM was rather simple:

  • 2 equal size pieces of PCB  Size depends on what you have, but do not make them too small. I used 12×3 cm.
  • 1 piece of 0.5-1.0 cm plastic for a baseboard. I used an old cutting board.
  • 1 clear/translucent cover, I used the lid of a whipped cream spray can.
  • 1 piece of  thin 4 wire cable, length depending on your need

pcbprobe2I glued the two piecesof pcb back to back. drilled a hole in all 4 corners and through soldered a piece of wire through each hole, thus anchoring the plates together. I removed some copper around the solder so it would become an island isolated from the rest of the plate. (See picture).

Soldering the plates together in the corners may not be necessary if you decide to electrically isolate them from the soil with e.g. shrink tube.

Eventually I will place an NTC on the plate as well after it is covered with Shrink tube. Esthetically it might be better to put the NTC under the shrink tube, but that could create an air pocket.


baseplateI made the base plate from a o.5 cm thick piece of soft plastic. Cut out a round shape  with a 5.5 cm diameter to fit the base of my  clear dome and  made a slit 3 x0.3 cm into that in which the PCB  fits snug. made a round hole for the connecting cable.




I soldered two wires on the top of the PCB, one on each side. Soldered wires on an NTC, insulated those, attached the NTC to the bottom of the PCB with the wires leading to the top and then covered the PCB with shrink wrap.

probeEventually the probe looks like this (picture)probe3


A capacitive soil humidity sensor: Part 2

capacitive74HC14_attinyIn a previous article I presented a simple way to read a capacitive moisture sensor with a simple RC generator.
In this post I will present a sensor with some added functionality that can be read through I2C. The circuit (figure) doesnt need much explanation: the RC generator we saw in the previous article and the two variable resistors in a voltage divide read by analogue inputs. The Attiny 45 (NOTE, it is NOT an Attiny25) is the heart, or rather the brains of the sensor. As the Attiny  functions as an I2C slave we will need the TinyWireS library. The library comes with some examples and one example was quite easy to rework to what I needed. The code is as follows.

#define I2C_SLAVE_ADDRES 0x4
#include <TinyWireS.h>//
#define TWI_RX_BUFFER_SIZE ( 16 )

volatile uint8_t i2c_regs[] =
// Tracks the current register pointer position
volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);

byte LDRvalue;
byte NTCvalue;
int MoistPulse;

 * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the
 * send-buffer when using this callback
void requestEvent()
	// Increment the reg position on each read, and loop back to zero
	if (reg_position >= reg_size)
		reg_position = 0;

 * The I2C data received -handler
 * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does
 * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly,
void receiveEvent(uint8_t howMany)
	if (howMany < 1) { // Sanity-check return; } if (howMany > TWI_RX_BUFFER_SIZE)
		// Also insane number

	reg_position = TinyWireS.receive();
	if (!howMany)
		// This write was only to set the buffer for next read
		i2c_regs[reg_position] = TinyWireS.receive();
		if (reg_position >= reg_size)
			reg_position = 0;

void setup()
	pinMode(1, INPUT);

void loop()
	 * This is the only way we can detect stop condition (
	 * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead).
	 * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop.

void readSensors()
	LDRvalue = (analogRead(A2)) >>2; // max value is 1023/4=255 is 1 byte (FF) physical pin3=PB4=A2
        i2c_regs[0] = LDRvalue;
	NTCvalue = (analogRead(A3)) >>2; // max value is 1023/4=255 is 1 byte (FF) pin2=PB3=A3
	i2c_regs[1] = NTCvalue;
	//pulsepin= pin6=PB1
	MoistPulse = pulseIn(1, HIGH);
	i2c_regs[2] = highByte(MoistPulse); // or use = MoistPulse >> 8;
	i2c_regs[3] = lowByte(MoistPulse); // or use = MoistPulse & 0xFF;

I have called the pulseIn function with an integer rather than with a long. This means that you will have to choose a value for R3 that gives a reasonable range for the type of soil that you use. A range of say 0-200 uS is very reasonable. Once you have done that you can also add a timeout to the pulseIn function. This should be abt 2 times the pulselength you expect (but depends on the duty cycle). With regard to the two variable resistors, they are in pull up so their value is Rntc = Rseries/((1023/ADC) – 1));  For the NTC this could be substituted in a Steinhart Hart approximation

The code to call the values (and that is loaded onto the master arduino) is even simpler:

#include <Wire.h>
void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output

void loop() {
  for (byte i=0;i<4;++i){
  Serial.println(readRegister(i),HEX); // print the character
Serial.println(" ");

uint8_t readRegister(uint8_t regaddress)
	Wire.requestFrom(4, 1);


This code only prints out the values, you still need to combine the LSB and MSB from the cycle time and e.g. switch a pump based on the value. You could do that with this function:

int combine (byte lsbv, byte msbv)
	int value = msbv << 8;
	value = value | lsbv;
	//value= msbv<<8 | lsvb;//if you want to do it in one go
	return value;

Don’ t forget that the I2C lines need pull-up resistors of 4.7-10k.

In a next article I will present the construction of the probe itself.

A capacitive soil humidity sensor: Part 1

An automated plant/garden watering system is a popular application for  the Arduino and other microcontrollers. The humidity sensor that is often used is  often a resistance meter: 2 probes in the soil form a resistor and as part of a voltage divider that gives info on the amount of water in the soil.
The major shortcoming of these sensors is that since there is a current flowing, the probe is sensitive to electrolytic corrosion. Another shortcoming is that it doesnt really give information on the soil humidity, but more on the  ion concentration in the soil. Remember: pure water is a bad conductor, It are the ions in the water that make it a conductor.

To get around the corrosion, people have started to feed the probe with AC rather than DC current, but at best the circuits for this supply a pulsating DC current. Another  possibility to minimize corrosion is to  switch off  the current to the probe and only switch it on when a measurement is taken, say every 5  minutes.

All these measures help but even then, just due to the contact with moist soil, the metal on the probe will corrode and weather.
Another method is to encase the probes in plaster. Some people swear by it but I  think it is bothersome. Also the plaster encased probe has a lag as it will retain water  for some time after the  soil is already dry and it will still be dry for some time after the soil is already moist.

Capacitive measuring is a way to avoid these problems. With capacitive measurement the ‘plates’ of the capacitor can be electrically isolated from the soil and the soil in fact forms the dielectrum of the capacitor. Water makes a good dielectrum, whereas ions dont. Capacitive measuring therefore will have a better correlation with the actual amount of water in the soil than resistive measuring and, as said, ideally there will not be any corrosion.

Although the Arduino can measure capacity, it needs 3 pins for that. Also, it isnt really practical to have a long wire as part of your soil probe capacitor go to your Arduino as the wire and whether it is  straight or curly or in a loop, will act as a parasitic capacity and affect the measurement.
Putting your Arduino right onto your plantbed might also not be the best solution.

RC Oscillator With 74HCT14

A better way to do this is to introduce an RC oscillator in which the soil functions as a capacitor and the Arduino measures the frequency that comes out of the oscillator. More water  will increase the value of the ‘capacitor’ which usually will lower the frequency (or increase the cycle time) and that can be measured with the arduino.

An easy RC oscillator can be seen in the figure to the right. A 74HC14 or 74HCT14 Inverter Schmitt-trigger is all you need. For the HC version the Frequency is:
for the HCT version it is:

But in fact the frequency isn’t really that important because we are not making a frequency meter. We are only interested in changes of the frequency that relate to  dry, moist or wet soil. The workings of this type of Oscillator are explained here. and here. The theory behind the frequency calculation is explained here.

leydenjarI tested my set-up initially with a sort of Leyden Jar as a capacitor. Simply put I taped two pieces of alufoil on the outside of a glass jar, attached wires to it and tried if I could measure a change between an empty and a full jar. I started out using a 100k resistor, but only got a decent range after using a 2M2 resistor: an empty jar gave me 1uSec (maybe less, but I guess that was my lower limit) a half full jar around 50uS and a full jar about 100uS (measured with PulseIn). From using a known capacitor I knew I had to use the formula f=1/T=1/(0.67*R*C), but as said, neither the frequency or the actual capacitor value are of much importance as we are just looking for  changes.

Nevertheless the capacity of this jar (when full) could be calculated from
Now ofcourse this isn’t entirely correct as with PulseIn We only measured half a cycle, so in fact the Capacity is more likely to be 136pF, provided the dutycycle is 50% (some sources say it is 50% others say it is 33% with the space  2*mark).

byte pin = 8;
unsigned long duration;

void setup()
  pinMode(pin, INPUT);

void loop()
  duration = pulseIn(pin, HIGH);
  Serial.print("Time ");
  Serial.print(" usec ");
  Serial.print(" kHz ");
  Serial.println(" Hz");

Then it was time to do some garden field tests. There are several ways to construct a probe: two pieces of PCB at a distance from eachother, One piece of PCB with two plates etched onto it, or a piece of double sided PCB. With regerd to the latter, we tend to think of a capacitor as two plates with a dielectrum in between, but in fact it can also be two  plates with a dielectrum around it.

capacitive probe-textMy garden field test, using two insulated plates of PCB (picture) kinda gave similar results as with the Leyden Jar so I knew I had a decent design.

Yet, two plates is not really very handy: you have a loose wire connecting the plates and as that forms part of the capacitor it introduces stray capacitance, so I decided to go for either a double sided PCB, or a single sided PCB with two plates etched onto it and then place the oscillator on that PCB as well. Frankly, that idea isnt new as many of the (semi)DIY (e.g. the ‘Chirp’) or commercial capacitive probes follow that design as well.

Now it is always good  that before you make a PCB to think through what you want. As I was using only 1/6th of the 74HCT14, I was thinking maybe I could use the other gates as RC oscillators as well  for e.g. an LDR or NTC. Now ofcourse I immediately dismissed that again as I could just as well use an analog read of those and I would have to run extra cables that would all carry a frequency signal, no doubt those would interfere, but it got me thinking. The ‘Chirp’ has a big brother that has an I2C interface, if I would add that, I could add some other sensors (light, temperature)  to my probe. With just the capacitive sensor I would have to run 3 wires (+Vcc, signal, ground). With I2C 4 wires (+Vcc, SDA, SCL, Ground) would be enough for a number of sensors on my probe. Also, as I have various plantbeds, having a number of I2C probes wouldnt require  more inputs on my Arduino.

Obviously, adding I2C meant adding a microcontroller, preferably a cheap one, which easily brings one to the attiny25/45/85 series. If you have good eye sight and a steady hand, you could consider the soic version that is available from 30-70 cts. If you go for a DIP version, that is around 0.9-1 euro. Considering one can get an entire Pro Mini for about 1.20, obviously that is a narrow gap and I (or you) could consider giving each plantbed a totally dedicated  Pro Mini microprocessor that could take care of the irrigation as well.
Having said that, in the past, I have made a self contained system for plantbeds, just using 1 Opamp, so maybe I should just consider this I2C excercise a ‘learning excercise’

capacitive74HC14_attinyI came up with the following circuit. It is easy to recognise the RC oscillator. The cycle signal is fed to PB1 whereas the analog inputs on PB3 and PB4
A3= PB3=physical pin2;A2=PB4=physical pin3.
Pin PB2 is used as SCL signal and PB0 as SDA signal for the I2C interface.

If for any reason you do not have a 74HCx14 in your toolbox, there are other ways of constructing an RC generator. E.g. a 555 or a 74HC00. Even a single transistor could be used. With this type of oscillator the dutycycle approaches 50%


In a next article I will discuss how to implement the I2C software.

Simple EEPROM Module for Arduino or other microcontroller

256 EEPROMs come in handy if you want to store some data without losing it. Many microcontrollers come with some internal EEPROM, but as EEPROMs have a finite (though very large) number of writes before they start becoming faulty, my anal retentive character always had a problem with using that internal EEPROM.
There are other reasons too why you might want to use an external EEPROM: data logging in which you just want to swap an EEPROM rather than having to read out your microcontroller in the field.
Anyway, I just wanted to share a simple 5 minute build EEPROM module that is a bit simpler than a prior one i published.
1x 24LC256 EEPROM (or other size)
2x 4k7 resistors
stripboard 5 strips of 8
8 pin DIL IC socket (optional)

256pin I am using a 24LC256. That is a 256 kiloBIT EEPROM so in fact only a 32kiloBYTE EEPROM in my traditional way of thinking. These are not to expensive. Can be had for around 80 ct USD.
Although the board can also be used for smaller EEPROMS, like a 24C32, I would advise against that. If that is what you need, buy a 50 ct DS1307 RTC module that includes a 24C32 (which is actually 4kByte).

Anyway, the 24LC256 is an I2C EEPROM, which is pretty standard and which makes use easy
Pins A0, A1 and A2 select the I2C addresses, (A0=pin1, A1=pin1, A2=pin3).
The addressing is as follows

1 0 1 0 A2 A1 A0 x

So if you connect pins A0, A1, A2 to GND the I2C address will be 1010000 = 0x50 in hexadecimal.
If you connect them all to Vcc it will be 1010111=0x57.
As 0x50 is an address that is often used, I decided to connect A2 and A1 to ground and A0 to Vcc, which gives 0x51. It also made the design a tadd simpler.
Pin 7 is the ‘WriteProtect’ pin that needs to be pulled HIGH for ReadOnly and LOW for Read/Write. Obviously I connected it to ground.
The pull up resistors are both 4k7
You will find many EEPROM libraries in the Arduino Playground I tend to use the following code to read and write:

void writeData(int device, unsigned int addr, byte data)
// writes a byte of data 'data' to the chip at I2C address 'device', 
// in memory location 'add'
    if ( addr > 65535 )
        addr = addr | B00001000;
    Wire.write((int)(addr >> 8));   // left-part of pointer address
    Wire.write((int)(addr & 0xFF)); // and the right
byte readData(int device, unsigned int add)
// reads a byte of data from memory location 'add' in chip at I2C address 'device'
    byte result; // returned value
    Wire.beginTransmission(device); // these three lines set the pointer 
				    // position in the EEPROM
    Wire.write((int)(add >> 8));    // left-part of pointer address
    Wire.write((int)(add & 0xFF));  // and the right
    Wire.requestFrom(device, 1);    // now get the byte of data...
    result =;
    return result; // and return it as a result of the function readData

Special Notes if using the 24LC1025


This board can also be used for larger EEPROMS, but……… if you use it for the 24LC1025, you need to make a small adaptation. With this chip A2 MUST be tied to Vcc for it to operate.

The 24LC1025 has an internal addressing boundary limitation that is divided into two segments of 512K bits. Block select bit ‘B0’ to control access to each segment.

The addressing is determined by

1 0 1 0 B0 A1 A0 R/-W  

in which the ‘Block select bit is used to address the lower or higher 512k Block The chip thus has 2 different addresses. with the A0A1 selection as in my board those are:

1010101 =0x55

1010001 =0x51

For memory access from 0..65535 the I2C address for the Memory Chip is 0x51. If you want to access memory between 65536..131071 the Chip address is 0x55

You cannot write across the 65535..65536 byte boundary with breaking the operation into two write() calls. One to chip 0x51, the other to chip 0x55.

Adding Shiftregisters to an Attiny10

I have a problem: if I underuse a microcontroller, i feel uncomfortable. So if I see a project with an Arduino or standalone Atmega328 that uses only say 2 pins, I start thinking ‘Attiny’. But even then I would feel bad only using 2 pins of say an attiny85.

For a summer project for a friends daughter, she needed a number of LED’s to flash (on a costume). Well great for an Atmega328, after all that has a lot of pins, but then using an Atmega328 just to flash some LED’s? When it can do so much more? Plus, I had my bare Atmega328 chips already destined for other projects.

I had Attiny85 and Attiny13 chips, the latter being a great candidate… but that only has 4 pins to drive LED’s with, so i was thinking ‘Shift Register’. I still had some 595’s and 164’s.
But they need about 3 pins ‘underusing’ the Attiny13.
Anyway… I had an Attiny10, just one that I had been playing with.
Now I would not really suggest anyone to get these as even at aliexpress they are relatively expensive: I saw 10 for about 8 USD, while for about 1.60 USD one can already get a pro-mini. I might be anal retentive but I am not stupid. If you are lucky enough to frequent Japan though, they are available there for only 35 cts (eurocents).
Also they are in SOT23-6 which makes soldering difficult. And they cannot be programmed via ICSP like the Attiny85.
Mine however came from a guy who had bought a couple of them and gave me one to play with.
So, plenty of reasons to skip this chip, but as I had one, I saw it as a challenge to use it.
The circuit I used is pretty standard:
There are SOT23 to DIL adapters but they are kinda expensive plus that seemed defeating the purpose of using a small chip, so for testing and programming I etched a small board (I know, will probably never use it again) with a  clothes-pin as main ingredient (to keep the attiny10 in place). For the resistors I used sip packages.

Programming the Attiny10 is not done through ICSP but  through TPI. TPI programming can be done roughly via 3 ways:

  • A commercial AVR programmer (STK or AVRISP)
  • An FTDI break out board that has DTR CTS and RTS broken out
  • Your Arduino.

I opted for the latter and this is how to do that.

attiny10Connect the Attiny10 with digital pins D10-D13 as indicated in the circuit to the right.

Then you need the programming firmware. This has been developed by Keri Duprey. The latest version can be found here:

ATtiny4_5_9_10_20_40Programmer.ino or check here. The latter code does not program the Attiny20 or Attiny40, but solved some hickups in the former code

The former program can be used standalone or with a GUI that can be found here:
GUI: ATTiny4_5_9_10_20_40_Programmer.jar

The program  expects a hex file to be copied in the serial monitor. If you are using the GUI, it just lets you upload the hex file.

If you prefer to program the Attiny with an FTDI brak-out board, check this blog. Further interesting reading is found here.