Pages

Wednesday, 23 August 2017

A Suicidal Circuit

Somewhere under that mess is a 555-timer
I wanted to make a circuit that would be turned on by a push-button switch, supplying a load with a relatively high current, run for a fixed (but configurable) length of time, then turn itself and the load off automatically, using next to no power when in 'standby' mode, waiting for the next button press.

The reason I wanted to do this is that there's a sink on our sailing boat which gets emptied by an electric pump.  At present, you have to stand there, holding a button to run the pump until the sink is empty.  Wouldn't it be nicer to be able to press the button then walk away to carry on with life?  Well yes, it would!  Let's see if we can do something about it!

The pump can run dry without being damaged, so it doesn't matter if it overruns slightly once the sink is empty.  What I basically need to do is set the delay a bit longer than the average length of time I stand there holding the button.  It would be cool to have a sensor that would report when the sink was empty and stop the pump at exactly the right time, but that would introduce a lot more complexity into the project.  One thing that I have learnt from my experience with electronics on boats is that simple is better.  Once salt air starts getting into things, all hell breaks loose!  I tend to get carried away and want to automate everything.  Then it breaks and my wife gets grumpy.  On a previous boat, I had all the lights rigged up to a central control system.  When things headed South with the control system, it was like a disco in there!

A further consideration is that I would like to be able to run the sink in manual mode i.e. how it currently is - hold the button down to run the pump, let it go to stop the pump.  I want to do this because the system runs on battery power.  If the batteries are getting low, I don't want to waste juice by having the pump running for 30 seconds if there's just a splash of water to be emptied.  Most importantly, if the timing circuit breaks, I don't want to be left with a sink full of dirty water while hearing "I told you so" coming from the direction of my wife!

I remembered using the 555 timer back in school.  It's a useful little IC which can be used in a surprising variety of ways.  After a bit of investigation and experimentation with different configurations, I decided to go with the standard monostable circuit but modified so that it triggers itself when the circuit is powered up.

Here is the circuit that I ended up with:



It would have been simpler to use an N-channel MOSFET as a low side switch because then the output of the 555 could be connected directly to the MOSFET's gate.  However, I generally don't like low side switching "out in the wild".  On a PCB as part of some logic system, I think it's fine, but I don't like devices having power continuously on their live rails.  If some water caused a short between the pump's negative supply and ground, the pump would start running and not stop until the batteries were completely dead.  I should mention that it's a 12V system, so the risk of electric shock isn't an issue.

This is why I went with a P-channel MOSFET, so that I could switch the positive rail, but I then had to invert the timer's output using an NPN transistor.  Make sure the MOSFET can handle enough current to run your intended load.  Although I haven't tried it myself, I think you can simply put multiple MOSFETS in parallel to increase the current limit, but you might want to investigate any caveats of this approach before trying it.

How the circuit works

There are already plenty of good resources on exactly how a 555 timer works, so if you want to know all the details, you can look them up, but in this case, all you need to know is:
  • To start the timer running (and set the output high), the trigger pin needs to be pulled down to below 1/3 VCC
  • To stop the timer running (and set the output low), the threshold pin needs to be pulled up to above 2/3 VCC

Because the trigger pin is connected to the discharged capacitor, C2, which is initially at 0V (i.e. below 1/3 VCC), the chip is triggered as soon as it powers up, starting a timing cycle.

Because C2 is connected to VCC via a resistance, it will slowly charge up and, after a certain amount of time, it will reach the magic threshold voltage of 2/3 VCC.  Because a potentiometer is used, you can, obviously, speed up or slow down how quickly the capacitor charges, thereby extending or reducing the time delay of the circuit.  With the values of resistance that I chose, the delay can be set to anywhere between about 5 and 30 seconds.

Once the threshold voltage has been reached, the timer sets the output low and also connects the discharge pin to ground, discharging the capacity ready for the next timing cycle.  R3 stops the capacitor draining too quickly.  Its value isn't too critical - it was just the first low-value resistor that I picked up.  Without it, I found that the timing cycle would restart.  I guess that the trigger pin was falling below 1/3 VCC before the residual charge in the circuit had been used up.

Once the timer puts its output low, it shoots itself in the foot and kills its own power supply.  Q2's base is starved of current and stops conducting across its emitter/collector.  This allows the base of Q1 to be pulled to VCC by R1, and BOOM it stops conducting across the drain/source and the power to the 555 is cut.  Lights out, no talking, sleep well!

The only thing that can power the circuit back up so that the pump will start running again is to manually connect the Q1's gate to earth, which is done via the push button, S1.

C1, across the Q2, is there to prevent any induced currents, static charge etc. from firing the circuit up.  I was finding that if I touched the live side of the circuit, it would start up and it would also run when it was first connected to the power.  I tried a 100nF ceramic capacitor at first, but that wasn't beefy enough to absorb these errant currents.

The DPDT switch, S2, is used to completely bypass the timing circuit and directly connect the push button to the motor, to allow the "WCM" mode of operation (Wife-Compatible Manual mode!).

The LED lights up when the output is on.  This lets you test the circuit/set the time without having a load connected and it will allow for easier fault finding if something stops working after the circuit has been installed under the sink.  R5 is a fair bit larger than necessary, but I only needed the LED to light dimly seeing as it will be installed in a dark cupboard under the sink.

The flyback diode, D2, is present to protect the circuit because I'm using it to drive an inductive load.  If your load isn't inductive, you can leave it out.

I decided to use a low-power CMOS version of the 555 timer.  I don't see any reason why you couldn't drop an NE555 into this circuit, although I haven't tested it myself.

I'm using 12V, but this circuit can be used, unchanged, on a fairly wide range of voltages without affecting the timing.  Just check the datasheets for the 555 timer, MOSFET and capacitors that you use to ensure they can all handle whichever voltage suits your needs.  In my case, I could use anything from 2V - 15V (or even 18V if I fancied living on the edge and pushing the 555 to its absolute maximum rating!).

Here's the finished product on stripboard.  The push button, potentiometer and flyback diode aren't yet present.  They will connect where you see a couple of extra rows on the stripboard but I'm waiting until I have a suitable enclosure because I don't know how long to make the wires until then

Finally, there is no 0V output from the circuit because I will connect the pump directly to the battery negative and only ground the timer circuit with a thin wire spurred off the main negative lead.  There didn't seem any point making thick lines on the stripboard to carry the pump's high-current back to ground, as I had to do with the positive trace supplying the pump.

Thursday, 23 March 2017

Setting up Google Test, Google Mock & Arduino Mock in Sloeber (Eclipse)

The last project I worked on (a rechargeable battery analyser) was the most complicated Arduino project I have written in terms of software.  Up until this point, my projects have been much simpler and I haven't missed testing them too much.

That being said, I hate writing code without using TDD.  I could go on at great length about why this is and why writing a failing test before you get stuck into the code will make your life so much better, your code cleaner/better structured, reduce your development time and probably get you a hot girlfriend.  Actually, if you talk about TDD in public, that last part is most likely not going to come true, but I had to trick Google into raising this post's search rank somehow.

Anyway, the reason I'm not going to talk about any of those things is that seeing as you're here, you probably already know all that stuff and just want to get your test environment set up.  I had a really slow and frustrating time trying to get any test framework up and running in my Arduino development environment.  I don't think that much of the Arduino world cares about testing because I found next to no information and had to work most things out for myself.  There are definitely some people who do care care, though, so hopefully our numbers will grow.  Anders Arnholm went to the effort to create mocks for the main Arduino classes and shared them in his arduino-mock project, which has been forked several times.  Many thanks for that!

My goal is to test the bulk of my code without using any of the Arduino functions i.e. I will be testing my application's logic only.  There will be some cases where it makes sense to check the interactions between my code and the Arduino libraries, which is where arduino-mock will come in.  This allows the tests to be run on my development machine (I will not be trying to deploy tests to run on the Arduino itself).  This in turn makes for a quick turnaround when running the tests, which is essential for the way that I develop.  I will generally write 1 line or less of code before switching between writing a test and writing production code.

This is my environment:
  • Sloeber v4.0 (the excellent Eclipse-based Arduino IDE written by Jan Baeyens)
  • Google Test/Google Mock v1.8.0
  • macOS Sierra (10.12.3).  I wish I wasn't on a Mac, but I needed it for work and now I'm stuck with it.  I dream of the day I can ditch it for a Linux setup again!

Disclaimer:
Tutorials written in this manner are quite "fragile".  If anything differs between your and my development environments, or versions of software move on, things might not work out as expected for you.  Hopefully, though, in seeing how I got tests running in my environment will give you enough knowledge to tweak things to get them running on yours

1. Create new project

Obviously, use whichever values make sense for your setup.





Now you should have an empty project called unit_testing:


2. Create folder structure

Within your project, create these directories:
  • lib
  • include
  • src/test





3. Install CMake

To build the arduino-mock library, you will need CMake.  Install it, then get it running on the command line following the useful instructions shown in-app:


Once you can view the CMake version in your terminal, you know you're good to go:



4. Build arduino-mock

I wanted to be able to mock objects.  You don't have to do this.  I actually got the setup working with only Google Test to start with.  To do that, ignore anything that follows about arduino-mock and just build the Google Test project, then add libgtest_main.a to your project.

Download and extract arduino-mock in a temporary location.


Create another temporary directory and CD into it in a terminal.  From there, run:
cmake path/to/extracted/arduino-mock
Once that finishes, from the same location (i.e. the second temp. directory), run:
make
You should see make downloading the Google Test project and building everything.  I just realised that you might not have make installed.  If you don't, Google knows!

5. Copy libraries to project

You need to copy the libraries you just built into your project.  Put libarduino_mock.a and libgmock_main.a into the lib directory that you created in step 2.  You have to dig down to find the gmock library:





Now copy these three directories into the include directory of your project:
  1. include/arduino-mock from the extracted zip of arduino-mock (the first temporary directory you created)
  2. lib/gtest/gtest/src/gtest/googletest/include/gtest from the second temporary directory (where you ran make)
  3. lib/gtest/gtest/src/gtest/googlemock/include/gmock from the second temporary directory (where you ran make)

6. Create build configuration

Create a build configuration that you will use to build your unit tests.  This is done in the properties page for the project (right-click the project -> properties):


Choose the most appropriate build type to import based on your system.  You basically need a build that will create an executable on the platform you are developing on, because that's where the tests will run (i.e. your desktop/laptop and not the Arduino!).

7. Include/exclude items from the builds

Make sure you're working with the gtest configuration that you just created (you might need to switch from 'Release' in the drop-down).

Add the lib directory as a library search path in the linker settings:



Add the two libraries that we need to include.  Note that that the library name is different to the file name for that library.  As far as I'm aware, this is based on convention.  If you're not on Mac, maybe the names you need will be different so bear this in mind.  I'm a Java man, so I'm just feeling my way with C++ at the moment.



Add the root project directory, the include and the src/test directories to the compiler's include paths:




Exclude the core directory from the gtest configuration:



Exclude the Arduino sketch file (.ino) from the gtest configuration:






Exclude the src/test directory from the Release configuration (i.e. the configuration that builds your Arduino code for deployment)



If you see "Program -E not found in PATH" in the problems view, set the Arduino board details for the gtest configuration.  I don't think this problem would actually stop anything from working, but it's annoying to have it there!  There's probably a better way of solving this issue.  Ideally, we would get Sloeber to ignore the gtest configuration altogether.  If you know how, please comment and tell me!



8. Open the C++ perspective

This perspective makes it easy to switch between build configurations and to launch the tests when we get to that stage:



Use this button to switch between build configurations and to run the build:



9. Create demo unit tests

Set the contents of the sketch file, unit_testing.ino to this, taken from the arduino-mock-sample project:
 #ifndef UNIT_TESTING  
 #include "Arduino.h"  
 #endif  
   
 /*  
  DigitalReadSerial  
  Reads a digital input on pin 2, prints the result to the serial monitor  
   
  This example code is in the public domain.  
  */  
   
 // digital pin 2 has a pushbutton attached to it. Give it a name:  
 int pushButton = 2;  
   
 // the setup routine runs once when you press reset:  
 void setup() {  
   // initialize serial communication at 9600 bits per second:  
   Serial.begin(9600);  
   // make the pushbutton's pin an input:  
   pinMode(pushButton, INPUT);  
 }  
   
 // the loop routine runs over and over again forever:  
 void loop() {  
   // read the input pin:  
   int buttonState = digitalRead(pushButton);  
   // print out the state of the button:  
   Serial.println(buttonState);  
   delay(1);    // delay in between reads for stability  
 }  
   

Create an example file that holds your "application logic", Bob.cpp:




This is the content of Bob.cpp:
 #ifndef bob_cpp  
 #define bob_cpp  
   
 class Bob {  
 public:  
  int one() {  
   return 1;  
  }  
   
  int two() {  
   return 2;  
  }  
 };  
   
 #endif  

Create example unit test file src/test/unit_tests.cpp with this content:
 #define UNIT_TESTING  
   
 #include "gtest/gtest.h"  
 #include "arduino-mock/Arduino.h"  
 #include "arduino-mock/Serial.h"  
 #include <Bob.cpp>  
 #include "../../unit_testing.ino"  
   
 using ::testing::Return;  
   
 TEST(MathTest, TwoPlusTwoEqualsFour) {  
  EXPECT_EQ(4, 2 + 2);  
 }  
   
 TEST(BobTest, BobOne) {  
  Bob bob;  
  EXPECT_EQ(1, bob.one());  
 }  
   
 TEST(BobTest, BobTwoWillFail) {  
  Bob bob;  
  EXPECT_EQ(999, bob.two());  
 }  
   
 TEST(loop, pushed) {  
  ArduinoMock* arduinoMock = arduinoMockInstance();  
  SerialMock* serialMock = serialMockInstance();  
  EXPECT_CALL(*arduinoMock, digitalRead(2)).WillOnce(Return(1));  
  EXPECT_CALL(*serialMock, println(1, 10));  
  EXPECT_CALL(*arduinoMock, delay(1));  
  loop();  
  releaseSerialMock();  
  releaseArduinoMock();  
 }  
   

Run a build, to make sure that the executable has been generated for the next step.  Ensure that gtest is the current configuration (select the drop-down by the hammer icon), then click the hammer icon to run the build

10. Create run configuration 




In the page shown below, you need to browse and select the executable that is produced by the gtest build configuration.  It will be located within your [workspace]/[project]/gtest directory


Now hold your breath and click Run.  If all goes to plan, you should have 3 passing tests and 1 failing test, which was coded specifically to fail, to check that Google Test is doing its job OK.



If this isn't what happens, it's time to locate the palm of your hand, then locate your forehead, then help those two items locate each other:



I did this many times before I got the whole thing working!  If you have followed each step exactly, comment with as much detail as you can about what's not working and I'll try and help.

Wednesday, 15 March 2017

Addressing multiple MCP4724s in the same Arduino project



So, you want to add a DAC to your Arduino project?  No?  Then what do you want?  Oh, you want to add three (or more) DACs to your Arduino project.  Well then, my friend, you're screwed.  We all know that you can only have two addresses: The address when the A0 pin is tied to ground and the address when it is tied to VCC. 

You could get a few more addresses by shopping at different places, as the addresses are set differently in some cases, but that's hassle, right?  Plus, you probably did what I did and just ordered as many as you needed from the same place and are now stuck with a maximum of two unique addresses.

The cheap-ass MCP4725s I got down eBay for about £0.95 a pop have the address 0x60 when the A0 pin is tied to ground and 0x61 when it's tied to VCC.  When I say "A0 pin", what I mean is the address solder pads.  If you spend a bit extra ($4.95) and buy from Adafruit, not only will the addresses be 0x62/0x63, but you will actually have an A0 pin to play with!  That alone may make it worth your while to treat yourself, as you will soon see.

So, how can I address 4 MCP4725s when they only have two unique addresses?  I turned to the data sheet to look for a solution to my addressing problem.  It says:

The address byte is the first byte received following the START condition from the master device. The first part of the address byte consists of a 4-bit device code which is set to 1100 for the MCP4725. The device code is followed by three address bits (A2, A1, A0) which are programmed as follows:
  • The choice of A2 and A1 bits are provided by the customer as part of the ordering process. These bits are then programmed (hard-wired) during manufacturing 
  •  The A2 and A1 are programmed to ‘00’ (default), if not requested by customer 
  •  A0 bit is determined by the logic state of A0 pin. The A0 pin can be tied to VDD or VSS, or can be actively driven by digital logic levels. The advantage of using the A0 pin is that the users can control the A0 bit on their application PCB circuit and also two identical MCP4725 devices can be used on the same bus line.
    When the device receives an address byte, it compares the logic state of the A0 pin with the A0 address bit received before responding with the acknowledge bit. The logic state of the A0 pin needs to be set prior to the interface communication. 
Well, first of all, no one asked me to provide the A2 and A1 bits as part of the ordering process.  I'll have to contact eBay about that.  Secondly, there's the answer!  We can change the state of A0 dynamically because the unit checks what its address should be every time it receives an I2C transmission.  Sweet!

What this means is that we can sacrifice one of the Arduino's digital output pins per ADC4725 and use it as a chip-select pin.  Sure, it means that we've turned the lovely two-wire I2C interface into some sort of grotesque Frankenstein three-wire interface, but at least you get to use your DACs and there's always I2C IO expanders if you run out of digital pins in your project, so quit your jibber jabber.

Onto the nitty gritty.  If, like me, you opted for the cheapskate option and are now wondering how to access the A0 pin, you need to break it out for yourself.  If you're squeamish, look away now, because what follows is not pretty.

The middle of the three ADDR solder pads (circled in yellow) must be connected to a new header pin

In my defence, my soldering iron is a piece of junk with a huge tip which is about to snap off but I can't find replacements and I've also got crappy big solder which doesn't seem to flow properly.  I wonder if any of these things is to do with being a cheapskate and always selecting what to buy based on price and price alone?  Nah, how could it?  Oh, and for good measure, I have to solder kneeling on the floor in front of a chest of drawers which I protect from being burnt with newspaper.  In this instance, I used pliers and elastic bands to hold things kind of steady while I worked.  No elastic bands were harmed in the making of this project.  Actually, one did get burnt, but not fatally.  I need a workshop!

I used a small strand of wire, which I separated out from a multi-stranded wire, to connect the middle ADDR solder pad to the seventh header pin, which I glued in place using epoxy.  The boards came with six-pin headers unsoldered and needed to be put together upon arrival.  I could have soldered a seven-pin header on, but in my excitement, I soldered the headers onto all boards as soon as they turned up and then couldn't be bothered to unsolder them.  I think that you'll agree that the glued-on look works, well, though.

Soldered in place and covered in UHU glue

Once you've seen how good a glued-on header pin can look, you'll never go back

The soldering took for absolutely ages because I kept shorting the solder pads together and having to desolder and start again.  Once done, I covered the thin strand of wire in UHU to protect it from oxidisation and to keep it in place.

That takes care of the hardware.  Now how do you drive these things?  Well luckily for you, I've taken care of the software changes.  I forked the Adafruit MCP4725 Arduino library.  You can find my version here: https://github.com/mitchyboy9/Adafruit_MCP4725

I won't bother explaining how to use the library because there is an example sketch that shows how to address multiple MCP4725s.

Here are two MCP4725s connected up for testing.  The resistor/capacitor combo in the background is another way of creating an analog output using a PWM signal

This shows how to wire the Frankenstein MCP4725s up to an Arduino Uno.  I2C, power &ground are as usual.  Choose any digital pins you like for addressing and configure them in software (2, 3 & 4 are just an example here)

Happy DACing.

Friday, 3 March 2017

SOIC to DIP Conversion

I had a few Texas Instruments BQ32000 real time clock chips lying around that I have been wanting to play with for ages.  The only problem?  They're in the SOIC-8 package type.  Bummer.  I want a nice easy DIP to push satisfyingly into my breadboard.



A quick search on eBay revealed that you can get pre-made boards that you solder your chip onto and hey-presto, you've got a DIP package.  However, I was feeling impatient (after all, when will you be more conscious of the passing of time than when trying to get an RTC up and running?!) plus, for the price of the conversion board, I may as well just buy an RTC that's in the correct form factor and start using it as soon as the postman drops it off.

I had some stripboard and some header pins also lying around...Hmm, can anyone sense a soldering iron session coming on?

Step 1:

Take a picture of the stripboard and quickly sketch where the chip will go (on my Galaxy Note - such a handy phone), to make sure I don't get it wrong when I'm getting carried away with the craft knife in the next step.  The red rectangle is the body of the chip, the white lines are the pins, the black lines are where I will need to cut and the blue are where I will need to solder new connections later.

Why, oh why, didn't I choose red for the cut lines and black for the chip outline, I hear you cry?  I don't know why, but this is one of those moments that I'll regret for the rest of my life.


Step 2:

Make sure the chip lines up, then get a sharp knife and hack away.




Step 3:

Create little solder pads where the chip's feet will go (you might want to check that you have done your cutting correctly with a continuity tester)


Step 4:

Solder the chip on, create the 'jumper' connections between the outer strips and the outer legs of the pin and then solder on the header pins.





Does it look pretty?  Hell no!  But, does it get the job done?  Hello no!

I got readings back from the chip, but the time never updated and when I checked the oscillator fail bit, it was set.

I forgot that the BQ32000 runs on 3.3V and I connected it to my 5V Arduino.  I had intended to use a potential divider to step the voltage down (and hope that it worked at whatever the I2C frequency runs at on the Arduino), but in my excitement, I just connected it straight up.

I had also made such a mess of the soldering that I thought maybe I had overheated the chip.

I desoldered that chip and put another on.  This time I tried to keep my soldering quick.  To rule out the 5V/3.3V issue, I created an Arduino on a breadboard, running on 3.3V at 8MHz (using the internal oscillator).  This was ridiculously easy to do.  I'll try and write a post about it.

I could have used a logic-level shifter, but I didn't have one and they cost about as much as an RTC anyway and in any case, weren't you listening before?  I want this RTC running, like, NOW!

Here is the second BQ32000 connected to an ATmega168 running on 3.3V (clocked at 8MHz)

Second attempt?  Same result.  Either I'm not using the chip correctly (but I think I am - I checked that the run bit was set), or I keep frying them with my ham-fisted soldering.  As I said previously, you can get RTCs including a battery online really cheaply, so at this point, I cut my losses and ordered one of those.

It's not all bad, though, because I like the sound of the DS3231 with its programmable alarms so I have abandoned the BQ32000.  I'm thinking of using the DS3231's alarm feature to wake my Arduino out of a power down state on a sensor project I'm about to start.  Plus, now I've got a ready-made SOIC-8 to DIP-8 converter for the next time I feel like destroying a chip.