2012-10-02

Ethernet-connected temperature sensor, part 2: design/schematic capture

(Since I'm writing this not only after making the schematic, but also after making the PCB layout and after buying all the components, I won't go through this in steps, but rather just jump to the full schematic, and go through it as-is instead.)

The final schematic

Slightly annotated schematic

Unannotated schematic

Power regulation

First out, we have the power input and 5 volt regulator, in the top left of the schematic.
Not much of anything of note here, just a plain LDO/linear regulator circuit.
Two high-temperature (for the longer lifespan) electrolytic caps on the input, as a local energy reserve. One 10 µF low ESR ceramic, since the regulator's datasheet points out that's what you should use to get stability.
On the output side, the resistors are, of course, chosen to give 5 volts, via the formula Vout = 1.21 V * (R3/R1 + 1) = 5.0336 V
(The 1.21 V is the voltage of the regulator's internal bandgap voltage reference.)
The set resistors are 0.1 % tolerance, IIRC. Not really necessary, but since this is a one-off build, the additional cost is negligible!
On the output is another 10 µF low ESR ceramic cap, again because that's what the datasheet recommends.
I also chose to separate the ground for the input from the main ground plane, and run it through a regular (thick) trace, instead, all the way to the regulator - which is why you might spot the "NET_TIE" component that ties them together at a single point. The reasoning for this (which is really irrelevant for this project) is to keep high-frequency currents of the ground plane, for noise/EMI concerns. (The input power comes from a switchmode supply.)
More on this in the PCB design post. However, do note that I'm far from a professional engineer - I started with this hobby less than 9 months ago - so this rationale might not be perfectly sensible to a professional. I hope it is, though!
Also, since there is no analog stuff on this board, it almost certainly doesn't matter at all.

After that subcircuit, we have the 3.3 V regulator. It's pretty much a straight clone of the 5 V one, except that it's powered from the 5 V regulator and doesn't need input electrolytics, and that it of course has different resistor values to set the output voltage properly.

The microcontroller

To the bottom left - not circled, since that would be a bit silly - is the project's brain: the Atmega328 microcontroller. As mentioned in the first post in this series, I chose that particular model because I wanted Arduino compatibility, and I already had an Arduino Uno (which uses a socketed Atmega328P-PU).
100 nF bypass cap as per usual, 16 MHz crystal (again, for Arduino compatibility - a 20 MHz one, which would fit the 328 spec, would ruin timing unless code is changed) with 22 pF load capacitors - same as the Arduino boards.
Aside from the layout and programming, subjects of upcoming posts, there isn't much interesting going on with it.

The reset circuit

There's a capacitor between the RESET pin and ground, to help reduce noise that might cause accidental resets. A pullup resistor, since the reset pin is active low, and we don't want it to become low without the button being pressed (or the programmer pulling it low). And, last but perhaps not least, a smaller resistor between the switch and ground, as the AVR Hardware Design Considerations [PDF] guide suggests, apparently to reduce di/dt voltages due to parasitic inductance when the capacitor is emptied.
If an external switch is connected to the RESET pin it is important to add a series resistance. Whenever the switch is pressed it will short the capacitor, the current through the switch can have high peak values. This will cause the switch to bounce and give steep spikes in 2-10ms periods until the capacitor is discharged. The PCB tracks and the switch metal will introduce a small inductance, this inductance can generate high voltages according to Vi = L* di/dt. These voltages are most likely outside the specification of the RESET pin. By adding a series resistor between the switch and the capacitor the peak currents generated will be significantly [sic], these currents won’t be large enough to generate high voltages at the RESET pin. An example connection is shown in Figure 3-2.
Figure 3-2 shows the pullup resistor, the capacitor, and also a reversed diode between VCC and reset. However, it appears that a ton of hobbyists (a huge majority in a small, non-representative forum poll) skip the diode, with no real ill effects, so I did too.

Aside from that, there's not much to see here.

ISP interface

One subject that might be worth bringing up regarding the Atmega328, though, is the In-System Programming (ISP) interface.
Most members of the Atmega family are programmed via a SPI bus, connected to four pins: three SPI pins (MISO (Master In Slave Out), MOSI (Master Out Slave  In), SCLK (clock)) plus the RESET pin.
Since I need the SPI bus for the Ethernet module, this proved to be a slight challenge - mostly because there was slightly conflicting information on the best way to solve the possible issue of bus contention.
Programming works like this: you connect a programmer to the ISP interface - a 2x3 pin header - which pulls and holds the microcontroller into reset mode via the RESET pin. That causes it to listen to SPI signals sent by the programmer.
So far so good... However, we also want the Ethernet module connected to the same pins. If it were guaranteed to behave properly, and tri-state its pins, there would be no problem here, as it couldn't possibly interfere when its pins are all high-impedence and essentially disconnected.
However, it seems that quite a few SPI devices out there aren't always so nice, so we need some way to ensure it doesn't interfere with the programming process.

Researching this, I found two different options:
1) Use a pull-up resistor on the SS (slave select) line; when the programmer resets the microcontroller, it will tri-state all pins - including SS - which causes it to float high. This should then cause the Ethernet module to also tri-state and "disconnect", until SS is pulled low again. (SS is active low.)
2) Another solution, as recommended by Atmel in the AVR ISP documentation, is to add series resistors to the SPI bus. The programmer connects directly to the microcontroller, while other SPI devices connect to it through ~5k resistors. This way, if the Ethernet module attempts to interfere, the programmer will massively overpower it.

The first solution, using an SS pullup, seems straightforward and easy. However, it also seems some SPI chips - including the WIZnet W5100 Ethernet chip (the predecessor to the W5200 I'm using) had a bug where it didn't tri-state when SS was high (keep in mind that SS is active low!). This bug is supposedly fixed in the W5200, but I didn't dare take the risk of relying on that method alone, so I chose to use both solutions... except that I'll use 0-ohm jumpers for the series resistors, unless/until that proves not to work.

Debugging

Since, from what I could tell, it seems the only "real" way to debug the Atmega328 is via debugWire, an interface only available with hardware debuggers like the JTAGICE mkII (€290) or AVR Dragon (€50, but I've heard stability/reliability complaints), I ended up going with a different solution.
I did buy a programmer, the AVR ISP mkII (€33), but it doesn't support debugging.

The solution I chose - granted, it is inferior - was to add a UART header to the board (just the TX and RX pins on the micro, plus ground), and to use my Arduino Uno as a UART<->USB bridge. That way, I can access the serial console even when the project is on its custom PCB. What I can't do, however, is set breakpoints, step through code, and inspect variable values... Something which I've managed without, so far - on microcontrollers, at least. I wouldn't say the same for other projects (e.g. OS development!).

Sensors

There really isn't much - or anything at all - to say about the sensors in this post (as I intend to keep this post about the schematic, not the manufacturing part of it all). The only reason I'm even writing this section is to make it clear I didn't forget about it!

Ethernet module

There are a few things worth mentioning here, but I've already talked about most of them! One is that the WIZnet chip is powered off 3.3 volts (and 1.8 volts, through an internal regulator), unlike the rest of the PCB which runs off 5 volts... but I've already talked about the voltage regulators.
Another thing is the trouble with the ISP interface and the SPI bus (SS pullup/series resistors for the SPI lines), which I've also mentioned previously.

So, is there anything left to say?
Well, not a lot. The module has three pins aside from the 4 SPI pins and power/ground pins: power down (usually known as shutdown), which causes the chip to power down and save energy if held low. Since this is a 24/7 device, that sends samples many times a minute (currently every 10 seconds), I simply wired that to VCC.

Then there's the RESET line, which I wired to a pin on the microcontroller, so that the code can reset it when required. Not much interesting here, either.
Lastly, there's the INT (interrupt) pin, which the module uses to signal that it wants the microcontroller's attention. However, it appears that the Arduino Ethernet library doesn't use this functionality at all.
I considered rewriting the library to change this, but it was quite frankly a bit of a mess, and seems to work either way, so at least for the time being, I'll just live with polling. It's not as if performance is crucial.

Add-on header

Towards the end of the design part of the project, I was considering adding other types of sensors, especially humidity and light. (This project was/is intended as a simple greenhouse monitor.)
Those sensor types seem to have one thing in common: there are no cheap, decent digital sensors around. Humidity sensors appear to be mostly capacitive in nature, and I've never dealt with measuring such things before. Since I was ordering the project and PCB before prototyping, I didn't want to risk it.

As for light sensing, all useful solutions I could find were analog in nature (no matter whether they used photodiodes, phototransistors or other components at their core). That's not necessarily a horrible thing, of course, but I decided against it for pretty much the same reason as the humidity sensor - I didn't want to design, layout the board and buy the parts without testing it properly first. There was also the argument that precision analog circuits require low-noise designs.

And so, I scrapped those ideas - for the time being - and went for another: an add-on header. That is, a "slot" (pretty much a 12-pin DIP socket) where a future daughterboard can fit.
All but 4 of the otherwise unused microcontroller pins go to this header. There's power (5 V, 3.3 V and ground), plus the SPI bus pins, the I2C bus pins, the 1-Wire bus pin, two other ADC pins (4 ADC pins in total, since the I2C bus shares pins with the ADC) and one of the external interrupt pins, the other going to the Ethernet module.

This way, I can add on pretty much anything (one way or the other) at a later date. I'm still considering adding the humidity and light sensors, though only after testing them out properly on a breadboard first, to make sure that they're sensitive enough to be of use throughout the whole range of humidities and especially light levels they will experience.
Natural illuminance spans many orders of magnitude - a non-moonlit night can be as dark as 10^-4 (0.0001) lux, while direct sunlight can reach >10^5 (130000 or so) lux. The sensor would hardly need to give accurate readings for each of these extremes, but it should be able to tell the difference between ~10-30k lux (daylight, but not direct sunlight) and ~30k+ (direct sunlight) - something that might not be possible with a simple circuit, as they might get saturated too early.

Everything else

Everything major is mentioned above, and only three small things remain.

One is the LEDs (power, network status and general status).
The power LED is simply wired between 5 V and ground, with a current-limiting resistor, of course.
The others are wired from 5 V to microcontroller pins, again with current-limiting resistors.
You can wire them up either way: 5 V - LED - resistor - µC pin, or µC pin - LED - resistor - ground.
In the first case, the LED lights up when the pin is low (and sinks current), and in the other, the pin sources current when the pin is high.

I'm not using the ADC for this project (if I do end up with that daughterboard, I might use an external ADC for added precision and noise, rather than dragging that sensitive low-level analog trace across 5 inches of PCB), but I still made sure to make it usable, just in case.
By having a decoupling capacitor between the AREF (analog reference) pin and ground, rather than connecting AREF straight to the 5 V rail, you can select between the internal voltage reference and 5 V, in software.
If no external voltage is applied to the AREF pin, the user may switch between AVCC and [internal] 1.1V as reference selection.
Left are... the test points. Whoop-ti-do. I chose a model that looked nice for hooking on oscilloscope probes. What I didn't quite add properly was a ground pad, for use with the ground spring (when you want better measurements, by not using the relatively long, inductive ground clip).
I'm not sure there's much more to say on this subject, but they are Harwin's model S1751-46.
There are also two test pads on the PCB for 5 V and 3.3 V, intended for multimeter use.

Next up: PCB layout and enclosure planning

Well, that's about it for this time!
These posts turn out longer than I anticipated when I first got the idea to blog about this project.
The next post will be, as stated above, about the PCB layout and enclosure choice. See you then!

2012-09-29

Ethernet-connected temperature sensor, part 1: Intro, planning


(My original plan was to make posts about my "backlog" of projects first, so that the posts end up in the same order as the projects did. I've reconsidered, so that I can write about at least part of my current project in "real time", rather than after the fact. I'm currently at the stage where I have a working prototype, and have a custom PCB order on the way (literally, it's in the mail) - my guess is that it'll be here next week!
In a series of a few posts, I'll go through the entire project, from the idea to the final result, along with the many issues and considerations I went through.)

Intro

Back in February (2012), when I had only been working with Arduino/electronics for a month (prior to that, I had no experience with electronics - I couldn't have told you the difference between voltage and current), I was thinking about what to build next. I had previously bought two Maxim DS18S20 1-wire bus temperature sensors, so something utilizing them felt like a good choice.
I built up a circuit using one of the DS18S20 sensors and a regular parallel character display (16x2, HD44780 compatible) to show the current temperature. When I had all the code for that working, I added a 1024 kbit EEPROM to the mix. More coding to get the EEPROM working, but soon enough I had a program that read the temperature, and wrote the current time and temperature to the EEPROM, every 10 minutes.
(Actually, it didn't write the current time, but the number of seconds since starting up, since I didn't have an real-time clock chip handy.)
In either case, it worked! I then wrote a small utility to dump the EEPROM contents via the serial link, left the thing to log for a day, and then graphed the data using gnuplot - after calculating the log timestamps based on the boot time + the offset I'd stored.

Many months later, in late August, when I'd gained a ton of knowledge (in part from taking MIT's online 6.002x "Circuits and Electronics" course the first time it was offered), I was yet again looking for a project of appropriate difficulty.
The temperature logger idea came back to me, except that the goal this time around was to make something a lot more custom and permanent than a breadboarded circuit with ~25 jumper wires in a huge mess.
The entire goal was to design a product from scratch - begin with an idea, move on to writing down how things are supposed to work, then start working on a schematic, etc. - and when all that is done, design a PCB for it, and build the thing up!
Of course, having a custom PCB with parts on it doesn't make a final product. It also needed a enclosure of some sort, a power supply, cabling, programming, and more.
This first post will, apart from the long intro above, be about the early stages - the goals and the early planning.

Setting up the goal

I started fooling around a bit in a schematic editor, to try to get a feel for what I'd end up with. I had already decided to base the entire project around the Atmel Atmega328 microcontroller - simply because I wanted Arduino compatibility, and the Atmega328P-PU was what I already had in my Arduino Uno. I figured that if there would be any problems with the in-systems programming of the chip, I could always physically remove the chip, put it in my Arduino, and program it that way.

At first, the idea was to use the microcontroller, add an EEPROM for data storage and a real-time clock for time-keeping, connect the sensors and pretty much be done with it. I wasn't very happy with how manual this process would be, though - since EEPROMs pretty much only come up to 1024 kbit (128 kiB) storage space, you can't log temperatures for very long before you have to empty it. In addition, doing so would of course require bringing it to a computer, or bringing a computer to it. Far from optimal.
Soon thereafter, I found out about the FTDI "Vinculum" devices - the VDIP1 is a fully integrated USB host addon, with everything you need - the USB port itself and the controller chip. All I'd have to do is plug one in, write some code to interface with it, and I would have access to a whole USB memory stick worth of storage - currently available up to a ridiculous 256 GB worth of storage. With such plentiful storage space available, it could log for literally ages before running out of space.
(At one sample every 10 seconds, storing a 32-bit timestamp and two 16-bit temperature readings, it could go on for just over 10000 years before 256 GB is used up!)

It didn't take long to ditch that idea as well, though. Sure, the storage would last forever, but you still had to remove the USB stick, bring it to a computer and import the data before you could see what it had logged.
I started thinking about a solution that would work better in real-time - some sort of network connection.
After looking around a bit, I ended up going with Ethernet. Wi-Fi was another candidate, but I figured that in either case, you would probably have to either set up an access station, or drag an Ethernet cable (or both!) to use it in any sort of "remote" area, such as in a greenhouse.

After some time spent looking at the various Ethernet modules available, I ended up with the WIZnet WIZ820io. It was small(!), relatively cheap at 18 euros, fully integrated, and had a chip compatible with the Arduino Ethernet library. It would also be easy to mount, as it's essentially a 12-pin DIP package. Awesome!

At this stage, I'd decided to use the Atmega328 microcontroller, the WIZ820io Ethernet module, DS18S20 temperature sensors, and to interface it all with a computer (via Ethernet, of course) that does the slightly more heavy lifting of actually logging, processing and graphing the data, and finally present it to the user.
Here's a block diagram of the project in its final state:
Block diagram for the project. Filled arrow: data, unfilled arrow: data request.
The data acquisition board (DAQ board), i.e. the physical part of the project, runs the sampling process every 10 seconds. After reading the temperatures, it sends the readings via Ethernet to the computer, where a small Python program receives them, and stores them to an RRDtool database.
I chose RRDtool for several reasons: I have experience using it, the database format is well-suited for the task (the database never grows in size; it stores data "in a circle", so the oldest samples are eventually overwritten), and it can create rather pretty graphs - especially with some tweaking.
The database stores the data for a very long time - currently 20 years - before it is overwritten, though at different resolutions. If you want to look at data older than a year, for example, there will be one reading every 15 minutes. For more recent data, the resolution is 1 minute (past year) or 10 seconds (past two weeks).

At this point, I had the basic idea for the project down: sampling the temperature, and storing the readings in a database. What remains is to display the data to a user.
It was pretty clear from the beginning that the best way to present the data would be via a graph, on a simple web page. It'd accept user input regarding what to graph (i.e. which time span to display), and generate the graph.
To make it a bit more modern than to manually enter the date/time strings into text fields, I decided to use jQuery to create the UI, to allow for interactive date picker widgets, zooming in on the data by selecting areas of the graph, etc.

Despite having all this decided, essentially everything remained left undone. I hadn't created the circuit schematic, made the PCB layout, ordered a single component, or written a single line of code. All of that remained - and will be discussed in the coming blog posts.
The next post will focus on the schematic/circuit design. See you then!

As this post is lacking in images, here's one of the current UI:
The datepicker widgets show up when you click inside the text input boxes.

2012-09-28

Temperature logger developments

I hope to get this blog up and running soon enough, at which point there will be a lot more text. In the meantime, some pictures from today's work on the temperature logger/DAQ project!

The PCBs are in the mail, I hope to receive them next week... this'll have to do in the meantime!

11 meters of cable - the 1-Wire bus works just fine!

Heatshrunk sensor. There's a TO-92 package in there somewhere.
I had the sensor running while working. I first tried it in the freezer, then heated it, and finally added the heat shrink tubing.