Sunday, 1 November 2015

One Small Step ...

... gulp!

Well it's a big step for me, and you'll see why pretty soon. But let's start with a gratuitous arty-looking shot of where we're headed ...

So, as a bit of an introduction, I've been messing around with a number of projects. Having got the hang of designing my own PCBs and getting them made and sent from China for very little money and just a lengthy wait (ok, about a 10 day turnaround if you pay extra for DHL), what I found I've started doing is pipelining my hobby.



So what I mean is, I have an idea for a project, then I design a circuit, research components, breadboard it, write some code, and then when I'm confident enough that it's going to get me somewhere I order some PCBs and wait.

Then, while I'm waiting, I have an idea for a project, I design a circuit, research components, breadboard it, write some code, and when I'm confident enough that it's going to get me somewhere I order some PCBs ... and so on.

This way, by the time the boards arrive for project X, I've already submitted a PCB order for project Y and am busy breadboarding project Z.

This is magic. It not only stops me getting bored, but it allows me to fail (and therefore learn) at three times the rate that I was achieving previously!

Accelerated failure! Perfect. I should patent this idea or something ...

Accelerated failure

So, following my terminology above, I've managed to successfully fail with project Y before even receiving the PCBs. How cool is that?

I'll get to the "small step" thing soon, honest, but in case you're wondering what I'm blathering on about, here's the current state of projects X, Y and Z.

Project X - I've got hold of an ArduCAM Mini module which I've ported to work with a PIC and then combined this with an ESP8266 so I can automate the process of capturing a full colour HD resolution image and then email it to myself for posterity using WiFi. The ultimate aim is to build some kind of time-lapse photography system. The basics work fine, I have some working boards but things need tweaking to allow low-power modes etc. and I still haven't tidied up the software ... so, a work in progress which I'll bore you with in a later blog ...

Project Y - If you remember back in December last year I was messing about with some 8x8 LED matrices. Well, the eBay seller that I bought these LEDs from was having a bit of a sale. Not being able to resist a bargain, I bought a load more of these LED arrays and thought it would be good to use PWM (remember the fan?) to drive each of the 64 LEDs at a different brightness level. So, a quick design with a 74HC138 multiplexer and a PIC16F648A, which features "high current" sink/source for direct LED driving, and I was quickly on my way to waiting for some more PCBs to arrive .... but ....

... too keen .... far too keen ...

Thinking that I could get a useful range of brightness levels while multiplexing all 64 LEDs on an individual basis was wrong. Well, not wrong, more like stupid.

So .... before I tell you about Project Z, I need to tell you why Project Y failed.

Project Y ... or Y not!

This was the basic idea. A single 8x8 LED matrix with the cathodes driven low via a 74HC138 inverting multiplexer and the anodes connected directly to the PIC via current limiting resistors.
The plan was to run the PIC at 20MHz from an external oscillator (saves me a pin) and cycle through each LED by setting one (and only one) anode high - by very careful programming - and one (and only one) cathode low - courtesy of the 74HC138 because that's what it does - and while I'm delaying for a bit on that one LED, to set the PWM duty cycle in proportion to the required brightness and use the PIC's built-in PWM output to drive the enable line on the multiplexer. So effectively toggling the LED on and off to vary its brightness.

By running the PIC at its maximum allowable speed and configuring the PWM for ~78KHz,, this gave me about 12.5 microseconds dwell time per LED, which was enough for about ten cycles of PWM to get the required brightness.

So, even though this worked, and worked quite well, it looked a bit dim. I probably should have done the testing in daytime rather than evening because I thought it was just a matter of tweaking the current limiting resistors a bit to get as much current as possible through each LED without exceeding the 25mA peak limits of the PIC source pin. So I designed some PCBs that matched the physical size of the LED matrix and which held the '138 and the resistors, thinking I'd have a nice module that I could piggy-back multiple copies of onto another board where a collection of PICs would orchestrate a larger display.

Well, wrong.

As soon as the order for the boards had gone in, I set about maximising the brightness by measuring the current consumption and reducing the resistor values to get a happy medium. This is where I failed. Even removing the resistor completely (normally not a wise idea!) only gave me an average current draw of just over a milliamp. Pathetic.

The reason eventually dawned on me, that by multiplexing all 64 LEDs individually, the brightest that any of then could be was only going to be one sixty-fourth of its maximum. Effectively, my duty cycle had an upper limit of ~1.5%, which I was then reducing further by applying PWM on top! Doomed to fail.

Thus, Project Z was born ...

Project Z

Wondering how this LED display thing is really done, I stumbled upon Application Note 1216 from Avago Technlogies, entitled "Introduction to Driving LED Matrices".

Yes, I should have read that first, but hey ... impatience is something else I need to work on ...

Anyway, if you read that PDF, you'll see that multiplexing LED matrices isn't done one pixel (LED) at a time, it's done one row at a time! 

The whole thing starts with the required frame rate - normally no less than 60Hz - which is required for persistence of vision to fool the eye into thinking that the display isn't flickering. So, for the sake of argument, we'll aim for 100Hz, which means a single frame will last for 10 milliseconds. As we have eight rows and we're multiplexing them, then it follows that each row will be active for one eighth of that 10ms, so each row gets 1.25ms (or 1250 microseconds).

Now the 1250us time slice for that row is further divided into a number of time slots that relate to the number of desired brightness levels. Still with me? Ok, then each LED in that row is held on for the number of time slots equivalent to its required brightness. 

For example, keeping the mental arithmetic simple, suppose we want 125 different brightness levels (aka grey levels). Then the row time of 1250us is divided into 125 slots, each of 10us and this 10us period represents our "inner loop" at each step of which we decide if each LED in the active row needs to be on or off. We can do that simply by decrementing its grey level within that loop and turning the LED off when we reach zero.

Sounds like a good plan, my multiplexing overhead goes from one-sixty-fourth to one-eighth, my LED brightness increases accordingly and I only need minor changes to my code. Hmmm..... really?

Suppose that all 8 LEDs in the active row have the maximum grey level of 125. They will all be on for all of that 1250us time slice. During that time they will each be drawing 25mA, which means 25 x 8 = 200mA needs to be sourced and sunk (sinked?) ... that's well outside the maximum limits of both the PIC and the multiplexer. If we don't want a nasty accident, something beefier is required....

Skinning a cat

As in "there's many ways..." - don't worry if you don't understand, no animals were harmed ...

Anyway, there are a number of solutions for this LED driving problem. You can buy dedicated LED driver chips, I've used some myself with the previous foray into LED matrices. You can get built-in current limiting, PWM, dot correction, yada yada ... for example, things like Texas Instruments' TLC5941 and many others. But it all boils down to the same things:

  • You need a way of sourcing current
  • You need a way of sinking current
  • You need a method of multiplexing
  • You need a way of controlling grey levels

Well, I've already got all of these, just that the first two are not man enough for the job. This was because the PIC handled both the sourcing and the grey level control, and the '138 handled both the sinking and the multiplexing. So, let's delegate those sourcing and sinking jobs to something else ...

More source sir?

I found a few possible components for sourcing eight channels at suitable current levels, but these were not as common as the sinking counterparts. I eventually settled on another Texas Instruments chip, the TLC59213, which is an 8-bit parallel Darlington source driver with an input latch. Its can be driven directly from TTL or CMOS levels and it can source up to 500mA per channel, which is easily enough for what I need.

Here's the "Typical Application Diagram" from the datasheet.

In my application, I'll be using this to drive the 8 LEDs in a single column - so, like I explained above but with rows and columns swapped. Therefore, at any one time there may be more than one output channel active, so - like it's shown in the diagram - this is where I need to put my current limiting resistors (so that the 8 LEDs in the active column are effectively driven in parallel, each with its own resistor).

There was also an older, similar chip from Allegro called UDN2981, which although discontinued some time ago is still available for some eBay sellers. However, apart from being old and difficult to obtain (I did get some to try), it also doesn't have the input latch. That latch is very useful for me, because it means I can take my time - in the code - setting up my high/low outputs on the PIC without worrying that it will cause glitches on the display as I switch columns. Once I've set up the new configuration, I just pulse the clock input to latch my new outputs to the LED. Nice.

One other alternative I considered was the TPIC6B595, which is a high-current 8-bit shift register. It can also handle up to 500mA per channel and it otherwise behaves just like a normal '595 shift register and is in fact pin-compatible. However, having to serially shift in the 8-bit LED pattern for the active column takes longer than setting up the parallel outputs of the TLC59213 and I was a bit wary of introducing this delay into the innermost loop of my scanning code. I didn't try it, so I don't know if it would be a problem ... just felt a lesser option for me.

Ok, so that's the beefy source (beef sauce?) sorted - at the cost of one more component - so what about the sink?

Sinking, sinking ....

Easy choice here and really only one way to go. Yet another TI component (no, I don't get commission!), the ULN2803A high-voltage, high-current, 8-channel NPN Darlington array. The "A" on the end means that this part has built-in 2.7K base resistors for each Darlington pair, so it's an easy one to use directly from a CMOS driven output from the PIC.

Eight channels in, eight 500mA sinks out. Again, more than enough for what I need, but at the cost of yet another component (see where I'm going here?).

Only one complication here is that the sinks - which relate to my LED columns - are the ones driven by the multiplexer (because I don't have enough pins on the PIC). However, the 74HC138 multiplexer I used in Project Y is inverting - so all but one output is HIGH. Whereas, the ULN2803A expects a HIGH input to activate each sink channel. Simple solution though is to swap out the 74HC138 for its non-inverting companion, the 74HC238, which is otherwise identical.

Ok, we have the technology .... we can rebuild him ...

8x8 Greyscale LED Matrix Driver

Remember that the point I'm trying to reach here is to have a small PCB, small enough to just fit a single 8x8 LED matrix, that contains as much of the driver circuitry as possible, so that I can use it in conjunction with another board - or by flying ribbon cables - so I can hook up a larger display.

Bearing that in mind, here is the full schematic for such a board. It contains the source and sink drivers, the multiplexer, the eight current limiting resistors and the 8x8 LED matrix. It has some pin headers so I can hook it up to power and to the PIC (just click on it to see it larger).

Notice that the row and column pin ordering is now not so logical. You'll see why in a moment.

So what's with the "small step"?

Ok, finally, I get to the point! You probably got there before me though, and I'd be surprised if you didn't. But ... if you're still wondering .... just think ....

... one 16-pin IC, one 18-pin IC, one 20-pin IC, eight resistors, one capacitor, 16 connectors for the LED matrix and 14 pin headers for connection to the PIC. All on a PCB that's a maximum of 33 millimetres square....

Not a snowball's chance in hell.

It doesn't fit. It will never fit. You knew it wouldn't. I knew it wouldn't. You always knew what I'd have to do. You told me. I didn't listen. I put my fingers in my ears and went "la la la".

Surface mount.


I got there eventually.

I'd always said "I'd have to get boards made for everything" .... crap ... "It's not easy to breadboard with SMD" ... crap ... "It's difficult to solder" .... crap ... actually all crap. All my excuses, that is.

If you've been paying attention to my accelerated failure technique, you'll realise (although I didn't) that I've developed the habit of getting boards made for everything anyway. So I may as well design SMD boards right? You get more space to play with and you can use both sides of the board. Components are very often cheaper and you have a wider selection of parts to choose from. No brainer. No brain at all, more like.

As for the other "objections", look at this:

What is it? I'll tell you what it is. It's a TSSOP-20 to DIP adapter. You take a tiny 20-pin device, like the TLC59213 in the picture (ring any bells?), solder it on, add some 0.1" pin headers and you stick it ... in your breadboard .... and it works. Easy.

Who made it? I did. How many attempts? One.Was it easy? Well, a bit shaky to be honest, but it was much easier than my large sausage-like fingers and rubbish eyesight thought it would be.

Yes, I have arrived. I shall celebrate with a cold can later .... but for now, we have a board to design!

Squeezing it in ...

Easy to fit everything but routing is more tricky. Pin pitch is smaller, so more difficult to route tracks between pins. Even if you do, you have to make them narrow enough to get the right clearance and then make sure they can still take the required current and don't add too much impedance ... yes, a whole new world of problems, but now I'm here I don't think I'll be going back.

The fact is that I did it. You can now see that the non-sequential numbering of the headers is purely to aid in routing. These bloody LED matrices don't nicely have eight anodes on one side and eight cathodes on the other, but they're spread around in some unknowable but seemingly consistent configuration. Anyway, like I said, I did it.

Here's the top of the board:

And here's the bottom (mirrored, so as viewed from the top):

Maybe you can see lots wrong with it, but it's my first, so it's special. I will always love it. Here's the real thing.

So, now, I can try to get this mess off my breadboard and crack on with the real aim of the project, which is to build an arbitrary-sized display by combining the modules - drive each one with its own PIC to distribute the computing load (and hence the need for an FPGA) and see if I can do anything useful or interesting with it.

Before and after

So, before I took that one small step, this is what my breadboard looked like with just one of these LED matrices wired up:

Now, this is what it's like with two of them:

Neat eh? Now I can start to progress with trying to drive more than one of these modules somehow, but that's another project ... project ...errrm .... whatever comes after Z, I guess ....oh .... bugger .... you see what I did by not thinking ahead .... again? 

Accelerated failure is a success ..... !

Video evidence

Just in case you're still reading ..... ;-)

Ok, I'm off to start or finish another project now .... more later ....

Sunday, 6 September 2015

PIC fan boy ...

... that's me

So, here's a nice quick and useful project (for a change!). At work, hanging round the EE types, trying to pick up tips or pick up ideas or just pick brains, I see that they use these fume extractors so that they don't breathe in the nasty stuff that gets produced when the flux burns off as you're soldering...

You can buy something cheap and cheerful if you like, but - I thought - much better to make your own, with a few tweaks.

So, rather than having the fan switched on all the time, how about automating it so that it would switch on and off when necessary, without me having to touch anything? 

Sounds good. 

Even better would be if I could place it just adjacent to the PCB I happened to be be working on, and then as I approach the board with my soldering iron, the fan could switch on and ramp up speed to suck (or blow) away the fumes until I moved my hands away again. Cool eh?

Well I thought so too.

4-pins on my fan

So, I had an old (well old'ish) PC case fan with the requisite wires necessary for controlling the speed. The four pins are used as described in this PDF, which I've summarised below.

The 12V and GND are self explanatory, and just supply the fan with power. The green sense pin is optionally used if you want to read back the actual speed of the fan, and I'm not concerned about that. The important one here is the blue "control" pin, which is actually a Pulse Width Modulated (PWM) input that you can drive to control the speed of the fan. Internally, the fan pulls this up to 5V (according to the spec) or 12V (according to my measurements, which I'm glad I double-checked!) and you can pulse it by pulling it low. So, by default, if it's unconnected, it's effectively full on. 

PWM, as you can read in this SparkFun tutorial is a simple waveform that has a variable proportion of on-time to off-time at some fixed frequency. In the case of the 4-pin PWM fan, the standard specifies 25kHz (give or take a bit) as the frequency.

So, a picture being worth a thousand words, courtesy of SparkFun's CC license, this is what it means:

As you can see, the duty cycle can be used to convey information to the device you're controlling. The length (i.e. time) of each period is defined by the frequency, so for 25kHz, that's a period of 1/25000 or 40 microseconds. So a duty cycle of 75% means that the line is high for 30 microseconds then low for 10 microseconds; 50% means it's high for 20 microseconds then low for 20 microseconds; 25% means it's high for 10 microseconds then low for 30, and so on.

4-pin fans normally respond to a subset of the full 100% range of duty cycles and will commonly spin at some predefined minimum RPM below say 20%. This is to ensure that there is always some airflow in case of problems. The datasheet for the particular fan you choose should show the details. For example, for the fan I'm using, the chart looks like so:

You can see that with 12V, you can't make the fan spin at anything less than about 400RPM.

Ok, how to produce this variable PWM signal? Well, a PIC of course!

To bit-bang or not ...

It would be possible, and pretty simple, to use a timer, an interrupt routine and a bit of code to pull a pin low according to whatever duty cycle you choose. But, with some PIC devices, it's even easier than that because the PWM behaviour is encapsulated in a dedicated hardware module on the chip and you can configure it with a few register settings and then you're free to do whatever else you like (or need) in the code.

For example the tiny 8-pin PIC12F1822 has more than enough to do what we need. The particular feature to look for is the "ECCP (Enhanced/Capture Compare PWM) Module" - it may come in slightly different terms on other devices but PWM is often associated with CCP (capture and compare) peripherals as it's easy to provide both functions from similar hardware.

The PIC12F1822 also has a 4-channel 10-bit ADC, which we'll need for the proximity sensor. More of that later. For now, we need to figure out what to put in the registers that control the PWM output.

The PIC uses one of its 8-bit timers, TMR2, in the PWM mode, so the registers that control the frequency (i.e. period) and duty cycle are PR2, T2CON, CCPR1L and CCP1CON. The datasheet also gives the crucial equations that we can use to determine how to set the right values.

The annoying thing is that the equations aren't written in the way we need to use them. For example, equation 24-1; we want to know what value to set to PR2. We already know the period we want (40 microseconds) and our clock frequency, Fosc, (in this case I've configured the PIC to use its internal 8MHz oscillator), so we just plug in what we know to the equation and rearrange it to get PR2.

So, PR2 = (Period/4*Tosc)-1, which with our period of 40 microseconds and Tosc of 1/8MHz, gives us PR2 = 79. Simple eh? It would be much simpler if the datasheet just gave that formula in the first place because I expect most people would start with what they know to calculate what they want [sigh].

Anyway, now we know PR2, we only need to calculate how to set the 10-bits that are spread over all eight bits of CCPR1L and two bits of CCP1CON. Confused? Yes - why not just have a bigger register? Well, because it's an 8-bit PIC I guess, so it makes sense. 

In any case, we only need to mess with equation 24-3 now because we want to specify the duty cycle ratio (that's our 25%, 50%, whatever) to get the corresponding value for CCPR1L:CCP1CON<5:4>.

Looking at equation 24-3, it's obvious that if we set it to zero, it will give zero percent duty cycle. What about 100%? Well, like we did with equation 24-1, we just rearrange it and plug in what we know. As we already calculated PR2 to be 79, we know that the denominator, 4(PR2 + 1) must be equal to 4*(79+1) = 320. Then with our desired duty cycle of 100% (i.e. a ratio of 1), we can see that setting CCPR1L:CCP1CON<5:4> to 320 will give us 100%. 


We can scale other percentages accordingly, so a percentage between zero and 100 will be scaled to a value between zero and 320, and write a simple function that takes a percentage and sets the correct values in the registers:

So, you can see from the above equations where the magic number of 320 comes from in that code, and the two lines in the middle are just splitting the 10-bit value into two registers. 

The final line is used to turn off the fan completely if the duty cycle is zero - remember that the fan has a minimum speed, even if we set the duty cycle to zero, so I've configured another PIC pin to switch a MOSFET that cuts the power to the fan when I really want it off. You'll see that in the schematic.

Speaking of schematics ...

It's probably time to show you what I've done.

Perhaps not a lot of explanation needed, but just in case....

The main power is 12V, so there's a jumper (JP1) drawn there so I can connect to my PSU. The PIC only needs 5V, as does the proximity sensor, so I have 5V voltage regulator with associated smoothing capacitor providing the power to the logic.

Pin 5 (RA2) is the one configured for PWM output, which pulls the fan's control pin to ground via a 2N7000 MOSFET. The crucial thing to note here is that all of the talk about PWM above, with the various percentage duty cycles, assumed that this relates to the percentage of time the output is high. Whereas, the fan's control signal is pulled up internally, so it's by default high, and we want to pull it down to slow the speed. Luckily, this is trivial to do with the PIC because we can simply flip a bit to choose whether the PWM output is active-high or active-low. Look at the specification of CCP1M in the CCP1CON register in the datasheet. Very nice.

As I mentioned in the code snippet about, pin 6 (RA1) is used as a low-side switch to allow me to switch the GND connection to the fan on or off. Effectively switching the fan off whenever RA1 is not high.

The final part of the puzzle is the proximity sensor, which is fed in to one of the PIC's ADC channels, so I can read the approximate distance from my hand/soldering iron during operation. This connects through JP2, and has a 10uF capacitor to smooth out any bumps as it draws quite a bit of current. I'd better tell you about that next.

Getting closer ...

So, the proximity sensor I chose is the Sharp GP2Y0A41SK0F, which outputs an analog voltage of between 0.3V and 3.1V over a range of 30cm to 4cm respectively. 

In testing, I recorded outputs of zero to 3.2V on my oscilloscope, so that's the way I've coded it.

Code .... just a little bit ...

Which is true. There's hardly any code in this project, and I'm only using a tiny fraction of what the PIC can do. It seems a waste, but there you go .... you can buy a lot of features for very little cost these days.

So, the code.

Leaving aside the configuration bits and other housekeeping gubbins (you can download the whole source code below as usual), the main function starts out configuring the internal oscillator and setting all pins as digital except the ADC channel we're using (that's AN3 on RA4).

Next, we configure the PWM module. This is where we load PR2 with our calculated value of 79, and set the correct bits in CCP1M to use PWM in active-low mode. The remainder of the code just configures TMR2 with a 1:1 pre-scaler and then kicks everything off.
Next, we configure RA1 as an output, so we can switch the fan on or off via the MOSFET, and configure the ADC on channel 3, so we can read the proximity sensor.
Now, the main loop does as much or as little as you'd expect. It reads the ADC and converts the reading into a duty cycle percentage to be applied to the PWM output, then reads the ADC again and sets a new PWM duty cycle, then ... etc.

Note that the code forces anything less than 15% to zero, so we switch off the fan at the point where it will no longer respond to lower duty cycles (remember that chart from the fan's spec?). Also, even though we have a 10-bit ADC available, I disregard the lower two bits because it simplifies the code and we don't need that precision anyway.

Laying out the board

Now, this is a nice small and tidy circuit, so I decided to stop using the mysterious and slightly intimidating auto-routing features that Eagle provides and made this the first board that I routed manually.

I've used thicker traces, and actually it looks pretty good to me and the auto-router didn't do anything other than complicate matters. So I think I'll be routing manually from now on.

Here's the layout:

And here's some pictures of the assembled board.

Seeing is believing ...

As always, we have to prove that the damn thing does what it's meant to do, even though I haven't yet put it in a nice enclosure (and probably won't because I've had my fun now!).

So, I've hooked up the power supply, the fan and the proximity sensor like so...

... and I've recorded a short video of the gizmo in action ..... enjoy!

Source code

If you'd like the full source code for this project, you can download it here.

Saturday, 27 June 2015

Don't be so wet! ...

.... or so dry!

It's been six months since my last post, a long time but I've been busy.

Continuing my exploration of all things electronic, I've been happily making stuff, making mistakes, making a fool out of myself by asking stupid questions of anyone and everyone, but also learning a lot. I've compounded all the practical work with a couple of free online courses too - both from Coursera, I've stumbled successfully through Linear Circuits and also Introduction to Electronics - not too advanced, but useful nonetheless and certainly as much as I could manage with a full time job!

So, what's with the "wet and dry" theme?

How to explore your own hobby while keeping your "significant other" happy!

My wife is a keen gardener. That's keen with a capital K, and gardener with a capital G. So we have an active and ever evolving garden, plus more houseplants than you can shake a stick at.

So, for my next project, I cunningly suggested that I might make her something that would allow her to monitor the state of her houseplants from the comfort of the sofa - that is to say, a wireless plant moisture monitoring system! No, I didn't mention that you can buy such things for very little money and with much more hope of success, but I got the green light to start building things, which was the main result I wanted ... hehe.

Wireless wetness

If you Google or eBay for nRF24l01p, you'll find loads and loads of people who will sell you these little units very cheaply:

What it is, is a 2.4GHz wireless transceiver that you can talk to with Arduino, Pi, PIC, whatever and generally get simple wireless capability into your projects very easily. So I bought a handful.

They run off 3.3V so rather than using my normal preference of 5V PICs, I chose to use one of the PIC16LF range of low power microcontrollers, in this case the PIC16LF1554, which has much more available than I needed for this project (I just need SPI and ADC really) but it did allow me to test and prototype with a UART talking to my PC via a TTL to USB adapter.

The grand plan

So the grand plan was to have a number of moisture monitoring sensors, each one stuck into a favoured houseplant pot, and each periodically measuring the soil moisture level and pinging off a packet of data to a central monitoring station, which would collect and collate the various wetness reports and allow them to be presented in a suitable manner.

I planned to use simple resistive moisture sensors because a) they are cheap, and b) they are cheap. So a few quid on eBay and a long wait for China Post and I harvested a dozen of these:

To read the moisture level, you simply wire this as part of a voltage divider that you sample through the microcontroller's ADC (analog to digital) pin to get a resistance measurement that you blindly assume is both accurate and varies in a linear relationship with the moisture level. Neither of these are true, but who cares - that's not the point! I did pay homage to some advice though that warned against always sampling with the same polarity - risk of gradual electroplating of one prong from the other - so I always take two ADC readings, one with polarity reversed, to even up the battle a little.

To make things even more interesting (complicated), I also wanted a way to reconfigure the sensor units without having to reprogram their PICs, so I used a simple protocol that allows me to remotely adjust the frequency of wetness sampling for each individual sensor. It goes something like this:

  • Sensor wakes from sleep mode.
  • Sensor takes two ADC readings and creates a packet of data.
  • Sensor sends data to the master unit.
  • Sensor waits a reasonable number of milliseconds for a reply.
  • If the reply arrives and requests reconfiguration, the sensor adjusts its sleeping time.
  • Sensor goes back to sleep.

By using the PIC's watchdog timer to wake it from sleep mode, along with some suitable preset combinations of prescaler and counter, I could manage a sampling period of anything between 15 seconds and 16 hours. The former useful for testing and the latter 8-hour or 16-hour period being used in practice.

The sensor

The sensor circuit went through two revisions. Mainly because I was stupid. Ok, no "mainly", but only because I was stupid!

But then you don't learn anything without making mistakes, so stupidity is a good thing ;-)

So the first version of the sensor PCB looked like this:

The first stupid mistake is the battery on the left. I chose the wrong part in Eagle, so instead of having a battery holder, I had a fixed battery with welded solder tags that you can't remove from the board without desoldering. So obviously, you also can't switch it off. Hmmm .. too keen to get the boards ordered, and I don't mind admitting it. Lesson learnt. Probably.

The second stupid mistake was that I forgot to add the recommended 10uF capacitor across the power terminals of the RF unit. In practice it didn't seem to matter, but as I was going to redesign anyway, the second version attempted to fix these issues. The final schematic for the sensor was like so:

At the top left is the 4x2 header to receive the nRF24l01+ unit, then under that is the voltage divider circuit to the moisture sensor (JP1), and apart from power and bypass cap, that's it. So it now looks like this:

The battery can be removed or replaced as required and so I now have a nice stock of the other, fixed tag, batteries because I found I could buy 80 of them for ~£5 on Amazon. Ho hum.

Anyway, I made six sensor boards, each PIC pre-programmed with a unique identifier that gets put in the data packet when sending to the master. So the master correlates the sensor ID with its - also pre-programmed - list of houseplant names, ready for display. Hooray - nearly done.

Mastering the master

The master unit is actually the more complicated part of the system. Not because it has any inherent complexity, but really because it's difficult to fit all of the code into the 4096 words of flash memory and 256 bytes of RAM. For anyone familiar with MPLAB X, how many times have you seen your resources so completely used as this?

This is because we need the code for talking to the RF unit, the code for talking to the OLED, the code for interacting with the 23LCV1024 SRAM, various text strings, and also font mappings. Quite a lot to fit in!

Anyway, here's the schematic:

I've put a 3.3V LDO there because I'm powering it from a 5V wall-wart even though it's 3.3V throughout - it's much easier to find spare 5V supplies in the rummage boxes. So, nothing too difficult to see there - the external RAM has a fixed battery (I knew they would come in useful!) to keep its content safe during power off and I've also added a jumper in there to clear the RAM if I want to start again. In the code, it first reads the RAM looking for a magic number to see if it was previously initialised or not. If not, it writes six pages of empty data to the SRAM with the plant names coded from a 5x7 font. So the display is really just mapped to the SRAM and the PIC only needs to write the bars for the incoming data and read back a single page at a time to display.

The populated board looks like so:

Power comes in top left, the PIC is bottom left and the SRAM bottom right. The momentary push switch at top right allows one to cycle through the six houseplants to see the current moisture level and a bar chart history over the last 128 sample periods (only 128 because the OLED is 128 pixels wide).

Seeing is believing ...

So, finally (yes I know I'm rushing), I've made a short video of the master unit in action so you can see the principle. As usual, I'll link to the code downloads at the bottom ...

One thing that may be interesting is what happens to the soil moisture sensor after a few months use. This is what my first sensor looks like now, after something like five months in an indoor plant pot (over-watered, as it happens!):

Source code downloads

As promised!

Plant monitor sensor
Plant monitor master

Wednesday, 17 December 2014

PIC and mix ...

... or maybe PIC and pray!

Well, after my last post regarding the PIC microcontroller, I've got hold of a bunch more PICs (some from eBay, some directly from Microchip) and these include the relatively modest PIC16F648A of which I successfully bid on a tube of 25 for less than twenty quid, which I think is a bargain.

The headline spec is as follows:

  • 7Kb Flash program memory
  • 256 bytes RAM
  • 20MHz maximum speed

It also has 256 bytes of EEPROM, a capture/compare/PWM module, a USART, two comparators and a programmable voltage reference. The 7Kb program memory equates to 4096 instructions - because this PIC has a 14-bit instruction word - and the 20MHz maximum speed really means 5 MIPS because each instruction is executed in 4 clock cycles (20MHz / 4 = 5 MIPS). 

The data sheet notes that this PIC "fits in applications ranging from battery chargers to low power remote sensors". So, I decided to do nothing of the kind .....

The Matrix

Ok, not this one ...

 ... but this, slightly less impressive but definitely cheaper one (this was about 3 quid, delivered) ...
It's spooky that it's sort of the same colour greenish colour, but anyway - I'd bought as a kit to piddle about with on the Arduino. 

It has a single 8x8 matrix of LEDs, driven by a MAX7219 and hooked up to the microcontroller by a simple serial interface. You can address each of the 64 LEDs individually and make all sorts of fun patterns (really?), well that's what the blurb said when I bought it. You can also chain a few of them together, to drive something like a scrolling text display, which is why there is a five-pin header on the right hand side too.

Now driving this with the PIC instead of the Arduino would have been quite trivial. I could even almost copy the Arduino MAX7219 library and port it to C on the PIC. Also, 8x8 wasn't interesting enough and I didn't want to chain them, I wanted maybe a 2x2 block of these matrices, so I'd end up with a 16x16 array - big enough for something "useful" (ahem). Well, it's a learning exercise innit?  

So, off to eBay again, and I picked up a few more LED matrices for about a pound each, and also a small stock of MAX7219's.

Circuit training

Now all I needed was a way to hook four of these together so I could drive the composite array with my PIC. The basic circuit was quite simple - sixteen lines from the MAX7219 to the LED matrix, a current limiting resistor and a couple of capacitors for smoothing and decoupling. Multiply by four, chain the MAX7219's together and you get something like this:

Now, the nice thing about designing this circuit using EAGLE is that it's easy to create a corresponding design for a custom PCB, just by dragging and dropping the components of your circuit onto a bare board layout. Ok, it's not quite that simple, but it's easy enough for a novice like me and I was keen to go through the process of designing a PCB and having it professionally made (which is actually unbelievably cheap, if you're prepared to wait for it to arrive from China).

Board? Me?

So, stumbling through the EAGLE tutorials and gleaning whatever advice I could understand from the Internet, I ended up with a board design like this:

I used EAGLE's auto-routing feature for the track layout - having never done this before and having little confidence that any changes I made would be "better", I just did my best to make it look pretty, exported the files in the generally accepted Gerber format, and sent the whole lot off to ITEAD Studio along with my £19 payment, and waited .....

... OK, I didn't have to wait as long as I thought. Eleven days later, my 10 (yes ten) boards arrived by air mail from China, and even to my unpractised eye, looked very good quality. See what you think :

Top view of the board
Bottom view of the board
Now, with nothing stopping me apart from waiting for the soldering iron to heat up, I got cracking. First, I populated the IC sockets, headers, resistors and caps ...

... and then fitted all four of my LED matrices, one at a time:

One down, three to go
All safely installed, if slightly untidy

Slight deviation

While all of this was going on (i.e. the waiting part), I was busy preparing the PIC for the arrival of the super-matrix. Looking through my boxes of bits, I also found a 16x2 LCD panel, like this:

16x2 LCD panel
And, having nothing better to do, I started off building this into my PIC environment, so I could use it for debugging, if nothing else. Previously I'd been debugging using a logic analyser and a spare PIC pin to trigger collection of crucial signals on the part of the circuit under investigation, but found that there's no real replacement for the ability to dump out some text or some hex to see what's happening inside the PIC. The mid-range PICs I tend to use don't support in-circuit debugging without an external debugging header (which costs money - too much to warrant the expense).

There are numerous examples of driving these LCDs, so I won't repeat the detail here. In summary, I'm driving it in 4-bit mode rather than 8-bit (saves 4 pins) and also doing this via an M74HC595 shift register, which means that - by doubling up on the shift register and LCD enable lines, I only use 4 pins in total from the PIC. I'm trying to save as many as possible to add more stuff later.

So, the final circuit for the PIC was as follows. Note the DIN, CS and CLK outputs that are destined for the 16x16 LED matrix assembly. The remainder is the LCD and its 595 driver, an ICSP header for programming the PIC in circuit, and an external crystal and load caps to get the PIC cranked up to 20 meg. Bottom right is a 10K trimpot to adjust the LCD contrast.

Happy days

Now, putting the whole lot together - with the PIC and LCD on a bit of stripboard, and some hastily written test code, we have lift off! ...

So far so good, but there was still a bit of capacity left on the PIC - I'd only used 50% of the 256 bytes of RAM and about 30% of the program memory. Not bad from the free (non-optimised) XC8 compiler supplied by Microchip. Also, I hadn't really done anything useful with the LED matrix other than flash up a hardcoded smiley.

So, back to the box of bits, and out comes an old (very old) PS/2 mouse. One with a real ball.

The final lap

Finally, with the help of this description of the PS/2 mouse interface, and a couple of my remaining PIC pins, I wired up the mouse and added the code necessary to initialise it and respond to its signals.

I didn't show it on the schematic above, but the mouse connects to the PIC pins RB0 (mouse clock) and RB1 (mouse data). These pins are both used as open collector signals, so I have enabled the internal pull-ups on PORTB rather than use external pull-up resistors. It works well, and seems to be stable, which is all I could hope for.

So, now, at last, from that modest PIC, normally used for battery chargers etc., I'm supporting a 16x2 LCD display via a 595 shift register, a set of four MAX7219's each driving an 8x8 LED matrix, and a PS/2 mouse, that I have programmed to "draw" on the LED matrix. All in all, this would have been the starting point for an innovative arcade game thirty years ago (sigh - feeling old now), but it's taught me a lot - most of all it's taught me how little I still know and how much I'm enjoying this resurrected hobby ....

Take a look at the final video to see everything working together, and if you really feel inclined to do anything like this yourself, download the source code from here.

That's all until I've finished my next "project" - involving some of the more powerful PICs and a couple of (at least) wireless transceivers .... watch this space ....