Computing stuff tied to the physical world

Squeezing a bit more

Reducing power consumption is a game with deminishing returns.

This is a good time to show how much information can be obtained using an oscilloscope. It doesn’t have to be a fast and fancy one, but it does need to have a good low-end voltage range. The nice Hameg HMO2024 unit used here can display a very low 1 mV/div, which is 10 mV/div with a standard 10x probe. With our 10 Ω resistor, we’ll only need 100 mV/div:


There is a lot of information in this scope capture:

  • the vertical scale shows current, but is measured as voltage-over-a-10Ω-resistance
  • you can clearly see the power-up spike, and then the 40 ms IR sensor measurement
  • just when the 2nd measurement starts, power to the sensor is cut, after ≈ 54 ms
  • the red line is calculated by the scope as being the accumulated charge consumption
  • when the sensor is shut down, 1.5 mC (milli-coulombs) have been consumed
  • if we do this once per second, it’ll be equivalent to an average current of 1.5 mA
  • the starting current (on the left) is not zero, zooming in shows that it was ≈ 1 mA
  • likewise the ending current is ≈ 4 mA

The starting current is with the LED off, i.e. the current of the LPC810 itself. The ending current is with the LED turned on, which uses an extra 3 mA of current. On the next iteration, the level of these two lines will be reversed, since the LED is being toggled.

Based on this image, we can deduce just about everything that’s happening:

  • the LED is on half the time (it is being toggled to blink, after all)
  • when on, it draws 3 mA, so its average current consumption is 1.5 mA
  • the LPC810 is never sleeping, and consumes about 1 mA, 100% of the time
  • the average current equivalent of that brief huge spiky pattern is another 1.5 mA

Bingo: the GPA is drawing 4 mA on average, and now we have a good insight as to why!

Note that a 10 Ω resistor is bit too high for these currents. When measuring a 3 V drop over the resistor, this also means that only 2 V remain to power the circuit itself, well below it’s design range. Those 1.8 V spikes from the IR sensor are almost cutting power off – a better choice with these current spikes would have been a 1 Ω resistor, and 1/10 th of the losses. The oscilloscope then needs to be able to display voltages 10 times as low.

Only blink when it matters

One reason we didn’t achieve a truly long battery life, is that this didn’t factor in the 50% ON time of the indicator LED. It’s toggling between nothing and 3 mA – day in, day out.

This problem is a bit tricky. There are two cases: the car is not present, or the car has been parked and we’ve left. In both cases, the blinking LED is just wasting precious energy.

With no car present, the IR distance sensor will return a low voltage, indicating maximum range. We can handle this by turning the LED permanently off below a certain threshold:

if (v <= TOO_FAR) {             // if too far away: don't blink
    LPC_GPIO_PORT->SET0 = 1<<4; // turn LED off
    delay(1000);                // do nothing for one second
    continue;                   // loop to get next readout

But what about when the car is parked right in front of the GPA? The code as it is now will constantly read out the IR sensor, and cause the LED to blink rapidly. We need to add a sense of change to the system – if nothing has changed for some time, then go into a slow idling pattern, waking up occasionally just to check whether there is a new change.

This sort of logic complicates the code a bit, but here is the 5-idle version with the new idling behaviour. Feel free to upload and try it out – or read on for the next improvement.

Powering down the µC

A second reason why the power reduction didn’t reach the expected level, is that we didn’t put the LPC810 to sleep, only the IR sensor. Let’s address this issue as well.

Note that all versions of the GPA code are running the SysTick clock at 1,000 Hz, i.e. one interrupt every millisecond. This is very convenient, because it allows us to simply count interrupts to introduce a delay – which is precisely what this code does:

void delay (int millis) {
    while (--millis >= 0)
        __WFI(); // wait for the SysTick interrupt

Putting the LPC810 to sleep takes – as always – a bit more code, but the nice part is that we don’t have to turn the SysTick timer off. We can simply go into power-down, and the µC will automatically stop all main clocks. On wake-up, the SysTick will resume its timing role.

Apart from the code which does the powering-down, we only need to change these lines:

    delay(1000);  // do nothing for one second

to this:

    sleep(1000);  // sleep for about one second

The wake-up timer uses its own ultra low-power clock, which is not so accurate: the main clock has an accuracy of ± 1%, whereas the low-power one can be off by as much as 40%!

In this case, it doesn’t really matter. We just need to wake up “often enough”.

Now we’re cookin’

The low-power clock may be less accurate, but it sure lets us consume far less power: the LPC810’s current consumption drops from 1 .. 3 mA to less than 10 µA in power-down.

Total current consumption of the GPA is now as follows:

  • 5% of the time (about once a second), the GPA’s current draw will be 30 mA
  • 95% of the time, the GPA will consume only about 10 µA: 3000 times less

Drawing 30 mA 5% of the time is like drawing 30 x 5% = 1.5 mA all the time on average. Add to that the 10 µA, which is negligible, we can now estimate the run time on 2,000 mAh batteries to be 2,000 / 1.5 = 1,333 hours ≈ 56 days ≈ 2 months. Bingo, as predicted!

To try this out if you don’t have a chip pre-loaded with the software, upload the 6-sleep version to your LPC810. Then it’s capable of running for 2 months on a set of batteries.

A new oscilloscope check confirms the power down and the IR sensor consuming 1.25 mC every 1.1 second. That’s less than 1.2 mA on average, i.e. a 70-day estimated battery life.

The 6-sleep code includes all the preceding refinements, including the 5-idle logic.

How about a year?

So much for the low-hanging fruit. We went from 2 days to 2 months. Not bad.

Now we’re going to need more tricks. The IR sensor can’t be used too often, yet we do want to detect a car the moment it comes into the garage. Perhaps something like this:

  • only check once every 6..10 seconds until an approaching car is detected
  • run once a second and blink as needed, then auto power-down after a while

Sure enough, that should lead to a 6 times better battery lifetime, or about a year.

But there is another way to skin this cat, leading to considerably greater savings:

  • humans and cars don’t move around in the dark, right?
  • if we attach an LDR, we could check for changes in the ambient light level
  • only when the light changes do we start reading distances with the IR sensor
  • and again, after a while we make the GPA auto power-down

This is infinitely better as power-saving technique than just slowing the IR sensor readings down a bit, because an LDR can be enabled and read out in a fraction of a millisecond. By waking up once a second, getting work done within that millisecond, and going back to sleep, we get a 0.1% duty-cycle solution for the most common case: nothing happening.

With a 0.1% duty cycle at say 5 mA, we’ll end up with an average current of 5 µA (plus the 10 µA used the other 99.9% of the time). Only very occasionally will we need to go all the way and enable that power-hungry IR sensor – a few times a day perhaps, whenever there is some activity in the garage.

Let’s triple that value and use a conservative estimate of 50 µA average current use by the GPA. On 2,000 mAh AA cells, it’ll now last 2,000 / 0.050 = 40,000 hours: over 4 years.

Admittedly, it will take a bit more effort and time to get the code right for this approach, but the LPC810 should be up to this task since it has a second unused comparator input.

Note how the challenge has changed from getting the GPA to work to making it clever.

To use this final long-lasting GPA version, you need to connect an LDR between pins 7 and 8 of the LPC810 and upload the 7-complete code into it:

DSC 4862

Depending on light levels, idle current has been measured to be a mere 20 .. 70 microamps.

This version does not come pre-loaded on the LPC810 because it requires the LDR to work. Without LDR it will shut off after 100 iterations, and never get triggered to wake up again.

Finishing touches

There’s one free I/O pin. This could be used in combination with the current LED/TX pin to connect an I2C expander, and then a 7-segment display, but frankly… it’s not really worth a whole bunch of extra components. The blinking LED is doing its job just fine.

So now that it’s working nicely, we can finally install our new Garage Parking Aid. As mentioned in the introduction, there are many ways to construct a nice enclosure for it, but since this was only intended as simple introduction, we’ll punt and just use it as is.

Here is the GPA on a wooden support, and positioned just right to detect a car bumper:

Gpa installed

Everything was attached using double-sided tape (already on the back of the breadboard).

The behaviour of the GPA is as follows: 10 blips on power-up, with serial output, then it enters blink mode. With nothing in front, blinking stops. When no change occurs 32 times in a row, blinking also stops, only to resume when the car is at least half a meter away or so.

While idling, the GPA looks for an object and measures its distance about once a second.


If you combine a nice circuit with a programmable µC, you get magic. It’s that simple.

Both these aspects are essential: picking suitable components and figuring out how to connect them together on the one hand, and getting to grips with the capabilities of the selected µC on the other. It all adds up to a very potent – and above all: flexible! – mix.

This is also why projects like these are best “invented along the way” – there is no way to plan it all up front. Programming lets us constantly come up with new creative solutions.

Speaking of programmability: swapping chips during development is tedious. If we could avoid that, we’d increase our productivity and we could explore new ideas a lot faster.

[Back to article index]