Category Archives: ESP8266

HC 2016 Experiments

Throughout the development of the Home Control 2016 project I’ve constantly had the software tied a via a serial umbilical to my PC to monitor passing messages, make sure all is well etc. and to periodically check on RAM space to make sure nothing I’m doing is running away with precious memory.

You may have seen elsewhere that I’ve been working with a prototyping board which is basically an ESP12 with a prototyping area in which I’ve put rows of pins for ground, 3v3, 5v and the two lines I use for I2c as I add various peripherals culminating in the recent idea to use an Arduino 328 chip as an “ultimate peripheral”.

Well, we’ve taken that one a stage further and we’ve been discussing making our own prototyping board (Aidan’s a whizz at PCBs and of course we use the likes of Dirty PCBs in China so it is quite cheap to knock up a few boards) and the last few days I’ve been formulating a planas Aidan puts together the schematic. What I’ve realised is that I always run out of the power and ground lines no matter what I do. Add to that the FTDI so I can monitor serial Comms and it all gets a bit messy.

Display for HC2016

So right now we’ve been discussing a board with the ESP-12 module with lots of pins and additionally a 328 SMT chip with Xtal. Of course that means 2 serial monitors. I’ve been playing with the old QDTech 128*160 displays since I discovered that they work pretty well when driven from the proper SPI pins on Arduinos (don’t even think of using software SPI on them) and ramping up the SPI speed – and so it was that in conversation, we were saying “if only you could scroll them” – that led to thoughts of having a RAM buffer larger than the total available on the ESP8266 or Arduino and… well, I thought I’d use our friend Google to go take a look. It turns out – I was completely unaware of this and VERY pleasantly surprised to find – that the QDTECH chip has the ability to scroll up built in – all that is needed is to scroll up an area then paint a fast horizontal black line after each scroll. 

There is a version of the driver for the board here and at some point in 2014, it turns out that an M J Sage added this scrolling ability. Well done.  I wonder if he or she realised what a useful addition this could be.

So now we have a display, easily driven by the 328 which can scroll constantly (I’ve had it on several night’s test) and hence provide a boatload of status info. Top and bottom can if needed remain static.

First Stab

We’re going to incorporate the display onto the prototyping board and it won’t take any additional space as it will sit neatly over the other components! The image above probably bears no relation to the final board but I’m just trying to convey an idea here. The prototyping area on the right of the board will be chock-full of PTH holes but there will be long runs of connected holes for power and I2c as these end up being needed the most with connector wires. All 0.1” of course.

With the QDTech display you can connect the reset line to the 328 reset and hence here are my first thoughts at the use of the 328 which will have access to A6 and A7. I’ve pretty much got this working – just need to add in the temperature handling code I already have for Dallas and DHT chips.

D0-7 – general purpose port extender – inputs or outputs or any mix
D8     D/C for QDTECH
D9     16- BIT PWM out
D10  16-BIT PWM out
D11   MOSI for QDTECH
D12   MISO
D13   SCLK for QDTECH
A0      CS for QDTECH
A1      Temperature
A2      Temperature
A3       Debounced input
A4      I2C to ESP
A5      I2C to ESP
A6      Analog in 1
A7      Analog in 2

Aside from losing GPIO2 and GPIO14 inputs (as they’ll run the I2c) the ESP use will remain the same.  The only restriction being that we cannot run ESP PWM at the same time as the I2c due to timing interference– a pain but not something I can see away around. The I2c 16-channel PWM controller does seem a good way around this as it offloads all PWM work onto a cheap board – for single colour PWM lighting the new 16-bit PWM on the 328 works fabulously.

Given that the 328 can handle inputs for the main board we can do away with our normal GPIO2 and GPIO14 and they can have the job of I2c, leaving all normal outputs as for the existing system.

I guess the end-game here will be the smallest possible board that contains both the 328 and the ESP wired to this spec for general use. But that comes later after we see how well all of this works in practice. First the prototyping board. Watch this space.

Sadly in the link I’ve enclosed, the author refers to Banggood who used indeed to offer these displays for under £3 at a time when there were no software drivers for them – (I think we paid £2.60) but I’ve noticed recently that Banggood have been getting greedy and jacking their prices up – a cursory check of the link shows they now want £5.48 for these simple LCD displays – well good luck with that Banggood.

The only ones I’ve found up to now – and the price is good – as usual – is AliExpress.

Someone have another link?  the board has an 8-way connector at one end and a larger connector at the other – with a full size SD socket on the underside. See the AliExpress link.

This blog entry could well change dramatically as we spot fatal flaws in the plan above Smile

Facebooktwittergoogle_pluspinterestlinkedin

ADS1115 I2C A/D Convertor

Coming up next on HC2016 project -  the ADS1115 I2C 4-channel A/D convertor.

ads1115This item came from AliExpress – a very nice purple board – very clean – and importantly – very cheap at £1.89.

I started off looking at some Adafruit code for a similar chip and immediately spotted something wrong and noticed some of the code comments seemed incorrect – one of our readers offered a solution but ultimately – as I plan only to use this as a straight-forward 4-channel A/D convertor, to study the Texas data sheet.  Page 11 seemed pretty clear – I put ground to ground Vcc to 3v3, the “address” pin to ground (that pin can offer up to 4 addresses amazingly – grounded gives the base address of  0x48. Of course like other i2c 7-bit addresses this will be shifted left by one – but that’s already done in my routines.

As described on page 11, all you have to do is sent a 16-bit command (MSB first) to the config register, a zero to the pointer register then read 2 bytes (MSB first) from the read conversion register. What could be easier.

Having a need for a different number of parameters than before – in this case a receive where only the address is fired out – no parameters but just read 2 bytes back I made a new function which should make it easier to talk to devices in the future..

ic2_general(address,buffer,transmit_length,receive_length);

That way I get to need only one I2c function to do the lot – passing zero or more bytes – and receiving zero or more bytes.  I could see me back-fitting older code with this.

And (cutting out lots of experimenting) it works – I didn’t need a library for simple reading – it’s easy.

If you look at page 19 of the data sheet there are all manner of options for the config reg – I chose 4.096v as the full scale input – and using an argument I can setup which input (1,2,3,4) or read (0).

Initially {ads1115:1}  - that sets up input A0 and continuous conversion

then

{ads1115:0} – reads the value back.

Now an important point here – if you wire up the unit to 3v3 – you should NOT exceed that – so in my case I ended up with a reading around 26,385 when connecting the relevant input to 3v3 because of course this device can handle positive and negative inputs.

That value, given a top value of 32,767 for 4.096v full range indicates my supply voltage is 3.296.  My meter suggests Vcc is 3.28v so one of them is out just a TAD (mind you as the meter only had 2 digits after the decimal point the real value could have been very near 3.29 – so I’m not complaining – the readings were pretty consistent, not varying more than 3 digits and zero volts was showing at value 3 which seems reasonable given my shoddy wiring on this prototype.

Reading data - reasonably quickly

All in all – a nice addition for under £2 all in… so in one example I currently measure 12v battery voltage on my Pergola using the ESP built in A/D – now I can measure battery AND solar charger and figure out current and losses from there. That’ll make for some pretty graphs. I’m sure you can think of some much better uses.

Facebooktwittergoogle_pluspinterestlinkedin

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"}

For clarification - that is a string - which starts and ends with "{" - it is not JASON or ann object. So if you want to send this from, say a Node-Red function you'll have to consider escaping strings.

You might wrap the whole thing in single quotes for example.

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