Category Archives: ESP8266

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.

read_thumb2

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.

3ms

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.

https://bitbucket.org/scargill/esp-mqtt-dev/src 

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…

void ICACHE_FLASH_ATTR
i2c_master_writeByte(uint8 wrdata)
{
    uint8 dat;
    sint8 i;

    for (i = 7; i >= 0; i--) {
        dat = wrdata >> i;
        I2C_MASTER_SET_DC(dat,0);
      //  i2c_master_wait(I2C_DELAY_5);
        I2C_MASTER_SET_DC(dat,1);
        while (!GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SCL_GPIO))) {}
       I2C_MASTER_SET_DC(dat,0);
    }
}

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

Facebooktwittergoogle_pluspinterestlinkedin

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”

Facebooktwittergoogle_pluspinterestlinkedin

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…

{nano:9,1,13,1}

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:

{nano:9,1,13,0}

Or how about reading the state of input 10?

{nano:9,2,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
  • 6 DIGITAL INPUTS or OUTPUTS

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 READ_INPUT_PULLUP 3
#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;
  eeprom1=EEPROM.read(ADDR_LOC1); eeprom2=EEPROM.read(ADDR_LOC2); 
  if ((eeprom1^eeprom2)==255) device=eeprom1; // programmable address
  bigcount=0;
  Wire.begin(device);           // join i2c bus with address #9 by default
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent); 
  for (int a=0;a<MAXPORTS;a++) ports[a]=0;
  paramp=0;
  retParam=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;
tcount=count;
paramp=0;
// no time consuming in here or the routine to send a byte back will be missed.
  while ((tcount--)&&(paramp<128))
   {
    params[paramp++]=Wire.read(); 
   }
  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;
          break;
    case READ_INPUT:
          if (ports[params[1]]!=2) { ports[params[1]]=2; pinMode(params[1],INPUT); } 
          retParam=digitalRead(params[1]); params[0]=0;
          break;
    case READ_INPUT_PULLUP:
          if (ports[params[1]]!=3) { ports[params[1]]=3; pinMode(params[1],INPUT_PULLUP); } 
          retParam=digitalRead(params[1]); params[0]=0;
          break;          
    case SET_PWM:
          if (ports[params[1]]!=4) { ports[params[1]]=4; pinMode(params[1],OUTPUT); } 
          analogWrite(params[1],params[2]); params[0]=0;
          break;
    case READ_ANALOG:
          if (ports[params[1]]!=2) { ports[params[1]]=2; pinMode(params[1],INPUT); } 
          retParam=analogRead(params[1]); params[0]=0;
          break;    
    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
          break;      
    default: break;  
    }
}

Facebooktwittergoogle_pluspinterestlinkedin

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

Facebooktwittergoogle_pluspinterestlinkedin

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.

http://www.aliexpress.com/item/Smart-Electronics-PCA9685-16-Channel-12-bit-PWM-Servo-Driver-I2C-Interface-for-Arduino-Raspberry-Pi/32464046768.html?spm=2114.13010608.0.73.QEOjVb

https://www.adafruit.com/product/815

(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)

{pca9685:64,0,1600}

{pca9685:64,1,4000}

where 0 is OFF and 4095 would be full on.

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

{pca9685:64,0xffff,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_start();
i2c_master_writeByte(PWMAddr << 1);
if (!i2c_master_checkAck())
{
i2c_master_stop();                   // End I2C communication
iprintf(RESPONSE, "Bad PCA9685 I2C\r\n");
}
else
{
i2c_master_writeByte(addr);
i2c_master_checkAck();
i2c_master_writeByte(d);
i2c_master_checkAck();
i2c_master_stop();                   // End I2C communication
}
}

uint8_t IFA pwmRead(uint8_t addr)
{
uint8_t a;
i2c_master_start();
i2c_master_writeByte(PWMAddr << 1);
if (!i2c_master_checkAck())
{
i2c_master_stop();                   // End I2C communication
}
else
{
i2c_master_writeByte(addr);
i2c_master_checkAck();
i2c_master_stop();     i2c_master_start();
i2c_master_writeByte((PWMAddr << 1)|1);
if (!i2c_master_checkAck())
{
i2c_master_stop();
}
else
{
a = i2c_master_readByte();
i2c_master_stop();
}
}
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)
{
PWMAddr=chipAddr;
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);
os_delay_us(5000);
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)
{
PWMAddr=chipAddr;
i2c_master_start();
i2c_master_writeByte(PWMAddr << 1);
if (!i2c_master_checkAck())
{
i2c_master_stop();                   // End I2C communication
}
else
{
i2c_master_writeByte(LED0_ON_L+4*num);
i2c_master_checkAck();
i2c_master_writeByte(on);
i2c_master_checkAck();
i2c_master_writeByte(on>>8);
i2c_master_checkAck();
i2c_master_writeByte(off);
i2c_master_checkAck();
i2c_master_writeByte(off>>8);
i2c_master_checkAck();
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.

Facebooktwittergoogle_pluspinterestlinkedin

I2C Continuum

Updated August 07. 2016: This article which started off discussing the “new addition” of i2c to the home control software, is now NOT ONLY about an I2c  2/4 line LCD display facility recently added to the ESP8266 boards – but there’s a PARALLEL version as well, making use of GPIO 4,5,12,13,15 and 16. And NOW – I’m adding a pretty crude interface for the Seeeed OLED displays with other OLEDs to follow.

Comments below about format apply equally to the I2c and parallel versions – for the latter, simply use device 255. Note when you do that you lose GPIO13 as an indicator automatically until next power-up.

Success with I2c – once I realised there was something up at the Arduino end which I could work around, my ESP8266 I2c endeavours have been coming on in leaps and bounds!

And here is my test rig – or one of them – I have one for I2c display and another for parallel display  - the latter is just as messy and has more wires:

I2c

So what you’re looking at there from top to bottom – is a prototyping ESP8266 board (the author will recognise it) just because I had it handy – ESP-12 based, running my rapidly developing software (which now has loads of spare RAM thanks to the SDK 2.0). I put a simple set of i2c commands in there then promptly realised that a series of commands sent by MQTT would not be a lot of use. I then proceeded to waste the day, having already talked successfully to an 8-bit port expander, trying to get one of those back-of-an-LCD I2C boards to work – as it was based on the same chip.

Parallel versionAfter several hours of considering taking up brick-laying I realised the damned thing was bust – and went off in search of my  cheap Chinese port expander – that’s the red thing you see in the middle. The only difference is this does not have a transistor to power an LCD backlight so I just hardwired that. At the bottom – the original test 4-line LCD. Over on the right, an irrelevant Arduino-type board which is also talking I2c successfully.

Having decided I liked the idea of plugging one of the cheap LCDs onto the odd home control board for information purposes, I set about doing something I’ve never done before – reading the Hitachi data sheet. These things are quite cute once you get over starting in 8-bit mode then switching to 4-bit to save on wires etc… (so in total you only need 6 signals to talk to the LCD) and after some timing experimenting (clear screen command takes a while – over 1.5ms) as you can see I finally have a working LCD – and by the look of it, rock-solid reliable.

So what is driving that display (which is updating every second virtually instantly)…

This:

node-red

and inside that inject?

Topic: freddy/toesp

Payload: {hitachi:39,"$1MQTT test$2$i$3Time $t$4Date $d"}

That’s all. So assuming you’re familiar with MQTT (if not – look at other articled in here) the destination is the little board “freddy” – and the new command I’ve just added – “hitachi” talks to an i2c board (the expander) device #39 and sends out that string.

Rather than have a boatload of commands which would be unwieldy in the home control setup – or special characters which might cause issues – I used the dollar as an escape character. Here’s what I’ve implemented up to now

  1. $$ -  well that shows a dollar on the screen !!
  2. $s -  setup – sets up a virgin LCD and clears the screen
  3. $c  - clear the screen
  4. $1 – set the cursor to line 1 -  ($2 $3 $4)
  5. $t  -  fire out the time
  6. $d – fire out the date
  7. $i  -  fire out the current ip address

I’ll probably settle on a 2-liner as they are sub-£2 from China – indeed for 20-off just over £1 – and at £1.34 for the port expander – around £3 to add a nice little display to some of the ESP8266 boards – can’t be bad. indeed, using one of the port expanders for an ultra-low-cost i2c keypad isn’t a bad idea. 45p for the keyboard, £1.34 for the expander… Sub-£2 keypad.

Clearly one way to wipe a line would be “$1               $1” which is probably fast enough for most purposes. I’ll likely think of some more commands.

A reminder that the right hand side of this blog contains links to the Home Control 2016 project, ROMs etc.

And now I have this big decision.. whether to spend £1.34 on a PCF-base port expander… which I need to poll regularly if attaching a keyboard – and no spare pins for a beeper – OR to spend £1.68 on an Arduino Nano which can be turned into an I2c peripheral (granted I might need 2 pull-up resistors) with keyboard buffering and a beep facility…..   OR…. go the whole hog and use another ESP8266 to make a completely wireless keypad.

OLED from SeeedAnd on that latter note – if you abandoned serial I/O which would net one more output – that gives up to 10 control pins – enough for a keyboard and beeper and light. Hmm…£1.43 for an ESP12, 17 pence for a 0.1” adaptor board.   Fully buffered keypad…. Big decision…

And finally – device 255 is reserved for  a PARALLEL version of this using 6 GPIO pins – 3,4,12,13,15 and 16 – operation is identical. All in the code – including the OTA ROMS. Documented in the WORD manual.

Update: On the right you see a Seeed OLED – I starting with this library, code intended for Arduino, I’ve heavily modified it to run in the normal ESPRESSIF SDK environment – but I have to say – the original Arduino version was SLOW, so VERY slow and this is still a little slow – especially the screen clear – I’ve pulled that into one function with an inner loop of I2c bytes, way faster than the original  but even THEN it is hardly nippy – but the important thing is that “Hello World” works – so soon I’ll add the above commands and then figure out a way to speed it up. Right now I can manage {seeed:”Hello world”} or similar. Current software and ROMs are on the web.

Facebooktwittergoogle_pluspinterestlinkedin

Nextion Update

As you may know the home control software can work with Nextion displays and there is a  project on the blog on that subject – I note that one or two people are having issues here so rather than reply without pictures -  here’s a general  update.

Home Control 2016 startupCurrently with the home control software, version 1.531 (see right) and Nextion Editor version 0.36 (it just updated on my automatically)  and I’m doing this on Windows 10.

After powering up the home control board, you MUST for the first time issue the instruction {set_serial:2} to the ESP8266 at which point the board will reboot and part of the start up serial info will show as on the right – “Initialised software serial to 57600 baud” – this indicates that the unit is ready to work with the Nextion display. GPIO4 and 5 are used for this purpose and the Nextion board can be powered directly from ours. Ground, to_nextion, from_nextion, 5v – that is how our board is marked but of course you don’t need to use our board. Incidentally don’t be tempted to use your 5v FTDI to power any but the smallest of Nextion boards – I tried this on the large 7” model and killed the FTDI…you’ll need a separate (common ground) power supply for that and most likely anything over the 4.2” display. Don’t forget to change that set_serial command if you plan to use GPIO4 and 5 for something else as the setting is stored in FLASH.

In a simple test I have a plain Nextion panel with two buttons on it. In the background to the page – in the Nextion Editor – I have a “preinitialize event” which contains nothing more than “bauds=57600” without the quotes – this ensures the Nextion board powers up at 57600 baud for the purpose of sending data back and forth.

The two example buttons are marked “up” and “down” and the “touch press event” for each is as follows..

get "nodered~up"

and

get "nodered~down"

If you look at my documentation  - this is a notation I created that returns the above – for example the first one, to the ESP8266 and converts that into an MQTT message:

topic: nodered

payload: up

That’s it – press the up button and the message “up” is sent to topic “nodered” – could be any message you like – and any payload. You can use this directly to turn things on and off without even passing through Node-Red – OR you you have node-red intercept the incoming MQTT message and do something with it. So pressing a button might have an effect on the Nextion display for example. If you see the Nextion WIFI touch-display project you’ll see you can get WAY more ambitious than just a couple of buttons.

mqtt-spy

And lo – as I press buttons – you see the messages coming into MQTT-SPY (or whatever you use to test your MQTT).

That just leaves output to the Nextion itself from the board.

Again for the purposes of demonstration I add a text box in the Nextion editor – the default name for the first new text box would be “t0” so I rename this to “mytext”.

nextion text box

Not very pretty and normally I would NOT use their buttons etc. but make up my own imagery using PowerPoint or similar – but it’ll do for demo purposes.

Nextion displayNow I have to say, the worst part of this is the Nextion editor – progress is moving slowly with this – when you come to program it – make sure you have the right port address because it is hopeless at searching – and if it gets stuck you end up using task manager to reset it – comes up as PRJ or something – I’d so like to get my hands on the source code to give it a good shake-up.

Anyway, there it is- you end up with a window in this case with default text “newtxt”.

nextion display[5]Fire out the command {to_nextion:"mytext.txt=\"Hello\""}

You can do this serially or via MQTT- as the example from MQTT_spy shows.

This results in “Hello” without quotes appearing in the text box. Why the backslashes – that is to “escape” the quotes so they don’t end up terminating the string above – in other words so the quotes are passed through.

The WORD manual for my software describes the “to_nextion” and “set_serial” commands.

Have fun.

mqtt-spy[7]

Facebooktwittergoogle_pluspinterestlinkedin

ESP8266 Home Control Update

As the blog entry on using my home control code ROMS for ESP8266 is filling up and of course as much of the information is now dating I thought I’d do a new blog to bring everyone up to speed and move the conversation to this blog entry. The good news is  - the code is now running under SDK 2.0 – i.e. bang up to date at the time of writing.

Firstly – yes, everything works – but the procedure for flashing ESP-12 etc has changed ever so slightly. I have updated the binary files to run on Espressif SDK 2.0 and updated the RBOOT code I use for OTA (over-the-air updating) to the latest version.

To backtrack a little

For anyone new in here – some background - I’ve written software for the ESP8266 which has been in operation for some time and is under constant development. It allows the ESP8266 to control things like simple lights, serial LEDs, PWM LEDs and read sensors etc, talking via WIFI and MQTT to whatever central system you have – for example a Raspberry Pi with Node-Red. I’ve written a node to allow endless units to log in and to provide central communications for them. The software is rock solid and runs 24-7.

I use Windows to develop the software using the Cherts unofficial development environment. This provides an IDE using Eclipse for running and compiling C code. It is not necessary to use any of this if you simply FLASH the ROMS which are available – but of course if you do use the IDE you can customise code for your own use.  The projects Home Control 2016  and Nextion WiFi Touch Display both use the same software and are the end result of many years developing home control. Personally I access much of this equipment using Apps like Blynk and more recently Imperihome (see also this article, this and this).  Tools I use in Node-Red include my own BigTimer node.  All of these options were chosen after much deliberation.

So what have I learned and what has changed?

All has been going well until recently when the Espressif SDK for ESP8266 was updated, firstly to 1.54 then very quickly followed by 2.0 and all of a sudden I and other started to have issues starting up ESP8266 boards. This is now resolved incidentally.

Firstly one of my problems was lack of serial output on power-on. Some serial (115Kb) status messages I have on power up, just point-blank refused to show. I figured the code might be starting at the wrong place. But no, a quick port flick at power-up proved that everything was working – but no serial out.

After much debugging, I discovered that there would be no serial output until this function:

  wifi_set_opmode(0);

had been called. Prior to SDK 1.54 this was NOT the case. Simple enough - I put this at the start of my code – I’ve just checked and web updating works just fine - but merely moving this function to the start solved all the serial output issues.

Incidentally much is made of the “garbage” that comes out of the ESP8266 on power up – it is just that Espressif chose to use 78,600 baud instead of a more popular one. If user software is set to this speed rather than, say, 11500 (which is what I use) then things look very different – diagnostic on power up followed by user code – all very seamless. Problem is – not that many serial terminals support 78k.. but I digress.

The second problem was a tendency for the unit to run away with itself, firing out garbage as if the ESP-12 was broken. It would SEEM that post-SDK-1.53 or thereabouts – it is NECESSARY on initial run, to flash location starting 0x3fc000 (end of the 4th page in a 4MB Flash chip) with the default file esp_init_data_default.bin which is found in the Espressif development kit.  If this has already been blown (previous installation) then it is not necessary to redo that, but with a CLEAN FLASH, failure to flash this area results in the continuous rubbish on output. Again this did not seem to be the case before SDK 1.53/4 – I have NEVER flashed that location in the past. Once blown it is not necessary to blow this again for OTA. Still – now we know.

I’ve just had a Skype chat with Espressif engineers to try to dig deeper. They have confirmed the small file at the end is essential (I probably didn’t notice it before as I’d generally be using boards already programmed) – the serial issue we’re still trying to understand – but it all works.

System Data

There are 2 relevant files here. A file called blank.bin sits at 0x3fe000 (top of the third MB in a 4MB Flash i.e. ESP-12) and contains default system parameters produced in the SDK.  NOT setting this initially seems to have no effect on my code.

A file called esp_init_data_default.bin sits at 3fc000 and contains default system parameters stored in the SDK. This is a 1K file. This HAS to be blown when first setting up a chip.

What to do

There is a binary file called esp_init_data_default.bin which I have added to the server at www.scargill.net – this is in addition to rboot.bin and romx.bin

In the Espressif setup there is a file called ESPTOOL – there are exe versions and .py versions of this floating around (see below). This is what I use to flash the ESP8266 chips – there are others – you may use them – but I can’t VOUCH for them!

https://github.com/themadinventor/esptool

https://github.com/metalheart/esp8266/raw/master/bin/esptool.exe

In Windows this works for me – you will have to check for yourself.

To completely wipe an ESP12 – including all data and setup etc and assuming COM3 in this case (not necessary but if it makes you feel better)…

esptool.exe  -p COM3 -b 115200 erase_flash

To initially flash the code from scratch… assuming you have the 3 files mentioned above…

esptool.exe -p $(COM3) -b 115200 write_flash -fs 32m -ff 80m -fm qio 0x00000 rboot.bin 0x02000 romx.bin   0x3FC000 esp_init_data_default.bin 

Obviously you can change port, speed and file locations. I usually double up on that baud rate but this one is safe.

If you insist on trying this with an ESP-01 (no way will OTA work) – that 3FC000 address becomes just 0xFC000 as they only have 1MB of Flash unless you upgrade them (discussed in another blog in here – done – easy).

As an alternative, I’ve tried NODEMCU FIRMARE PROGRAMMER and that seems to work…

NodeMCU

Nodemcu[6]

And so there it is – the source is updated on the web and requires SDK 2.0 or better to run. The ROMS are updated and the new file is up there.

Bear in mind there is some data here NOT being erased (see full erase command higher up) – in my case at 0x79000 – or around half way up the first megabyte – this is USER data – stored passwords etc. it was put here for compatibility with ESP-01 but I’m about to move this way up to 0xf800 leaving the best part of a MB for code – plenty of room.

And why?

Why worry about updates indeed? Well, one good reason – is that recently, updates to the SDK have used LESS precious RAM – the kind that programs (not data) run in – so with 2.0 there is more margin for expansion – which means more features and more room for more features! It is fine having 1MB to put code in but that is generally NOT the limiting factor with the ESP8266. The code ultimately has to run in RAM and there’s a slight bottleneck there – the gains of later SDK updates help a lot.

Update 31/07/2016

Having now  added i2c and parallel LCD displays to the board, I set a parallel LCD running from MQTT and updating all 4 lines of the display, once a second from Node-Red. While this was running (it’s been running all afternoon – I thought I’d try a test)… I set my serial terminal program fire out lots of on-off commands in a row – which is WAY over the top…

I set up 30 on/off commands for GPIO0 – to run at 80ms each – as you can see clean as a whistle.  I dropped that to 50ms per instruction and the board rebooted – I’m guessing that is a buffer overflow – but then – that simply is not going to happen in real life or anything like it.

I figured I’d go for broke - with 390 (I got sick of cut and paste) commands sent at 80ms it lasts almost to the end then rebooted – again a sure sign of the buffer being in trouble either overflow or wrap – backing that off to 100ms gave zero errors so not a wrap issues – Very happy with this – typically the boards get no more than a few instructions a seconds – often MUCH less. For the sake of it I think this coming week I may just take a look at this – firstly to see if at such speed, my terminal is screwing up – and if not – I’ll see if I can narrow that down but it is utterly academic

serial tester

A complete and utter aside

I don’t use the Arduino setup but as I was thinking about user data, I just checked the Arduino EEPROM library SOURCE for ESP8266 and the Arduino environment does NOT use the 3-sector trick employed in the SDK. When you update the EEPROM (which is actually FLASH on the ESP8266), the sector is wiped (even if you have user data smaller than 4k, a 4k sector is still used) and then updated from RAM – not ideal.  I have suggested to the designer that it might be a good idea to change this. Right now he’s busy working on ESP32 code.

So there it is – all working – hopefully I’ll soon get some clarification on the routine I mention above that I had to move. Time to start adding new features!!!

Facebooktwittergoogle_pluspinterestlinkedin

ESP8266 Meets Arduino via I2C

If you’ve been reading the blog regularly you’ll know I added I2c to the ESP8266 code some time ago – that is, the ability to send an I2c message either to read or write – originally intended and still working with cheap I/O expanders – so you lose 2 wires (GPIO4 and 5) and gain another 6 or 14 for one or two I/O expander boards.

Well, I’ve updated it as of tonight.

Of course, ESP12 talking to Arduino is nothing new but given what we’ve built up here with the ESP boards and Node-Red I thought it might be useful to have the option to expand further.

What a few hours ago seems like something in the distance – well, it is done – and it works – and it has LOTS of potential. Read on.

ESP8266 and Arduino and I2c

What you see above (the FTDI is just stuck into the ESP8266 board for power) is a 1284 Aiduino boards flashing lights  - controlled by MQTT – that is, the ESP12 board on the RIGHT is taking in the MQTT and sending commands via I2c to the 1284-based board and to the little red expander in the middle (on the same 2 pins).

Hence, I’ve spent the day working on the I2c code adding the ability to send multiple byte parameters and to receive a byte (I could have made it receive multiple bytes but for simple control a byte will do).

ATMEGA1284The next step was to set up an Arduino – or in my case specifically an ATMEGA1284 chip to talk to the ESP – hence giving us the ability to control Arduino ports via Node-Red.  Now as yet another blog entry here will testify, you can of course connect (now that the node is fixed) an Arduino directly to the Raspberry Pi in charge – but puts too many physical constraints up.  I had no intention of developing Firmata on the ESP – and so a simple i2c protocol was develop and SO much more can be done.

Right now I have an ESP8266  on the bench with a 2-wire I2c connection to an I/O expander – and an Arduino-type board using the 1284. I can talk to both from the ESP (and hence from my Arduino wirelessly via MQTT) and can control the following:

  • Any pin as an output (and PWM outputs where appropriate
  • Any pin as an input (and analog inputs where appropriate)

So first things first – I used  the Atmega1284 simply as I have loads of them – both DIP40 and surface mount in our little AIDUINO boards. The 1284 has twice the RAM of a 2560 and is easy to use. However this would work equally well in a normal Arduino or in the massive 2560 boards.. the only difference being which two pins are used for i2c. The red chart above, shamelessly stolen from ManicBug’s website shows the pins (in parentheses the numbering system I use).

So in the ESP8266 (grab the latest ROMS or SOURCE) I have a simple method of communication which can be used by MQTT or serial. The format is similar to that used elsewhere in the home control system.

i2c:  device, return, param1, param2, param3, param4, param5.

Not all parameters are needed.

So – to talk to an i2c expander sitting as device 39, connected to pins 4 and 5 of the ESP board…

{i2c:39,0,3}

device 39, no return value, send out 3 (which lights up the bottom 2 LEDS.

{i2c:39}

This returns the value in the port expander.  this is covered in two previous blogs.

http://tech.scargill.net/sunday-morning-experimenting/

http://tech.scargill.net/i2c-expansion-for-raspberry-pi/

So what has changed is that the code can now send out multiple parameters – and optionally receive information back.

{i2c:8,0,1,20,1}

The above sends out to device 8, expecting nothing back, type 1 means set a port bit, bit 20 in this case (see red table above) – to 1.

{i2c:8,1,4,30}

Above – device 8, 1 means return a byte, type 4 means read analog value and port number is 30 – the instruction will return the value of the analog input.

1 is digital out, 2 is digital in, 3 is PWM out, 4 is analog in – you must use appropriate ports – not all are able to handle analog in or PWM out… and you don’t have to worry about port direction setting – this is checked before any operation and set.

There is SO much more potential here but only so many hours.  I will likely make the settings for outputs non-volatile at some point – and add in all manner of device monitoring and probably also make use of the multiple serial ports on these devices.

For now that’s not bad for a Sunday session.  If you’re seriously interested I’ll make the Arduino code available but right now it is highly volatile – but it works!!

Facebooktwittergoogle_pluspinterestlinkedin

Sunday Morning Experimenting

I figured after a couple of horrendous days figuring out what was wrong with my ROMS, it was time for a morning’s relaxing.  Some time ago I added I2c to the Home Control software but never actually got around to doing anything with it.  The i2c parallel expansion modules I got from Ebay have their own pull-up resistors on them… could I get away with hooking 2 boards up without having to dismantle surface-mount pull-ups on on?

test ledsSo first things first I wired up some test LEDs comprising a some AQUA LEDs I had lying around and 120r resistors. I looked all over for pre-made leads with female 0.1” connectors on them but as usual ended up making up my own. If anyone knows of a good cheap source of these – do let us know in here.

Next stop I needed a test board and the obvious one to use was one of the samples I got from Bob Elmour.

A few extra ground, 3v3 and 5v lines (0.1” connector strip) along with GPIO4 and GPIO5 brought out and I was in business. Ok, not the prettiest layout but good enough for testing.

And… yes, I’m not sure I’d want to go beyond two without removing resistors – but they work. With one DIP switch set to ON-ON-ON and the other to ON-ON-OFF I found I could easily use i2c to turn on and off LEDS on both boards at addresses 39 and 38 respectively.

ESP8266 board

It is worth noting that the output DRIVE capability of the little red boards is not that good (as the outputs are also used as inputs with pull-ups) and so to get a decent output I fastened the LED + leads to +3v3 and used the expander boards to SINK current (which means the output logic is inverted).

Using the come control software, lighting up those 4 LEDS is simple.

{i2c:39,0,3}

{i2c:38,0,3}

(The zero is a recent addition and simply says there is nothing being returned. See future blogs for more extensive use involving multiple parameters and an optional return value).

So for the loss of 2 wires, you get 16 outputs using I2c and at a cost for boards of around a fiver. Not entirely sure how well that compares to sticking an ATMEGA24560 onto the ESP and doing some custom software to let you control the outputs (I have thought about this)… but it is certainly one easy way to get more inputs and outputs.

Facebooktwittergoogle_pluspinterestlinkedin