<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>rocketnumbernine</title>
	<atom:link href="http://www.rocketnumbernine.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.rocketnumbernine.com</link>
	<description>Andrew&#039;s Project Blog - hardware, software, things</description>
	<lastBuildDate>Sun, 16 May 2010 08:48:18 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Decoding a Rotary Encoder</title>
		<link>http://www.rocketnumbernine.com/2010/03/06/decoding-a-rotary-encoder/</link>
		<comments>http://www.rocketnumbernine.com/2010/03/06/decoding-a-rotary-encoder/#comments</comments>
		<pubDate>Sat, 06 Mar 2010 22:03:02 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[interrupts]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=406</guid>
		<description><![CDATA[This article details a simple approach to decoding the output of a 2 bit incremental Rotary Encoder.  The example uses interrupts with AVR GCC on an Arduino platform, but the same interrupt setup can be used on most AVR chips and the approach will of course work on any device.
Rotary Encoders can offer high [...]]]></description>
			<content:encoded><![CDATA[<p>This article details a simple approach to decoding the output of a 2 bit incremental <a href="http://en.wikipedia.org/wiki/Rotary_encoder">Rotary Encoder</a>.  The example uses interrupts with AVR GCC on an Arduino platform, but the same interrupt setup can be used on most AVR chips and the approach will of course work on any device.</p>
<div id="attachment_419" class="wp-caption aligncenter" style="width: 510px"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2010/03/EncoderOnArduino.png" alt="" title="Encoder On Arduino" width="500" height="357" class="size-full wp-image-419" /><p class="wp-caption-text">Rotary Encoder on Arduino prototype shield</p></div>
<p>Rotary Encoders can offer high precision, long life and a simpler/digital interface over analogue devices, such as potentiometers, for reading a rotational movement on a computer.  They&#8217;re often fairly expensive, but I recently picked up a bargain pack on eBay and Mouser also have a <a href="http://www.mouser.com/Passive-Components/Encoders/_/N-6g7nx?Keyword=rotary+encoder&#038;Ns=Pricing|0">selection</a> for around a dollar.</p>
<p>There are a number of interface and encoding techniques used by encoders, ranging from devices that provide a digital output of the angle of the shaft &#8211; with resolutions ranging from 8 to over 8000 counts per revolution, to simple 2 bit incremental encoders which report clockwise or counterclockwise movement of the shaft, this article looks at decoding the latter.</p>
<p>The rotary encoder indicates movement by toggling the output of two pins from high to low or vice-versa, the direction of rotation is indicated by which line goes high (or low first) as shown in the following diagram from wikipedia:<br />
<a href="http://en.wikipedia.org/wiki/File:Quadrature_Diagram.svg" class="image"><img alt="" src="http://upload.wikimedia.org/wikipedia/en/thumb/6/68/Quadrature_Diagram.svg/300px-Quadrature_Diagram.svg.png" width="300" height="100" class="aligncenter" /></a></p>
<p>The waveform produced from the encoder I tested with when rotating clockwise then counter clockwise is shown below:</p>
<p><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2010/03/RotaryEncoder-Output.bmp" alt="Rotary Encoder Waveform" title="Rotary Encoder Waveform" class="aligncenter size-full wp-image-415" /></p>
<p><strong>Decoding the Encoder</strong><br />
There are many ways of decoding the changes in pin logic level to direction of rotation, but I think the following is the simplest.  If you look at the waveforms above, a clear pattern emerges: travel from left to right over the waveform above (simulating rotation the shaft in one direction), when the inputs are the same (both high or both low) the last input to have changed will be A, if the inputs are different then the last input to have changed will be B.  If the shaft is rotated in the reverse direction (travelling from right to left over the waveform) the opposite is true.  If we write these conditions in binary expressions: A is equal to B, last changed pin is A, direction is left we can create a truth table:</p>
<table border="1"  align="center">
<tr>
<th>A==B</th>
<th>changedPin==A</th>
<th>direction==left</th>
</tr>
<tr>
<td>true</td>
<td>true</td>
<td>false</td>
</tr>
<tr>
<td>true</td>
<td>false</td>
<td>true</td>
</tr>
<tr>
<td>false</td>
<td>true</td>
<td>true</td>
</tr>
<tr>
<td>false</td>
<td>false</td>
<td>false</td>
</tr>
</table>
<p>From this we see that the we can use a simple <a  href="http://en.wikipedia.org/wiki/Exclusive_or">XOR</a> to calculate the  direction of travel (direction == left) = (A == B) ^ (changedPin == A)</p>
<p>Note, that the above generates 4 rotation signals on each complete quadrature rotation &#8211; with some encoders this is too high a resolution (the mechanical ones I&#8217;ve tested this with are &#8217;stepped&#8217; &#8211; they click as the shaft is turned, resting with with both pins at zero).  So it may be better to just record movement when both pins pins have fallen to the low state (A == 0 &#038;&#038; B == 0) and ignore other changes.</p>
<p><strong>Detecting Pin Changes</strong><br />
The two pins from the rotary encoder are attached to digital IO pins on the microcontroller and held to ground with a resistor until rotation causes them to be go high.  Rather than polling for changes, interrupts are used to trigger execution of a handler function every time the line state changes.  This allows for other operations to be done whilst waiting for input.</p>
<p>In this example AVR external pin change interrupts are used.  These can be used to detect changes on nearly all of the devices IO pins.  PCINT18 and PCINT19 are used below, these are triggered by changes to the AVR IO pins PD2 and PD3 &#8211; Arduino pins D2 and D3 respectively, see <a href="http://arduino.cc/en/Hacking/PinMapping168">here for a mapping</a>.  Pin change interrupts are handled in 3 groups, PCINT0..7, PCINT8..14, PCINT16&#8230;23 and are controlled by the PCICR and PCMSK0-PCMS2 registers, we&#8217;re using pins in the same group to simplify setup.  Note that we have to use the same interrupt handler to receive events for both pins, the pin value is queried to see which has changed:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> setup<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; Serial.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">19200</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; pinMode<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">2</span>, INPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// 2 Encoder pins as inputs</span><br />
&nbsp; pinMode<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">3</span>, INPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #666666;">// enable interrupts on those two pins:</span><br />
&nbsp; PCICR <span style="color: #000040;">|</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000080;">&lt;&lt;</span> PCIE2<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <br />
&nbsp; PCMSK2 <span style="color: #000040;">|</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000080;">&lt;&lt;</span> PCINT18<span style="color: #008000;">&#41;</span> <span style="color: #000040;">|</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span> <span style="color: #000080;">&lt;&lt;</span> PCINT19<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; sei<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p><strong>Debouncing</strong><br />
The mechanical encoder I tested with create multiple triggers on a single transition due to bouncing.  The encoders datasheet claims a maximum bounce of 5ms, but I didn&#8217;t see more than 1ms.  The waveform below shows a very much worse case of a pin transitioning from high to low.</p>
<p><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2010/03/RotaryEncoder-Bounce.bmp" alt="" title="Rotary Encoder Output Bounce" class="aligncenter size-full wp-image-408" /></p>
<p>This is simply debounced in software by waiting for 1ms and then reading the pin values &#8211; if neither has changed from the stored value we ignore the trigger.  Note, that this technique will fail if the shaft is being rotated to fast and the width of the cycle approaches 1ms or the two signals are less than 1ms apart.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:200px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">volatile</span> uint8_t pinValues<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> <span style="color: #008000;">&#123;</span><span style="color: #0000dd;">0</span>,<span style="color: #0000dd;">0</span><span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">int</span> position <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<br />
ISR<span style="color: #008000;">&#40;</span>PCINT2_vect<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; _delay_ms<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #0000ff;">int</span> pin0 <span style="color: #000080;">=</span> digitalRead<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #0000ff;">int</span> pin1 <span style="color: #000080;">=</span> digitalRead<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>pin0 <span style="color: #000040;">!</span><span style="color: #000080;">=</span> pinValues<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; rotary_encoder_change<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, pin0<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>pin1 <span style="color: #000040;">!</span><span style="color: #000080;">=</span> pinValues<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; rotary_encoder_change<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, pin1<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>The previous values are stored in a two value byte array and we refer to pins A and B as 0 and 1 in the code to simplify things.  The Rotary Encoder decode logic is the simple boolean expression ((pinValues[0] == pinValues[1]) ^ changedPin) which returns true or false to indicate clockwise or counter clockwise shaft rotation.  This is used to increment or decrement an integer counter, which the main loop prints back to the host computer.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> rotary_encoder_change<span style="color: #008000;">&#40;</span>uint8_t changedPin, uint8_t value<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; pinValues<span style="color: #008000;">&#91;</span>changedPin<span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> value<span style="color: #008080;">;</span><br />
&nbsp; position <span style="color: #000040;">+</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #008000;">&#40;</span>pinValues<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> pinValues<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #000040;">^</span> changedPin<span style="color: #008000;">&#41;</span> <span style="color: #008080;">?</span> <span style="color: #0000dd;">1</span> <span style="color: #008080;">:</span> <span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">void</span> loop<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; Serial.<span style="color: #007788;">println</span><span style="color: #008000;">&#40;</span>position<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; delay<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">100</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p><strong>Conclusions</strong><br />
This is a fairly simple technique that works well for slow rotations of the shaft, but fast rotations of the shaft get lost or be reported in the wrong direction &#8211; good for replacing potentiometers as instrumentation dials but not for recording the exact movement of a motor etc.</p>
<p>Full source is <a href="http://code.google.com/p/rocketnumbernine/source/browse/trunk/AVR/rotary_encoder/rotary_encoder.pde">here</a>.</p>
<p><strong>References/Bibliography</strong><il></p>
<li><a href="http://en.wikipedia.org/wiki/Rotary_encoder">Wiki Rotary Encoder Page</a> </li>
<li><a href="http://arduino.cc/en/Hacking/PinMapping168">Arduino/Atmega168 pin mapping</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf">Atmega 168/328 datasheet</a> &#8211; see chapter 11 and 12 for interrupt details.</li>
<p></il></p>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (2)'>Using SPI on an AVR (2)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (3)'>Using SPI on an AVR (3)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/' rel='bookmark' title='Permanent Link: Using the MAX6675 Thermocouple-to-Digital Converter'>Using the MAX6675 Thermocouple-to-Digital Converter</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2010/03/06/decoding-a-rotary-encoder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>External Time Capsule Fan</title>
		<link>http://www.rocketnumbernine.com/2009/11/22/external-time-capsule-fan/</link>
		<comments>http://www.rocketnumbernine.com/2009/11/22/external-time-capsule-fan/#comments</comments>
		<pubDate>Sun, 22 Nov 2009 15:24:34 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[projects]]></category>
		<category><![CDATA[fan]]></category>
		<category><![CDATA[Time Capsule]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=391</guid>
		<description><![CDATA[
My Apple Time Capsule runs hot &#8211; approaching 50°C to the touch &#8211; this isn&#8217;t helped by the lack of space it has and the Apple TV stacked on top (I&#8217;ve added some legs to give some space below and above for air to flow.   On large backups/restores during the summer &#8211; the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/rocketnumbernine/4124951592/" title="External Time Capsule Fan"><img src="http://farm3.static.flickr.com/2721/4124951592_86fafe62f0.jpg" width="500" height="234" alt="External Time Capsule Fan" /></a></p>
<p>My <a href="http://www.apple.com/timecapsule/">Apple Time Capsule</a> runs hot &#8211; approaching 50°C to the touch &#8211; this isn&#8217;t helped by the lack of space it has and the <a href="http://www.apple.com/appletv/">Apple TV</a> stacked on top (I&#8217;ve added some legs to give some space below and above for air to flow.   On large backups/restores during the summer &#8211; the device often went into over heat warning mode.  There&#8217;s also worrying <a href="http://www.guardian.co.uk/technology/blog/2009/nov/04/apple-time-capsule-failures-early">reports</a> of the power supply overheating and Time Capsules <a href="http://timecapsuledead.org/">dying</a>.</p>
<p>I originally thought of a standard PC fan with some kind of thermistor /thermocouple/sensor and a simple control circuit to activate the fan when temperature gets too hot, but stumbled across <a href="http://www.arctic-cooling.com/catalog/product_info.php?mID=279&#038;cPath=3_47_80">Arctic Cooling Pro TC F9 fan</a> which has a temperature sensor on a 40cm cable to turn up the fan speed when the temperature rises above 32°C.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/4124949764/" title="Fan with stand attached  (click for annotations)"><img src="http://farm3.static.flickr.com/2566/4124949764_f8bdb763ba.jpg" width="500" height="333" alt="Fan with stand attached" /></a></p>
<p>Replacing the plug with a 2.1mm power jack to fit a 12V wall wart PSU and creating a stand with a loop of wire coat hanger sleeved in heat shrink to give it a nice black cover to match the fans case and the unit was ready to go.  Taping the end of the temperature sensor to the top of what felt the hottest part of the Time Capsule (over the power supply next to the power inlet) reduced the temperature to less than 30°C.  I though the fan might be too low powered initially but it manages to cool all the devices on the shelf it&#8217;s on.</p>
<p>The unit is silent &#8211; at least quieter than the ambient noise and hopefully will extend the life of the Time Capsule.</p>
<p><b>References/Bibliography</b></p>
<ol>
<li><a href="http://www.arctic-cooling.com/catalog/product_info.php?mID=279&#038;cPath=3_47_80">Arctic Cooling Pro TC F9 fan</a>
<li><a href="http://timecapsuledead.org/">The Apple Time Capsule Memorial Register</a>
<li><a href="http://www.guardian.co.uk/technology/blog/2009/nov/04/apple-time-capsule-failures-early">Guardian: What&#8217;s killing Apple&#8217;s Time Capsules after 18 months?</a>
</ol>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/' rel='bookmark' title='Permanent Link: SMT Table Top Reflow Oven (part 1)'>SMT Table Top Reflow Oven (part 1)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/08/27/smt-table-top-reflow-oven-part-2/' rel='bookmark' title='Permanent Link: SMT Table Top Reflow Oven (part 2): Controlling the Heater Elements'>SMT Table Top Reflow Oven (part 2): Controlling the Heater Elements</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/04/10/5v-33v-bidirectional-level-converter/' rel='bookmark' title='Permanent Link: 5V-3.3V bidirectional level converter'>5V-3.3V bidirectional level converter</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/11/22/external-time-capsule-fan/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SMT Table Top Reflow Oven (part 2): Controlling the Heater Elements</title>
		<link>http://www.rocketnumbernine.com/2009/08/27/smt-table-top-reflow-oven-part-2/</link>
		<comments>http://www.rocketnumbernine.com/2009/08/27/smt-table-top-reflow-oven-part-2/#comments</comments>
		<pubDate>Thu, 27 Aug 2009 20:24:16 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[projects]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[reflow oven]]></category>
		<category><![CDATA[relay]]></category>
		<category><![CDATA[SMT]]></category>
		<category><![CDATA[soldering]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=361</guid>
		<description><![CDATA[ In a previous article I described insulation of a mini/toaster oven with the aim of using it for table top reflow soldering.  Some manual tests have been encouraging.  This article documents creation of the circuitry required to turn the ovens heating elements on and off under control of a microcontroller.  I&#8217;m [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/rocketnumbernine/3735221789/" target="images"title="Oven Heater Element Control Circuit"><img src="http://farm3.static.flickr.com/2444/3735221789_014454f8f2.jpg" width="500" height="267" alt="Oven Heater Element Control Circuit" /></a> In a <a href="http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/">previous article</a> I described insulation of a mini/toaster oven with the aim of using it for table top reflow soldering.  Some manual <a href="http://www.rocketnumbernine.com/2009/06/13/bidirectional-level-converter-pcb/">tests</a> have been encouraging.  This article documents creation of the circuitry required to turn the ovens heating elements on and off under control of a microcontroller.  I&#8217;m still not convinced that the oven can increase its temperature fast enough to warrant attempting to recreate a &#8216;proper&#8217; reflow profile, but even if not,  using a microcontroller to log and display the temperature and turn off the heating elements when the peak is reached will still be worthwhile.</p>
<p><b>The circuitry below involves mains electricity, don&#8217;t try this unless you are sure you know what you are doing &#8211; check, test and insulate repeatedly and thoroughly.</b>  There are a number of commercial relay control boards available, for example <a href="http://www.futurlec.com/Relay_4.shtml">Futurlec</a> and <a href="http://www.elektor.com/products/e-blocks/modules/relay-board.530431.lynkx">Elector</a>.</p>
<p>The Hinari HTP033 oven has two elements and a total power rating of 630W &#8211; so each draws just over 1.3A at 240V (UK mains voltage), this obviously can&#8217;t be provided directly from a microcontroller IO pin but requires some kind of <a href="http://en.wikipedia.org/wiki/Relay">relay</a>.  There&#8217;s a huge range of relays available &#8211; I choose a <a href="http://www.digchip.com/datasheets/download_datasheet.php?id=920665&#038;part-number=SRRHN-1C-S-5VDC">IMO SRRHN-1C-S-5VDC</a>, this can operate at 5Volts, draws 100mA (I actually found it took under 75mA) and is fairly cheap (a few £).  Although a 5V device can be driven from a microcontroller IO pin, 100mA is too high a load, 40mA is the maximum for most AVR Microcontroller IO pins, although the maximum current drain for the entire device is around 200mA, so 40mA can only be driven on a few IO pins at once.</p>
<p><b>Driving the relay</b><br />
A simple transistor/resistor circuit can be used to control the relay with much lower power drain.  Basically the transistor (I used a 2N2222A) is being used as a current amplifying switch. <a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/07/relay-control.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/07/relay-control-300x224.png" alt="Relay Board for Heater Element Control" title="Relay Board for Heater Element Control" width="300" height="224" class="alignright size-medium wp-image-366" /></a> When the transistor is being used in on/off mode &#8211; only approximate mental/back of the envelope maths are needed to calculate the values of the resistors (<a href="http://www.google.co.uk/search?q=using+transistor+as+power+switch">Search Google for more background</a>). </p>
<p>From the transistors <a href="http://www.st.com/stonline/products/literature/ds/9288.pdf">datasheet</a>, when the 100mA of current required to power the relay flows from collector to emittor the transistor will provide a minimum gain of just under 100 &#8211; so atleast 1mA  needs to flow into the transistors base, if the IO pin is high at 5V and there&#8217;s a 1V voltage drop from the transistors base to emitter, a resistor of 4K will provide this (R = V/I = (5V-1V)/1mA).  To cope with less gain and a lower Vbe voltage, it&#8217;s best to provide much more current to I used a 1330R and measured 3.5mA going into the base of the transistor when on.</p>
<p>Resistor R2 connects the base to ground when the input is unconnected.  This ensures the relay will be safely turned off during microcontroller startup.  The 10K resistor ensures the current flowing through it when the input is high will be low.</p>
<p>The relay is just a coil of wire which acts as an electromagnet when current flows through it, unfortunately when the power is switched off it will act as an inductor pumping current back into the circuit &#8211; the diode protects the transistor when this happens by providing a &#8216;return path&#8217; to the 5V supply.</p>
<p><b>Installation</b><br />
The circuit (2 of them) was simple enough to build on a <a href="http://www.flickr.com/photos/rocketnumbernine/3862249901/" title="Oven Relay Box" ><img src="http://farm3.static.flickr.com/2611/3862249901_17b03ddfd3_m.jpg" class="alignleft" width="240" height="187" alt="Oven Relay Box" /></a>Prototype/Vero board (pictured above) and housed in a plastic box to protect from earthing.  I bypassed the ovens element and timer controls and passed the live mains wire to the relay box with an output to each of the elements.</p>
<p>Some brief tests with an Arduino turning on the relay control pins showed that the relevant oven element came on perfectly, with a reasuring click from the relay as it switched.<br />
Now I have more control over the ovens elements the plan is to do more extensive testing to see how controllable the temperature is.</p>
<p><b>References/Bibliography</b></p>
<ol>
<li><a href="http://www.digchip.com/datasheets/download_datasheet.php?id=920665&#038;part-number=SRRHN-1C-S-5VDC">IMO SRRHN-1C-S-5VDC</a>
<li><a href="http://www.google.co.uk/search?q=using+transistor+as+power+switch">Google Search: Using transistor as a power switch</a></p>
<li><a href="http://www.st.com/stonline/products/literature/ds/9288.pdf">2N2222A transistor datasheet</a>
<li>Commercial Relay boards: <a href="http://www.futurlec.com/Relay_4.shtml">Futurlec</a> and<a href="http://www.elektor.com/products/e-blocks/modules/relay-board.530431.lynkx">Elector</a>.
<li> Some other relay control articles on the web <a href="http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=119">SparkFun</a>
</ol>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/' rel='bookmark' title='Permanent Link: SMT Table Top Reflow Oven (part 1)'>SMT Table Top Reflow Oven (part 1)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/03/07/first-arduino-project-the-finger/' rel='bookmark' title='Permanent Link: First Arduino Project: the finger'>First Arduino Project: the finger</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/03/27/xyloduino-simple-arduinopiezo-organ/' rel='bookmark' title='Permanent Link: Xyloduino: Simple Arduino/piezo organ'>Xyloduino: Simple Arduino/piezo organ</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/08/27/smt-table-top-reflow-oven-part-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Using SPI on an AVR (3)</title>
		<link>http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/</link>
		<comments>http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/#comments</comments>
		<pubDate>Fri, 03 Jul 2009 21:08:29 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[at90usb162]]></category>
		<category><![CDATA[atmega328]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[interrupts]]></category>
		<category><![CDATA[master/slave]]></category>
		<category><![CDATA[SPI]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=284</guid>
		<description><![CDATA[This is a follow up to Using SPI on an AVR (1) and Using SPI on an AVR (2) articles which illustrated using an AVR Microcontroller to communicate with some simple SPI Slave devices.
This entry shows two AVR Micro controllers communicating with each other through SPI &#8211; one acting as Master and one as Slave. [...]]]></description>
			<content:encoded><![CDATA[<p>This is a follow up to <a href="http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/">Using SPI on an AVR (1)</a> and <a href="http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/">Using SPI on an AVR (2)</a> articles which illustrated using an AVR Microcontroller to communicate with some simple SPI Slave devices.<br />
This entry shows two AVR Micro controllers communicating with each other through SPI &#8211; one acting as Master and one as Slave.  An interrupt handler is used in the slave to notify it when data is being received.  One device is an at90usb162 on a <a href="http://www.prjc.com/teensy">Teensy Board</a> running AVR GCC code, the other an Arduino (with ATmega328) although the code should run on most AVR microcontrollers and Arduino versions that are SPI capable.</p>
<p><b>AVR SPI Slave Mode</b><br />
When a device is operating as the SPI slave device it receives data under control of the master:</p>
<ol>
<li>The slave devices slave select (SS) pin is brought low by the master.
<li>The master oscillates the SCK clock as it places bits onto the MOSI line and reads from the MISO line.
<li>It&#8217;s the master&#8217;s responsibility to use the SPI mode the slave is expecting (whether data is written and read on the rising or falling edges of the clock) and to make sure the clock rate is not too high for the slave.
</ol>
<p>The AVR&#8217;s built in SPI hardware takes care of receiving and processing the SPI data and placing the received data a byte at a time onto the SPI data register buffer, the program simply needs to consume the read bytes from the buffer fast enough.</p>
<p>There are two ways for the program to ascertain when data is ready, it can either poll the SPI status register to see when a byte has been received (SPSR  = (1&lt;&lt;SPIF)) &#8211; the same send_spi() helper function that was developed in a previous article can be used.<br />
Alternatively the SPI  system can be configured to generate an interrupt when a byte has been received and is ready to read from the buffer.  This is achieved by setting the SPIE bit in the SPI control register (SPCR = (1&lt;&lt;SPIE)), I encapsulated this as a parameter to the spi setup helper function developed earlier.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p><b>Example</b><br />
To reduce the amount of code to be written, each program (the AVR GCC and Arduino) acts as both master and slave, and either part can be replaced with the other (ie. two Arduinos can be used etc.).  The circuit is shown below, apart from the SPI connections each device has an LED and a push button connected.<br />
<a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/spi-masterslave.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/spi-masterslave.png" alt="spi-mqasterslave" title="spi-masterslave" width="500" height="257" class="aligncenter size-full wp-image-343" /></a></p>
<p>When the push button on one device is pressed, the LED on the other flashes.  This is achieved using the following logic:</p>
<ol>
<li>The device is put into SPI slave mode so that an interrupt is raised when data is received on the SPI bus.
<li>When the button is pressed the program puts the AVR into SPI master mode and sends the slave a message (a number of bytes) then goes back into slave mode.
<li>The program&#8217;s SPI interrupt handler simply stores the bytes received in a buffer until a terminating null byte (0&#215;00) is received, it then parses and processes the message.
<li>Currently a single message type is supported &#8211; FLASH_LED (0&#215;00) which is followed by a byte containing the number of times the slave should flash its LED &#8211; so to make the slave flash its LED 5 times the master would send 3 bytes &#8211; 0&#215;01, 0&#215;05, 0&#215;00.
</ol>
<p>With the SPI system in slave mode and with interrupts enabled the interupt service handler for SPI_STC_Vect will be called when a byte has been received.  All the handler implementation does (below) is save the byte received from SPI in a buffer (incoming) and checks if the byte received is null or we&#8217;ve filled the buffer, if so the parse_message() is called to process the data received.  As stated previously the interrupt handler mu st return fast enough to handle the next received byte.  Whilst the handler is running interrupts will be disabled and if it takes too long data will be lost.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ISR<span style="color: #008000;">&#40;</span>SPI_STC_vect<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; incoming<span style="color: #008000;">&#91;</span>received<span style="color: #000040;">++</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> received_from_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>received <span style="color: #000080;">&gt;=</span> BUFSIZE <span style="color: #000040;">||</span> incoming<span style="color: #008000;">&#91;</span>received<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> <span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; parse_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; received <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>The received_from_spi() function simply reads the byte read from the SPI pipeline and sets the value of the next byte to be sent &#8211; note the SPDR buffer is double buffered so the value can be written before being read.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> received_from_spi<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> data<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; SPDR <span style="color: #000080;">=</span> data<span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #0000ff;">return</span> SPDR<span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Using an interrupt handler to receive and process the SPI data allows the AVR to perform other tasks, or sleep, until all data is ready.</p>
<p><b>Sending a SPI message on button press</b><br />
We also use an interrupt to trigger sending of a message when a button is pressed in the SPI master.  We configure the AVR to  trigger an interrupt when a pin goes low due to the button being pressed.  The Arduino has a helper function to set this up:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; attachInterrupt<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, button_pressed, FALLING<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>This will result in the function &#8220;button_pressed&#8221; being called when external interrupt 0 (Connected to Arduino pin D2) goes from high to low (FALLING).  In native AVR GCC this takes a little more effort &#8211; we set the relevant bits in the EICRB register to receive an interrupt on a falling signal (ISCO1 and ISC00), enable external interrupts in EIMSK register,  and then enable interrupts (sei()).  See the External Interrupt Channel of the relevant AVR <a href="http://www.atmel.com/dyn/resources/prod_documents/doc7707.pdf">datasheet</a> for details of the registers.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;EICRB <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>ISC01<span style="color: #008000;">&#41;</span> <span style="color: #000040;">|</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #000080;">&lt;&lt;</span>ISC00<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;EIMSK <span style="color: #000040;">|</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>INT0<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;sei<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>The above configuration results in the handler named ISR(INT0_vect) being called when the INT0 pin goes from high to low, both this and the Arduino&#8217;s button_pressed() just call the send_message function to transmit a message.  This attempts to put the device into SPI master mode, checks that it was successful (If its select pin isn&#8217;t low) and if so selects the other device, sends 3 bytes, then deselects the other device and goes back into slave mode:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">void send_message()<br />
{<br />
&nbsp; setup_spi(SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8);<br />
&nbsp; if (SPCR &amp; (1&lt;&lt;MSTR)) { // if we are still in master mode<br />
&nbsp; &nbsp; SELECT_OTHER; // tell other device to flash LED twice<br />
&nbsp; &nbsp; send_spi(FLASH_LED_COMMAND); send_spi(0x02); send_spi(0x00);<br />
&nbsp; &nbsp; DESELECT_OTHER;<br />
&nbsp; }<br />
&nbsp; setup_spi(SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE);<br />
}</div></td></tr></tbody></table></div>
<p>The AVR spec says the SPI clock frequency in the slave device shouldn&#8217;t exceed the MCU frequency/4 &#8211; I&#8217;ve found frequency/8 is safer.</p>
<p>We&#8217;ve seen that the slave device just stores byte received until it receives the terminating null byte, it then calls parse_message().  This checks the value of the first byte in the buffer and parses the remaining bytes accordingly.  The current implementation just supports the single FLASH_LED_COMMAND which reads the next byte and flashes an LED that number of times.  If we receive an unexpected message the LED is flashed repeatedly:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> parse_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #0000ff;">switch</span><span style="color: #008000;">&#40;</span>incoming<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #0000ff;">case</span> FLASH_LED_COMMAND<span style="color: #008080;">:</span><br />
&nbsp; &nbsp;flash_led<span style="color: #008000;">&#40;</span>incoming<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">default</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp;flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>The complete programs are shown below and are also included as examples in the SPI helper library zip below<br />
AVR GCC:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:200px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &lt;avr/interrupt.h&gt;</span><br />
<span style="color: #339900;">#include &lt;util/delay.h&gt;</span><br />
<span style="color: #339900;">#include &lt;spi.h&gt;</span><br />
<br />
<span style="color: #339900;">#define FLASH_LED_COMMAND 0x01</span><br />
<span style="color: #339900;">#define OTHER_SELECT_PIN PB6</span><br />
<span style="color: #339900;">#define SELECT_OTHER PORTB &amp;= ~(1&lt;&lt;OTHER_SELECT_PIN)</span><br />
<span style="color: #339900;">#define DESELECT_OTHER PORTB |= (1&lt;&lt;OTHER_SELECT_PIN)</span><br />
<br />
<span style="color: #339900;">#define BUFSIZE 20</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> incoming<span style="color: #008000;">&#91;</span>BUFSIZE<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">short</span> <span style="color: #0000ff;">int</span> received<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<br />
<br />
<span style="color: #666666;">// flash led that's connected to pin PD7</span><br />
<span style="color: #0000ff;">void</span> flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> count<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;DDRD <span style="color: #000040;">|</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>PD7<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span>count<span style="color: #000040;">*</span><span style="color: #0000dd;">2</span><span style="color: #008080;">;</span> i<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;PORTD <span style="color: #000040;">^</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>PD7<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;_delay_ms<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">75</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// send a SPI message to the other device - 3 bytes then go back into</span><br />
<span style="color: #666666;">// slave mode</span><br />
<span style="color: #0000ff;">void</span> send_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>SPCR <span style="color: #000040;">&amp;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>MSTR<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #666666;">// if we are still in master mode</span><br />
&nbsp; &nbsp;SELECT_OTHER<span style="color: #008080;">;</span> <span style="color: #666666;">// tell other device to flash LED twice</span><br />
&nbsp; &nbsp;send_spi<span style="color: #008000;">&#40;</span>FLASH_LED_COMMAND<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x02</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;DESELECT_OTHER<span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// called when the button pushed and pin INT0 goes from 1 to 0</span><br />
ISR<span style="color: #008000;">&#40;</span>INT0_vect<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;send_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;_delay_ms<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">500</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// 'debounce'</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// parse the data received from the other device</span><br />
<span style="color: #666666;">// currently just knows about the FLASH_LED_COMMAND</span><br />
<span style="color: #0000ff;">void</span> parse_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #0000ff;">switch</span><span style="color: #008000;">&#40;</span>incoming<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #0000ff;">case</span> FLASH_LED_COMMAND<span style="color: #008080;">:</span><br />
&nbsp; &nbsp;flash_led<span style="color: #008000;">&#40;</span>incoming<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">default</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp;flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// called by the SPI system when there is data ready.</span><br />
<span style="color: #666666;">// Just store the incoming data in a buffer, when we receive a</span><br />
<span style="color: #666666;">// terminating byte (0x00) call parse_message to process the data received</span><br />
ISR<span style="color: #008000;">&#40;</span>SPI_STC_vect<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;incoming<span style="color: #008000;">&#91;</span>received<span style="color: #000040;">++</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> received_from_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>received <span style="color: #000080;">&gt;=</span> BUFSIZE <span style="color: #000040;">||</span> incoming<span style="color: #008000;">&#91;</span>received<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> <span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;parse_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;received <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">void</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #666666;">// make sure other device is unselected (pin is HIGH) and setup spi</span><br />
&nbsp;DESELECT_OTHER<span style="color: #008080;">;</span><br />
&nbsp;DDRB <span style="color: #000040;">|</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>OTHER_SELECT_PIN<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #666666;">// raise interrupt when the button is pushed and INT0 pin goes</span><br />
&nbsp;<span style="color: #666666;">// from 1 to 0 (pin PD0 at AT90usbXXX, pin PD2 on ATmegaXXX,</span><br />
&nbsp;<span style="color: #666666;">// arduino pin 2)). The code in ISR(INT0_vect) above will be called</span><br />
&nbsp;EICRB <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>ISC01<span style="color: #008000;">&#41;</span> <span style="color: #000040;">|</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #000080;">&lt;&lt;</span>ISC00<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;EIMSK <span style="color: #000040;">|</span><span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>INT0<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;sei<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #666666;">// flash LED at start to indicate were ready</span><br />
&nbsp;flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #0000ff;">while</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> <span style="color: #666666;">// do nothing</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>Arduino:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:200px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &lt;spi.h&gt;</span><br />
<span style="color: #339900;">#include &lt;util/delay.h&gt;</span><br />
<br />
<span style="color: #339900;">#define BUTTON_PIN 2</span><br />
<span style="color: #339900;">#define LED_PIN 3</span><br />
<span style="color: #339900;">#define FLASH_LED_COMMAND 0x01</span><br />
<br />
<span style="color: #339900;">#define OTHER_SELECT_PIN 7</span><br />
<span style="color: #339900;">#define SELECT_OTHER digitalWrite(OTHER_SELECT_PIN, LOW);</span><br />
<span style="color: #339900;">#define DESELECT_OTHER digitalWrite(OTHER_SELECT_PIN, HIGH);</span><br />
<br />
<span style="color: #339900;">#define BUFSIZE 20</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> incoming<span style="color: #008000;">&#91;</span>BUFSIZE<span style="color: #008000;">&#93;</span><span style="color: #008080;">;</span><br />
<span style="color: #0000ff;">volatile</span> <span style="color: #0000ff;">short</span> <span style="color: #0000ff;">int</span> received<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
<br />
<span style="color: #666666;">// flash led that's connected to pin PD7</span><br />
<span style="color: #0000ff;">void</span> flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> count<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;pinMode<span style="color: #008000;">&#40;</span>LED_PIN, OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span>count<span style="color: #000040;">*</span><span style="color: #0000dd;">2</span><span style="color: #008080;">;</span> i<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;digitalWrite<span style="color: #008000;">&#40;</span>LED_PIN, i<span style="color: #000040;">%</span><span style="color:#800080;">2</span><span style="color: #000080;">==</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;_delay_ms<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">75</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// send a SPI message to the other device - 3 bytes then go back into</span><br />
<span style="color: #666666;">// slave mode</span><br />
<span style="color: #0000ff;">void</span> send_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>SPCR <span style="color: #000040;">&amp;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span>MSTR<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span> <span style="color: #666666;">// if we are still in master mode</span><br />
&nbsp; &nbsp;SELECT_OTHER<span style="color: #008080;">;</span> <span style="color: #666666;">// tell other device to flash LED twice</span><br />
&nbsp; &nbsp;send_spi<span style="color: #008000;">&#40;</span>FLASH_LED_COMMAND<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x02</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;DESELECT_OTHER<span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<br />
<span style="color: #666666;">// called when button pushed and pin INT0 goes from 1 to 0</span><br />
<span style="color: #0000ff;">void</span> button_pressed<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;send_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;_delay_ms<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">500</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> &nbsp;<span style="color: #666666;">// 'debounce'</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// parse the data received from the other device</span><br />
<span style="color: #666666;">// currently just knows about the FLASH_LED_COMMAND</span><br />
<span style="color: #0000ff;">void</span> parse_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #0000ff;">switch</span><span style="color: #008000;">&#40;</span>incoming<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #0000ff;">case</span> FLASH_LED_COMMAND<span style="color: #008080;">:</span><br />
&nbsp; &nbsp;flash_led<span style="color: #008000;">&#40;</span>incoming<span style="color: #008000;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">break</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">default</span><span style="color: #008080;">:</span><br />
&nbsp; &nbsp;flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">20</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #666666;">// called by the SPI system when there is data ready.</span><br />
<span style="color: #666666;">// Just store the incoming data in a buffer, when we receive a</span><br />
<span style="color: #666666;">// terminating byte (0x00) call parse_message to process the data received</span><br />
ISR<span style="color: #008000;">&#40;</span>SPI_STC_vect<span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;incoming<span style="color: #008000;">&#91;</span>received<span style="color: #000040;">++</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">=</span> received_from_spi<span style="color: #008000;">&#40;</span><span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>received <span style="color: #000080;">==</span> BUFSIZE <span style="color: #000040;">||</span> incoming<span style="color: #008000;">&#91;</span>received<span style="color: #000040;">-</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#93;</span> <span style="color: #000080;">==</span> <span style="color: #208080;">0x00</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp;parse_message<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; &nbsp;received <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">void</span> setup<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;<span style="color: #666666;">// make sure other device is unselected (pin is HIGH) and setup spi</span><br />
&nbsp;DESELECT_OTHER<span style="color: #008080;">;</span><br />
&nbsp;pinMode<span style="color: #008000;">&#40;</span>OTHER_SELECT_PIN, OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_INTERRUPT, SPI_SLAVE<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #666666;">// raise interrupt when INT0 pin falls (arduino pin 2))</span><br />
&nbsp;<span style="color: #666666;">// the function button_pressed will be called</span><br />
&nbsp;attachInterrupt<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, button_pressed, FALLING<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #666666;">// flash LED at start to indicate were ready</span><br />
&nbsp;flash_led<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<br />
<span style="color: #0000ff;">void</span> loop<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p><em>References</em></p>
<ul>
<li><a href="http://code.google.com/p/rocketnumbernine/downloads/list">AVI SPI library</a>
<li><a href="http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus">Serial Peripheral Interface</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc7707.pdf">AVR AT90USB82/162 Datasheet</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc8025.pdf">AVR ATmega48/88/168/328 Datasheet</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf">AVR151: Setup And Use of The SPI</a></li>
</ul>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (2)'>Using SPI on an AVR (2)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (1)'>Using SPI on an AVR (1)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/' rel='bookmark' title='Permanent Link: Using the MAX6675 Thermocouple-to-Digital Converter'>Using the MAX6675 Thermocouple-to-Digital Converter</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Using the MAX6675 Thermocouple-to-Digital Converter</title>
		<link>http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/</link>
		<comments>http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/#comments</comments>
		<pubDate>Sat, 27 Jun 2009 18:51:55 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[MAX6675]]></category>
		<category><![CDATA[SPI]]></category>
		<category><![CDATA[Thermocouple]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=287</guid>
		<description><![CDATA[I&#8217;ve been asked for the code used to read the MAX6675 Thermocouple-to-Digital Converter used to measure the temperature in my ongoing SMD Reflow Oven project.  The following is based on an Arduino (with a home built SPI helper library) but is fairly generic and should be applicable to most platforms.
Maxim&#8217;s MAX6675 8-pin SOIC chip [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/p1010187/" rel="attachment wp-att-375"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/p1010187.jpg" alt="MAX6675 on Breakout Board" title="MAX6675 on Breakout Board" width="250" height="167" class="alignright size-full wp-image-375" /></a>I&#8217;ve been asked for the code used to read the <a href="http://datasheets.maxim-ic.com/en/ds/MAX6675.pdf">MAX6675</a> Thermocouple-to-Digital Converter used to measure the temperature in my ongoing <a href="http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/">SMD Reflow Oven</a> project.  The following is based on an Arduino (with a home built SPI helper library) but is fairly generic and should be applicable to most platforms.</p>
<p>Maxim&#8217;s MAX6675 8-pin SOIC chip is a compact and simple to use solution for converting the output of a type K thermocouple to a digital temperature value read over SPI.  It provides Digital to Analogue conversion of the voltage produced by the thermocouple, cold-junction compensation, noise reduction and processing of the result into a binary temperature value at a precision of 0.25°C. </p>
<p><div id="attachment_288" class="wp-caption alignright" style="width: 295px"><a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/max6675-circuit.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/max6675-circuit.png" alt="SO - MISO (Arduino D12), SCK (Arduino D13), CS (Arduino D8)" title="MAX6675 Circuit" width="285" height="250" class="size-full wp-image-288" /></a><p class="wp-caption-text">SO - MISO (Arduino D12), SCK (Arduino D13), CS (Arduino D8)</p></div> Circuit used (from the datasheet sheet) is shown to the right.  I used a breadboard for the circuit but created a <a h ref="http://www.batchpcb.com/product_info.php?products_id=20538&#038;check=1586acac99a545c865a8a0ae59868ddc">breakout board</a> for the (SMD) MAX6675 chip and decoupling capacitor with <a href="http://www.batchpcb.com/">BatchPCB</a>.</p>
<p>The thermocouple is connected to pins 2 and 3 &#8211; if connected the wrong way around the temperature output from the MAX6675 will go down as the end of the thermocouple is heated.  Connecting the MAX6675 to the Arduino is straightforward &#8211; just power and the SPI MISO and SCK (clock) and chip select line (^CS).  Pin D8 was used to select the device.</p>
<p><b>SPI Setup</b><br />
From the <a href="http://datasheets.maxim-ic.com/en/ds/MAX6675.pdf">datasheet</a> we see that the MAX6675 transmits the temperature in 2 bytes &#8211; most significant bit first.  The clock is expected to be idle low and data can be read when it is falling (SPI mode 1).  The MAX6675 can take a maximum SPI clock rate of 4.3MHz &#8211; as the Arduino was running at 16MHz a SPI data rate of Clock/8 (2MHz) was specified so the device was operating well within its tolerances.<br />
The following sets up up the MAX6675 chip select pin (Arduino Pin D8) control pin, SPI and the Arduino Serial line:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#define MAX6675_SELECT_PIN 8</span><br />
<span style="color: #339900;">#define DESELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, HIGH)</span><br />
<span style="color: #339900;">#define SELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, LOW)</span><br />
<br />
<span style="color: #0000ff;">void</span> setup<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp; pinMode<span style="color: #008000;">&#40;</span>MAX6675_SELECT_PIN, OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; DESELECT_MAX6675<span style="color: #008080;">;</span><br />
&nbsp; setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; Serial.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">19200</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p><b>Reading the Temperature</b><br />
Reading the temperature value is equally straightforward.  Select the device, wait atleast 100ns (this is close to the time that it will take the AVR to start sending data on the SPI bus anyway but I put in a microsecond delay to be certain), read the two bytes from SPI, and deselect the device.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;SELECT_MAX6675<span style="color: #008080;">;</span><br />
&nbsp;delayMicroseconds<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> highByte <span style="color: #000080;">=</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> lowByte <span style="color: #000080;">=</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;DESELECT_MAX6675<span style="color: #008080;">;</span></div></td></tr></tbody></table></div>
<p>The 16-bits read from the device in two bytes need to be processed slightly:<br />
<a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/max6675-bitfield.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/06/max6675-bitfield.png" alt="MAX6675 Bitfield" title="MAX6675 Bitfield" width="504" height="70" class="alignright size-full wp-image-310" /></a></p>
<p>Bit 2 in the 2nd byte will be high if the device cannot detect an attached thermocouple, otherwise the 12 temperature value bits spread across the 2 bytes (6-0 of the hight byte, and 7-3 of the low byte) need to be shifted into a single numeric value (highByte << 5 | lowByte>>3).</p>
<p>The program simply prints the bytes received on an error and the temperature (divided by 4 to get the value in degrees) if it has been read successfully.</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>lowByte <span style="color: #000040;">&amp;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Not connected &quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span>highByte, HEX<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">println</span><span style="color: #008000;">&#40;</span>lowByte, HEX<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">short</span> value <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>highByte <span style="color: #000080;">&lt;&lt;</span> <span style="color: #0000dd;">5</span> <span style="color: #000040;">|</span> lowByte<span style="color: #000080;">&gt;&gt;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span>value<span style="color: #000040;">/</span><span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;.&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">println</span><span style="color: #008000;">&#40;</span>value<span style="color: #000040;">%</span><span style="color:#800080;">4</span> <span style="color: #000040;">*</span><span style="color: #0000dd;">25</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>The MAX6675 has a maximum conversion time of 0.22 seconds. If the device is sampled faster than this it will continue to output the temperature that was first read without any indication that it is being read too fast &#8211; I found a delay of atleast 250ms between readings the device worked well.</p>
<p>The complete sampling code is shown below:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:200px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339900;">#include &lt;spi.h&gt;</span><br />
<br />
<span style="color: #666666;">// MAX6675 connected to pin D9</span><br />
<span style="color: #339900;">#define MAX6675_SELECT_PIN 8</span><br />
<span style="color: #339900;">#define DESELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, HIGH)</span><br />
<span style="color: #339900;">#define SELECT_MAX6675 digitalWrite(MAX6675_SELECT_PIN, LOW)</span><br />
<br />
<span style="color: #0000ff;">void</span> setup<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;pinMode<span style="color: #008000;">&#40;</span>MAX6675_SELECT_PIN, OUTPUT<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;DESELECT_MAX6675<span style="color: #008080;">;</span><br />
&nbsp;setup_spi<span style="color: #008000;">&#40;</span>SPI_MODE_1, SPI_MSB, SPI_NO_INTERRUPT, SPI_MSTR_CLK8<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;Serial.<span style="color: #007788;">begin</span><span style="color: #008000;">&#40;</span><span style="color: #0000dd;">19200</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span><br />
<br />
<span style="color: #0000ff;">void</span> loop<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><br />
<span style="color: #008000;">&#123;</span><br />
&nbsp;delay<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">500</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #666666;">// select the device, wait &gt; 100nS, read two bytes, deselect</span><br />
&nbsp;SELECT_MAX6675<span style="color: #008080;">;</span><br />
&nbsp;delayMicroseconds<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> highByte <span style="color: #000080;">=</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #0000ff;">unsigned</span> <span style="color: #0000ff;">char</span> lowByte <span style="color: #000080;">=</span> send_spi<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;DESELECT_MAX6675<span style="color: #008080;">;</span><br />
<br />
&nbsp;<span style="color: #666666;">// if bit 3 is high thermocouple is unconnected</span><br />
&nbsp;<span style="color: #0000ff;">if</span> <span style="color: #008000;">&#40;</span>lowByte <span style="color: #000040;">&amp;</span> <span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #000080;">&lt;&lt;</span><span style="color: #0000dd;">2</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;Not connected &quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span>highByte, HEX<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot; &quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">println</span><span style="color: #008000;">&#40;</span>lowByte, HEX<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span> <span style="color: #0000ff;">else</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp;<span style="color: #666666;">// temperature value is in bits 6-0 of highByte and 7-2 of lowByte</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">short</span> value <span style="color: #000080;">=</span> <span style="color: #008000;">&#40;</span>highByte <span style="color: #000080;">&lt;&lt;</span> <span style="color: #0000dd;">5</span> <span style="color: #000040;">|</span> lowByte<span style="color: #000080;">&gt;&gt;</span><span style="color: #0000dd;">3</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp;<span style="color: #666666;">// 1 bit is 0.25 degree 'divide' by 4 to show degrees</span><br />
&nbsp; &nbsp;Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span>value<span style="color: #000040;">/</span><span style="color: #0000dd;">4</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> Serial.<span style="color: #007788;">print</span><span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;.&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span> Serial.<span style="color: #007788;">println</span><span style="color: #008000;">&#40;</span>value<span style="color: #000040;">%</span><span style="color:#800080;">4</span> <span style="color: #000040;">*</span><span style="color: #0000dd;">25</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp;<span style="color: #008000;">&#125;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p><b>Conclusions</b><br />
Compared with manual reading and conversion of the thermocouple voltage to temperature the MAX6675 is a delight to use.  Although it is not a cheap device it is comparable to other thermocouple processing devices (for example the <a href="http://www.analog.com/en/other/ios-subsystems/ac1226/products/product.html">AC1226</a> and <a href="http://www.linear.com/pc/productDetail.jsp?navId=H0,C1,C1010,C1073,P1181">LTK001</a>) but is fairly unique in having a digital/SPI output rather than a cleaned up voltage per Centigrade value that also requires a D/A converter.</p>
<p><b>References/Resources</b></p>
<ol>
<li><a href="http://code.google.com/p/rocketnumbernine/downloads/list">AVR SPI Helper Library</a>
<li><a href="http://datasheets.maxim-ic.com/en/ds/MAX6675.pdf">MAX6675 Spec sheet</a>
<li><a href="http://www.batchpcb.com/index.php/Products/20538">Break out board PCB</a>
</ol>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (3)'>Using SPI on an AVR (3)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (2)'>Using SPI on an AVR (2)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (1)'>Using SPI on an AVR (1)</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Bidirectional Level Converter PCB</title>
		<link>http://www.rocketnumbernine.com/2009/06/13/bidirectional-level-converter-pcb/</link>
		<comments>http://www.rocketnumbernine.com/2009/06/13/bidirectional-level-converter-pcb/#comments</comments>
		<pubDate>Sat, 13 Jun 2009 00:00:24 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[projects]]></category>
		<category><![CDATA[3.3V]]></category>
		<category><![CDATA[5V]]></category>
		<category><![CDATA[BatchPCB]]></category>
		<category><![CDATA[LDO]]></category>
		<category><![CDATA[MCP1700]]></category>
		<category><![CDATA[MOSFET]]></category>
		<category><![CDATA[regulator]]></category>
		<category><![CDATA[shifter]]></category>
		<category><![CDATA[TXS01xx]]></category>
		<category><![CDATA[voltage conversion]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=243</guid>
		<description><![CDATA[
The Level converter PCB has finally arrived from BatchPCB.  Their service was easy to use and took about 4 weeks to arrive (as advertised).
Because the board was less than the minimum 1&#8243; square they had already doubled it up so I got 2 for $2.50 + $1.20 postage (untracked and uninsured) and $10 handling. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/rocketnumbernine/3608036805/" title="level converter pcb" target="images"><img src="http://farm4.static.flickr.com/3661/3608036805_71e9c81a87_m.jpg" width="254" height="201" class="alignleft" alt="level converter pcb" /></a></p>
<p>The <a href="http://www.rocketnumbernine.com/2009/04/10/5v-33v-bidirectional-level-converter/">Level converter</a> PCB has finally arrived from <a href="http://www.batchpcb.com/">BatchPCB</a>.  Their service was easy to use and took about 4 weeks to arrive (as advertised).</p>
<p>Because the board was less than the minimum 1&#8243; square they had already doubled it up so I got 2 for $2.50 + $1.20 postage (untracked and uninsured) and $10 handling.  With this size the service obviously dwarfs the PCB cost so its worth batching up your order to reduce the overhead.  I had ordered two of the level converter board and another very small SOIC-8 break out board and received 8 pieces for $21.20. </p>
<p>I was keen to use this to test SMT soldering in my <a href="http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/">converted mini oven</a>.  Adding paste using a syringe was much harder than anticipated.  The paste was fairly thick and left thin tails which required cleaning up.<br />
<a href="http://www.flickr.com/photos/rocketnumbernine/3607988649/" target="images" title="bi-directional level converter board by rocketnumbernine"><img class="alignright" src="http://farm4.static.flickr.com/3369/3607988649_029d288cac_m.jpg" width="240" height="153" alt="bi-directional level converter board" /></a>Despite dozens of tests with the temperature gauge on the oven, half way through the process it stopped working so I had to play it by ear &#8211; I turned the oven off just after the solder went molten and reflowed around the components (a magical sight).  I might have left it a little late as the PCB has a slight brown tint to it.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3607987821/" target="images" title="bi-directional level converter board"><img src="http://farm4.static.flickr.com/3317/3607987821_10d94e0919.jpg" width="500" height="399" alt="bi-directional level converter board" /></a></p>
<p>The excess solder that hadn&#8217;t been cleaned off the board had formed small balls which could be chipped off as can be seen below.  The pads which had too much paste formed balls around the pins of the chip.  Otherwise the solder flowed around the components surprisingly well.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3607989261/" title="bi-directional level converter board closeup" target="images"><img src="http://farm3.static.flickr.com/2473/3607989261_f6b97a4cb6_m.jpg" class="alignleft" width="240" height="199" alt="bi-directional level converter board closeup" /></a>I had made two screw ups with the PCB layout: first the the labels are too small to read, secondly more serious I mixed up the pin layout on the MCP1700 LDO, which resulted in it burning out when connected to 5V &#8211; luckily without harming any other components.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3621298527/" title="Fixed PCB" target="images"><img src="http://farm4.static.flickr.com/3378/3621298527_000f39ecac_t.jpg" class="alignright" width="100" height="100" alt="Fixed PCB" /></a>It was just about possible to replace the burnt out component with a T0-92 version soldered to the capacitor pads.  This worked fine and the power shift and logic level converter worked as expected.  I need to test the max amount of current that the LDO 5V-3.3V downshifter can provide without getting too hot (the T0-92 package is likely to be better than the SOT-23 anyway).</p>
<p>
<b>TI TXS0104E and family</b><br />
Another option in level conversion is the <a href="http://focus.ti.com/docs/prod/folders/print/txs0104e.html" target="images">Texas Instruments TXS0104E</a> and <a href="http://focus.ti.com/docs/prod/folders/print/txs0104e.html#relatedproducts" target="images">family</a> these are available in 2-8 bit conversion packages in both open-drain and push pull versions.  These chips also have a output enable pin which can be used to pu the I/O pins into tri-state mode which could be useful.</p>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/04/10/5v-33v-bidirectional-level-converter/' rel='bookmark' title='Permanent Link: 5V-3.3V bidirectional level converter'>5V-3.3V bidirectional level converter</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/' rel='bookmark' title='Permanent Link: SMT Table Top Reflow Oven (part 1)'>SMT Table Top Reflow Oven (part 1)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/' rel='bookmark' title='Permanent Link: Using the MAX6675 Thermocouple-to-Digital Converter'>Using the MAX6675 Thermocouple-to-Digital Converter</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/06/13/bidirectional-level-converter-pcb/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SMT Table Top Reflow Oven (part 1)</title>
		<link>http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/</link>
		<comments>http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 14:44:01 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[projects]]></category>
		<category><![CDATA[MAX6675]]></category>
		<category><![CDATA[reflow oven]]></category>
		<category><![CDATA[SMT]]></category>
		<category><![CDATA[soldering]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=222</guid>
		<description><![CDATA[
My soldering iron is dirt cheap, low power and pretty poor for soldering SMT components.   After looking at the price of a more suitable replacement I decided that it was worth looking at the option of making an SMT Reflow oven from a mini/toaster oven, it would cost less than a decent temperature [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/rocketnumbernine/3592488632/" title="Testing Uninsulated Oven"><img src="http://farm4.static.flickr.com/3563/3592488632_71386c23ca.jpg" width="500" height="333" alt="Testing Uninsulated Oven" /></a></p>
<p>My soldering iron is dirt cheap, low power and pretty poor for soldering SMT components.   After looking at the price of a more suitable replacement I decided that it was worth looking at the option of making an <a href="http://en.wikipedia.org/wiki/Reflow_soldering">SMT Reflow</a> oven from a mini/toaster oven, it would cost less than a decent temperature controlled iron and be fun to create.</p>
<p><b>The Oven</b><br />
I seem to be suffering from several of the <a href="http://en.wikipedia.org/wiki/Lead_poisoning#Symptoms_and_effects">symptoms of lead poisoning</a> already, so use lead-free solder and want to continue, which means a higher temperature is required.</p>
<p>Googling for lead-free solder reflow temperature profiles gives lots of results from both solder and parts manufacturers (<a href="http://www.altera.com/literature/an/an353.pdf">Altera</a>, <a href="http://www.wolfsonmicro.com/uploads/documents/en/WAN0158.pdf">Wolfson Micro</a>, <a href="http://www.latticesemi.com/lit/docs/technotes/tn1076.pdf">Lattice Semiconductor</a>, and <a href="http://www.kester.com/Data%20Sheets/Solder%20Pastes/No-Clean/R276%20Lead-free%20Global%20(03Oct07).pdf">Kester</a>), and the &#8217;standard&#8217;: <a href="http://www.jedec.org/download/search/jstd020d-01.pdf">IPC/JEDEC J-STD-020D.1</a>.  These suggest that a max temperature of between 235-255°C is required and the ability to ramp up the temperature towards the max to reduce the time at the high temperatures (30 seconds within 5% of the max).</p>
<p>This is tough for a mini oven, many are advertised with a maximum of 220°C.  However, some experiments recording the temperature of my parents cheap Hinari Tiny Top with a thermocouple attached to a multimeter, showed that it could get up to over 255°C (the ovens thermostat seems to cut out at around 260°C &#8211; less than the rated 280°C) despite only using 630 Watts.  The only caveat is that as it approached the maximum it could only raise the temperatures by about 0.5-1.0°C/Second. However, the oven was also loosing a lot of heat, particularly from the top, so some insulation may help things.</p>
<p>I considered some of the more powerful ovens (1300-2500W), in particular one with a fan would have been good to regulate the temperature around the oven, but they have correspondingly larger spaces to heat &#8211; 10-24 litres &#8211; compared with the smaller 6.5 litres.  I decided to go with a <a href="http://www.amazon.co.uk/gp/product/B001IBI8FE?ie=UTF8&#038;tag=rocketnumbernine-21&#038;linkCode=as2&#038;camp=1634&#038;creative=6738&#038;creativeASIN=B001IBI8FE">Hinari HTP033</a>:</p>
<ol>
<li>It has two heating elements which allows for more slightly more fine grained temperature control (rather than on/off of a single element)
<li>Has a transparent door allowing the reflow process to be monitored
<li>The housing looks easily to insulate and modifiable
<li>£20 delivered from ebay (Amazon were out of stock)
</ol>
<p><b>The Plan</b></p>
<ol>
<li>Insulate Mini Oven.
<li>Thermocouple to monitor temperature.
<li>Microcontroller monitoring the temperature and controlling the heater elements.
<li>USB interface for control/uploading and downloading temperature profiles.
</ol>
<p>As stated above &#8211; if the ovens heating elements aren&#8217;t quick enough, then using a microcontroller to control the temperature is redundant overkill.  Its just enough to turn on the oven, put the board in when the temperature gets high enough, then turn off and open the door when the maximum temperature is achieved.  If this was the case the backup plan was to just add an LCD screen showing the current temperature and use the oven manually.</p>
<p><b>Thermocouple</b><br />
I thought that measuring the temperature would be simply a matter of connecting a <a href="http://en.wikipedia.org/wiki/Thermocouple">thermocouple</a> (which creates a voltage difference based on the temperature difference between the two metals in its probe) to an Analogue to Digital Converter in some configuration and reading off the temperature value, but it appears to be a fairly non trivial <a href="http://srdata.nist.gov/its90/download/type_k.tab">task</a>.  Luckily there are a number of off the shelf integrated circuits that the thermocouple can be connected to directly and produce a digital temperature reading.  I choose the <a href="http://datasheets.maxim-ic.com/en/ds/MAX6675.pdf">MAX6675</a>, which provides 0.25°C resolution from 0-1023°C on a simple to use SPI output in an 8 pin SOIC.</p>
<p><b>Testing</b><br />
To get temperatures from the oven a <a href="http://www.pjrc.com/teensy/index.html">Teensy</a> at90usb162 board was used to poll the temperature every second and send it to the USB, where it was copied into a spreadsheet.</p>
<p>Chart below shows two test runs of the oven with both elements on (I turned off the oven earlier on the second run).</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3593350708/" title="Uninsulated Oven Temperature Profile" target="images"><img src="http://farm4.static.flickr.com/3322/3593350708_c94cf436d4.jpg" width="500" height="375" alt="Uninsulated Oven Temperature Profile" /></a></p>
<p>Surprisingly it got up to to well over 300°C, before I cut the power, with no sign of a thermostat limiter.   The temperature rises at roughly 0.9°C a second to 200°C then slows down to about 0.5°C/Sec. to 250°C.  Although the slow down towards the peak is disappointing &#8211; this is probably just about usable although it would be better to reduce the time spent near the maximum.<br />
The amount of heat escaping from the oven is fairly excessive &#8211; the temperature of the top of the oven was approaching 100°C so some insulation will help to increase the gradient.</p>
<p><b>Insulation</b><br />
After some research I chose to use <a href="http://www.designengineering.com/products.asp?m=sp&#038;pid=75&#038;tid=1">Reflect-A-Gold</a> sheet for insulation, this aerospace/automotive heat insulation isn&#8217;t the cheapest available but was fairly easy to use and claims to reflect 80% of radiant heat up to 850°F.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3592489430/" title="Partially insulated oven" target="images"><img src="http://farm4.static.flickr.com/3309/3592489430_3072fe3384_m.jpg" class="alignright" width="239" height="240" alt="Partially insulated oven" /></a></p>
<p>The HTP033 is made of riveted sheet metal with a slightly thicker back plate to keep it rigid, after drilling out 4 rivets the oven basically falls apart.  The side and top comes away from the internals of the oven allowing it to be just about completely wrapped with the Reflect-A-Gold sheet.  Most of the oven had two layers of sheet, with several layers around the edges of the door to increase the closeness of the fit (without there was a 5mm gap with the door closed).</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3591683079/" title="Insulated Oven"><img src="http://farm3.static.flickr.com/2453/3591683079_f16a63a79a.jpg" width="500" height="334" alt="Insulated Oven" /></a></p>
<p>Results after insulation are are shown below, the oven was turned off as close as possible to 245 °Centigrade.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3592544367/" title="Insulated Oven Temperature Profile"><img src="http://farm4.static.flickr.com/3610/3592544367_56d185973e.jpg" width="500" height="375" alt="Insulated Oven Temperature Profile" /></a></p>
<p>After insulation the oven temperature increases by about 1°C/S. to 200°C and 0.75°C/S. after that (Compared with 0.9°C/S. and 0.5°C/S. respectively for the uninsulated oven).   Temperature inside the case behind the ovens controls went up to about 50-60 °C &#8211; perhaps still a little too hot to house the electronics.</p>
<p><b>Conclusions and Future Work</b><br />
I&#8217;m fairly happy with the performance of the oven, considering its cost and size.   Next steps are:</p>
<ol>
<li>More temperature tests to see if the performance can be increased.
<li>Do some test &#8216;reflows&#8217; &#8211; just turning on the oven and turning off when it reaches the maximum temperature to see what temperature is required by the solder and how good the results are.
<li>Develop a controller/relay board and investigate controlling the heating elements under processor control.
</ol>
<p><b>References/Resources</b></p>
<ol>
<li>Other projects: <a href="http://openhardware.net/Misc_Stuff/ToasterSMD/">&#8220;Toaster oven SMD&#8221;</a>, <a href="http://www.homanndesigns.com/SMDToasterOvenProject.html">&#8220;SMD ReflowToaster Oven&#8221;</a>, <a href="http://www.circuitcellar.com/library/print/0704/Lacoste_168/index.htm">&#8220;Easy Reflow&#8221;</a>, <a href="http://www.seattlerobotics.org/encoder/200006/oven_art.htm">&#8220;Have you seen my new soldering Iron?&#8221;</a>, <a href="http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=59">&#8220;Reflow Skillet&#8221;</a>.  And products:  <a href="http://www.thesiliconhorizon.com/Products.htm">&#8220;techFX reflow 2.0 controller with PID control!&#8221;</a>, <a href="http://www.articulationllc.com/product.sc?categoryId=-1&#038;productId=13">&#8220;Artic Reflow Oven&#8221;</a>, <a href="http://www.apsgold.com/reflow-ovens/low-volume/gf-c2-reflow-oven">&#8220;GF C2 Reflow Oven&#8221;</a>.
<li>Various reflow temperature profiles: <a href="http://www.altera.com/literature/an/an353.pdf>Altera</a>, <a href="http://www.wolfsonmicro.com/uploads/documents/en/WAN0158.pdf">Wolfson Micro</a>, <a href="http://www.latticesemi.com/lit/docs/technotes/tn1076.pdf">Lattice Semiconductor</a>, and  <a href="http://www.kester.com/Data%20Sheets/Solder%20Pastes/No-Clean/R276%20Lead-free%20Global%20(03Oct07).pdf">Kester R206 Solder Paste</a>.
<li><a href="http://www.jedec.org/download/search/jstd020d-01.pdf">IPC/JEDEC J-STD-020D.1 Moisture/Reflow Sensitivity Classification for Nonhermetic Solid State Surface Mount Devices</a>
<li><a href="http://www.leadfreemagazine.com/pages/pdf/pain_out_of_reflow.pdf">Taking the Pain Out of Pb-free Reflow, Lead Free Magazine</a>
<li><a href="http://datasheets.maxim-ic.com/en/ds/MAX6675.pdf">MAX6675 K-type Thermocouple-to-Digital Converter</a>
<li><a href="http://www.designengineering.com/products.asp?m=sp&#038;pid=75&#038;tid=1">Reflect-A-Gold Heat insulation sheet and tape</a>
</ol>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/08/27/smt-table-top-reflow-oven-part-2/' rel='bookmark' title='Permanent Link: SMT Table Top Reflow Oven (part 2): Controlling the Heater Elements'>SMT Table Top Reflow Oven (part 2): Controlling the Heater Elements</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/11/22/external-time-capsule-fan/' rel='bookmark' title='Permanent Link: External Time Capsule Fan'>External Time Capsule Fan</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/' rel='bookmark' title='Permanent Link: Using the MAX6675 Thermocouple-to-Digital Converter'>Using the MAX6675 Thermocouple-to-Digital Converter</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/06/03/smt-table-top-reflow-oven-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Using SPI on an AVR (2)</title>
		<link>http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/</link>
		<comments>http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/#comments</comments>
		<pubDate>Tue, 12 May 2009 21:19:11 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[at90usb162]]></category>
		<category><![CDATA[atmega328]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[DS1305]]></category>
		<category><![CDATA[interrupts]]></category>
		<category><![CDATA[RTC]]></category>
		<category><![CDATA[SPI]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=178</guid>
		<description><![CDATA[ This is a follow on to &#8220;Using SPI on an AVR (1)&#8221; and illustrates using SPI to communicate with a real time clock chip, it also illustrates use of external interrupts to initiate code on the microcontroller.
Maxim DS1305 Real Time Clock
The DS1305 Serial Alarm Real-Time Clock is an 18 pin DIP clock chip.  [...]]]></description>
			<content:encoded><![CDATA[<p> This is a follow on to <a href="http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/">&#8220;Using SPI on an AVR (1)&#8221;</a> and illustrates using SPI to communicate with a real time clock chip, it also illustrates use of external interrupts to initiate code on the microcontroller.</p>
<p><b>Maxim DS1305 Real Time Clock</b><br />
The <a href="http://datasheets.maxim-ic.com/en/ds/DS1305.pdf">DS1305</a> Serial Alarm Real-Time Clock is an 18 pin DIP clock chip.  When setup with a 32.768kHz crystal and optional backup battery, it provides a real time clock, 2 programmable alarms that drive I/O pins (which can be used to trigger interrupts on the MCU), 96 bytes of RAM and a rechargeable battery charger accessible from SPI or 3-wire interconnect.</p>
<p>The datasheet contains a simple circuit, without a battery attached V<sub>CC2</sub> and V<sub>BAT</sub> should be connected to ground and V<sub>CC1</sub> and V<sub>CCIF</sub> to 5V, for SPI operation SERMODE pin should be connected to 5V, then SDO is MISO, SDI is MOSI, SCK clock, and CE chip enable.</p>
<p><b>SPI Configuration</b><br />
From the datasheet we read that the device samples the state of the clock when the chip enable pin goes high to decide whether the SPI master is using a high or low idle clock level allowing either CPOL of 0 or 1 to be used.  Data is sampled on the trailing edge of the clock (CPHA=1) so SPI mode 1 or 3 can be used.  Data is read and written MSB first.  Unlike some SPI devices the chip select pin is driven high to select the chip.</p>
<p>All DS1305 functionality is accessed through 127 byte-wide data registers.  All registers have one address for reading (0&#215;00-0&#215;7F) and one for writing (0&#215;80-0xFF) as shown in Figure 2 of the <a href="http://datasheets.maxim-ic.com/en/ds/DS1305.pdf">datasheet</a> and copied below:<br />
<a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/ds1305-registers.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/ds1305-registers.png" alt="DS1305 data registers" title="DS1305 data registers" width="501" height="367" class="aligncenter size-full wp-image-179" /></a></p>
<p><b>Using the DS1305</b><br />
The register structure of the DS1305 makes the communication protocol to the device very simple.  The MCU transfers a byte containing the address of the data to be read or written.  If writing to a register it then writes the byte to MOSI and ignores the data on MISO, if reading it writes a dummy byte to MOSI and reads the register value from MISO.  The DS1305 SPI Slave uses the address transferred in the first byte to determine whether to &#8216;read&#8217; or &#8216;write&#8217; the next byte.</p>
<p>The device also supports burst mode &#8211; if the chip select is kept high after a read or write, further data can be sent or received with an implicit address increment.  So the current date/time can be sent in a stream of bytes to set the current time.:</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// set current date/time to 23/04/09 20:32:47 </span><br />
setup_spi<span style="color: #009900;">&#40;</span>SPI_MODE_1<span style="color: #339933;">,</span> SPI_MSB<span style="color: #339933;">,</span> SPI_NO_INTERRUPT<span style="color: #339933;">,</span> SPI_MSTR_CLK16<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
select_ds1305<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x80</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// write address of first Date/Time register (for seconds)</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x47</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds seconds = 47</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x32</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds minutes = 32</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x20</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds hours in 24hour mode = 20</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x05</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds day of week = 5 (thursday)</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x23</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds date = 23</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x04</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds month = 04</span><br />
send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x09</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// next byte holds 2 digit year = 09</span><br />
deselect_ds1305<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>Note, that the DS1305 uses Binary Coded Decimal with each decimal digit being represented in 4 binary bits, so 47 in decimal is represented as 0&#215;47 in hex.<br />
When only a single digit is required (for example to represent the most significant digit in the 12 hour clock time (0 or 1) only 1 bit is used.</p>
<p>A simple library of helper functions, macros, and structures simplifies usage further, for example:</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// enable the oscillator in the control register to</span><br />
<span style="color: #666666; font-style: italic;">// make the device &quot;tick&quot; every second</span><br />
set_control<span style="color: #009900;">&#40;</span>DS1305_EOSC<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #666666; font-style: italic;">// set current date/time to 23/04/09 20:32:47</span><br />
DS1305_DATETIME current <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><span style="color: #208080;">0x47</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x32</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x20</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x05</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x23</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x04</span><span style="color: #339933;">,</span> <span style="color: #208080;">0x09</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
set_time<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>current<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>After enabling the oscillator and setting the current time, get_time() can be used to fetch the value of the current time, which will increment every second.</p>
<p>The DS1305 also has two programmable alarms which can be configured to trigger either at a specific time of the week, or once every second, minute, or hour.  The status register can be polled to see when the alarm has triggered or, more usefully, one of the interrupt lines (INT0 and INT1) can be made to go low when the alarm trigters (by setting the INTCN and AIE0 and AIE1 flags in the control register).  The 7th bit of the alarm time registers (second, minute, hour, and day) are used to choose the granularity of the alarm shown on table 1, page 7 of the <a href="http://datasheets.maxim-ic.com/en/ds/DS1305.pdf">datasheet</a> and repeated below:</p>
<p><a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/ds1305-timermasks.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/ds1305-timermasks.png" alt="DS1305 timer mask values" title="DS1305 timer mask values" width="473" height="111" class="aligncenter size-full wp-image-195" /></a><br />
For example, to set alarm 0 to trigger at 10:33:03 every day and bring the INT0 pin low would require:</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">set_control<span style="color: #009900;">&#40;</span>DS1305_EOSC <span style="color: #339933;">|</span> DS1305_INTCN <span style="color: #339933;">|</span> DS1305_AIE0<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
setAlarm<span style="color: #009900;">&#40;</span><span style="color: #208080;">0x03</span><span style="color: #339933;">,</span><span style="color: #208080;">0x33</span><span style="color: #339933;">,</span><span style="color: #208080;">0x10</span><span style="color: #339933;">,</span><span style="color: #208080;">0x00</span> <span style="color: #339933;">|</span> DS1305_ALARM_SET<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p><b>Invoking an Interrupt on Microcontroller</b><br />
If the INT0 pin of the DS1305 is connected to a pin on the microcontroller we can initiate an interrupt to execute some code when the alarm triggers.</p>
<p>On the Microcontroller we enable external interrupts on the INT0 pin (which differs across different AVR Microcontrollers) so that when the line goes from high to low.</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// raise interrupt when INT0 pin falls (pin PD0 at AT90usbXXX, pin PD4 on ATmegaXXX)</span><br />
EICRA <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>ISC01<span style="color: #009900;">&#41;</span> <span style="color: #339933;">|</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span><span style="color: #339933;">&lt;&lt;</span>ISC00<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #666666; font-style: italic;">// enable interrupts</span><br />
EIMSK <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>INT0<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
sei<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></td></tr></tbody></table></div>
<p>More details of the options available to set up interrupts (for example whether the interrupt should be triggered on rising or falling edges) is included the &#8220;External Interrupts&#8221; Chapter in all AVR datasheets.</p>
<p>After configuration, when an interrupt occurs the following Interrupt Service Routine will be called, the code fetches the alarm time to clear the interrupt flag on the DS1305</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #666666; font-style: italic;">// called when pin INT0 changes</span><br />
ISR<span style="color: #009900;">&#40;</span>INT0_vect<span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// get alarm value to clear alarm interrupt flag on DS1305</span><br />
&nbsp; DS1305_DATETIME alarm<span style="color: #339933;">;</span><br />
&nbsp; get_alarm0<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>alarm<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; flash_led<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p>The example code is included in the SPI helper library below.<br />
<strong>Updated 2010/02/24:</strong> SPI library code moved to Google Code</p>
<p><b>References/Resources</b></p>
<ol>
<li><a href="http://code.google.com/p/rocketnumbernine/downloads/list">AVR SPI helper library<a/></li>
<li><a href="http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus">Serial Peripheral Interface</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc7707.pdf">AVR AT90USB82/162 Datasheet</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc8025.pdf">AVR ATmega48/88/168/328 Datasheet</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf">AVR151: Setup And Use of The SPI</a></li>
<li><a href="http://datasheets.maxim-ic.com/en/ds/DS1305.pdf">DS1305 datasheet</a></li>
</ol>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (3)'>Using SPI on an AVR (3)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (1)'>Using SPI on an AVR (1)</a></li>
<li><a href='http://www.rocketnumbernine.com/2010/03/06/decoding-a-rotary-encoder/' rel='bookmark' title='Permanent Link: Decoding a Rotary Encoder'>Decoding a Rotary Encoder</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Review: The Saleae Logic</title>
		<link>http://www.rocketnumbernine.com/2009/05/01/review-the-saleae-logic/</link>
		<comments>http://www.rocketnumbernine.com/2009/05/01/review-the-saleae-logic/#comments</comments>
		<pubDate>Fri, 01 May 2009 23:39:15 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[reviews]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[Logic Analyzer]]></category>
		<category><![CDATA[Saleae Logic]]></category>
		<category><![CDATA[SPI]]></category>
		<category><![CDATA[USB]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=151</guid>
		<description><![CDATA[I&#8217;ve been thinking of getting a &#8220;cheap&#8221; computer based Logic Analyzer for some time. There&#8217;s a quite a few around, at the low end they seem to fall into two groups:

Those with inbuilt memory/buffering that can sample at rates of 100MHz+ and cost around £300/$500. For example, the LA1034 LogicPort and DigiView DV1-100
Those with no [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been thinking of getting a &#8220;cheap&#8221; computer based <a href="http://en.wikipedia.org/wiki/Logic_analyzer">Logic Analyzer</a> for some time. There&#8217;s a quite a few around, at the low end they seem to fall into two groups:<br />
<il></p>
<li>Those with inbuilt memory/buffering that can sample at rates of 100MHz+ and cost around £300/$500. For example, the <a href="http://www.pctestinstruments.com/">LA1034 LogicPort</a> and <a href="http://www.tech-tools.com/dv_dv1.htm">DigiView DV1-100</a></li>
<li>Those with no or little memory/buffering that rely on transferring the data to a computer through USB that can sample at 20-25MHz and cost around £100/$150. For example, the <a href="http://www.usbee.com/sx.html">USBee SX</a> and <a href="www.saleae.com/logic">Saleae Logic</a>.</li>
<p></il></p>
<p>Whilst some of the more expensive analyzers have very useful features, I don&#8217;t think I&#8217;d utilize them enough to justify the cost &#8211; I can&#8217;t see needing greater than 20 MHz sampling in the near future (I&#8217;ll mainly be looking at I/O pins of MCUs running at less than 16MHz) and 8 inputs is probably enough, I&#8217;d rather get something cheaper now and purchase an oscilloscope later. I ended up choosing the <a href="www.saleae.com/logic">Saleae Logic</a> because:</p>
<ol>
<li>The software (which can be <a href="http://www.saleae.com/downloads/">downloaded</a> and run in demo mode) seems intuitive and quick to learn and they&#8217;re promising mac and linux versions.</li>
<li>The device looks cute.
<li>There seems to be a few people using them with no major issues reported.
</ol>
<p>I ordered Sunday directly from Saleae ($150 + $30 USPS Express Mail), it shipped Monday, and arrived Thursday (less than 60 hours door-to-door from San Francisco to London) with no added duty from UK customs!</p>
<p><b>Out of the Box</b></p>
<p>Out of its case with USB cable, 20cm patch cable, and packet of E-Z-Hook probe clips the Logic looks tiny, although its metal case is stylish and rugged.<br />
The patch cable fits snugly into the Logic, as has been commented on elsewhere it&#8217;s possible to plug them into the Logic upside down (which according to a <a href="http://www.sparkfun.com/commerce/product_info.php?products_id=8938#comment_2125">Sparkfun product page comment</a> can permanently damage the device).  Otherwise the patch cables and probes are superb.</p>
<p><a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/logic-out-of-box.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/logic-out-of-box.png" alt="Saleae Logic out of the box" title="Saleae Logic out of the box" width="500" height="385" class="aligncenter size-full wp-image-155" /></a></p>
<p><b>Running under Parallels</b><br />
I normally use a Mac, and there have been reports of people using the Logic on Windows XP running under <a href="http://www.parallels.com">Parallels</a>, although Saleae say it will run slower.  Running on Windows XP via Parallels on a MacBook, I failed to get it to sample above 0.2MHz so all the following examples were done on a PC.<br />
This is a disappointment &#8211; hopefully a Mac version will be available <a href="http://saleae.vox.com/library/post/inventory-assembly-fulfillment-new-marketing-test-sales-sluggish-linuxmac-whats-next.html">soon</a>.</p>
<p><b>Test of Maximum Sampling Rate</b><br />
To test the maximum sampling rate a simple Arduino program was used that toggled an IO pin between 0 and 1. Another pin was set high before the loop to use as a trigger to the Logic:</p>
<div class="codecolorer-container cpp default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="cpp codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #0000ff;">void</span> loop<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; digitalWrite<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, HIGH<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> i<span style="color: #000080;">=</span><span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i<span style="color: #000080;">&lt;</span><span style="color: #0000dd;">10</span><span style="color: #008080;">;</span> i<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span> <span style="color: #008000;">&#123;</span><br />
&nbsp; &nbsp; digitalWrite<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, LOW<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; &nbsp; digitalWrite<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">1</span>, HIGH<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; <span style="color: #008000;">&#125;</span><br />
&nbsp; digitalWrite<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">0</span>, LOW<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
&nbsp; delay<span style="color: #008000;">&#40;</span><span style="color: #0000dd;">500</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span><br />
<span style="color: #008000;">&#125;</span></div></td></tr></tbody></table></div>
<p>A Logic probe hook wire was connected to pin 0 and 1, and the grey ground pin to the Arduino Ground.</p>
<p><a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/logic-clock.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/logic-clock.png" alt="Saleae Logic analysis of simple clock signal" title="Saleae Logic analysis of simple clock signal" width="507" height="195" class="aligncenter size-full wp-image-152" /></a></p>
<p>Above shows the two input pins as seen on the Logic, the first two trigger bits on pin D0 was set to 0 and 1 so the logic would start recording when it sees that pin go from low to high. All that needs to be done is to set the sampling rate, the amount of data to capture (ideally the logic would allow you to specify this by time as well as bytes) and press sample. As soon as the device sees the trigger pattern on pin D0 it begins to sample and the data can be seen on the screen.</p>
<p>The Logic shows that the signal is non-symmetrical &#8211; the low phase is 3.333μs, whilst the high is 3.667μs, the 3.333 is the time for the digitalWrite, whilst the longer high signal time also includes the overhead of the for-loop (incrementing and compairing i).</p>
<p><b>Protocol Analyzers</b></p>
<p>The Logic comes with protocol analyzers for I2C, SPI, Serial and 1-Wire which can simplify investigation by decoding the binary pin levels into more user readable values according to the protocol.  Upto four analyzers can be configured and then applied to the main logic analyzer window (so configurations for different chips and circuits can be saved).</p>
<p>The following shows a two byte analysis of the SPI communication between an Arduino and a Analogue to Digital Converter described <a href="http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/">here</a>.</p>
<p><a href="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/logic-spi.png"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/05/logic-spi.png" alt="Saleae Logic analysing a SPI signal" title="Saleae Logic analysing a SPI signal" width="662" height="157" class="aligncenter size-full wp-image-153" /></a></p>
<p><b>Conclusion</b></p>
<p>The Logic seems a great device and is well worth the investment &#8211; It has excellent functionality, works as described, and has great looking hardware and software, the only caveat is that Mac and Linux software isn&#8217;t yet available.</p>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (3)'>Using SPI on an AVR (3)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/' rel='bookmark' title='Permanent Link: Using the MAX6675 Thermocouple-to-Digital Converter'>Using the MAX6675 Thermocouple-to-Digital Converter</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (2)'>Using SPI on an AVR (2)</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/05/01/review-the-saleae-logic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using SPI on an AVR (1)</title>
		<link>http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/</link>
		<comments>http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 20:57:26 +0000</pubDate>
		<dc:creator>andrew</dc:creator>
				<category><![CDATA[howto]]></category>
		<category><![CDATA[at90usb162]]></category>
		<category><![CDATA[atmega328]]></category>
		<category><![CDATA[AVR]]></category>
		<category><![CDATA[DAC]]></category>
		<category><![CDATA[MCP3201]]></category>
		<category><![CDATA[Serial]]></category>
		<category><![CDATA[SPI]]></category>

		<guid isPermaLink="false">http://www.rocketnumbernine.com/?p=124</guid>
		<description><![CDATA[
The Serial Peripheral Interface &#8211; SPI &#8211; allows digital devices to communicate using only 4 wires, additional devices can be added to the same &#8216;bus&#8217; with the addition of only a single selection wire for each device.
There are many integrated circuits and other devices that can be controlled via SPI, this entry details a simple [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/04/mc3201-spi-closeup.jpg" alt="MC3201 ADC being used with SPI" title="MC3201 ADC being used with SPI" width="240" height="142" class="alignright size-full wp-image-128" /></p>
<p>The <a href="http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus">Serial Peripheral Interface</a> &#8211; SPI &#8211; allows digital devices to communicate using only 4 wires, additional devices can be added to the same &#8216;bus&#8217; with the addition of only a single selection wire for each device.</p>
<p>There are many integrated circuits and other devices that can be controlled via SPI, this entry details a simple experiment with a MCP3201 12-bit Analogue to Digital Converter.</p>
<p><b>Background</b><br />
Each end of a SPI connection is acting in one of two roles &#8211; Master or Slave.  The master is responsible for initiating and controlling the communication.</p>
<p><a href="http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus"><img src="http://www.rocketnumbernine.com/blog/wp-content/uploads/2009/04/381px-spi_single_slavesvg.png" alt="SPI Master/Slave Connections" title="SPI Master/Slave Connections" width="381" height="119" class="aligncenter size-full wp-image-130" /></a></p>
<p>The basic mode of operation is very simple: When the master wishes to initiate transfer of data:</p>
<ol>
<li>It sets the SS (<b>Slave Select</b> &#8211; often called CS &#8211; chip select) pin low to tell the slave that communication is about to start</li>
<li>The master writes a bit of information onto the MOSI (<b>Master Out Slave In</b>) wire (sets it to 0 or 1) and the slave does the same on the MISO wire (either of these can be omitted if the data transfer is one way)</li>
<li>As the master ticks the clock line SCLK it  will read the value of MISO  (<b>Master In Slave Out</b>) wire (which the Slave has written) and the slave will read the value of the MOSI wire (whether the data is sampled as the clock rises or falls depends on which mode is in operation)</li>
<li>The process is repeated from (b), transferring a bit of data on each pulse of the clock until all data is transferred</li>
</ol>
<p>The above can be implemented in software using normal I/O pins but nearly all AVR microcontrollers have hardware support, thus to transfer a byte is simply a matter of doing:</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">SPDR <span style="color: #339933;">=</span> <span style="color: #208080;">0x2A</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// set byte to send (0x2A)</span><br />
<span style="color: #666666; font-style: italic;">// loop until SPI flag is set to signal</span><br />
<span style="color: #666666; font-style: italic;">// &nbsp;data has been transferred.</span><br />
<span style="color: #b1b100;">while</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span>SPIR <span style="color: #339933;">&amp;</span> _bv<span style="color: #009900;">&#40;</span>SPI<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #666666; font-style: italic;">// byte received from slave is now in SPDR register</span></div></td></tr></tbody></table></div>
<p>In master mode any I/O pin on the MCU can be used as chip select to tell the slave that it is being selected.  In slave mode the SS pin will be lowered to indicate that this device is being selected.<br />
The I/O pins used for SPI vary across the AVR family, for example the pins for the AT90/ATmega/ATtiny are shown below along with the Arduino mappings.</p>
<table border="1" align="center">
<tr>
<td><b>MCU/Device</b></td>
<td><b>SS</b></td>
<td><b>SCK</b></td>
<td><b>MOSI</b></td>
<td><b>MISO</b></td>
</th>
<tr>
<td>AT90USB82/162 </td>
<td>PB0</td>
<td>PB1</td>
<td>PB2</td>
<td>PB3</td>
</tr>
<tr>
<td>ATmega48/88/168/328 </td>
<td>PB2</td>
<td>PB5</td>
<td>PB3</td>
<td>PB4</td>
</tr>
<tr>
<td>ATtiny8</td>
<td>-</td>
<td>-</td>
<td>PA6</td>
<td>PA5</td>
</tr>
<tr>
<td>Arduino</td>
<td>10</td>
<td>13</td>
<td>11</td>
<td>12</td>
</tr>
</table>
<p><b>Setup</b><br />
Although the pins may be different, setup is fairly consistent across all (as well as the spec sheets for individual MCUs AVR SPI support is described in <a href="http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf">AVR151: Setup And Use of The SPI</a>) </p>
<p>SPI is configured using by setting the SPI Control Register (SPCR) with the following bits:</p>
<ul>
<li><b>Enable &#8211; (SPE)</b> &#8211; 1 to enable SPI
<li><b>Master/Slave &#8211; (MSTR)</b> &#8211; whether the MCU is acting as a master or slave.
<li><b>Clock Divisor &#8211; (SPR0, SPR1, SPXI2 in SPSR)</b> indicates the frequency of the clock, represented as a divisor of the MCU clock
<li><b>SPI timing mode (CPOL, CPHA)</b> &#8211; controls if data is output to the MISO and read on the rising or falling edge of SCK</li>
<li><b>Data Order &#8211; (DORD)</b> &#8211; whether the MCU is acting as a master or slave.
<li><b>Enable Interrupt (SPIE)</b> &#8211; whether an interrupt should be raised on successful transfer of data.
</ul>
<p>To simplify setup I created a basic helper library (currently just for master mode) with a setup function that takes a timing mode, data order, interrupt, and master clock/slave spec arguments, and #defines for the values &#8211; <a href='http://code.google.com/p/rocketnumbernine/source/browse/trunk/AVR/spi/spi.h'>spi.h</a>, <a href='http://code.google.com/p/rocketnumbernine/source/browse/trunk/AVR/spi/spi.c'>spi.c</a>. </p>
<p>Following shows some simple SPI interaction with the MCU acting as master with a simple device.</p>
<p><b>SPI to a 12 bit A/D convertor</b><br />
The picture below shows a Microchip Technology MCP3201 12 Analogue to Digital converter connected to the SPI pins of an MCU.  Although most AVRs have an ADC (the AT90USB162 doesn&#8217;t)- the MCP3201 offers higher precision than the 10-bits in most.</p>
<p><a href="http://www.flickr.com/photos/rocketnumbernine/3476497093/" title="Testing SPI interaction between a AT90USB162 (in a teensy board) and an MC3201 ADC"><img src="http://farm4.static.flickr.com/3550/3476497093_7fd2e0ef8c.jpg" width="500" height="356" alt="Testing SPI interaction between a AT90USB162 (in a teensy board) and an MC3201 ADC" /></a></p>
<p>Control of the MCP3201 D/A converter is fairly straightforward and detailed in the (<a href="http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf">datasheet</a>.  When the microcontroller sets the ^CS pin to low the chip samples the input to IN+ (a potentiometer provides the input in the circuit above) sends the digital representation on D<sub>out</sub> line as the CLK line is pulsed by the master.  The MCP3201 is a read only device MOSI is not used.</p>
<p>From the <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf">datasheet</a> we see the clock frequency can be a max of 1.6MHz at 5V &#8211; using a divider of 16 (assuming 16MHz Microcontroller clock) for SPI will give us a safe 1MHz clock frequency.  The device is agnostic about whether operating with leading or trailing clock (can be used in any SPI timing mode).<br />
The only tricky part is that the 12 bits will be delivered in 2 bytes (most significant bit first), which will have to be recomposed into a single value &#8211; see figure 6.1 of the <a href="http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf">datasheet</a>.  The following samples the value and displays the value of the top 3 bits by lighting one of  the 8 LEDs on the port B.</p>
<div class="codecolorer-container c default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:200px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br /></div></td><td><div class="c codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #339933;">#include &lt;avr/io.h&gt;</span><br />
<span style="color: #339933;">#include &lt;util/delay.h&gt;</span><br />
<span style="color: #339933;">#include &lt;spi.h&gt;</span><br />
<br />
<span style="color: #339933;">#define SELECT_ADC PORTB &amp;= ~(1&lt;&lt;PB4)</span><br />
<span style="color: #339933;">#define DESELECT_ADC PORTB |= (1&lt;&lt;PB4)</span><br />
<br />
<span style="color: #993333;">unsigned</span> <span style="color: #993333;">short</span> read_adc<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// select ADC wait 100 microseconds then read two bytes</span><br />
&nbsp; SELECT_ADC<span style="color: #339933;">;</span><br />
&nbsp; _delay_us<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> one <span style="color: #339933;">=</span> send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0xFF</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; _delay_us<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">100</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">char</span> two <span style="color: #339933;">=</span> send_spi<span style="color: #009900;">&#40;</span><span style="color: #208080;">0xFF</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; DESELECT_ADC<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// 12 bits of ADC value is bottom 5 bits of first</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// byte and top 7 bits of second, move into 16 bit int</span><br />
&nbsp; <span style="color: #b1b100;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#40;</span><span style="color: #208080;">0x1F</span> <span style="color: #339933;">&amp;</span> one<span style="color: #009900;">&#41;</span> <span style="color: #339933;">&lt;&lt;</span> <span style="color: #0000dd;">7</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">|</span> <span style="color: #009900;">&#40;</span>two <span style="color: #339933;">&gt;&gt;</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #009900;">&#123;</span><br />
&nbsp; DDRB <span style="color: #339933;">|=</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span>PB4<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// chip select for ADC</span><br />
&nbsp; <span style="color: #666666; font-style: italic;">// use port D for LEDs</span><br />
&nbsp; DDRD <span style="color: #339933;">=</span> <span style="color: #208080;">0xFF</span><span style="color: #339933;">;</span><br />
&nbsp; PORTD <span style="color: #339933;">=</span> <span style="color: #208080;">0x00</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #666666; font-style: italic;">// make sure ADC is unselected and setup spi</span><br />
&nbsp; DESELECT_ADC<span style="color: #339933;">;</span><br />
&nbsp; setup_spi<span style="color: #009900;">&#40;</span>SPI_MODE_0<span style="color: #339933;">,</span> SPI_MSB<span style="color: #339933;">,</span> SPI_NO_INTERRUPT<span style="color: #339933;">,</span> SPI_MSTR_CLK16<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #993333;">unsigned</span> <span style="color: #993333;">int</span> num <span style="color: #339933;">=</span> read_adc<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; PORTD <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #339933;">&lt;&lt;</span> <span style="color: #009900;">&#40;</span>num <span style="color: #339933;">&gt;&gt;</span> <span style="color: #0000dd;">9</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// use the top 3 bytes to turn on LED</span><br />
&nbsp; &nbsp; _delay_ms<span style="color: #009900;">&#40;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span> &nbsp;<br />
<span style="color: #009900;">&#125;</span></div></td></tr></tbody></table></div>
<p><strong>Updated 2010/02/24: </strong>SPI library code moved to Google Code</p>
<p><em>References</em></p>
<ul>
<li><a href="http://code.google.com/p/rocketnumbernine/downloads/list">AVR SPI Helper Library</a></li>
<li><a href="http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus">Serial Peripheral Interface</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc7707.pdf">AVR AT90USB82/162 Datasheet</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc8025.pdf">AVR ATmega48/88/168/328 Datasheet</a></li>
<li><a href="http://www.atmel.com/dyn/resources/prod_documents/doc2585.pdf">AVR151: Setup And Use of The SPI</a></li>
</ul>


<p>Related posts:<ol><li><a href='http://www.rocketnumbernine.com/2009/07/03/using-spi-on-an-avr-3/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (3)'>Using SPI on an AVR (3)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/05/12/using-spi-on-an-avr-2/' rel='bookmark' title='Permanent Link: Using SPI on an AVR (2)'>Using SPI on an AVR (2)</a></li>
<li><a href='http://www.rocketnumbernine.com/2009/06/27/using-the-max6675-thermocouple-to-digital-converter/' rel='bookmark' title='Permanent Link: Using the MAX6675 Thermocouple-to-Digital Converter'>Using the MAX6675 Thermocouple-to-Digital Converter</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.rocketnumbernine.com/2009/04/26/using-spi-on-an-avr-1/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 4.741 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2010-09-06 10:17:40 -->
