<?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>Stack Overflow</title>
	<atom:link href="http://embeddedgurus.com/stack-overflow/feed/" rel="self" type="application/rss+xml" />
	<link>http://embeddedgurus.com/stack-overflow</link>
	<description>Thoughts on embedded systems by Nigel Jones</description>
	<lastBuildDate>Mon, 30 Aug 2010 15:50:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Classic race conditions and thoughts on testing</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/classic-race-conditions-and-thoughts-on-testing/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/classic-race-conditions-and-thoughts-on-testing/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 15:50:54 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Firmware Bugs]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=525</guid>
		<description><![CDATA[At a rather fundamental level this blog is about how I do embedded systems. Implicit in a lot of the articles is the concept that I believe what I&#8217;m doing is &#8216;right&#8217;, or at least &#8216;better&#8217;. Well today I thought I&#8217;d write about something I got wrong (at least on the first pass).
This is the [...]]]></description>
			<content:encoded><![CDATA[<p>At a rather fundamental level this blog is about how I do embedded systems. Implicit in a lot of the articles is the concept that I believe what I&#8217;m doing is &#8216;right&#8217;, or at least &#8216;better&#8217;. Well today I thought I&#8217;d write about something I got wrong (at least on the first pass).</p>
<p>This is the scenario. I&#8217;m currently working on an NXP LPC17xx ARM Cortex design. Like all modern processors, the LPC17xx has a number of sophisticated timers with all sorts of operating modes. Well it so happens that I am using  four (out of a possible six) interrupt sources for one particular timer. The hardware architecture of the processor routes all of these interrupts to one vector and thus one interrupt handler. Here&#8217;s what I wrote:</p>
<pre>void TMR3_IRQHandler(void)
{
 if (T3IR_bit.MR0INT)
 {                                            
  /* Do stuff */
 }

 if (T3IR_bit.CR0INT)
 {        
  /* Do stuff */        
 }

 if (T3IR_bit.MR1INT)
 {                                            
  /* Do stuff */
 }

 if (T3IR_bit.CR1INT)
 {                                            
  /* Do stuff */
 }

 T3IR = 0x3F;            /* Acknowledge all interrupts */

 ...
}</pre>
<p>Thus in the ISR I tested each of my interrupt sources, took the appropriate actions in the sections marked &#8216;Do stuff&#8217;, acknowledged the interrupts, did a bit of clean up and I was done.  The &#8216;Do Stuff&#8217; sections were quite complicated and so this was where I spent my time. Anyway having finished coding the ISR, I took a short break and came back to re-examine the code. As I was re-reading the code, I realized that I had made a classic mistake. In case you haven&#8217;t spotted it, the problem is in the line where I acknowledge all interrupts. Consider the following sequence of events:</p>
<ol>
<li>Interrupt source CR1INT is asserted and the CPU vectors to this ISR.</li>
<li>I test the various interrupt flags and discover that CR1INT is set and do the requisite work.</li>
<li>While I&#8217;m doing the requisite work, interrupt source MR1INT becomes active.</li>
<li>I clear all interrupt sources (including MR1INT) and terminate the ISR</li>
<li>As a result I have missed an interrupt.</li>
</ol>
<p>The way this should have been coded is to acknowledge each interrupt bit individually. I.e. like this:</p>
<pre>void TMR3_IRQHandler(void)
{
 if (T3IR_bit.MR0INT)
 {                                            
  /* Do stuff */
  T3IR_bit.MR0INT = 1;                    /* Clear the interrupt */
 }

 if (T3IR_bit.CR0INT)
 {        
  /* Do stuff */    
  T3IR_bit.CR0INT = 1;                    /* Clear the interrupt */
 }

 if (T3IR_bit.MR1INT)
 {                                            
  /* Do stuff */
  T3IR_bit.MR1INT = 1;                    /* Clear the interrupt */
 }

 if (T3IR_bit.CR1INT)
 {                                            
  /* Do stuff */
  T3IR_bit.CR1INT = 1;                    /* Clear the interrupt */        
 }

 ...
}</pre>
<p>So how did this mistake come about? I think there were two culprits:</p>
<h2>Mistake 1</h2>
<p>The first mistake I made was in using another timer ISR as a template. The code I copied had just a single interrupt source, and thus acknowledging all of the sources was reasonable.</p>
<h2>Mistake 2</h2>
<p>I was too concerned with the &#8216;real work&#8217; of the ISR. I should have written the ISR outline first and only then worried about the real work.</p>
<p>Notwithstanding the above, I did do one thing correctly &#8211; and that was to finish the code, walk away, and then come back to re-examine it. At no time did I reach for the debugger to test my code &#8211; which was just as well because quite frankly the chances of this bug being caught by testing are vanishingly small. Indeed just about the only way a bug like this would get caught is via code inspection &#8211; which is why I&#8217;m such a firm believer in code inspection as a debugging tool.</p>
<p>Anyway if you found this informative, you may find this <a href="http://embeddedgurus.com/stack-overflow/2008/12/knowing-my-weaknesses/">account </a>of another mistake I made equally enlightening.</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/classic-race-conditions-and-thoughts-on-testing/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>A foreign perspective on variable names</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/a-foreign-perspective-on-variable-names/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/a-foreign-perspective-on-variable-names/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 23:25:17 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=520</guid>
		<description><![CDATA[This blog is read by people from all over the world. I make this point not to brag, but rather to demonstrate that designing embedded systems is a truly global effort. Remarkably, despite this, it appears that a huge amount of embedded code is commented in English and / or uses English nomenclature for variable [...]]]></description>
			<content:encoded><![CDATA[<p>This blog is read by people from all over the world. I make this point not to brag, but rather to demonstrate that designing embedded systems is a truly global effort. Remarkably, despite this, it appears that a huge amount of embedded code is commented in English and / or uses English nomenclature for variable and function names. This is of course wonderful for those of us that are native English speakers. However I&#8217;ve often thought that designing embedded systems is hard enough without having the additional burden of working in a foreign language.</p>
<p>Anyway, I mention this as preamble because last week I found myself in a rather unusual situation for me. Namely I was handed a fairly sophisticated driver which was written by a native German speaker. Now one of the things I have always liked about the Germans is that they don&#8217;t kowtow to the altar of the English language &#8211; and so I found myself looking at code that was commented entirely in German and that used almost exclusively German for function and variable names. I was thus faced with trying to understand it &#8211; which with my limited knowledge of German was not at all easy.</p>
<p>Anyway, as I went through the code I found myself entering variable names into an online German-English dictionary &#8211; with very limited success. Now while part of the problem was undoubtedly the technical nature of the words, I don&#8217;t have the slightest doubt that the real problem was that the author was using abbreviations / slang / jargon as well as concatenating words (e.g. (in English) bufferindex) such that the online dictionaries were flummoxed. The net result was that I had a much harder time interpreting the code than would have been the case if I had understood the variable names. Needless to say this got me thinking. How many times has a non-native English speaker looked at some of my code and entered variable names into a dictionary only to be told that there is no such word? If you subscribe to the belief that you write code for other people to read then it follows that one should take the spoken language barrier into consideration. If one does, then certain &#8216;rules&#8217; become apparent:</p>
<ol>
<li>Don&#8217;t abbreviate unless you have to. While BufrWrtLmt may be understandable to native English speakers, it must be really hard to comprehend for others.</li>
<li>In concatenating words, make the word boundary clear either via underscore or via camel-case. Thus buffer_index or bufferIndex.</li>
<li>Pay attention to your spelling. A simple spelling mistake such as writing temprature when you meant temperature can completely stymie someone using a dictionary. While I don&#8217;t know of a tool that spell checks variable names, there are several tools available for spell checking comments.</li>
</ol>
<p>As a passing observation, not only will these changes make your code easier to comprehend for non-native English speakers, it will also do wonders for those of us that purport to speak English as our native tongue!</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/a-foreign-perspective-on-variable-names/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Setting a bad example &#8211; final thoughts</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-final-thoughts/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-final-thoughts/#comments</comments>
		<pubDate>Sun, 15 Aug 2010 13:49:13 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=516</guid>
		<description><![CDATA[While I am sure that I could extend the setting a bad example  series of   articles I think it&#8217;s time to move on to other topics. Before I do so I&#8217;d like to give some final thoughts. The series has generated a lot of excellent comments. While the majority have been in response to [...]]]></description>
			<content:encoded><![CDATA[<p>While I am sure that I could extend the setting a bad example  <a href="../../2010/08/setting-a-bad-example-part-1/">series</a> of   articles I think it&#8217;s time to move on to other topics. Before I do so I&#8217;d like to give some final thoughts. The series has generated a lot of excellent comments. While the majority have been in response to a particular coding construct, a number of readers have expressed their frustration at how pervasive this problem is with vendor supplied code. My experience agrees with this assessment. In other words while this series has taken IAR to task, I don&#8217;t have the slightest doubt that if I had bought an ARM evaluation board from Keil, ImageCraft etc that I would have found similar things to complain about. In other words my experience is the norm and not the exception. Now I don&#8217;t think I&#8217;m going too far out on a limb by observing that  the code supplied with evaluation boards is very influential in that:</p>
<ol>
<li>It is likely to find itself incorporated into hundreds, if not thousands of products.</li>
<li>Will be used both verbatim and as a template for future code by huge numbers of inexperienced engineers.</li>
</ol>
<p>Thus the bottom line is that the code supplied with evaluation boards needs to be of the highest quality and to incorporate as many best practices as possible. While it would be great if this blog was influential enough to cause the vendors to change their ways, I suspect that little will really happen until people start complaining. Those of you that work for large organizations which buy a commensurate number of licenses are in the best position to make the change happen by loudly complaining to your sales representative every time you find some lousy code.</p>
<p>As always, thanks for reading.</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-final-thoughts/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Setting a bad example &#8211; part 5</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-5/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-5/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 20:13:26 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=512</guid>
		<description><![CDATA[This is the fifth part in a series of   articles in which I’m ‘highlighting’ what I consider to be lousy   code  provided by IAR in their NXP LPC1764 development kit. This code excerpt is  taken from usb_t9.c in the AudioDevice project.
/*************************************************************************
 * Function Name: UsbCoreReq
 * Parameters:  UsbCoreReqType_t Type
 *
 [...]]]></description>
			<content:encoded><![CDATA[<p>This is the fifth part in a <a href="../../2010/08/setting-a-bad-example-part-1/">series</a> of   articles in which I’m ‘highlighting’ what I consider to be lousy   code  provided by IAR in their NXP LPC1764 development kit. This code excerpt is  taken from usb_t9.c in the AudioDevice project.</p>
<pre>/*************************************************************************
 * Function Name: UsbCoreReq
 * Parameters:  UsbCoreReqType_t Type
 *
 * Return: Int32U
 *
 * Description: Return device states
 *
 *************************************************************************/
Int32U UsbCoreReq (UsbCoreReqType_t Type)
{
 switch(Type)
 {
 case UsbCoreReqDevState:
   return(UsbDevCtrl.State.DS);
 case UsbCoreReqDevSusState:
   return(UsbDevCtrl.State.Suspend);
 case UsbCoreReqConfiquration:
   return(UsbDevCtrl.Configuration);
 case UsbCoreReqInterface:
   return(UsbDevCtrl.Interfaces);
 case UsbCoreReqDevOwnAddress:
   return(UsbDevCtrl.DevAdd);
 case UsbCoreReqWakeUpEnableStatus:
   return(UsbDevCtrl.Feature.RemoteWakeupEnable);
 case UsbCoreReqSelfPoweredStatus:
   return(USB_SELF_POWERED);
#if USB_HIGH_SPEED &gt; 0
 case UsbCoreReqSpeed:
   return(UsbDevCtrl.HighSpeed);
#endif // USB_HIGH_SPEED &gt; 0
 }
 return((Int32U) -1);
}
</pre>
<p>I suspect that on first blush many readers will not be too offended by this function. However it contains several things that are pet peeves of mine. I&#8217;ve listed them in the order that they occur in the function</p>
<ol>
<li>As with most of the code, I found the function header to be almost useless. Having read it multiple times and also having looked at the code, I&#8217;m still not really clear what the purpose of this function is other than to provide access to some of the parameters of the structure UsbDevCtrl.</li>
<li>This function does nothing more than switch on a parameter and return a value. As I outlined in this <a href="http://embeddedgurus.com/stack-overflow/2010/02/efficient-c-tip-11-avoid-passing-parameters-by-using-more-small-functions/">post</a>, IMHO one should use multiple simple functions rather than one large function such as this. The resulting code is smaller, faster and the purpose of each function is much clearer. It also avoids the problem that is discussed in point 7 below.</li>
<li>The author has used the variable name &#8216;Type&#8217;. While I know this is legal and it may even be somewhat meaningful in this case, I find the idea of using &#8216;Type&#8217; as a variable name just plain confusing.</li>
<li>The function contains no-less than nine return statements. Most coding standards require that a function have a single exit point. I have to admit that if you&#8217;d asked me ten years ago whether I thought this was a good idea I&#8217;d have probably equivocated. However in recent years I have really made an effort to ensure that all my functions have a single exit point &#8211; and I have found it has improved my code a lot. Of course there are the odd cases where it really is unavoidable. However in this case, maintaining a single exit point would have been trivial.</li>
<li>The argument to the return statement is in parentheses. This seems to be a popular construct, which I simply do not understand. What benefit do the parentheses confer? To those that ask what harm are they doing, then I would suggest that they make the code harder to read.</li>
<li>The switch statement has no default clause. Yes, one will fall through to the last return statement &#8211; but it&#8217;s a sloppy way of handling it.</li>
<li>The pièce de résistance is of course the cast of -1 to an unsigned integer. The function is declared as returning an unsigned integer &#8211; but in one case it returns a signed integer that is cast to unsigned. I&#8217;m sure that you will not be surprised to hear that none of the functions that call UsbCoreReq() check to see if &#8220;-1&#8243; has been returned.</li>
</ol>
<p>I don&#8217;t think this example is quite as horrific as some of the others I have highlighted &#8211; but it&#8217;s still pretty bad. As always your comments make this interesting!</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-5/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
		<item>
		<title>Setting a bad example &#8211; part 4</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-4/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-4/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 00:54:28 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=508</guid>
		<description><![CDATA[This is the fourth part in a series of  articles in which I’m ‘highlighting’ what I consider to be lousy   code provided by IAR in their NXP LPC1764 development kit. This example  is taken from the VirtualCom project but can be found in almost all of the projects.
This code excerpt is taken [...]]]></description>
			<content:encoded><![CDATA[<p>This is the fourth part in a <a href="../../2010/08/setting-a-bad-example-part-1/">series</a> of  articles in which I’m ‘highlighting’ what I consider to be lousy   code provided by IAR in their NXP LPC1764 development kit. This example  is taken from the VirtualCom project but can be found in almost all of the projects.</p>
<p>This code excerpt is taken from a file &#8216;Terminal_18_24&#215;12.c&#8221;.</p>
<pre>/*************************************************************************
 *
 *    Used with ICCARM and AARM.
 *
 *    (c) Copyright IAR Systems 2006
 *
 *    File name   : Terminal_18_24x12.c
 *    Description : Font Terminal 18 (24x12)
 *
 *    History :
 *    1. Date        : December 2, 2006
 *       Author      : Stanimir Bonev
 *       Description : Create
 *
 *    $Revision: 28532 $
 **************************************************************************/
#include "drv_glcd.h"

static const unsigned char TextStream [] = {
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

<strong>... One thousand five hundred and thirty+ more lines of data</strong> <strong>without a comment</strong>

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

FontType_t Terminal_18_24_12 =
{
 12,
 24,
 0,
 255,
 (pInt8U)TextStream,
 "Terminal 18 (24x12)"
};
</pre>
<p>Other than the header shown above, there is not a single comment in a 1566 line file. To help complete the picture, here is the excerpt from the header file drv_glcd.h which defines the data type FontType_t.</p>
<pre>typedef struct _FontType_t {
 Int32U H_Size;
 Int32U V_Size;
 Int32U CharacterOffset;
 Int32U CharactersNuber;
 pInt8U pFontStream;
 pInt8U pFontDesc;
} FontType_t, *pFontType_t;
</pre>
<p>I have not omitted the comments &#8211; there just aren&#8217;t any.</p>
<p>Now it&#8217;s reasonably clear that this file is used to define a font. To illustrate my complaint with this file, I will pose what I consider to be a quite reasonable situation.</p>
<p>The sales department comes to engineering and says &#8220;90% of our sales for this product are in Germany. We have received complaints from Germany that the digit seven is rendered incorrectly &#8211; can you please correct it?&#8221; (For those of you that don&#8217;t know, in Germany a &#8216;7&#8242; is usually rendered with a  horizontal bar through the body. I would demonstrate it &#8211; but I can&#8217;t within the limitations of my editing environment).</p>
<p>Now the question is, how big a job should this be &#8211; and how big a job will it actually be based upon how the font has been implemented? I will let you the reader decide the answer to the first question. To the second question however, I will suggest an answer of days. The reason is that before I can possibly make the change I have to get the following questions answered:</p>
<ol>
<li>How is TextStream[] indexed? It&#8217;s likely by ASCII number &#8211; but who knows for sure?</li>
<li>Just how many bytes are there per character?</li>
<li>How do the bytes map onto the character &#8211; by row or by column and do they start at the bottom, the top, the left or the right?</li>
<li>What about <em>italics </em>and <strong>bold</strong>? Are they included in this font definition or not? If not, is there a separate file that defines them, or is it done algorithmically?</li>
<li>Is there a German style &#8216;7&#8242; already in the font map that I could just use?</li>
</ol>
<p>All of these questions could have and should have been answered in the font file. If it was me, I would have done it via a combination of coding changes and comments. For example I might have done something like this:</p>
<pre>
<pre>static const unsigned char TextStream [N_TYPES][N_CHARS][FONT_SIZE_IN_BYTES] =
{
 /* Start of standard fonts (c.f. bold and italic) */
 {
  /*  Character 0. This is the nul character and is non-printing.
  Appears so as to make indexing into TextStream[][] easy */
  {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    ...</pre>
</pre>
<p>Would this have been a lot of work up-front? Absolutely. However compared to what the poor sod that has to maintain the font has to go through, it would have been time well spent. Unfortunately the industry seems to measure productivity based on how quickly code is written &#8211; and not on how easy it is to maintain. I for one would like to see it changed!</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-4/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Setting a bad example &#8211; part 3</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-3/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-3/#comments</comments>
		<pubDate>Sat, 07 Aug 2010 22:27:33 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=493</guid>
		<description><![CDATA[This is the third part in a series of  articles in which I’m ‘highlighting’ what I consider to be lousy  code provided by IAR in their NXP LPC1764 development kit. This example is taken from the Accelerometer project. The accelerometer is accessed via an I2C bus, and so the main purpose of this example [...]]]></description>
			<content:encoded><![CDATA[<p>This is the third part in a <a href="../2010/08/setting-a-bad-example-part-1/">series</a> of  articles in which I’m ‘highlighting’ what I consider to be lousy  code provided by IAR in their NXP LPC1764 development kit. This example is taken from the Accelerometer project. The accelerometer is accessed via an I2C bus, and so the main purpose of this example code is to demonstrate how to use the I2C interface. If you have ever had to write an I2C driver you will know that they are deceptively hard. In my case the project I&#8217;m working on does indeed need an I2C driver &#8211; and so I was expecting to be able to borrow heavily from the IAR code. Alas I found the code to be almost completely useless. To see why, read on &#8230;</p>
<p>Upon examination of the I2C driver the first thing I found were a number of &#8216;helper functions&#8217;. For example:</p>
<pre>/*************************************************************************
 * Function Name: I2C_EnableI2C
 * Parameters: void
 * Return: void
 * Description: Enable I2C device.
 *************************************************************************/
#pragma inline
void I2C_EnableI2C(void)
{
 I2C2CONSET |= I2CON_I2EN;
}
</pre>
<p>While in general I&#8217;m all in favor of these types of helper functions, I had three problems with the way they were implemented.</p>
<ol>
<li>Clearly if anyone other than the I2C driver was to invoke these functions then really bad things would happen. Despite this, the author has not seen fit to declare the function static, thus opening them up for the world to use.</li>
<li>These helper functions are located at the top of the file.  There has been an interesting thread of discussion on this blog regarding whether this is good, bad or indifferent practice. Personally I strongly dislike it as it puts an implementation minutiae in my face &#8211; when want I want to know is &#8216;what&#8217;s the big picture&#8217;. Thus IMHO these types of functions should be at the end of the file &#8211; but I recognize that there are those who disagree!</li>
<li>The next thing that puzzled me  was that I couldn&#8217;t find the definition of &#8216;I2CON_I2EN&#8217; anywhere in the  file. Clearly it had to exist somewhere and so a project wide search  showed that it was defined in the the file i2c_drv.h. Now the only  module that could possibly have any interest in the value of &#8216;I2CON_I2EN&#8217;  is the driver code i2c_drv.c. Despite this, the author has seen fit to  put the define in the header file rather than the C file. I have to  admit that I have seen this done by a lot of other people &#8211; and for the  life of me I cannot understand the logic. Why would you go out of your  way to make public something that inherently should remain private? When  combined with the fact that the helper functions are also public the  only possible explanation is that the author expected code outside the  driver to interact with the I2C hardware!</li>
</ol>
<p>I also noticed that these functions were being declared without a prototype &#8211; and yet the code was compiling without a warning. I thus examined the compilation options &#8211; and sure enough the author had the &#8216;Require prototypes&#8217; box <strong>unchecked</strong>.</p>
<p><a href="http://embeddedgurus.com/stack-overflow/files/2010/08/CompOptions.jpg"><img class="aligncenter size-full wp-image-494" title="CompOptions" src="http://embeddedgurus.com/stack-overflow/files/2010/08/CompOptions.jpg" alt="" width="534" height="477" /></a>Now to be fair to the author, and for reasons only known to IAR, this is the default setting. Notwithstanding this, building code without requiring prototypes is just inexcusable.</p>
<p>Anyway, next up in the driver was an initialization function and then this function:</p>
<pre>/*************************************************************************
 * Function Name: I2C_MasterWrite
 * Parameters:  unsigned char addr -- the slave address which you send message to
 *        unsigned char *pMsg -- the point to the message
 *        unsigned long numMsg -- the byte number of the message
 * Return: int
 *                 0: success
 *       non-zero: error number
 *
 * Description: Transmit messages
 *
 *************************************************************************/
int I2C_MasterWrite (unsigned char addr, unsigned char *pMsg , unsigned long numMsg)
{
 return I2C_Transfer (addr, pMsg , numMsg, WRITE, 0);
}
</pre>
<p>I looked at the header and was immediately disappointed as I noticed the following:</p>
<ol>
<li>The author had suddenly and mysteriously switched to using the built in data types (char, int, long), despite the rest of the code in the project using defined data types Int32u etc. Whenever I see lack of data type discipline I know I&#8217;m in for a bad experience.</li>
<li>The first parameter was described as &#8220;the slave address which you send message to&#8221;. Well anyone that has done any work with the I2C bus knows that the concept of an address is poorly defined. In the I2C standard, addresses are 7 bits. However, what gets sent to an I2C slave is the address left shifted one place with a R/W bit placed in the LSB position. As a result, many people consider the slave address to be the byte that is transmitted with the LSB masked out. While I&#8217;m not particularly interested in arguing about which camp is correct, the point is that tremendous ambiguity exists in this area. As a result a well written I2C driver should be unambiguous about what it expects for a slave address. In this case I&#8217;m clueless as to what to pass to the driver.</li>
<li>The second parameter is a pointer to the message to be transmitted. However, the pointer is not defined as pointing to const &#8211; which it should be. Again this is indicative of someone who is sloppy.</li>
<li>The third parameter is described as &#8220;the byte number of the message&#8221;. I&#8217;m sure the author meant &#8220;the number of bytes in the message&#8221;. I&#8217;m not going to complain about this &#8211; on the assumption that the author&#8217;s native language is not English. Notwithstanding this, I do still have a problem with the third parameter &#8211; and that&#8217;s the choice of the data type. I have written a lot of I2C code in my life &#8211; and I have never been in a situation where I needed to send so many bytes to a peripheral that the length byte needed to be an unsigned long. I would have thought a 16 bit variable would have been quite enough.</li>
<li>The return type was defined as &#8216;int&#8217; with zero being success and non-zero being an error number. However, it was completely unclear what were the possible list of error numbers. IMHO if you are going to return an error code from a function then the return type should be an enumeration &#8211; which presumably via the suitable choice of enumeration names would describe the particular error. Notwithstanding this, I hunted around and in the header file for the driver I found the following:</li>
</ol>
<pre>/* Status Errors */
#define I2C_OK                         0       // transfer ended No Errors
#define I2C_IDLE                    1       // bus idle
#define I2C_BUSY                     2       // transfer busy
#define I2C_ERROR                   3       // err: general error
#define I2C_NO_DATA                 4       // err: No data in block
#define I2C_NACK_ON_DATA           5       // err: No ack on data
#define I2C_NACK_ON_ADDRESS       6       // err: No ack on address
#define I2C_DEVICE_NOT_PRESENT     7       // err: Device not present
#define I2C_ARBITRATION_LOST       8       // err: Arbitration lost
#define I2C_TIME_OUT                 9       // err: Time out occurred
#define I2C_SLAVE_ERROR           10      // err: Slave mode error
#define I2C_INIT_ERROR               11      // err: Initialization (not done)
#define I2C_RETRIES                 12      // err: Initialization (not done)
</pre>
<p>These appeared to fit the bill &#8211; or so I thought. However, looking at the body of the above code, it was apparent that all the real work got done in the I2C_Transfer() function and so I turned my attention to it. The first part of the code is below:</p>
<pre>/*************************************************************************
 * Function Name: I2C_Transfer
 * Parameters:  unsigned char addr -- the slave address which you send message to
 *        unsigned char *pMsg -- the point to the message
 *        unsigned long numMsg -- the byte number of the message
 *        LPC_I2C_TransMode_t transMode -- Read, Write, Write then read
 *        unsigned long numWrite -- this is only for "Write then read" mode
 *            
 * Return: int
 *                 0: success
 *       non-zero: error number
 *
 * Description: Transfer messages
 *
 *************************************************************************/
int I2C_Transfer (unsigned char addr, unsigned char *pMsg , unsigned long numMsg,
 LPC_I2C_TransMode_t transMode, unsigned long numWrite)
{
unsigned int timeout = DLY_I2C_TIME_OUT;
 if (transMode == WRITETHENREAD)
 {
   if (numWrite &gt;= numMsg)
     return 1;
   else
     I2CMsg.nrWriteBytes = numWrite;
 }
 else
   I2CMsg.nrWriteBytes = 0;
...
}
</pre>
<p>In looking at this code I noticed that it would immediately return the value of 1 if some criterion was met. However looking at my list of error codes, a 1 is &#8216;I2C_IDLE&#8217;. That clearly didn&#8217;t make sense. Despite this, on examining the rest of the function I found that it did indeed return the error codes listed above. In other words the author was just too lazy to define another error code and so he simply reused an existing error code &#8211; even though it had nothing to do with the issue at hand. By this point I was utterly convinced that the code was a complete train wreck.</p>
<p>While I also found a lot more to dislike about the implementation, my final complaint is actually a lot more subtle &#8211; but in many ways the most important of all. Having reviewed the entire driver, I realized that it didn&#8217;t contain an interrupt handler. The implication (which was borne out by closer code inspection) was that the I2C driver worked using polling. Now if you have done any work with I2C you will know that it is quite legal for an addressed I2C slave to stretch the clock and to in general take its sweet time responding to read requests. As a result it is quite usual for an I2C transaction to take a millisecond to complete. Throw in the cases where bus contention occurs and the worst case I2C transaction time can rapidly hit multiple milliseconds. Maybe it&#8217;s just me, but I don&#8217;t invest in a 100 MHz Cortex processor to have it spinning its wheels polling an I2C bus. Now while I can accept that in this case the author&#8217;s intention may have been to just demonstrate some basic I2C functionality, at no point in the source code comments or in a readme file did the author state &#8220;WARNING: This driver uses polling and may block for up to N ms&#8221;. IMHO any code that is likely to block must come with the appropriate warnings. The fact that this one doesn&#8217;t tells me a lot about the author&#8217;s attitude to real time response.</p>
<p>I think that will do it for the I2C driver. Next up &#8211; how to make code maintenance hard.</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-3/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Setting a bad example &#8211; part 2</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-2/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-2/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 19:28:48 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=486</guid>
		<description><![CDATA[This is the second part in a series of  articles in which I&#8217;m &#8216;highlighting&#8217; what I consider to be lousy code provided by IAR in their NXP LPC1764 development kit.
The following function is taken from the LCD_Demo project.
/*************************************************************************
 * Function Name: Dly100us
 * Parameters: void *arg
 * Return: void
 *
 * Description: Delay [100us]
 *   [...]]]></description>
			<content:encoded><![CDATA[<p>This is the second part in a <a href="http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-1/">series</a> of  articles in which I&#8217;m &#8216;highlighting&#8217; what I consider to be lousy code provided by IAR in their NXP LPC1764 development kit.</p>
<p>The following function is taken from the LCD_Demo project.</p>
<pre>/*************************************************************************
 * Function Name: Dly100us
 * Parameters: void *arg
 * Return: void
 *
 * Description: Delay [100us]
 *        
 *************************************************************************/
void Dly100us(void *arg)
{
volatile Int32U Dly = (Int32U)arg, Dly100;
 for(;Dly;Dly--)
  for(Dly100 = 500; Dly100; Dly100--);
}
</pre>
<p>An example of the invocation of this function is:</p>
<pre>#define GLCD_RESET_DLY                       50     // 5ms
...
Dly100us((void *)GLCD_RESET_DLY);
</pre>
<p>Quite frankly there is so much to offend one about this function that I&#8217;m not too sure where to begin.</p>
<h2>Software Delay Loops</h2>
<p>Anyone that works on embedded systems works out very quickly that software delay loops are a disaster. Now for low end processors, it is possible to craft a working delay function provided one knows the CPU clock frequency. However in this case, we are dealing with a Cortex 3 processor complete with the usual programmable PLL clock multiplier. Throw in a programmable number of wait states for Flash access, a 3-stage pipeline and of course different compiler optimization settings and it quickly becomes almost impossible to craft a software delay loop that can withstand changes in its environment. The author of this code has made no attempt to accommodate these sorts of changes and as a result this code will fail as soon as almost anything gets changed.</p>
<p>What is particularly bizarre about this example is that the processor has a huge number of hardware timers available &#8211; and yet they are not used.</p>
<h2>void * arguments</h2>
<p>Examination of the code shows that the function is declared as taking a (void *) argument. In crude terms the function expects to receive a pointer to anything. However as the example invocation shows, it is actually being passed an integer constant that has been cast to (void *). Furthermore, within the function, the code then casts the (void *) argument to Int32U. One wonders why on earth Dly100us() isn&#8217;t simply defined to accept an Int32u argument? Furthermore, since I believe it&#8217;s legal to cast just about anything to (void *) the author has insured that almost any parameter coding construct will be accepted by the compiler &#8211; including egregious errors.</p>
<h2>Formatting</h2>
<p>Within the limits of HTML formatting I have attempted to recreate the indentation used by the author. That is the &#8216;volatile&#8217; line starts in the left most column and subsequent lines are indented two spaces. There are no blank lines. Now while I&#8217;m aware that indentation and the use of white space is very much a question of personal preference IMHO the author&#8217;s style leads very much to be desired. In particular I found the code hard to read because of the lack of obvious indentation and also the lack of blank lines between e.g. the variable declaration and the actual code.</p>
<h2>Loops without braces</h2>
<p>Neither of the for loops is enclosed with braces. While I&#8217;m aware this is perfectly legal syntax, just about every coding standard I have ever seen, together with MISRA requires that all loops have braces. This isn&#8217;t a case of the language police enforcing their prejudices upon you. Countless studies have shown that requiring braces helps stop lots of problems. As such it&#8217;s the smart thing to do</p>
<h2>Putting a semi-colon at the end of a for loop</h2>
<p>In a similar vein to the previous remark, putting a semi-colon at the end of a for loop statement is just asking for trouble.  If you really can&#8217;t find the energy to add a couple of braces then at least do this:</p>
<pre>
<pre>for(Dly100 = 500; Dly100; Dly100--)
    ;</pre>
</pre>
<p>It&#8217;s ugly as anything &#8211; but at least its existence is obvious.</p>
<h2>Poor function name</h2>
<p>You will note that the function is called Dly100us(). This is a complete misnomer. The function is actually intended to delay N * 100us where N is the value of the argument passed to the function. Thus the function is incorrectly and misleadingly named.  Most coding standards require that functions have meaningful names.</p>
<h2>Poor variable names</h2>
<p>The author has used two variables that are very similarly named &#8211; Dly and Dly100, Maybe it&#8217;s just me, but I find code much harder to read when variable names are similar. Code that is hard to read is hard to maintain.</p>
<h2>Poor variable data types</h2>
<p>If we ignore the (void *) mess described above, it&#8217;s apparent that the argument to the function is intended to be an Int32U. However does this make sense? If the inner loop does indeed delay for 100 microseconds, then with an Int32U argument, the total delay possible is 2^32 * 100e-6 = 429496.7296 seconds or 119.3 hours. Personally in the rare case that I do use software delay loops, the delays are at most milliseconds &#8211; and not hours. As a result it seems to me that it would make a lot more sense if the argument to Dly100() was an 8 bit or possibly a 16 bit variable. By making this change you could help prevent stupid coding mistakes that result in ridiculous length delays.</p>
<h2>What about the watchdog?</h2>
<p>Most well designed embedded systems encompass a watchdog. This code as written completely ignores the implication of delaying beyond the watchdog interval. Thus a small change to the delay time could easily result in the system taking a watchdog reset.</p>
<h2>Summary</h2>
<p>All in all a dreadfully written function. I shudder to think that there are people out there using this code as a template for their systems.</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-2/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Setting a bad example &#8211; part 1</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-1/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-1/#comments</comments>
		<pubDate>Wed, 04 Aug 2010 11:30:14 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[General C issues]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=482</guid>
		<description><![CDATA[About a month ago I bought an ARM evaluation board from my favorite compiler vendor, IAR  Systems. Like most people I bought the board in part because it comes with a lot of example code showing how to configure the peripherals on the NXP LPC1768. Upon receiving the board, I  hooked it up and started [...]]]></description>
			<content:encoded><![CDATA[<p>About a month ago I bought an ARM evaluation <a href="http://iar.com/website1/1.0.1.0/658/1/?item=prod_prod-s1/487&amp;group=prod_prod_grp-s1/34">board</a> from my favorite compiler vendor, IAR  Systems. Like most people I bought the board in part because it comes with a lot of example code showing how to configure the peripherals on the NXP LPC1768. Upon receiving the board, I  hooked it up and started browsing the example code that came with it. To my dismay I discovered a plethora of what I consider to be shoddy coding practices. Now I am well aware that one person&#8217;s shoddy practices is another person&#8217;s standard operating procedure, and so I intend to steer clear of areas that are just a matter of taste. Notwithstanding this, over the next few posts I will describe some of the things I found in the code &#8211; and more importantly why I think they are shoddy.</p>
<p>Before I describe the first example, I will comment on why I&#8217;m doing this. Three years ago, almost to the day, I <a href="../2007/08/application-notes-code-quality/">wrote</a> about the lousy code that hardware manufacturers supply as part of  their application notes. When I wrote the post I had in the back of my  mind the idea that hardware manufacturers aren&#8217;t really interested in  code and so what should one expect? However when it comes to compiler vendors, what possible excuse do they have? To put it another way, where should engineers go to look for great examples of how to write embedded systems code if not the example code provided by compiler vendors? Do they not have a responsibility to publish code that uses best practices and sets a great example? Furthermore, even if they contracted the code out to some third party to write then I still think it is incumbent upon them to demand (and check) that the code is indeed the sort of code that they want to put their name on?</p>
<p>With all that being said, I will start with an example that is not particularly egregious!</p>
<h2>Right associativity of the = operator</h2>
<p>One of the lesser appreciated aspects of the C programming language is that the assignment (=) operator associates right to left. As a result the following is perfectly legal code.</p>
<pre>uint16_t a,b,c;

a = b = c = 6;
</pre>
<p>This code has the effect of setting all three variables to the value of 6. With that as a preamble, I found that the author of the evaluation board code loves this construct &#8211; even when it is inappropriate. For example consider this excerpt.</p>
<pre>/*************************************************************************
 * Function Name: GpioInit
 * Parameters: void
 * Return: void
 *
 * Description: Reset all GPIO pins to default: primary function
 *
 *************************************************************************/
void GpioInit(void)
{
 // Set to inputs
 FIO0DIR = \
 FIO1DIR = \
 FIO2DIR = \
 FIO3DIR = \
 FIO4DIR = 0;

 // clear mask registers
 FIO0MASK =\
 FIO1MASK =\
 FIO2MASK =\
 FIO3MASK =\
 FIO4MASK = 0;

 // Reset all GPIO pins to default primary function
 PINSEL0 =\
 PINSEL1 =\
 PINSEL2 =\
 PINSEL3 =\
 PINSEL4 =\
 PINSEL7 =\
 PINSEL8 =\
 PINSEL9 =\
 PINSEL10 = 0;
}
</pre>
<p>So why don&#8217;t I like this code? Well I have several complaints.  The main problem is that in my opinion one should only make use of the right associative property of the assignment operator if it is <strong>essential</strong> that multiple variables have the same starting value. That is, if I have a piece of code that can only possibly work if two variables start with the same value, then I will make use of this construct. For example:</p>
<pre>uint16_t foo, bar;
foo = bar = 21;     /* foo and bar must be equal to each other and start at 21 */
</pre>
<p>If instead it is merely coincidental that two variables start with the same value, then I will put their assignment on separate lines.</p>
<pre>uint16_t foo, bar;
foo = 14;
bar = 14;
</pre>
<p>In the IAR code there is no requirement that the various registers be locked together with a starting value.</p>
<p>My second complaint is that because there is no requirement that the various registers be locked together this code is now a pain to maintain. For example, consider the case where it became necessary to change the value of FIO2DIR to 0&#215;12345678; One would now have to do this:</p>
<pre>
<pre>
<pre>// Set to inputs
 FIO0DIR = \
 FIO1DIR = 0;
 FIO2DIR = 0x12345678;
 FIO3DIR = \
 FIO4DIR = 0;</pre>
</pre>
</pre>
<p>In other words I would have to edit an unrelated line (FIO1DIR) &#8211; which is a recipe ripe for disaster. To drive home this point, consider the case where rather than having to edit FIO1DIR I wanted to change just FIO4DIR. I would say that the likelihood of someone doing this is very high:</p>
<pre>
<pre> // Set to inputs
 FIO0DIR = \
 FIO1DIR = \
 FIO2DIR = \
 FIO3DIR = \
 FIO4DIR = 0x12345678;
</pre>
</pre>
<p>In other words they might not notice the line continuation operator and simply change the value of the register they are interested in. The code would compile; the results would be disastrous.</p>
<p>While I am at it I will opine on the use of the line continuation operator.  While this exists for good reason, it almost never leads to easy to read, easy to maintain code. In short I never use it unless I absolutely have no choice. To use it in a casual manner such as this is not good.</p>
<p>As a final point, I am sure that many people that purchase the evaluation board are quite inexperienced. The GpioInit function excerpted above makes <strong>unnecessary </strong>use of two advanced constructs (right associativity and the line continuation character). Furthermore the use of these constructs doesn&#8217;t make the code better &#8211; it makes it worse! I am quite sure that a novice C programmer would look at this code and be baffled as to what is going on &#8211; possibly triggering a call to IAR technical support.</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/08/setting-a-bad-example-part-1/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Tools to help lower power consumption</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/06/tools-to-help-lower-power-consumption/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/06/tools-to-help-lower-power-consumption/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 00:24:39 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Compilers / Tools]]></category>
		<category><![CDATA[Low Power Design]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=478</guid>
		<description><![CDATA[Regular readers will know that low power designs are an interest of mine. Indeed one of the very  first blog posts I made lamented how difficult it is to ascertain  how much energy it takes to perform various tasks typical to an embedded  system. Thus it was a pleasant surprise to receive [...]]]></description>
			<content:encoded><![CDATA[<p>Regular readers will know that low power designs are an interest of mine. Indeed one of the <a href="../2006/12/wanted-a-new-performance-metric/">very  first blog posts</a> I made lamented how difficult it is to ascertain  how much energy it takes to perform various tasks typical to an embedded  system. Thus it was a pleasant surprise to receive an IAR newsletter today announcing a <a href="http://www.iar.com/website1/1.0.1.0/2563/1/">tool</a> (&#8216;Power debugging&#8217;) that is explicitly designed to help one lower a system&#8217;s power consumption. The tool isn&#8217;t available yet, but if the propaganda is to be believed it should be a very interesting adjunct to the debugging arsenal. The sign up procedure to beta test the tool doesn&#8217;t seem to work properly, but on the assumption that I made it onto the beta tester list I will  post a review once I get my hands on it.</p>
<p>BTW I have to admit I found the name of the article / tool (&#8216;Power debugging&#8217;) a bit confusing in the sense that I interpreted power in the vernacular sense (e.g. &#8216;power walking&#8217;, &#8216;power breakfast&#8217;) rather than the engineering sense. I guess I&#8217;m just a victim of so much marketing hyperbole that I can&#8217;t recognize plain talk any more. Oh well!</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/06/tools-to-help-lower-power-consumption/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evaluating embedded code</title>
		<link>http://embeddedgurus.com/stack-overflow/2010/06/evaluating-embedded-code/</link>
		<comments>http://embeddedgurus.com/stack-overflow/2010/06/evaluating-embedded-code/#comments</comments>
		<pubDate>Sun, 20 Jun 2010 19:22:55 +0000</pubDate>
		<dc:creator>Nigel Jones</dc:creator>
				<category><![CDATA[Coding Standards]]></category>
		<category><![CDATA[Consulting]]></category>
		<category><![CDATA[General C issues]]></category>
		<category><![CDATA[complexity]]></category>
		<category><![CDATA[maintainability]]></category>

		<guid isPermaLink="false">http://embeddedgurus.com/stack-overflow/?p=471</guid>
		<description><![CDATA[One of the interesting aspects of being an embedded systems consultant is that I get to look at a lot of code written by others. This can come about in a number of ways, but most commonly occurs when someone wants changes made to an existing code base and the original author(s) of the code [...]]]></description>
			<content:encoded><![CDATA[<p>One of the interesting aspects of being an embedded systems consultant is that I get to look at a lot of code written by others. This can come about in a number of ways, but most commonly occurs when someone wants changes made to an existing code base and the original author(s) of the code are no longer available. When faced with a situation such as this, it is essential that I quickly get a sense for how maintainable the code is &#8211; and thus how difficult changes will be. As a result I have developed a few techniques to help me assess code maintainability which I thought I&#8217;d share with you.</p>
<h2>SourceMonitor</h2>
<p>After installing the code on my system, the first thing I do is run SourceMonitor over the code. <a href="http://www.campwoodsw.com/sourcemonitor.html">SourceMonitor</a> is a free utility that computes various metrics. The metrics and their values for a typical code base of mine are shown below.</p>
<p>Number of Files: 476</p>
<p>Lines of code: 139,013</p>
<p>Statements: 61,144</p>
<p>% branches: 6.3%</p>
<p>% comments: 41.7%</p>
<p>Functions: 2,509</p>
<p>Average statements / function: 11.8</p>
<p>Max Complexity: 158</p>
<p>Max depth: 9+</p>
<p>Average depth: 0.54</p>
<p>Average complexity: 2.38</p>
<p>Probably the only thing that needs explanation is &#8216;complexity&#8217;. The author of SourceMonitor is not computing the <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">McCabe</a> complexity index, but rather is computing complexity based upon Steve McConnel&#8217;s <a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1277056922&amp;sr=8-1">methodology</a>. The details of the implementation aren&#8217;t particularly important to me, as I&#8217;m more interested in comparative values.</p>
<p>While SourceMonitor helps give me the big picture, it is nowhere near enough &#8211; and this is where it gets interesting.</p>
<h2>Optimization Level</h2>
<p>The next thing I look at are the optimization levels being used. These can be very revealing. For example if a high level of optimization is being used for the debug build then it might be indicative that a non-optimized build either will not fit into the available memory, or possibly that the code doesn&#8217;t run fast enough unless optimization is turned on. Either is indicative of a system that is probably going to be tough to maintain. Conversely if the release build doesn&#8217;t use full optimization then I take this to mean that the code probably doesn&#8217;t work when optimization is turned on. I have <a href="http://embeddedgurus.com/stack-overflow/2008/07/efficient-c-tips-2-using-the-optimizer/">written</a> about this in the past and consider this to be a major indicator of potential code quality problems.</p>
<h2>C-V Qualifiers</h2>
<p>Having looked at the optimization levels, I then perform a grep on the code base looking for the number of instances of &#8216;<em>volatile</em>&#8216; and &#8216;<em>const</em>&#8216;. If the number of instances of <em>volatile </em>is zero (and it often is) and the optimization level is turned way down, then it&#8217;s almost certain that the author of the code didn&#8217;t understand <em>volatile </em>and that the code is riddled with potential problems. Whenever this happens, I get a sinking feeling because if the author didn&#8217;t understand <em>volatile</em>, then there is no chance that he had any appreciation for race conditions, priority inversion, non-atomic operations etc. In short, the author was a PC programmer.</p>
<p>The &#8216;<em>const</em>&#8216; count is less revelatory. If the author makes use of <em>const </em>then this is normally an indicator that they know their way around the compiler and understand the value of defensive programming. In short I take the use of <em>const</em> to be very encouraging. However, I can say that I have known some excellent embedded systems programmers who rarely used <em>const</em>, and thus its absence doesn&#8217;t fill me with the same despair as the absence of <em>volatile</em>.</p>
<p>Incidentally in my code base described above, there are 53 incidences of the use of &#8216;volatile&#8217; (note that I have excluded compiler vendor supplied header files which define all the various hardware registers as volatile). There are also 771 incidences of the the use of <em>const</em>.</p>
<h2>Static qualifiers</h2>
<p>Regular readers of this blog will know I am a big fan of the &#8216;<em>static</em>&#8216; qualifier. Static not only makes for safer and more maintainable code, it also makes for <a href="http://embeddedgurus.com/stack-overflow/2008/12/efficient-c-tips-5-make-local-functions-static/">faster</a> code. In fact, IMHO the case for <em>static </em>is so overwhelming that I find its absence or infrequent use a strong indicator that the author of the code was an amateur. In my example code base, <em>static</em> appears 1484 times.</p>
<h2>Case statements</h2>
<p>Regular readers of this blog also know that I am not a big <a href="http://embeddedgurus.com/stack-overflow/2010/04/efficient-c-tip-12-be-wary-of-switch-statements/">fan</a> of the case statement. While it has its place, too often I see it used as a substitute for thought. Indeed I have observed a strong inverse correlation between programmer skill and frequency of use of the case statement. As a result, I will usually run a grep to see what the case statement frequency is. In my example code, a case statement occurs 683 times, or once every 90 statements.</p>
<h2>Compilation</h2>
<p>All of the above &#8216;tests&#8217; can be performed without compiling the code. In some cases I own the target compiler (or can download an evaluation copy), in which case I will of course attempt to compile the code. When I do this I&#8217;m looking for several things:</p>
<ol>
<li>An absence of compiler warnings / errors. Alan Bowens has <a href="http://codereview.blogspot.com/2010/02/zero-tolerance.html">written</a> concisely and eloquently on this topic. The bottom line &#8211; compilation warnings in the release build are a major issue for me. Note that I&#8217;m more forgiving of compiler warnings in the debug build, since by its nature debug often ignores things such as inline commands, which can generate warnings on some compilers.</li>
<li>The compilation speed. Massive files containing very large functions compile very slowly. They are also a bear to maintain.</li>
<li>The final image size. This is relevant both in absolute terms (8K versus 128K versus 2M) and also in comparison to the available memory. Small images using a small percentage of the available memory are much easier to maintain than large images that nearly fill the available memory.</li>
</ol>
<h2>Lint</h2>
<p>The final test that I perform only rarely is to <a href="http://www.rmbconsulting.us/Publications/use-Lint-For-Code-Analysis.pdf">Lint </a>the code base. I do this rarely because quite frankly it takes a long time to configure PC-Lint. Thus only if I have already created a PC-Lint configuration file for the target compiler do I perform this step. Previously un-linted code will always generate thousands of warnings. However, what I&#8217;m looking for are the really serious warnings &#8211; uninitialized variables, indexing beyond the end of an array, possible null pointer dereferences etc. If any of these are present then I know the code base is in bad shape.</p>
<p>I can typically run the above tests on a code base in an hour or so. At the end of it I usually have a great idea of the overall code quality and how difficult it will be to modify. I would be very interested to hear from readers that are willing to perform the same tests on their code base and to publish the results. (Incidentally, I&#8217;m not trying to claim that my metrics are necessarily good &#8211; they are intended merely as a reference / discussion point).</p>
]]></content:encoded>
			<wfw:commentRss>http://embeddedgurus.com/stack-overflow/2010/06/evaluating-embedded-code/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
	</channel>
</rss>
