<?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>Frank&#039;s Random Wanderings</title>
	<atom:link href="http://blog.frankvh.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.frankvh.com</link>
	<description>A bunch of random musings, with a leaning towards electronics &#38; computers.</description>
	<lastBuildDate>Thu, 07 Jan 2010 16:28:49 +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>Atmel Xmega ADC Problems &amp; Solutions</title>
		<link>http://blog.frankvh.com/2010/01/03/atmel-xmega-adc-problems-solutions/</link>
		<comments>http://blog.frankvh.com/2010/01/03/atmel-xmega-adc-problems-solutions/#comments</comments>
		<pubDate>Sun, 03 Jan 2010 16:56:45 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=213</guid>
		<description><![CDATA[I&#8217;ve been working with the A/D converter on the Atmel Xmega AVR processors, and it&#8217;s been quite the handful. At this point in time (Jan 2010) the parts have some very serious issues, and I&#8217;ve lost a lot of time trying to get them to work as advertised. This posting is to share what I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working with the A/D converter on the Atmel Xmega AVR processors, and it&#8217;s been quite the handful. At this point in time (Jan 2010) the parts have some very serious issues, and I&#8217;ve lost a lot of time trying to get them to work as advertised. This posting is to share what I&#8217;ve found, and the best solutions I&#8217;ve determined to get the Xmega A/D converters to work.</p>
<p>If you haven&#8217;t already done so, you need to read Atmel application note AVR1300, &#8220;Using the XMEGA ADC&#8221;, as well as use the source code provided with that app note. </p>
<p>You also need to read the errata for the Xmega. The errata is found towards the bottom of the Xmega datasheet. I should point out that the errata only gives you a hint of the problems with the part, but at least Atmel acknowledges there are some big issues. I&#8217;ve been working a lot with Atmel&#8217;s tech support, and I must say they&#8217;ve been helpful (to the extent they can be) and responsive. Supporting a broken part can&#8217;t be easy for them either. They have told me that Atmel is working on a silicon revision to fix these problems, but they haven&#8217;t been able to tell me when it might see the light of day.</p>
<p>OK, here we go. The code snippets below are from my code; you&#8217;ll need to edit them slightly to suit your needs. But they will show you which AVR1300 functions to use.</p>
<p><strong>Singled-Ended Vs Differential</strong></p>
<p>The Xmega is a differential 12-bit ADC that can be used in either singled-ended or differential mode. Initially I&#8217;d been using it in single-ended mode, just because it&#8217;s easier, and I&#8217;d been getting errors of magnitude well in excess of 30 counts (LSBs). Obviously that&#8217;s enormous. In fact the errata implies that errors of up to 60 LSBs are possible. That&#8217;s almost 6 bits! At that point it&#8217;s closer to a random number generator than an A/D converter&#8230; </p>
<p>The best thing to do here is use differential mode. I found the best results came from tying one of the external ADC pins to GND, and using that as the &#8220;negative&#8221; input for the converter. You want to do this with no gain. Using gain only adds more error. So your code would look something like this (change your pin names as appropriate):</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ADC_Ch_InputMode_and_Gain_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK.<span style="color: #202020;">CH0</span><span style="color: #339933;">,</span> ADC_CH_INPUTMODE_DIFF_gc<span style="color: #339933;">,</span> ADC_DRIVER_CH_GAIN_NONE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 	<span style="color: #666666; font-style: italic;">// differential mode, no gain</span>
ADC_Ch_InputMux_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK.<span style="color: #202020;">CH0</span><span style="color: #339933;">,</span> pin<span style="color: #339933;">,</span> ADC_CH_MUXNEG_PIN1_gc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>			 <span style="color: #666666; font-style: italic;">// + &amp; - inputs</span></pre></div></div>

<p>It&#8217;s possible to use the internal GND reference, but my experiments seemed to favour using an external pin tied to GND.</p>
<p><strong>Xmega ADC Reference Voltage</strong></p>
<p>The part has an internal 1.00V reference voltage, that you&#8217;re supposed to be able to use as the reference voltage for the A/D. In practice this doesn&#8217;t work. The errata suggests this, and suggests the 1.00V reference is too low a voltage for the ADC to function properly. </p>
<p>I suspect the best solution is to provide a buffered external stable reference voltage of around 2V and feed it into the part via its external reference pin. In my case this wasn&#8217;t an option so I had to settle for something else. The next best option is to use the internal setting of VCC/1.6 as the ADC reference. In such a case your code will look something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ADC_Reference_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK<span style="color: #339933;">,</span> ADC_REFSEL_VCC_gc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> 		<span style="color: #666666; font-style: italic;">// use Vcc/1.6 as ADC reference</span></pre></div></div>

<p>With a 3.3V VCC, this gives a reference of 2.06V. The problem here is that the reference for an A/D is assumed to be stable. Very stable. That&#8217;s hard to claim for a VCC line, which may have all kinds of noise on it. So this falls into the &#8220;<em>do the best you can</em>&#8221; camp, but it&#8217;s still better than using the internal 1.00V.</p>
<p>If you don&#8217;t know what VCC is (perhaps you need to measure it), how do you accomplish that when VCC/1.6 is your ADC reference? The only way I know is by getting the ADC to sample the internal bandgap voltage. Something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ADC_Ch_InputMode_and_Gain_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK.<span style="color: #202020;">CH0</span><span style="color: #339933;">,</span> ADC_CH_INPUTMODE_INTERNAL_gc<span style="color: #339933;">,</span> ADC_DRIVER_CH_GAIN_NONE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
ADC_Ch_InputMux_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK.<span style="color: #202020;">CH0</span><span style="color: #339933;">,</span> ADC_CH_MUXINT_BANDGAP_gc<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>You&#8217;ll want to calibrate this yourself. The datasheet says the bandgap is 1.1V. I&#8217;ve found it&#8217;s a little less than that &#8211; more like 1.08V. There&#8217;s no way to put a multimeter on it directly, but you can get the ADC to measure it, and you can of course measure your VCC voltage, so that tells you what the bandgap actually is. Note that according to the errata, you cannot measure the bandgap if your VCC is below 2.7V, so in that case you&#8217;re probably out of luck, and you&#8217;d better look again at providing an external ADC reference voltage.</p>
<p>Note there is an error in the errata. (Yes, Atmel needs an errata for their errata&#8230;.). Errata #4 talks about using the A/D to measure the 1.00V internal voltage reference. Atmel tech support has confirmed this is not possible &#8211; the errata is wrong. The only &#8220;reference&#8221; you can measure is the bandgap.</p>
<p><strong>Signed vs Unsigned Mode</strong></p>
<p>The Xmega has a 12-bit A/D. It can be run in either signed mode, or unsigned mode. If you&#8217;re measuring a simple single-ended input referenced to ground (which most folks do), the way to get the full 12-bits of resolution is to use unsigned mode. In unsigned mode, the &#8220;negative&#8221; input of the ADC is tied to an internally generated voltage which is at the approximate midpoint of the ADC reference voltage. The problem is this internally generated voltage is very unstable, which has the effect of producing widely varying ADC outputs for a stable input voltage.</p>
<p>The solution is to use signed mode. In signed mode, the &#8220;negative&#8221; ADC input is under your control, and should be routed to a external pin which is tied to GND (as per &#8220;Singled-Ended vs Differential&#8221; above). Signed mode is selected much like this:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ADC_ConvMode_and_Resolution_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK<span style="color: #339933;">,</span> ADC_ConvMode_Signed<span style="color: #339933;">,</span> ADC_RESOLUTION_12BIT_gc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>In signed mode, with a simple single-ended input referenced to ground, you effectively have an 11 bit converter, not a 12. Output values will typically be in the range of 0 &#8211; 2047 (0 &#8211; 0&#215;7ff).</p>
<p><strong>ADC Sampling Speed</strong></p>
<p>For measuring internal signals you need to be running the ADC below 100 kHz. I&#8217;ve tried a bunch of different sampling speeds, and 62 kHz seems to be the sweet spot. If you&#8217;re using the internal 2 MHz CPU clock, this is an ADC prescaler of 32. Like so:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ADC_Prescaler_Config<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK<span style="color: #339933;">,</span> ADC_PRESCALER_DIV32_gc<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p><strong>ADC Offset</strong></p>
<p>I&#8217;ve struggled with this one. The AVR1300 app note &#038; example code shows a simple method of measuring the ADC&#8217;s DC offset, and subtracting it from every ADC measurement. I&#8217;ve found the DC offset to be relatively small: around -4 in my case. Yet when I try to &#8220;correct&#8221; my ADC measurements by subtracting it out, it makes my measurements less accurate, not more.</p>
<p>It almost makes me wonder if it&#8217;s not a real DC offset, but rather some artifact of the nonlinearity problems currently inherent to the ADC.</p>
<p>After much experimenting, I&#8217;ve decided not to use it. What I do is measure the ADC offset when the code starts up, and I print it out for informational purposes. But then I set the offset to zero, and leave it there. So I&#8217;m not using the offset (offset = 0 in my code) and this seems to produce better ADC results.</p>
<p><strong>ADC Calibration Bytes</strong></p>
<p>The AVR1300 code shows how to read the ADC calibration bytes into the appropriate ADC register. Like so:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">ADC_CalibrationValues_Set<span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>ADC_BK<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>I&#8217;ve found it doesn&#8217;t seem to make any real difference. I do indeed do it, but commenting this line out doesn&#8217;t appear to make a meaningful difference.</p>
<p><strong>Averaging &#038; Clipping</strong></p>
<p>Averaging ADC measurements certainly helps reduce their sample-to-sample variability. To take an ADC measurement, I take 4 and average them. This is well worthwhile.</p>
<p>The other thing I do is clip them to zero. Because I&#8217;m measuring single-ended voltages, a negative voltage is not physically possible (or desired). So after my average of 4 ADC measurements, if the result is less than zero, I make the result zero. This helps in my code later, because I know I don&#8217;t need to deal with negative numbers. Otherwise, because my ADC appears to have a slight negative &#8220;offset&#8221;, measuring a grounded pin can result in an ADC measurement of -3 for example, which is not meaningful. So something like this gets clipped to zero.</p>
<p><strong>Summary</strong></p>
<p>To summarise a long post on the care &#038; feeding of a currently rather broken Xmega ADC, here are my hard-earned suggestions:</p>
<ul>
<li>Use Differential mode / differential inputs. Tie an external ADC pin to GND if necessary.</li>
<li>Use either VCC/1.6, or an external reference voltage, for the ADC reference. Not the internal 1.00V. Use the ADC to measure the bandgap if that helps.</li>
<li>Use signed mode.</li>
<li>Consider using a 62 kHz ADC sampling rate.</li>
<li>Consider assuming the ADC offset is zero.</li>
<li>Average multiple ADC measurements (and clip if it makes sense in your application)</li>
</ul>
<p>Good luck! Let&#8217;s hope Atmel releases fixed silicon really soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2010/01/03/atmel-xmega-adc-problems-solutions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Atmel Xplain Xmega board Gotchas</title>
		<link>http://blog.frankvh.com/2009/11/15/atmel-xplain-board/</link>
		<comments>http://blog.frankvh.com/2009/11/15/atmel-xplain-board/#comments</comments>
		<pubDate>Sun, 15 Nov 2009 20:11:39 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=187</guid>
		<description><![CDATA[Atmel kindly gave me an Xplain Xmega board at one of their Xmega seminars. It&#8217;s a useful tool for ATXmega development, but it does have a couple of problems. I thought I&#8217;d mention the ones I&#8217;ve tripped over, in case anybody else sees the same problems.
Board Doesn&#8217;t Restart Properly
I&#8217;ve found that when the AVRISP2 programmer [...]]]></description>
			<content:encoded><![CDATA[<p>Atmel kindly gave me an Xplain Xmega board at one of their Xmega seminars. It&#8217;s a useful tool for ATXmega development, but it does have a couple of problems. I thought I&#8217;d mention the ones I&#8217;ve tripped over, in case anybody else sees the same problems.</p>
<p><strong>Board Doesn&#8217;t Restart Properly</strong></p>
<p>I&#8217;ve found that when the AVRISP2 programmer is plugged in, the Xplain always reboots properly. But when the programmer is unplugged and the board is &#8220;on its own&#8221;, so to speak, it doesn&#8217;t always reboot properly and the code in the Xmega128 doesn&#8217;t always run.</p>
<p>The reason is a hardware problem on the board. Atmel&#8217;s Xmega documentation states that the Xmega processors have a weak internal pullup on the reset line. If there are any external devices on the reset line, an additional external pullup may be required.</p>
<p>This is the case with Xplain. The ATXmega128 reset line also routes to the AT90USB1287 part on the board. It seems this small additional load is problematic for the Xmega. Adding a 10k pullup resistor to the Xmega reset line solved the problem and allowed the Xmega to reboot properly every time.</p>
<p>Take a look at the Xplain schematic (available on the Atmel website) to see where the reset signal goes. Personally, I found it very easy to solder an 0603 10k resistor on the back of the Xmega programming connector header, between pins 4 &amp; 6. The 0603 was the perfect size to fit between the solder joints for pins 4 &amp; 6 on the back of the board. But, a regular leaded resistor would work fine too.</p>
<p><strong>USB Serial Interface Doesn&#8217;t Work</strong></p>
<p>Yep, lots of people have pointed that out. The AT90USB1287 is supposed to implement a &#8220;virtual COM port&#8221;, allowing the Xmega to transmit &amp; receive at 9600 board, and have that available over USB thanks to the 1287. In theory. In practice, not so much. Atmel&#8217;s USB-to-serial interface doesn&#8217;t seem to work as advertised. I was able to confirm on my board that I was giving the AT90USB1287 the 9600 baud serial data it expected, but the thing never worked. I tried different drivers etc from the Atmel website, to no avail.</p>
<p>In theory you can reprogram the 1287 via the USB port, using Atmel&#8217;s &#8220;FLIP&#8221; utility (available on their website). For me, that didn&#8217;t work either, and I really tried hard. No FLIP for me!</p>
<p>So what to do? Here are a couple of options.</p>
<ul>
<li>Apparently this code works, if you can get it into the AT90USB1287:<br />
<a title="http://www.fourwalledcubicle.com/LUFA.php" href="http://www.fourwalledcubicle.com/LUFA.php" target="_blank">http://www.fourwalledcubicle.com/LUFA.php</a><br />
Build the &#8220;XMEGABridge&#8221; project, program the resulting .hex file into the 1287, and you&#8217;ll have a working USB to serial interface. Of course the big trick is actually doing the programming. If you can get FLIP to work, great. Otherwise, you&#8217;ll need to program the 1287 via its 10-pin JTAG programming header. Note I said &#8220;JTAG&#8221; &#8211; you&#8217;ll need a JTAG programmer, not the AVRISP2.</li>
</ul>
<ul>
<li>Give up on the 1287 completely &amp; solder a MAX232 device and DB9 connector to the board instead. This option worked for me because I had the parts required at hand, so it was fairly easy &amp; quick. I would imagine this might not be the case for everyone  though.</li>
</ul>
<p>Programming Atmel AVR processors has become a little more difficult with Atmel&#8217;s use of a 6-pin connector on their popular AVRISP2 programmer. This is a great little programmer, fast, cheap, and USB based.</p>
<p>But why oh why did they put a 6-pin connector on it, instead of the 10-pin connector they use almost everywhere else? Almost all of their development boards, including the Xplain, have 10-pin programming headers. But this little programmer has a 6-pin connector. So you need to make yourself an adaptor board, or adaptor cable, before you can even use it. What were they thinking?</p>
<p>In fact, ideally you need to make two different 6-to-10 pin adaptors.  One for Xmega devices that use the PDI programming interface (see <a href="http://blog.frankvh.com/2009/09/22/avr-xmega-and-avrisp-mk2/" target="_blank">my previous post</a>), and a different one for all the other AVR parts that use the older &#8220;SPI&#8221; or &#8220;ISP&#8221; programming interface. </p>
<p>There you have it. A pull-up resistor to cure the &#8220;Xplain doesn&#8217;t reset&#8221; problem, and a couple of options if your Xplain USB to serial doesn&#8217;t work. Have fun!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/11/15/atmel-xplain-board/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Atmel Xmega printf HowTo</title>
		<link>http://blog.frankvh.com/2009/11/14/atmel-xmega-printf-howto/</link>
		<comments>http://blog.frankvh.com/2009/11/14/atmel-xmega-printf-howto/#comments</comments>
		<pubDate>Sun, 15 Nov 2009 00:19:25 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=155</guid>
		<description><![CDATA[This is a surprisingly common question.  When using WinAVR, how do you get printf() working on an Atmel Xmega processor?  Hopefully this post will help explain how.
First of all, this documentation page has some good information regarding the different flavours of WinAVR printf:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html
Note the existence of the printf_P() function, which makes it easy to work [...]]]></description>
			<content:encoded><![CDATA[<p>This is a surprisingly common question.  When using WinAVR, how do you get printf() working on an Atmel Xmega processor?  Hopefully this post will help explain how.</p>
<p>First of all, this documentation page has some good information regarding the different flavours of WinAVR printf:</p>
<p><a title="http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html" href="http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html" target="_blank">http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html</a></p>
<p>Note the existence of the printf_P() function, which makes it easy to work with strings kept in program space (flash).  This can be super useful on an AVR, which has very little SRAM but loads of flash.  The regular printf() function will put your text string in SRAM, which is not always ideal.</p>
<p>The big question after reading that documentation page is: how do I initialise the UART, and how do I implement the putchar function, on an Xmega?  Because the example code on that webpage is geared towards the non-xmega parts.</p>
<p>Here&#8217;s some Xmega example code. Feel free to use it however you see fit.</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;avr/io.h&gt; </span>
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">int</span> uart_putchar<span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> c<span style="color: #339933;">,</span> FILE <span style="color: #339933;">*</span>stream<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">void</span> uart_init <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #993333;">static</span> FILE mystdout <span style="color: #339933;">=</span> FDEV_SETUP_STREAM <span style="color: #009900;">&#40;</span>uart_putchar<span style="color: #339933;">,</span> NULL<span style="color: #339933;">,</span> _FDEV_SETUP_WRITE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
&nbsp;
<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>
<span style="color: #009900;">&#123;</span>
    uart_init<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    stdout <span style="color: #339933;">=</span> <span style="color: #339933;">&amp;</span>mystdout<span style="color: #339933;">;</span>
&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: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;Hello, world!<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #993333;">static</span> <span style="color: #993333;">int</span> uart_putchar <span style="color: #009900;">&#40;</span><span style="color: #993333;">char</span> c<span style="color: #339933;">,</span> FILE <span style="color: #339933;">*</span>stream<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>c <span style="color: #339933;">==</span> <span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\n</span>'</span><span style="color: #009900;">&#41;</span>
        uart_putchar<span style="color: #009900;">&#40;</span><span style="color: #ff0000;">'<span style="color: #000099; font-weight: bold;">\r</span>'</span><span style="color: #339933;">,</span> stream<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Wait for the transmit buffer to be empty</span>
    <span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #009900;">&#40;</span> USARTC0.<span style="color: #202020;">STATUS</span> <span style="color: #339933;">&amp;</span> USART_DREIF_bm<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Put our character into the transmit buffer</span>
    USARTC0.<span style="color: #202020;">DATA</span> <span style="color: #339933;">=</span> c<span style="color: #339933;">;</span> 
&nbsp;
    <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #666666; font-style: italic;">// Init USART.  Transmit only (we're not receiving anything)</span>
<span style="color: #666666; font-style: italic;">// We use USARTC0, transmit pin on PC3.</span>
<span style="color: #666666; font-style: italic;">// Want 9600 baud. Have a 2 MHz clock. BSCALE = 0</span>
<span style="color: #666666; font-style: italic;">// BSEL = ( 2000000 / (2^0 * 16*9600)) -1 = 12</span>
<span style="color: #666666; font-style: italic;">// Fbaud = 2000000 / (2^0 * 16 * (12+1))  = 9615 bits/sec</span>
<span style="color: #993333;">static</span> <span style="color: #993333;">void</span> uart_init <span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #666666; font-style: italic;">// Set the TxD pin high - set PORTC DIR register bit 3 to 1</span>
    PORTC.<span style="color: #202020;">OUTSET</span> <span style="color: #339933;">=</span> PIN3_bm<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Set the TxD pin as an output - set PORTC OUT register bit 3 to 1</span>
    PORTC.<span style="color: #202020;">DIRSET</span> <span style="color: #339933;">=</span> PIN3_bm<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Set baud rate &amp; frame format</span>
    USARTC0.<span style="color: #202020;">BAUDCTRLB</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>			<span style="color: #666666; font-style: italic;">// BSCALE = 0 as well</span>
    USARTC0.<span style="color: #202020;">BAUDCTRLA</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">12</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Set mode of operation</span>
    USARTC0.<span style="color: #202020;">CTRLA</span> <span style="color: #339933;">=</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>				<span style="color: #666666; font-style: italic;">// no interrupts please</span>
    USARTC0.<span style="color: #202020;">CTRLC</span> <span style="color: #339933;">=</span> <span style="color: #208080;">0x03</span><span style="color: #339933;">;</span>			<span style="color: #666666; font-style: italic;">// async, no parity, 8 bit data, 1 stop bit</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">// Enable transmitter only</span>
    USARTC0.<span style="color: #202020;">CTRLB</span> <span style="color: #339933;">=</span> USART_TXEN_bm<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>This code shows the things you need to do, in its most basic form. It only demonstrates transmitting out the UART; there&#8217;s no receive here (we are talking about printf, after all).  This code:</p>
<ul>
<li>sets up the stdout FILE  (mystdout in this example)</li>
<li>initialises the UART. In this example USARTC0 is used, but you can of course use any USART block.</li>
<li>implements the putchar function</li>
<li>does a printf(&#8220;hello world&#8221;) forever in main().</li>
</ul>
<p>Note the initialisation sequence. With the Xmega it&#8217;s important to manually set the UART transmit pin, ie the corresponding port pin, as an output, and set it high, before configuring the UART. This is specified in the Xmega documentation, and is different to most other AVR parts which don&#8217;t have this requirement.</p>
<p>Note also that the UART is set to 9600 baud, no parity, 8 data bits, 1 stop bit. I have this code running on an ATXmega128 board (an Atmel Xplain board).</p>
<p>This should be enough to get things started, and you can build on it from here.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/11/14/atmel-xmega-printf-howto/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blackfin JPEG Encoding &#8211; an update</title>
		<link>http://blog.frankvh.com/2009/10/20/blackfin-jpeg-encoding-an-update/</link>
		<comments>http://blog.frankvh.com/2009/10/20/blackfin-jpeg-encoding-an-update/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 05:09:22 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=150</guid>
		<description><![CDATA[A little while ago I wrote about implementing fast JPEG encoding on an Analog Devices Blackfin. See the original post here:
Blackfin Fast JPEG Encoding
Since then I&#8217;ve moved to a new hardware platform, with a different blackfin processor and a different image sensor, which has caused me to revisit this code. I found that with the [...]]]></description>
			<content:encoded><![CDATA[<p>A little while ago I wrote about implementing fast JPEG encoding on an Analog Devices Blackfin. See the original post here:</p>
<p><a title="Blackfin Fast JPEG Encoding" href="http://blog.frankvh.com/2009/06/09/blackfin-fast-jpeg-encoding/" target="_blank">Blackfin Fast JPEG Encoding</a></p>
<p>Since then I&#8217;ve moved to a new hardware platform, with a different blackfin processor and a different image sensor, which has caused me to revisit this code. I found that with the previous code, image quality wasn&#8217;t as good as I thought it should be. Sometimes the jpeg image looked a little blocky, or pixelated. Not a lot, but a little bit, enough to notice.</p>
<p>Some digging revealed that it seemed to be related to the DCT (discrete cosine transform) function. In the Surveyor code there are two DCT functions. One, called DCT, is written in C. The other, called r8&#215;8dct, is written in assembler by Analog Devices. By default the jpeg encoder uses the assembler version, and rightfully so, because it&#8217;s a lot faster. But I found that when I switched to using the C &#8220;DCT&#8221; function, image quality was improved, and the jpg images looked like I&#8217;d expect them to.</p>
<p>As a result, I wrote an assembler implementation of the C &#8220;DCT&#8221; function, which is functionally identical to the C code, but a great deal faster. For my 752 x 512 YUV image, these are the speeds I measured for jpeg encoding:</p>
<ul>
<li>Using DCT, C function:  138 ms</li>
<li>Using DCT, my new assembler function: 92 ms</li>
<li>Using DCT, Analog Devices assembler function: 90 ms</li>
</ul>
<p>You can see that my DCT assembler function is not quite as fast as the Analog Devices one. But it&#8217;s very close; only 2 ms difference. Close enough! The new assembler DCT function is called jpegdct. I&#8217;ve revised the .zip file to remove the Analog Devices assembler function, and use my new one. This also has the side benefit that all of the source files are now under the GPL license. The new files are here:</p>
<p><a title="Blackfin Fast JPEG Encoder Files" href="http://blog.frankvh.com/wp-content/uploads/2009/10/jpeg.zip" target="_blank">Blackfin Fast JPEG Encoder Files</a></p>
<p>So there we have it. A fast JPEG encoder, fully GPL, and improved image quality. What more could we wish for?</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/10/20/blackfin-jpeg-encoding-an-update/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AVR Xmega and AVRISP Mk2</title>
		<link>http://blog.frankvh.com/2009/09/22/avr-xmega-and-avrisp-mk2/</link>
		<comments>http://blog.frankvh.com/2009/09/22/avr-xmega-and-avrisp-mk2/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 22:50:33 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=127</guid>
		<description><![CDATA[Recently I&#8217;ve been doing some Atmel AVR Xmega work. The Atmel website says that their low-cost programmer, the AVRISP2, can be used to program an xmega device. But their (current) documentation would appear to tell a very different story. If you read the documentation, you&#8217;d reasonably conclude that it wouldn&#8217;t work at all.
In fact the [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve been doing some Atmel AVR Xmega work. The Atmel website says that their low-cost programmer, the AVRISP2, can be used to program an xmega device. But their (current) documentation would appear to tell a very different story. If you read the documentation, you&#8217;d reasonably conclude that it wouldn&#8217;t work at all.</p>
<p>In fact the AVRISP MkII can be used to program an Xmega part. You just need to know how to hook it up.</p>
<p><a rel="attachment wp-att-128" href="http://blog.frankvh.com/2009/09/22/avr-xmega-and-avrisp-mk2/avrisp/"><img class="aligncenter size-medium wp-image-128" title="AVRISP" src="http://blog.frankvh.com/wp-content/uploads/2009/09/AVRISP-350x251.jpg" alt="AVRISP" width="350" height="251" /></a></p>
<p>First of all, make sure you&#8217;re using the very latest version of AVR Studio, as you&#8217;ll need to use that as your programming software.  (AVR Studio also contains a decent IDE, and a plugin to support the free WinAVR C compiler, so it&#8217;s actually much more than just a programming program, if you want it to be.)</p>
<p>The AVRISP2 has a 6-pin header.  Here&#8217;s how to connect it to an Xmega part:</p>
<blockquote><p>AVRISP2<br />
PIN</p>
<p>1    -    xmega PDI data pin<br />
2    -    xmega VCC power rail<br />
3    -    no connect<br />
4    -    no connect<br />
5    -    xmega PDI clock (often the xmega reset pin)<br />
6    -    xmega GND power rail</p></blockquote>
<p>That&#8217;s it. Only 4 pins to hook up. Now you can tell AVR studio which xmega part you have, select the AVRISP MkII programmer, and program away. Easy!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/09/22/avr-xmega-and-avrisp-mk2/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Free SPICE Analog Circuit Simulator</title>
		<link>http://blog.frankvh.com/2009/07/15/free-spice-analog-circuit-simulator/</link>
		<comments>http://blog.frankvh.com/2009/07/15/free-spice-analog-circuit-simulator/#comments</comments>
		<pubDate>Wed, 15 Jul 2009 18:31:32 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=112</guid>
		<description><![CDATA[Those in the know, know, that if you want to play with analog circuits, using a simulator first is a really good idea. There are many analog circuit simulators out there, some free, some mega-bucks, but the most common of all is SPICE. There are many different versions of SPICE available, and lately I&#8217;ve been [...]]]></description>
			<content:encoded><![CDATA[<p>Those in the know, know, that if you want to play with analog circuits, using a simulator first is a really good idea. There are many analog circuit simulators out there, some free, some mega-bucks, but the most common of all is SPICE. There are many different versions of SPICE available, and lately I&#8217;ve been using one that I&#8217;ve really been enjoying, called LTspice. You can download it here:<br />
<a title="http://www.linear.com/designtools/software/" href="http://www.linear.com/designtools/software/" target="_blank">http://www.linear.com/designtools/software/</a></p>
<p>LTspice is a free program provided by Linear Technology. Some of you may know it by its older name, SwitcherCAD, but it&#8217;s actually a full SPICE simulator. LinearTech provides models for almost all of their parts with LTspice, in addition to a large number of models for other popular parts, like various transistors, diodes, etc. What&#8217;s nice is that if LTspice doesn&#8217;t contain a model for your MOSFET of interest for example, but you can find a spice model on the MOSFET manufacturer&#8217;s website, just copy&amp;paste that model into LTspice and you&#8217;re good to go.</p>
<p>It also comes with lots of example circuits, and there&#8217;s a users manual on the website. For a free program it&#8217;s pretty well developed.</p>
<p>Here&#8217;s a simple example. Today I had an R-C circuit controlling a reset controller, and I wanted to know how long the R-C would take to reach a certain voltage to trip the controller. Well, it would be easy enough to work that out with a little math, but it&#8217;s way more fun to simulate it.</p>
<p><a rel="attachment wp-att-111" href="http://blog.frankvh.com/2009/07/15/free-spice-analog-circuit-simulator/ltspice-r-c/"><img class="alignnone size-medium wp-image-111" title="LTspice-r-c" src="http://blog.frankvh.com/wp-content/uploads/2009/07/LTspice-r-c-350x248.jpg" alt="LTspice-r-c" width="350" height="248" /></a></p>
<p>Click (twice) on the picture above to enlarge it. You can see the little schematic I drew, and the resulting classical R-C charging curve in red in the graph above. Quick, simple &amp; easy. What&#8217;s nice is that I can now easily extend this circuit, adding for example a current sink on the Vout line to simulate the load of my controller, and see the result on the R-C curve. This kind of tool makes experimentation and &#8220;what-if&#8221; thought processes very easy &amp; informative.</p>
<p>If you&#8217;ve never used a SPICE simulator before, or you&#8217;re just interested in learning more about how some of these simple circuits (or much more complex circuits) actually work, I&#8217;d encourage you to download LTspice &amp; give it a try. It&#8217;s a really great tool.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/07/15/free-spice-analog-circuit-simulator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SD Card Locks Don&#8217;t Lock</title>
		<link>http://blog.frankvh.com/2009/07/13/sd-card-locks-dont-lock/</link>
		<comments>http://blog.frankvh.com/2009/07/13/sd-card-locks-dont-lock/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 19:13:59 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=106</guid>
		<description><![CDATA[Here&#8217;s a little known fact about SD Cards. The little &#8220;lock&#8221; switch on the side of the card? It doesn&#8217;t lock the card.

This is a photo of a pretty typical SD card. On the left you can see the &#8220;lock&#8221; switch. You&#8217;d think that sliding this switch downwards, into the locked position, would write-protect the [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a little known fact about SD Cards. The little &#8220;lock&#8221; switch on the side of the card? It doesn&#8217;t lock the card.</p>
<p><a rel="attachment wp-att-105" href="http://blog.frankvh.com/2009/07/13/sd-card-locks-dont-lock/sd-card/"><img class="alignnone size-full wp-image-105" title="sd-card" src="http://blog.frankvh.com/wp-content/uploads/2009/07/sd-card.jpeg" alt="sd-card" width="375" height="468" /></a></p>
<p>This is a photo of a pretty typical SD card. On the left you can see the &#8220;lock&#8221; switch. You&#8217;d think that sliding this switch downwards, into the locked position, would write-protect the card. You&#8217;d be wrong.</p>
<p>I first stumbled across this fact on vacation, where at an internet cafe I ended up with a virus on a &#8220;locked&#8221; SD card.</p>
<p>The lock switch does nothing to the internals of the card. There is no switch or any electrical mechanism in the card. That switch is nothing more than a movable piece of plastic. The card itself has no idea whether the switch is in the locked, or unlocked, position.</p>
<p>In your card reader is a mechanism which senses the position of that lock switch, and reports its position back to the PC. The PC, ie the operating system or file manager in the PC, then has the option, if it so chooses, of not writing to the card if it knows the lock switch is in the locked position. However, it can just as easily ignore it. Electrically, there is nothing preventing it from writing to the card. This is what a virus can easily do. If there is a problem with your OS or file manager program and it ignores the switch position, it too will happily write to a &#8220;locked&#8221; SD card.</p>
<p>So beware. Don&#8217;t assume your card is safe simply because the switch says it&#8217;s locked. The card can still be written to, re-formatted, the card contents erased, etc. Accidents most certainly can happen, even though the switch is &#8220;locked&#8221;. It&#8217;s not locked, it&#8217;s never truly locked, so treat your card, and its contents, with all appropriate due care &amp; respect. I&#8217;ve no idea why the people who designed the SD card implemented a lock switch that doesn&#8217;t lock, but they did, and we&#8217;d be wise to remember that little fact.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/07/13/sd-card-locks-dont-lock/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Adobe PDF Alternative</title>
		<link>http://blog.frankvh.com/2009/06/22/adobe-pdf-alternative/</link>
		<comments>http://blog.frankvh.com/2009/06/22/adobe-pdf-alternative/#comments</comments>
		<pubDate>Mon, 22 Jun 2009 22:31:50 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=93</guid>
		<description><![CDATA[One of the most frustrating and annoying programs on my Windows computers used to be the Adobe PDF reader. Back in its early versions it was a fast, light, useful program. Then a few years ago somebody at Adobe drank a bottle of liquid stupid, and the program&#8217;s been hurtling downhill ever since.
The problems with [...]]]></description>
			<content:encoded><![CDATA[<p>One of the most frustrating and annoying programs on my Windows computers used to be the Adobe PDF reader. Back in its early versions it was a fast, light, useful program. Then a few years ago somebody at Adobe drank a bottle of liquid stupid, and the program&#8217;s been hurtling downhill ever since.</p>
<p>The problems with the reader are plentiful, but some big ones come to mind. That whole period where the reader basically forced you to install the Yahoo toolbar was a disaster. The current Adobe Updater (forced upon you with Adobe Reader) is even worse. I can&#8217;t count the number of times that either the reader, or its updater, has either flat-out crashed one of my machines, or bought it to its knees. I&#8217;ve tried every version, right up to the very latest, and the only thing I can say with confidence is: <em>Don&#8217;t Upgrade</em>. Whatever problems you might be having with the Adobe PDF reader today, installing a newer &amp; even more bloated version will only make things worse.</p>
<p>That&#8217;s the bad news. The good news is, there are some really fantastic alternatives. I don&#8217;t use the Adobe PDF reader, or writer, anymore, and you don&#8217;t need to either. And even better news: these greatly superior programs are free!</p>
<p>There are a few different alternatives to the Adobe software. You can research &amp; compare them all, as I did, but in this post I&#8217;m going to cut to the chase and simply tell you what I use &amp; recommend.</p>
<h3>Adobe Reader Alternative</h3>
<p>Use the <em>PDF-XChange PDF Viewer</em>. You can download it for free here:<br />
<a title="http://www.docu-track.com/downloads/users/" href="http://www.docu-track.com/downloads/users/" target="_blank">http://www.docu-track.com/downloads/users/</a></p>
<p>This has all the features of the free Adobe reader, plus a lot more. This one will also allow you to edit PDFs, something that you&#8217;d otherwise need to use the paid $$ version of the Adobe reader to do.</p>
<p>Once you have this program installed and you&#8217;ve confirmed it works, feel free to go to your <em>Start &#8211; Settings &#8211; Control Panel &#8211; Add or Remove Programs </em>and remove the Adobe PDF reader.  You won&#8217;t be needing it anymore.</p>
<h3>Adobe Acrobat PDF Writer Alternative</h3>
<p>Want to create your own PDFs for free? Yep, I thought so. It&#8217;s very easy to do. Download and install <em>PDF Creator</em> from here:</p>
<p><a title="http://www.pdfforge.org/" href="http://www.pdfforge.org/" target="_blank">http://www.pdfforge.org/</a></p>
<p>This program installs itself as a printer driver on your computer. Now you can generate a PDF from any program at all; word processing, spreadsheet, photo, etc.  All you need to do is go <em>File &#8211; Print</em> within your program of choice, and select the &#8220;PDF Creator&#8221; printer instead of your normal printer from the drop-down box. After you hit &#8220;print&#8221; it&#8217;ll ask you for a file name for your newly-created PDF file. Life doesn&#8217;t get any easier than that.</p>
<p>That&#8217;s it! A couple of free, fast, well-functioning programs for reading, editing &amp; creating PDF documents. Install these two, uninstall the Adobe programs, and you&#8217;ll have a smoother-running, more functional, PC.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/06/22/adobe-pdf-alternative/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>A Remarkable Sentence</title>
		<link>http://blog.frankvh.com/2009/06/19/a-remarkable-sentence/</link>
		<comments>http://blog.frankvh.com/2009/06/19/a-remarkable-sentence/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 17:55:56 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=90</guid>
		<description><![CDATA[Reading through the websitebaker themes website, I came across this rather remarkable, and amusing, sentence, and felt compelled to post it here:
Aoccdrnig to rscheearch at an Elingsh uinervtisy, it deosn&#8217;t mttaer in waht oredr the ltteers in a wrod are, the olny iprmoetnt tihng is taht the frist and lsat ltteer is in the rghit [...]]]></description>
			<content:encoded><![CDATA[<p>Reading through the websitebaker themes website, I came across this rather remarkable, and amusing, sentence, and felt compelled to post it here:</p>
<blockquote><p>Aoccdrnig to rscheearch at an Elingsh uinervtisy, it deosn&#8217;t mttaer in waht oredr the ltteers in a wrod are, the olny iprmoetnt tihng is taht the frist and lsat ltteer is in the rghit pclae.</p></blockquote>
<p>Hilarious.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/06/19/a-remarkable-sentence/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Blackfin Fast JPEG Encoding</title>
		<link>http://blog.frankvh.com/2009/06/09/blackfin-fast-jpeg-encoding/</link>
		<comments>http://blog.frankvh.com/2009/06/09/blackfin-fast-jpeg-encoding/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 21:59:50 +0000</pubDate>
		<dc:creator>frank</dc:creator>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Electronics]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://blog.frankvh.com/?p=31</guid>
		<description><![CDATA[Recently I&#8217;ve been doing a lot of embedded uClinux programming for the Analog Devices Blackfin BF537 processor. Writing drivers, application code, things like that. It&#8217;s a lot of fun.

One of the things I&#8217;d been battling with was finding a reasonably fast JPEG encoder. Now you need to understand that the BF537 doesn&#8217;t have a JPG [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I&#8217;ve been doing a lot of embedded uClinux programming for the Analog Devices Blackfin BF537 processor. Writing drivers, application code, things like that. It&#8217;s a lot of fun.</p>
<p><img class="alignnone" title=" " src="http://blackfin.uclinux.org/images/blackfin/blackfin-logo-txt.png" alt="" width="156" height="38" /></p>
<p>One of the things I&#8217;d been battling with was finding a reasonably fast JPEG encoder. Now you need to understand that the BF537 doesn&#8217;t have a JPG compression engine or anything like that, so it&#8217;ll never be screaming fast. The default uClinux JPEG library is libjpeg. Libjpeg is fairly slow. I wrote a reasonably-optimised DCT function in blackfin assembler for libjpeg &amp; posted it over at <a title="http://blackfin.uclinux.org" href="http://blackfin.uclinux.org" target="_blank">http://blackfin.uclinux.org</a> You can find the files, and a description, here at my original posting:</p>
<p><a title="Faster JPEG Encoding - files attached" href="http://blackfin.uclinux.org/gf/project/uclinux-dist/forum/?action=ForumBrowse&amp;forum_id=39&amp;_forum_action=ForumMessageBrowse&amp;thread_id=29816" target="_blank">Faster JPEG encoding &#8211; files attached</a></p>
<p>What&#8217;s cool is it appears to have been accepted into the mainstream blackfin uClinux distribution (SVN), judging by <a title="this tracker entry" href="http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&amp;tracker_item_id=4424" target="_blank">this tracker entry</a>.  So pretty soon everyone will be getting this faster libjpeg code by default.</p>
<p>Which is nice, and it helps, but it&#8217;s still too slow. My example 752 x 512 RGB image was taking around 260 ms to JPG encode using the &#8220;improved&#8221; libjpeg function. Too long. So I looked for alternatives.</p>
<p>I had tried FFMPEG. It&#8217;s faster, because the Analog Devices folks wrote some optimisations for it. It&#8217;s tricky to tell exactly how fast, because FFMPEG will duplicate frames to give you the framerate you request. Just because FFMPEG gives you 25 frames/sec doesn&#8217;t mean you&#8217;re getting 25 <em>different </em>frames per second. But that aside, the big problem I had with FFMPEG was its tendancy to malloc() and free() chunks of memory constantly. This would eventually result in memory fragmentation &amp; malloc() failing, sometimes in minutes, sometimes in hours. Problems like this I can do without, and it&#8217;d be a hard one to fix.</p>
<p>SCS Vision wrote a JPEG encoder for their leanXcam product. Their encoder appears to be based on one written by Nitin Gupta. Based on comments they wrote in their comment block (which I assumed to be correct &amp; did not personally verify), I calculated it would encode my image in around 290 ms. Obviously that&#8217;s not the big improvement I&#8217;m looking for.</p>
<p>Analog Devices has a very fast optimised JPEG encoder available, right off their Blackfin website, for free. But it only works with their proprietary VDSP+ tools. It&#8217;s not compatible with any of the open-source tools (gcc, uClinux, etc) and it&#8217;s only distributed in object code form, which makes it impossible to port. Tantalising, but useless.</p>
<p>Then recently I had a break. I stumbled across the <a title="Surveyor robot" href="http://www.surveyor.com" target="_blank">Surveyor robot</a> folks. A very bright fellow over there wrote a pretty decent JPG encoder, which took advantage of an Analog Devices optimised DCT function, as well as doing some other smart things in the code. It only handled YUV images, whereas my image is RGB. So before I could try it, I had to hack up a quick RGB24 to YUV422 conversion routine. But once I did, I was encoding my image in 165 ms. That&#8217;s clearly a substantial improvement over the libjpeg 260 ms.</p>
<p>With that success, I set to further optimising the code, both theirs and mine. By the time I was finished, my image was JPEG encoding in 96 ms. Go baby go!</p>
<p>Fast JPG encoding seems to be a common question for Blackfin, so I&#8217;m posting the final code here. Click on the link below to get to the download page:</p>
<p><a title="Blackfin Fast JPEG Encoder" href="http://blog.frankvh.com/wp-content/uploads/2009/10/jpeg.zip" target="_blank">Blackfin Fast JPEG Encoder</a></p>
<p>Now here&#8217;s how to call the function.</p>
<p>If you&#8217;re familiar with libjpeg, you&#8217;ll find this easier, because there&#8217;s nothing to set up or tear down.  encode_image() needs a pointer to the raw image in memory, a pointer to a chunk of memory where it can write the resulting JPG image, and a few other parameters. It returns another pointer, which is the next free location in memory where it had just been writing. So that you can work out how large the just-created JPG image is. It&#8217;s up to you to write the JPG image to a file (if indeed you even want to do that).</p>
<p>Here&#8217;s the function prototype:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">UINT8<span style="color: #339933;">*</span> encode_image <span style="color: #009900;">&#40;</span>UINT8 <span style="color: #339933;">*</span>input_ptr<span style="color: #339933;">,</span> UINT8 <span style="color: #339933;">*</span>output_ptr<span style="color: #339933;">,</span> UINT32 quality_factor<span style="color: #339933;">,</span> UINT32 image_format<span style="color: #339933;">,</span> UINT32 image_width<span style="color: #339933;">,</span> UINT32 image_height<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>It&#8217;s pretty simple. Pointers to the input raw image buffer (YUV or RGB) and an output image (JPG) buffer. A quality factor which ranges from 1 (highest) to 8 (lowest). I use 2. Setting this to 1 results in much longer execution time &amp; much larger filesizes. Image format can be:</p>
<ul>
<li>RGB  &#8211; this is RGB24</li>
<li>FOUR_TWO_TWO   &#8211; this is YUV422</li>
</ul>
<p>FOUR_ZERO_ZERO (monochrome YUV) is reported in the comments below as also working.</p>
<p>Image width &amp; height should be self-explanatory.</p>
<p>To call it, set up your image buffers as you see fit, then do something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">jpeg_buff_end <span style="color: #339933;">=</span> encode_image<span style="color: #009900;">&#40;</span>text_img_buff<span style="color: #339933;">,</span> jpeg_buff<span style="color: #339933;">,</span> <span style="color: #0000dd;">2</span><span style="color: #339933;">,</span> RGB<span style="color: #339933;">,</span> <span style="color: #0000dd;">640</span><span style="color: #339933;">,</span> <span style="color: #0000dd;">480</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Your JPG image is of filesize:  (jpeg_buff_end &#8211; jpeg_buff)</p>
<p>If you want to save your JPG to a file, you can do something like:</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;">jpegfp <span style="color: #339933;">=</span> fopen <span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;myimage.jpg&quot;</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;w&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fwrite <span style="color: #009900;">&#40;</span>jpeg_buff<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">,</span> jpeg_buff_end<span style="color: #339933;">-</span>jpeg_buff<span style="color: #339933;">,</span> jpegfp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
fclose <span style="color: #009900;">&#40;</span>jpegfp<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>That&#8217;s it.  Easy to use, and it&#8217;s the fastest thing, by far, I&#8217;m aware of for JPEG encoding on Blackfin uClinux.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.frankvh.com/2009/06/09/blackfin-fast-jpeg-encoding/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
