Monthly Archives: August 2016

Faster ESP I2C

Experimenting with I2c on the ESP8266? I am – and I’m having a great time with it. If you’re using my code you don’t really need to think about it but if you’re hunting around for better I2c for the ESP – or maybe interfacing the ESP8266 to Arduino – then you’ll love the stuff I’m doing right now – and yes, I AM looking for I2c experts to tell me if I’m doing something wrong because it is all going rather too smoothly.

I decided to take the end from the info from the last blog entry and separate it off as I learn more about I2c (which to recall is a simple 2-wire multi-drop serial communication protocol with separate clock and data).

Why read this? Well, up to now because I spotted a howling issue in the WIRE library for Arduino, found an improvement on the ESP8266 SDK I2C code in the ESPRUINO changes to the Espressif I2c code - I think I found a mistake in it, fixed it then SAILED past the original speeds, reducing a 15ms package best case to well under 3ms  while adding clock stretching into the bargain.  I should clarify at this point that I am NOT an expert in I2C but hey – I can’t get this to fail so I might be onto something! Read on!

So firstly let’s recall -  I’ve been trying to make an Arduino peripheral for the ESP8266 Home Control 2016 project.  I started with the WIRE library in Arduino, working on a small NANO device. I discovered that there are two buffers in WIRE that are 32 bytes in length and hence limit packages to less than that  - I replaced them with a couple of 128 byte buffers and solved lots of issues I’d been having – that is detailed in the last blog.

Where we left off, I’d made a test setup to send a message to the newly-created NANO peripheral which right now on my bench handles a QTECH display and some IO. The ESP8266 I2C is also talking to a BME280 temperature/pressure/humidity sensor and a PWM expander board – so there are 3 devices – some input, some output.

In the last blog entry I’d added a test command for the ESP which could be sent to the board serially or by MQTT and went like this…

{nano:9,7,"how are you today and the weather is nice - NO REALLY it certainly is.",0}

Simple enough – send a message to device 9 (my chosen default address for the NANO peripheral), command 7, a string – and a dummy 0 on the end to tell the device not to bother sending any return info.

As you can see below, this operation takes, using the standard Espressif Ic2 Master code, 15ms in total – not stunningly fast but ok.i2c_thumb2

Flush with the success of finding that buffer issue, I decided to go into the ESP I2C library and have a tinker – changing all the delays into ‘'#defines so I could mess with them. So without any real effort I could reduce delays from 14ms to 6ms – a very worthwhile improvement. bear in mind however that the ESP code has no clock-stretching and hence no way for the peripheral to slow things down. I am told that the call-back routine within WIRE holds the clock down until it is finished, in order to slow things down – this would do nothing but cause havoc for the Espressif code.

Below is a read operation which I got to work properly after reading  this video – as I had no idea what a re-start was – see the little green circle just after the third byte.


As you can see in the image above I address device 9 (18 as it is shifted left by one – i.e. 7 bit addresses but the bottom bit is reserved to indicate a read or write) – I fire command 2 to read port 4 – then with an I2s restart (start without a preceding stop), I  resend to the device with the LSB set (ie 19) and get a value 0 back (from a pin)  All in a matter of a millisecond.

I was at this point getting worried about lack of clock-stretching – in which a slave can hold the clock low to “stretch” things out a bit – about the only control the slave has!

It looked as if this forum might have some answers as their modification of the ESPRESSIF code certainly had clock stretching in it. It involved some changes and I decided to pick the best bits from their modification.

So they’ve simplified the code a little – while adding in clock-stretching – by replacing a simple delay with a check for clock low – easy enough when you look at it… but they also seemed to have completely messed up master_start – at least, they had it the opposite way to Espressif – and accordingly, repeated starts – as I use in getting data out of a Nano above – simply failed. The logic probe said this was all wrong.

So I reversed master_start back to the way Espressif have it  –so I ended up with a mix of the old and new – and the result – well, up to now everything works – and that long 15ms string send was now reduced to under 5ms from 15ms.

5ms string_thumb[2]

I tested the code with the PWM chip I’ve been playing with and the BME280 – so that is both reading and writing and up to now both were working perfectly. 

It was notable that the clock low period was now much longer than the clock high period and I wondered if there is any way to shorten that.  You know when you get deeply into code and all of a sudden it all becomes clear.  I realised that setting and checking ACK signals was a function – with all that entails – I changed that to a macro. I realised that delays in loops were really un-necessary as the loop itself would cause delays.. I took them out.

At this point I had backed everything up expecting my experiments to fail miserably. I tested the new code and everything worked. I got the logic probe out again.


My original test string at 15ms was now down to 3ms and according to the probe – all is well. I DID get it down to 2.5ms but the probe said I was doing restarts in the middle of the string – I’ll find another way around that one. Current state of the art – 2.9ms

As for reads – my original byte read was taking somewhat over 1ms – it now takes 0.25ms.

fastish read

And of course I’ve concentrated on the read and write routines leaving the inter-byte handshaking pretty much along so maybe there’s another 10% improvement to make here without dipping into ESP assembly language. 

The driver and firmware libraries in the repository above contain the modified Espressif i2c_master code – and also other I2c wrappers for sending packages – they are fine – any further optimisation needs a good solid look at the one file (and it’s header) for i2c_master.   Open to ideas (that don’t involve converting Arduino assembly language to work with the ESP SDK – been there, failed).

I have just noticed that in the write cycles, there is still more off-time than on for the clock – and so I just took a delay out – which SHOULD mean the off-time is way too slow but because of the time taken to call and process the function – we still end up with 0.9us on time and 1.3us off time – everything continues to work on the tests I have – yet the total time for that read drops from 0.25ms to 0.21ms and the string write time from 2.9ms to about 2.2ms – again – worthwhile improvements.

That simple change was made in the write routine…

i2c_master_writeByte(uint8 wrdata)
    uint8 dat;
    sint8 i;

    for (i = 7; i >= 0; i--) {
        dat = wrdata >> i;
      //  i2c_master_wait(I2C_DELAY_5);

Logic analyser says yes, 3 test items say yes… how low can it go!


I2C the Easy Way

I2c on IOTBEARIf you’re going to experiment with I2C – may as well do it the easy way. Having spent the past few days with a desk that looks remarkably like a bowl of spaghetti, I’ve finally gotten around to making a special IOTBEAR board up for the job. 18 each of ground, +3v3 and +5v lines – and 16 each of GPIO4 and GPIO5.

This gave me the opportunity to tackle that long string problem in Arduino Wire. A brief attempt with the logic analyser suggested that my ESP i2c was sending out at least one byte more than the Arduino was receiving – impossible to tell if more because the ESP would stop sending as soon as the Arduino would stop receiving.

And that brings me to a question – is anyone aware of a nice, pretty I2c and other protocol analyser based on a Raspberry Pi? Seems to me that would be a good use for an old RPI2?

Anyway I digress… I’ve had issues with I2c experiments in the past – usually when sending strings. I’ve looked up the issue on Google and found nothing. I was convinced it was a timing issue and at that point I Skyped my friend Peter Oakes in Canada – just as with Aidan who you’ll have read about in here, I often find that “two heads are better than one” when I’m getting bogged down.

We started sending I2c strings to the Arduino who’s receive buffer I’d put a Serial.println() statement in – to see how many characters it THOUGHT it was receiving.

29…. 30… 31… 32… 32   - EH

As I increased the length of string sent from the ESP (using ESP software I2c) to the Arduino (using the WIRE library) at 33 characters the Arduino thought it was getting 32 – at 34 it went to meet it’s maker.

VOILA – the WIRE library clearly has a buffer to store stuff – I did not believe at first that 1. the buffer would be so small and 2. this would result in a crude crash.  I went into the Wire Library (that’s a long story – I have dozens of WIRE libraries and it took a while to find the right one) – updated the buffer size in wire.h and… nothing – made no difference. I introduced an error into the .h file to make sure I had the right one – sure enough  - but no joy on fixing the problem.

I don’t know if Peter or I twigged first but in my ESP SERIAL buffering which I wrote myself, I have a 256 buffer for incoming characters – which fills until it gets a CRLF then transfers that to an output buffer of the same size – so that incoming characters can continue to arrive while processing the buffer. It occurred to us that maybe the Wire library has the same setup – SURE ENOUGH. Not only is there a buffer definition in arduino/hardware/arduino/avr/libraries/wire/src/wire.h but also in arduino/hardware/arduino/avr/libraries/wire/src/utility/twi.h

And yes, the directory structure IS that complicated (I’m on Arduino 1.69) – sure enough two separate 32 byte buffers are created.  As I have never seen this covered so I assume I’m the only person in the world who’s ever sent 32 bytes via I2c… but if you’re about to try the same – and you’ll need to if you want to try my peripheral software, then I suggest despite the deep hole this will leave in RAM (all 2K of it) – making both of these 128 bytes.

Since amending and re-compiling – I can now send long strings to the Arduino absolutely to my heart’s content!

{nano:9,7,"how are you today and the weather is nice - NO REALLY it certainly is.",0}

Around 15ms in total – not stunningly fast but fast enough not to interfere with the running of anything.

For more on I2C – see the blog entry “Faster ESP I2C”


Arduino Peripheral for HC2016

As many of you know, I don’t have a great deal of time for Arduino – I cannot tell you how many months I wasted on those daft cheap Ethernet boards for them which never really worked reliably no matter what I did – so I probably have a mental block by now.

However, there can be no arguing that a board costing £1.28 inc. postage has to be worth at least a second look. The picture below shows where this all fits into the scheme of things…

Home Control 2016

And so it was today, I’d just finished putting some polishing touches on the I2c code, fresh from having gotten the BMP280 working – and I was looking at A/D boards to add to the arsenal when I remembered that Arduinos have A/D in… not stunningly high definition but good enough for checking batteries and light levels etc.

Nano[6]At that point, mid-coffee I remembered I’d bought one of these little critters from AliExpress. Be careful – not all of these bring A4 and A5 out, some have micro-usb connectors, others don’t. Some have 3v3 regulators, some don’t.  I find the most useful ones just have the FTDI connector on them and no USB – but then I have FTDI connectors coming out of my ears.

For the purposes of this item – a 3v3 regulator is not needed as presumably if you’re fastening I2c devices to the ESP8266, you’ll feed 3v3 to the whole lot. Anyway, use whichever suits you best. I’m also assuming pullups are in place – the Arduino has pullups but I doubt they are strong enough.

SO – the point of this is – it is quite easy to make an Arduino into an I2c slave – so for £1.28 you can make a port extender, more inputs, some analog inputs, PWM outputs – just about anything really as long as whatever it is doing doesn’t take up any time as the board needs to respond to I2c commands quickly. I have a MUCH more powerful device on the way from China with lots more pins etc. but for now, the humble Chinese Nano gets the job.

The simple WIRE library with a little code turns the Nano or similar into a device – I’ve chosen to make it DEVICE 9 by default  – don’t REALLY want to use up ports making that programmable but then because the board has EEPROM I’ve made a hopefully reliable method to store the device number in EEPROM!

In the simplest example, sending I2c commands to this device from the home control software discussed elsewhere in this blog – let’s say to turn output 13 on…


And indeed that was the very first command I made it respond to as an I2c slave – mainly because on these boards, port 13 has a LED attached to it!!!

Clearly turning it off would be:


Or how about reading the state of input 10?


So here I’ve chosen to create the command nano – command 1 is set ports (2 is read ports)… port is 13, last parameter is 1 or 0 for on or off.  Immediately we have a port expander with several useful ports. For ease, the software I put into the Nano checks to see if the port has already been setup correctly and does that if not – hence avoiding annoying setup code at the ESP end.

With the simplest code and assuming A4 is used as the SCL and A5 is used as SDA, you end up with a “nano i2c peripheral” able to offer (if you get the right board offering A0-A7):

  • 6 8-bit PWM channels
  • 6 8-bit ANALOG inputs

i.e. ALL of that. You could instead choose to have 18 general purpose I/O lines etc.

I’m sure it would not take most of you too long to figure out ALL SORTS of other configurations but for the sake of this project and this board example– there are ports 2-21 where Arduino A0 is 14. Now,  if your board DOES have A6 and A7, note that they can ONLY be used as analog inputs – they cannot be used as ordinary inputs OR outputs – that’s just a simple feature of the board, not the software.

The point being – they are SO cheap and with this code make good general purpose I2c peripherals – you have to ask yourself – in some cases, why you would use anything else!

So before we start – this will only work for short strings or series of numbers with the standard WIRE library for Arduino – see the blog where I learned the hard way this weekend that WIRE has a 32 byte incoming buffer AND a 32 byte transfer buffer and if you try to send more than that – the Arduino crashes – I’ve updated my WIRE to 128 bytes (so that’s 192 bytes more than before ) and it is working a treat with long strings – the reason I want that is because though you won’t see it in this basic code, I’m now working on running QTECH 160*120 displays in the Arduino peripheral.

I’ve updated the code and here is the current state of affairs – evolving rapidly, for the Nano - expect this to change – again  -  this time tomorrow it will no doubt have changed - again.


// A simple i2c SLAVE - default device number 9 - reads instructions from
// master and either sets outputs or returns inputs accordingly.
#include <Wire.h>
#include <EEPROM.h>

#define MAXPORTS 21
#define ADDR_LOC1 0
#define ADDR_LOC2 1

#define SET_OUTPUT  1
#define READ_INPUT  2
#define SET_PWM     4
#define READ_ANALOG 5
#define SET_ADDRESS 6

byte ports[MAXPORTS];
byte params[6];
byte paramp;
byte retParam;
byte bigcount;
byte device=9;

void setup() {

  byte eeprom1,eeprom2;;; 
  if ((eeprom1^eeprom2)==255) device=eeprom1; // programmable address
  Wire.begin(device);           // join i2c bus with address #9 by default
  for (int a=0;a<MAXPORTS;a++) ports[a]=0;

void loop() {}  // not used yet

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {

  Wire.write(retParam); // respond with message of 1 bytes as expected by master
  //Wire.write(34); // respond with message of 1 bytes as expected by master
  //Wire.write(45); // test
  //Wire.write("This is it you know",19);

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void receiveEvent(int count) {
int tcount;
// no time consuming in here or the routine to send a byte back will be missed.
  while ((tcount--)&&(paramp<128))
  switch (params[0])
    case SET_OUTPUT:
          if (ports[params[1]]!=1) { ports[params[1]]=1; pinMode(params[1],OUTPUT); } 
          digitalWrite(params[1],params[2]? HIGH : LOW); params[0]=0;
    case READ_INPUT:
          if (ports[params[1]]!=2) { ports[params[1]]=2; pinMode(params[1],INPUT); } 
          retParam=digitalRead(params[1]); params[0]=0;
          if (ports[params[1]]!=3) { ports[params[1]]=3; pinMode(params[1],INPUT_PULLUP); } 
          retParam=digitalRead(params[1]); params[0]=0;
    case SET_PWM:
          if (ports[params[1]]!=4) { ports[params[1]]=4; pinMode(params[1],OUTPUT); } 
          analogWrite(params[1],params[2]); params[0]=0;
    case READ_ANALOG:
          if (ports[params[1]]!=2) { ports[params[1]]=2; pinMode(params[1],INPUT); } 
          retParam=analogRead(params[1]); params[0]=0;
    case SET_ADDRESS:
          EEPROM.update(ADDR_LOC1,params[1]); EEPROM.update(ADDR_LOC2,params[1]^255); 
          // update address - will take effect on next powerup of the device as you 
          // can only call "begin" once
    default: break;  


BMP280 for HC 2016

I have just added a working BMP280 implementation into the Home Control 2016 code (see right menu in blog) returning temperature and pressure.  Add that to the (already implemented) BME280 code, Seeed display, 16,channel PWM, port expansion and more, it’s not been a bad development week really! Manual updated.

The BMP280 as you know does not have humidity – but is cheaper than the BME280.The manual is updated and has details on addresses etc.  Just waiting now for the A/D board to turn up from China.  I’m quite getting into this i2c expansion.

This little picture attempts to show the current state of play for Home Control 2016. No doubt I’ve missed loads off but as you’ll see quite a bit has been added recently.

Home Control 2016


16 Channels of PWM for ESP8266

PCA9685This morning a little board turned up for me – the advert said “Smart Electronics” – but the board says Adafruit 16-channel 12-bit PWM board. At £1.38 each these represent EXCELLENT value – especially as the Adafruit originals are much more expensive. Nicely made with gold connections and all the connectors provided.

Actually when I bought these I was unaware of the Adafruit product – I didn’t see the likeness until I went looking for code to modify for my own use.

(the Adafruit board is blue, the one I have is dark purple) - In essence a very nice little  board which takes in 5v and I2C (in this case software I2C on the ESP8266) and gives out up to 16 channels of 12-bit PWM at up to 1,600hz without external clocks etc.

So right now I’ve added only basic control – a single command that has two uses – one to set up the board, the second to control individual channels. I’ve added this to the ESP8266 home control.

The command works like this – two examples – one for setup, one to control output 0 (ie bit 0 as you can control multiple bits at once) – and assuming device 0x40 (decimal 64)



where 0 is OFF and 4095 would be full on.

Here's another example - set all 16 outputs to 100


PWM ControlI checked out the Adafruit code for Arduino and made a very simplified version – I’m not sure I fully understand the two parameters (ON and OFF – the last two) because setting the first to 0 seems to give the full range using the last parameter only – maybe someone who’s already used this might enlighten us. Anyway, it works, reliably and it’s available. I’ve updated the source and the ROMS.

To test, I wired from the ESP ground, GPIO4 and 5 (already connected to an I2c device with pullups) and Vcc. I also connected +5v (that goes to the 5v rail on the board) and then I connected a LED to the +5v rail and PWM output 0.  really very simple. I guess what I need is some kind of timer-based control to allow slow ramping up and down of brilliance – which would mean you could arrange at least 16 channels of lighting from the ESP8266. Mind you – you can do that with serial RGB LEDS but they’re quite expensive compared to other lighting.

In the photo above I connected 8 outputs to +V and a bar-led – I bought these for testing just like this – as you can see I’ve put values from 2000 to 4060 in there and there’s a nice variation of brilliance on all of them. The speed this is working (1,600hz) in the background (all done by the chip) – waggling the display does not produce any kind of strobing effect). As for levels – at the very dimmest levels with a bright LED you can just tell the steps – but WAY, WAY better than simple 8-bit PWM.

All works – if anyone wants to take the software further who’s already been there, happy to incorporate any working additions.

Follow the Adafruit link to get their Arduino code – here (minus the ESP master library) is what’s left once I get what I wanted…

This is all in the home control software – just reproduced here so you can see what’s involved, maybe point out any improvements etc.

uint8_t PWMAddr=0x40;
#define PCA9685_MODE1 0x0
#define PCA9685_PRESCALE 0xFE

#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9

#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD

void IFA pwmWrite(unsigned char addr,unsigned char d)
i2c_master_writeByte(PWMAddr << 1);
if (!i2c_master_checkAck())
i2c_master_stop();                   // End I2C communication
iprintf(RESPONSE, "Bad PCA9685 I2C\r\n");
i2c_master_stop();                   // End I2C communication

uint8_t IFA pwmRead(uint8_t addr)
uint8_t a;
i2c_master_writeByte(PWMAddr << 1);
if (!i2c_master_checkAck())
i2c_master_stop();                   // End I2C communication
i2c_master_stop();     i2c_master_start();
i2c_master_writeByte((PWMAddr << 1)|1);
if (!i2c_master_checkAck())
a = i2c_master_readByte();
return a;

int IFA ifloor(float x) {
int xi = (int)x;
return x < xi ? xi - 1 : xi;

void IFA pwmFrequency(uint8_t chipAddr, float freq)
pwmWrite(PCA9685_MODE1,0); // saves a reset function
freq *= 0.9;  // Correct for overshoot in the frequency setting
float prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
uint8_t prescale = ifloor(prescaleval + 0.5);
uint8_t oldmode = pwmRead(PCA9685_MODE1);
uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep
pwmWrite(PCA9685_MODE1, newmode); // go to sleep
pwmWrite(PCA9685_PRESCALE, prescale); // set the prescaler
pwmWrite(PCA9685_MODE1, oldmode);
pwmWrite(PCA9685_MODE1, oldmode | 0xa1);  //  This sets the MODE1 register to turn on auto increment.

void IFA pwmSet(uint8_t chipAddr,uint8_t num, uint16_t on, uint16_t off)
i2c_master_writeByte(PWMAddr << 1);
if (!i2c_master_checkAck())
i2c_master_stop();                   // End I2C communication
i2c_master_stop();                   // End I2C communication

And so there it is – working 16-channels of PWM (or 32 or more) added to the home control setup so you can control these lights via MQTT or serial via a simple command.

If anyone wants to tinker – the lights all start up as ON – I’d rather they started up as OFF and I’d also like a master ON/OFF. Ok, I could do it the hard way I guess.

I could see a daughter board coming up with 16 MOSFETS on it… actually you could just use it for on-off control if you wanted  - at the price.

One of the BIG benefits for me is – the Espressif PWM is simply not that good – I use it – but for example, you cannot use that AND I2c at the same time because both the Espressif implementation and another I’ve tried both continue to mess with interrupts in the background even when on 100% or off 100%.  This neatly bypasses the issue.


NOT Rip-Off Britain for Raspberry Pi

Here’s a bit of a reversal.. normally I steer clear of the UK for pricing as we tend to pay over the top… I can’t help thinking I’m reading this incorrectly….

Raspberry Pi 3

However – here above is RS Components latest pricing for the Raspberry Pi 3 – the latest model – at just over £27

And that’s fine – compares to what, say the USA would pay. I think I bought a model 2 last year in the USA for slightly less.

But check this out…

Raspberry Pi 2AliExpress who you can normally count on a decent price…

Claiming 65% off and charging £38 for the old model 2 !!!

Am I missing something here?

The funny thing is – after seeing this – I found more – I found a Raspberry Pi 3 all on AliExpress – for £29.29 with free shipping – which is a GOOD price – then the older Pi2 for an amazingly high £53.98 (they are kidding, right~?)  – the two prices sitting right next to each other!!

Oh, here’s the link for the 3 in case anyone’s interested…



I’m sure Linux life would be a LOT easier for beginners if it were not for the pesky permissions..

You’ll see in previous blogs that with help from readers, I discovered that the WIRINGOP library will work with H3 chips – and allow access to the pins on for example the FriendlyArm NanoPi M1 boards.

A compiled C program such as this…

#include <stdio.h> // Used for printf() statements
#include <wiringPi.h> // Include WiringPi library!   const int pwmPin = 7;
int DELAY_MS = 30;
const int pwmValue = 75;   int main(void)
    // Setup stuff:
    softPwmCreate(pwmPin, 0, 100);
    printf("PWD is running! Press CTRL+C to quit.\n");
    int up;
    int down;
    {     {
      for(up = 11; up <= 21; up++)
            //pwmWrite(pwmPin, up);
            softPwmWrite (pwmPin, up);
      for(down = up; down >= 11; down--)
            //pwmWrite(pwmPin, down);
            softPwmWrite (pwmPin, down);
            delay(DELAY_MS * 2);
    }   }
    return 0;

can be compiled as such…

gcc -o pwm pwm.c -l wiringPi

and lo and behold you can control pins on the M1…. but only as ROOT user – which is utterly useless for many situations.

I then discovered elsewhere that THIS

sudo chown root:root pwm
sudo chmod 4755 pwm

makes the program work for normal users – in my case on new boards I always create a user PI with similar permission to the PI user on the Raspberry Pi.


And so it was that I got all excited when I realised, after discovering that WiringPi has some hardwired limits – (hardwarePWM for example does not work unless you use a REAL Raspberry Pi) that THIS exists for the M1 -

So this is a whole lot of code and demos… one of them is called MATRIX-GPIO_OUT

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include "libfahw.h"


int main(int argc, char ** argv)


int pin = GPIO_PIN(7);

int i, value, board;

int ret = -1;

if ((board = boardInit()) < 0) {

printf("Fail to init board\n");

return -1;


if (board == BOARD_NANOPI_T2)

pin = GPIO_PIN(15);

if (argc == 2)

pin = GPIO_PIN(atoi(argv[1]));

if ((ret = exportGPIOPin(pin)) == -1) {

printf("exportGPIOPin(%d) failed\n", pin);


if ((ret = setGPIODirection(pin, GPIO_OUT)) == -1) {

printf("setGPIODirection(%d) failed\n", pin);


for (i = 0; i < STATUS_CHANGE_TIMES; i++) {

if (i % 2) {

value = GPIO_HIGH;

} else {

value = GPIO_LOW;


if ((ret = setGPIOValue(pin, value)) > 0) {

printf("%d: GPIO_PIN(%d) value is %d\n", i+1, pin, value);

} else {

printf("setGPIOValue(%d) failed\n", pin);





return 0;


and so here is a C program that lets you control the actual pins of the M1 – it was the first example I came across – REALLY simple – compile it and sure enough like that previous program – it works – but only as ROOT user.

Thinking I was being clever I tried…

sudo chown root:root matrix-gpio_out
sudo chmod 4755 matrix-gpio_out

SADLY – it would not work as a non-root user even with this – no access.  Is anyone clever enough to know WHY and how to get around it – there are lots of example programs in this MATRIX library but Node-Red does not run as ROOT – cannot access root programs using SUDO and therefore the whole lot are useless to me (and others using similar software) as it stands. The Matrix manual is only available in Chinese so it is looking like WiringPI (or WiringOP) is the only way forward for non-root users of these boards – and that’s a shame. I hope I’m wrong.

Why does the WiringPi C code example work after user is changed to root – but THIS example does not?

Ideas anyone?


Banana Pi M2

banana pi m2 Updated December 13, 2016:  Technically referred to as the BP1-M2+  I received this Banana Pi board in the post this morning. It is SMALL – that is, the same width but just a tad wider than the FriendlyArm M1 and M2.

But there the similarity ends. Firstly this little thing has EMMC, microSD, Bluetooth, WIFI, Wired Ethernet, 2 USB sockets (a tad limiting), 1GHZ Arm quad-core processor, 1GB Ram, 8GB EMMC (which to me is too small but I’m sure people will find it useful – and as for backup… I’d rather use microSD), and it claims to run Android 4.4 smoothly – hence my comment about the EMMC – what use is 8GB for Android??!?!?

The Android version is a little old for me so I thought I’d try the recently updated Raspbian. The blurb SAYS the GPIO is compatible with Raspberry Pi (really? Does it run the Raspberry Pi modules for Node-Red? If so I’ll be impressed).

The downloads and docs are all here which is a big improvement on some others – Orange Pi with hopelessly out-dated images – others with non-working Google Drive images etc.. I got the image no problem for Debian and as I received no documentation with the board, I was grateful for the online version.

I DID notice no audio output other than that on HDMI – which is a bit of a bummer – I like to see a 3.5mm jack for audio. Sadly the manual refers to plugging in a 3.5mm jack for audio – but there is definitely no 3.5mm jack socket on the board.

There is also an IR receiver. I’ve yet to see one of these boards run it out of the box but there IS a reference to this in the manual! – would be awfully handy if this worked in Android for remote controlling stuff.

At this point I just about had the image downloaded and things were going downhill a little.

At the end of the instructions, sure it was obvious you could be now running your operating system – but from WHERE was unclear. I didn’t want to load it into EMMC.

I was encouraged to see WIRINGPI available - but it was not clear if this was a special – if it WAS a special I found myself wondering why they claimed above that the board was PI-image compatible??

THIS page - on copying images – got my interest – up to now in all the boards I’ve tested, the Raspberry Pi is the ONLY board that has a simple to use copy/backup facility that will make duplicate images even on different size SDs!! This would prove to be no good.

SO – first things first… claims about being Raspberry Pi compatible – MYTH (like all the rest) if it were compatible it would run the RPI ROMS and it does NOT – I just tested it – result – nothing.

But on the other hand for the FIRST TIME their package they describe as “Raspbian booted first time – and had an “expand file system” which after a reboot opened up the operating system to the full size of the SD (others – ARE YOU READING THIS!!!). Marvellous.

Not only that but their “Raspbian” which features the Raspberry Pi logo and looks really like a Pi – apart from the monitor overhang which made closing programs difficult - has the latest file backup system that ONLY (as far as I know) the Pi has had up to now – would it work? I took the Raspberry Pi image disk that was supposed to work with the Banana Pi – now defunct as it does not – and used that as the backup.

I booted up “Raspbian” as supplied on the Banana Pi site - and ensured the WIFI worked – it DID (however it only found one access point which compares badly to other systems which find even my neighbour’s access point). It said I had a connection – but a poor one – no more than 12ft away from the access point!!! 2ft away my PC streams movies on that connection!

I plugged in the USB with my microSD in the BP1-M2+ and ran the graphical backup program. All looked well as it found the USB3 drive and started partitioning. “preparing partitions” it said. After what seemed like a similar time to the Raspberry Pi, maybe a pit longer, the software went off to start copying the two partitions, just like the Pi. If I were honest it SEEMED a little slower than the Pi2 but there are so many factors to take in here. It copied partition one and then…

“Could not mount partition” – I have NEVER seen that in a Pi2 or 3 before (and I make live backups all the time)  so I took the chip out and formatted it on a PC – and re-inserted…Once again – “preparing partitions”… I’m sure it took longer than normal… (and remember when I do this normally it is on a system doing all SORTS of jobs with all SORTS of software. This is a simple empty system).

Partition one started to copy – 60%… 70%… 90%… slow.   Not in the same league as Pi3… it stuck at 100% for AGES – I was convinced it was going to fall over… and…

“Could not mount partition”. I tried this three times in total with different SD holders – same result.  Having failed to get anywhere I took the same chip in the same container, put it back into a Raspberry Pi 2 and initiated a backup. This worked PERFECTLY.

I’m sorry guys – this is NOT Raspberry Pi compatible – STOP CLAIMING COMPATIBILITY. the RPI backup program WORKS. This does NOT.

At this point I noted, having received a heatsink with no glue and having written back to ask if it was necessary, that the main ARM chip was running hot enough to cook an egg. Fortunately I found a little heatsink I had lying around and that improved matters.

I wondered if it was worthwhile doing the usual apt-get update/upgrade – and checked to ensure I had a WIFI signal. Sure enough my WIFI was connected – but I could not browse the web or do anything Internet-related. I got that IP address which means – no.   I even tried putting the address in manually – no.

As I was looking at the WIFI – I noted the volume control top right was on mute. I clicked on the slider to adjust it – nothing – would not come out of mute.

With no audio and no WIFI I thought I’d go off on a tangent and try the recommended ARMBIAN. Aside from (again) overscan on my monitor (which works perfectly with a Pi and various other boards) Armbian came up – with a very nice screen and packed full of utilities (but no SD backup). Once again the WIFI would not have it. I plugged in Ethernet and decided to give the video a try – I opened up Firefox – and went to the BBC iPlayer.  Sorry – HTML5 content will not work – you need the FLASH player – and we all know what getting that running is like.

At this point I was ready to give up… but there was one thing left to try.

Android – a particularly old Android 4.x but I figured it might be worth a try. I followed the instructions which unlike any other board I’ve tried did not include blowing an image with Win32DiskManager but instead a piece of converted Chinese software. I tried several times and failed but eventually got a complete, verified image. Put it into the M2, the Banana Pi info came up and then… blank. The instructions said wait a while the first time – I waited 15 minutes – still blank.

Such a promising start, it looked like an RPI, acted like an RPI but… I have to say, disappointed.

I left this for a while – and having given up totally on using this board for any graphical interface due to the fact  thaty there were SO many issues, I thought I’d have a go with Armbian Debian server, the text-only version which has worked well on the FriendlyArm Neon. After a couple of false starts probably due to using a slow SD, I convinced the M2+ to boot from an 8GB SD with Armbian. Aside from some overscan which made it very difficult to do the initial change of password as the text was somewhat off-screen, I managed to get past that stage and onto WinSCP to do the usual apt-get update and apt-get upgrade which worked a treat. I installed the server version of Jessie – so no graphical desktop but it would be easy to add in. I’m inclined to use larger SD cards if I’m installing a graphical interface but 8GB is more than enough for a command-line only setup even with all the extras I typically add including Node-Red, Mosquitto, SQLITE, PHPLiteAdmin, Webmin etc. by my script.

I ran my install script – see the home control project and although it seemed to run somewhat slower than usual, it did run (ignoring unused variable warnings which are irrelevant but keep popping up in part of the script – I do wish people would keep information to a minimum).

Ok, early days – but it does appear that everything works at least in this simple use of the board – I have yet to look at the hardware in depth – clearly the Raspberrry Pi GPIO stuff DOES NOT work – I installed WIRINGOP as this is after all an H3 board and sure enough – pin 40 – that’s GPIO21 – could be made to turn on and off by turning on and off GPIO number 25.

And so after much trial and error…

  • Pin 3 GPIO2 =   gpio write 8 on
  • Pin 5 GPIO3 =   gpio write 9 on
  • Pin 7 GPIO4 =  gpio write 7 on
  • Pin 11 GPIO17 = could not figure out – default off
  • Pin 13 GPIO27 = gpio write 2 on
  • Pin 15 GPIO22 = gpio write 3 on
  • Pin 19 GPIO10 = gpio write 12 on
  • Pin 21 GPIO9 = gpio write 13  on
  • pin 23 GPIO11 = gpio write 14 on
  • pin 29 GPIO5 = gpio write 21 on
  • pin 31 GPIO6 = gpio write 22 on
  • pin 33 GPIO13 = gpio write 23 on
  • pin 35 GPIO19 = gpio write 24 on
  • pin 37 GPIO26 = could not figure out – default off
  • pin 8 GPIO14 =  gpio write 15 on
  • pin 10 GPIO15 =  gpio write 16 on
  • pin 12 GPIO18 =  could not figure out – default off
  • pin 16 GPIO23 =  could not figure out – default on
  • pin 18 GPIO24 =  gpio write 4 on
  • pin 22 GPIO25 =  gpio write 6 on
  • pin 24 GPIO8 =  gpio write 10 on
  • pin 26 GPIO7 =  gpio write 5 on
  • pin 32 GPIO12 =  could not figure out – default off
  • pin 36 GPIO16 =  could not figure out – default off
  • pin 38 GPIO20 =  could not figure out – default on
  • pin 40 GPIO21 = gpio write 25 on

When I say I could not figure out p particular pin – I mean it would don’t respond to simple gpio commands – I assume those pins have other functions like serial that is not clear on the banana pi diagram. STILL not a bad haul!! A quick Node-Red lookup table will sort these and the NEO out…

NOW – take a look at my updated M1 article which not only has the pins for THAT chip but also now has a solution for general pin control – for non-root users..

December 13, 2016 I installed Armbian again after a long break - with my script it installed first time, no problem with everything working - and 4 UARTS appearing in Node-Red - at least 3 of which should be usable.



The NanoPi Neo

NeoBy now if you read this blog regularly you’ll have heard me rant on about the FriendlyArm boards – mainly because they are inexpensive and actually do work well as Pi alternatives – you’ll also note that I don’t blindly praise them – I’ve still not managed to get the T3 to run a 32gig SD of Android – and it’s an old Android to boot… but generally – I like their stuff.

SO it will come as no surprise then that I’m interested in the new NEO. And why would that be? Because it is SMALL and CHEAP. It has no WIFI or Bluetooth but it has hardwired Ethernet – just the job then for a NODE-RED central controller perhaps?  This is clearly aimed at a market not wanting a graphical interface as no hdmi out – but at the price – I’m happy with that.

So there’s a reason it is cheap – there are two versions, 256Mb RAM and 512MB RAM – I would not personally give time to the former – but the latter would, you would think, run Node-Red, SQLITE and Mosquito without issue… So the extra RAM puts the board at $9.99 plus whatever postage you get stuck with in your country…  cheap by any standard…

Neo in caseBut – looking at the docs – it seems that right now the main official option is for Ubuntu – I don’t know about you but when something says “An open source tiny PI” on the front of the box, you might expect it to be somewhat compatible with THE PI.. and that means Debian for me – and no doubt for most people familiar with the Pi.

The internal processor is an Allwinner H3 quad core like the Orange Pi so it is reasonable to assume that there will be alternative  software. It looks like there are 3 UARTS so one would hope for  two to be accessible.

There is one USB, a microSD slot, a micro USB OTG port and 2 USBs via headers.  The expansion port claims the usual, I2c, SPI etc but of course that will only happen if the software will support it.   Size is 40mm by 40mm – which makes it kind of smaller than a Pi Zero.

It occurred to me that setup could be a problem with this board as it has no SCREEN but read on – as it turns out it wasn’t an issue.

FriendlyArm sent a copy of Ubuntu which I’ve no interest in but thought I’d better try to ensure the board was ok. Sure enough it worked but the instructions on the box were the wrong way around. The blue LED flashes constantly – the green LED stays on – according to their info – it should be the other way around. Also to resize the SD they offer a Linux solution – assuming everyone has a Linux computer spare – or a simple SUDO fs_resize. The latter at first didn’t work until I realised that firstly the sudo command was not there and secondly I didn’t need it as I was root !!!

So all of that worked well – but I know for a fact my script won’t work on Ubuntu so I needed to get a working Debian

So – off I went to get ARMBIAN – and sure enough there is one version there for this particular board! Update 22/09/2016 – there have been some issues with the Armbian setup – read their site – but also see my script – it refers to a specific version of the legacy Jessie installation on the Armbian site (at the time of writing the latest). With the script this is running exceedingly well  - and yes, Node-Red can see serial ports 1, 2 and 3 (0 is in use for debugging).

I flashed a 16GB SD with the Armbian code using Win32DiskManager, plugged in the Ethernet and power. A dim green light came on. After a few seconds it brightened up.  And then maybe 30 seconds after that a blue light started flashing regularly along with the green – a sure sign SOMETHING was happening. On the Armbian website it warns that the first time boot could take minutes – so I left it.

Next stop Advanced IP scanner. Sure enough there was a board in my address range – sitting at – with my favourite tool, WinSCP, I used the login credentials root and 1234 and – no file list – it HAD logged in but nothing.  I wrote off to the Armbian guys and apparently logging in with Putty (SSH) was needed to make an initial password change – and sure enough – it worked. I went back to WinSCP – and bingo.

The software asked me if I wanted to change screen resolution which was a bit odd as I was running in a terminal and the board has no screen!!!  Not really sure what to do with that – why would they enable the graphical environment when there’s no screen. So – off I went (as root) to get tightvncserver – and sure enough it installed but would not run – complaining about lack of fonts. No big deal – I un-installed it. i had no intention of running a graphical environment on a board with no screen connection anyway !! Ultimately I did return to this and did get the graphical interface running as I wanted to see if I could get WIFI working on Armbian – but for the life of me could not get WIFI drivers to install.

I REALLY think this board needs a heatsink which was not initially supplied.  I wonder why it is that Raspberry Pi manage to run without one and these H3 boards end up running hot enough to cook eggs – there ARE H3 boards which are faster than the Pi but I don’t think this is one of them.  However the fact that it is so SMALL and inexpensive it is worth a little effort. Having said that with the latest Armbian the chip is running at 51 degrees C without the heatsink so that’s not bad.

Next stop, with the board running Armbian I left it  running my installation script designed for a Raspberry Pi to install a host of utilities and Node-Red, Mosquitto and SQLITE.   In the process I updated my script to include the new node-red-dashboard which is the worthy successor to node-red-contrib-ui and added things like “cu” which allow you to use the terminal as a serial VT100 terminal.


Overall? Well, I’m really happy – I have two working UARTS in Node-Red (UART1 and 2) I can’t find the pins for UART3 but Node-Red is happy to talk to it. UART0 works well as a serial monitor.  I’ll need to load up some GPIO tools etc. but the bulk of my stuff just seems to work.

Update 29/09/2016 – FriendlyArm just contacted me –just to confirm – on the NEO – they never did bring out GPIOA13 and GPIOA14 to the connectors and hence UART3 though technically “there”, is not actually available.

For connections – see here -

Now as it turns out they bear no resemblance to other boards (unless I’m missing something) – so I started to experiment with the help of links from people in here.

THIS FELLOW - got the M1 working with the Wiring Pi and so I installed that (H3 – same chip) – but could not get pin mappings to work.

I discovered that GPIO WRITE 24 ON turned on the little blue light on the board… and then purely by trial and error…

  • GPIO WRITE 10 ON  -  GPIOC3 – pin 24
  • GPIO WRITE 14 ON  -  GPIOC2 – pin 23
  • GPIO WRITE 12 ON  -  GPIOC0– pin 19
  • GPIO WRITE 13 ON  -  GPIOC1 – pin 21
  • GPIO WRITE  3 ON  -  GPIOA3 – pin 15
  • GPIO WRITE 6 ON  -  GPIOA2 – pin 13
  • GPIO WRITE 2 ON  -  GPIOA0 – pin 11
  • GPIO WRITE 28 ON  -  GPIOG6 – pin 8
  • GPIO WRITE 29 ON  -  GPIOG7 – pin 10
  • GPIO WRITE 24 ON  -  GPIOA6 – pin 12
  • GPIO WRITE 26 ON  -  GPIOG9 – pin 18
  • GPIOG8  (pin 16) could not turn on
  • GPIOG 11 (pin 7) – could not turn off
  • GPIOA1 (pin22) could not turn on

So – that’s a START!!! Just need I2c now!! The only issue for me here is that FriendlyArm ONLY provide and support UbuntuCore for the NEO which is of no interest to me.  I don’t know if this is down to a language problem or what but…ok, the ad does say Ubuntucore ready – but the name says “NanoPi” – and surely to qualify as a Pi you should be supporting the main operating system of the Pi – that being… Debian.

Interestingly their M1 product DOES support Debian – which is strange.  But here’s the problem – though WiringOp just happens to work for GPIO on both the M1 and the NEO, and compiled WiringOp programs can be made to work as user Pi,  as the company’s Matrix software which DOES give you access to I2c etc. seems to have some issues with any other than ROOT access - and FriendlyArm do not currently know how to get around that.

So the ONLY  the way forward here to make full use of these boards, is for someone brighter than me to work on WiringOP to make it completely compatible with the NEO and hopefully the M1 – at that point – we’re onto a real winner but it would be so much better – when someone brings out hardware products like this – which rely SO heavily on documentation and software – if they would get it right themselves!!!  The manual for the Matrix software is even now in Chinese only!

Update October, 2016: If you look at my later article which includes updates on the NEO, there is a DietPi out that works with this and my script and makes for a small, fast installation.

Conclusion: All down to postage… this is a marvelous little board you might describe as “cute”. With no 3.5mm jack I’ll have to get my hands dirty and solder that 0.1” edge connector on to get audio out. I’ll report on that later and it appears there’s a microphone input too on that connector along with an option for an IR input! Also look out for their new Lite version - I have one on the way - with WIFI instead of Ethernet - and it has 2 USBs. At the time of writing - the Armbian installation with a WIFI dongle on the Neo was not that good but the DietPi version works a treat.


Midweek Ramblings

Following my addition of the BME280 code to Home Control 2016, a couple of guys have suggested they might like to see more accuracy than the integer I use for temperature so I’ve added a new polled value {hightemperature} which is simply the temperature value *10 – but with that extra accuracy – so for example hightemperature mod 10 would give you the decimal point. Not sure I see a need for even higher precision so we’ll leave it at that – personally I just use temperature to the nearest degree.


I’m also playing as you know with port expanders and having already ran out of ports I’ve added an experimental additional 8 port outputs via one of those cheap port expanders I referred to in a previous blog entry.  So assuming this is set to address 38 (typically that’s switch 3 set to off, the others set to on) you can do simply control of out17 to 24, bearing in mind these things start off as inputs floating high.

Port expander

I’ve not attempted at this point to store values in FLASH or preset them on power up – let’s see how much use this gets.

See the Home Control 2016 manual for updates.

On a different tack, this might seem obvious to the hardware guys here and it should have been obvious to me as I’ve been working with electronic hardware since I was old enough to think -  but I made the mistake of getting lazy recently – on my new pergola. I set up on of our boards with a cheap Chinese relay board on GPIO12 – to control a water mister (it gets hot here).  So I would use the timed outputs for example {out12:6,2] which sets output 12 on for 2 minutes before timing out back to OFF state.

I had the water fittings all set to go, got my Imperihome App out, pressed the button and sure enough – excellent misting. I pressed the button to turn the mist off and…. nothing.

I figured a jammed relay – but no. Out of desperation I checked the actual state of the port as set in memory – and it said the output was on – but I’d turned it off – this was impossible. I sat and went through the code over and over – no issues.

I made the classic mistake of assuming the hardware was perfect and it had to be a software issue. In FACT, even though the misting system was kind of isolated from the board by the little external relay board, said relay was powering a 12v washing machine coil – and as it turns out the backlash from the coil was having the weirdest effect on the board – stopping that port turning off – to this day I still can’t explain it as it was actually affecting storage of info in the chip.  I can only assume a voltage spike getting back to the board itself.


I know, sounds daft, so I put a diode across the washing machine solenoid – something I should have done in the first place. Immediately – 100% perfect operation tested over and over. Worth knowing about. See purple diode below.

diode to stop interference

Also added {reset_config} command so that from serial you can reset the board to defaults  - for security this will not work from MQTT.


BME280 Sensor Box of Tricks

bme280Temperature, humidity and pressure readings in one chip? Certainly! The BME280.

I’ve recently spent more time than I care to think, trying to get a BME280 driver to work – finally done it by adapting some work from this fellow (Cosmin Plasoianu) who’s code is good but was out of date for the current Espressif SDK and also referred to another chip as so many bits of code do – the BMP280.

So what’s the difference? Well, the BMP280 is a modern temperature + atmospheric pressure chip – but it does NOT do what the lovely BME280 does – and that is humidity. In other words it can form a replacement for the DHT22 as long as you don’t mind using another wire (i2c). It responds quickly and is relatively accurate. The BME280 is also on a different I2c address to the BMP280.  Anyway – all SORTED.

It is not cheap at nearly £4 but adding in pressure lets you do all sorts of weather-predicting stuff!  As usual I limit accuracy to the nearest degrees C or percentage humidity because while seeing decimal points looks good  - the ultimate accuracy does not warrant it.

I’ve updated the manual {temp_type:3}  - and this uses i2c. The new command assuming GPIO4 and 5 are used for I2c and assuming there are pull-ups in use  - this  fills in the variables temperature, pressure and humidity which can be accessed as {temperature?} {pressure} and {humidity} as normal and are also generated automatically – see manual.

One more success for Home Control 2016.



Arduino Libraries and ESP8266

DallasSo I’m working on a side project – which may or may not go anywhere – to make a working version of my home control 2016 ESP8266 software in the Arduino environment. 

One popular device is the Dallas DS18b20 temperature sensor, a simple 3 wire device that looks like a transistor, has a single communications line and returns accurate temperature digitally.

Well, I’ve had this running for AGES on my code and can handle both the normal and P-suffix variety – so I was a bit dismayed after wasting an hour and throwing a chip away to find that the Arduino version does not.  Also it seems people are still writing libraries out there which wait for the chip – wasting valuable time – so I thought I’d do a short write-up on my own code.

Another annoyance I discovered was the need to predefine which GPIO pin you’re using for the temperature sensor – making dynamic change impossible. There really is no need for this.

So – how do I get around the delay – simple – I swap things around – instead of priming the unit, waiting and taking a reading, I take a reading and prime the unit – making the first ever reading after power-up a waste of time – and I use a flag to return zero the first time. This means no waiting and hence VERY fast reading. I also check the result and if the DS18b20 fails I try for a DS18b20P.

In my own code I use EASYGPIO which isn’t available on the Arduino version – which means (as I understand it) putting the GPIO pin from output to input means two operations, one to reverse the state of the pin and another to set the output value – but hey, it works.

No libraries needed of any kind though if you were cleverer than I you could dump my routines into a library. Of course nothing is new and some of my code is simply refactored from elsewhere as you’ll see.

Firstly – I’m not going for accuracy here, I’m only interested in temperature to the nearest degree – if you want more you’ll have to make minor changes. I’m also not interested in multiple devices per pin. I am however interested in changing pins without static declarations. Funny enough this all started for the Arduino, got adapted for ESP8266 and ended up back in an ESP8266/Arduino setup.

   Adaptation of Paul Stoffregen's One wire library to the ESP8266 and
   Necromant's Frankenstein firmware by Erland Lewin <>

   Paul's original library site:

   See also

   Stripped down to bare minimum by Peter Scargill for single DS18B20 or DS18B20P integer read

// Perform the onewire reset function.  We will wait up to 250uS for
// the bus to come high, if it doesn't then it is broken or shorted
// and we return;

void ds_reset(void)
  uint8_t retries = 125;

  pinMode(temperaturePort, INPUT_PULLUP);
  // wait until the wire is high... just in case
  do {
    if (--retries == 0) return;
  } while (!digitalRead(temperaturePort));
  pinMode(temperaturePort, OUTPUT);
  pinMode(temperaturePort, INPUT_PULLUP);

// Write a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
static inline void write_bit(int v)
  pinMode(temperaturePort, OUTPUT);
  if (v) {
  else {

// Read a bit. Port and bit is used to cut lookup time and provide
// more certain timing.
static inline int read_bit(void)
  int r;
  pinMode(temperaturePort, OUTPUT);
  pinMode(temperaturePort, INPUT_PULLUP);
  r = digitalRead(temperaturePort);
  return r;

// Write a byte. The writing code uses the active drivers to raise the
// pin high, if you need power after the write (e.g. DS18S20 in
// parasite power mode) then set 'power' to 1, otherwise the pin will
// go tri-state at the end of the write to avoid heating in a short or
// other mishap.
void ds_write(uint8_t v, int power)
  uint8_t bitMask;

  for (bitMask = 0x01; bitMask; bitMask <<= 1) {
    write_bit((bitMask & v) ? 1 : 0);
  if (!power) {
    pinMode(temperaturePort, INPUT_PULLUP);
    pinMode(temperaturePort, OUTPUT);

// Read a byte
uint8_t ds_read()
  uint8_t bitMask;
  uint8_t r = 0;

  for (bitMask = 0x01; bitMask; bitMask <<= 1) {
    if (read_bit()) r |= bitMask;
  return r;

So what you see above are the basic routines for talking to the two  chip variations. Here’s the actual code I call once a minute (you could use any interval) to store the temperature. I don’t stop interrupts as I might be running an RGB fader and I don’t want any flashing.

Doesn’t seem to present issues, never has, but if you wanted you could average temperature over time.


I run my heating without any of that and I don’t get glitches on my Home Control software – this is the same code but with changes for the Arduino-style port handling.  I wonder if I’m missing a single instruction to set an input to an output and make it zero at the same time?

   ds_write(0xcc, 1);
   ds_write(0xbe, 1);
   temperature = (int) ds_read();
   temperature = temperature + (int) ds_read() * 256;
   temperature /= 16;
   if (temperature > 100) temperature -= 4096;
   ds_write(0xcc, 1);
   ds_write(0x44, 1);
   if (gotDsReading == 0) { gotDsReading=1; temperature = 0; }    // ignore first reading
    Serial.printf(“Here’s your temperature %dc”,temperature);

It would be nice to see this in a stand-alone library somehow. temperaturePort is the number of the GPIO pin. I generally use 2 or 14 on the ESP and I don’t want them dedicated in case I want to use them for something else. Define gotDSReading and make it zero on power-up or change of pin. If the dummy value of zero is no good – change it.

Oh and in the process of putting this together I realised a slight silly in my main Home Control software – and that is now fixed….

Works for me!!