<?xml version="1.0"?><rss version="2.0">
<channel>
  <title>Alan&#039;s Ramblings - spi tag</title>
  <link>http://bleaklow.com:80/tags/spi/</link>
  <description>My opinions may be incorrect, but they are my own</description>
  <language>en</language>
  <copyright>Alan Burlison</copyright>
  <lastBuildDate>Wed, 29 Feb 2012 20:50:00 GMT</lastBuildDate>
  <generator>Pebble (http://pebble.sourceforge.net)</generator>
  <docs>http://backend.userland.com/rss</docs>
  <image>
    <url>http://bleaklow.com/images/misc/logo.gif</url>
    <title>Alan&#039;s Ramblings</title>
    <link>http://bleaklow.com:80/</link>
  </image>
  <item>
    <title>Connecting a HL1606 strip to an ATmega</title>
    <link>http://bleaklow.com:80/2011/03/09/connecting_a_hl1606_strip_to_an_atmega.html</link>
    <description>
          I&#039;ve been left &lt;a href=&#034;/2010/05/28/bidirectional_patterns_with_the_hl1606.html#comment1299357384118&#034;&gt;a comment&lt;/a&gt; asking how the HL1606 strips are connected up to an Arduino.  The wiring is really pretty simple, but depends on exactly which ATmega version you have, as the hardware SPI pins vary from MCU to MCU. The following assumes it&#039;s a ATmega328P as used on the more modern Duemilanoves, you&#039;ll need to refer to the MCU documentation and the board schematic to find the correct ports and pins for different Arduino versions.&lt;/p&gt;
&lt;p&gt;The 328P uses the following pins for hardware SPI:&lt;/p&gt;
&lt;pre&gt;
/CS    Port B Pin 2    (Arduino pin 10)
MOSI   Port B Pin 3    (Arduino pin 11)
MISO   Port B Pin 4    (Arduino pin 12)
SCK    Port B Pin 5    (Arduino pin 13)
&lt;/pre&gt;
&lt;p&gt;
I used Timer 2 to drive the fade clock on the strips.  The output of Timer 2 uses the following pin:
&lt;pre&gt;
TIMER2 Port B Pin 1    (Arduino pin 9)
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;The strips themselves have the following labelling on the inputs:&lt;/p&gt;
&lt;pre&gt;
S-I    Fade clock input
D-I    Data input
CK-I   Data clock input
L-I    Data latch input
&lt;/pre&gt;
&lt;p&gt;
So you need to wire up the strip as follows:
&lt;pre&gt;
ATmega      Strip
/CS     to  L-I
MOSI    to  D-I
SCK     to  CK-I
TIMER2  to  SI
&lt;/pre&gt;
&lt;p&gt;
Note that if you want to wire up more than one strip you&#039;ll need to work around the fact that the HL1601 strips don&#039;t implement the SPI protocol properly.  The easiest way is to gate the SCK signal with the /CS line so that when a strip is not being accessed it doesn&#039;t see the data clock.  I&#039;ve detailed the problem and the solution more fully in this &lt;a href=&#034;2010/05/27/how_the_hl1606_really_works.html&#034;&gt;earlier post&lt;/a&gt;,
&lt;/p&gt;</description>
      <category>Arduino</category>
    <category>Tech</category>
    <comments>http://bleaklow.com:80/2011/03/09/connecting_a_hl1606_strip_to_an_atmega.html#comments</comments>
    <guid isPermaLink="true">http://bleaklow.com:80/2011/03/09/connecting_a_hl1606_strip_to_an_atmega.html</guid>
    <pubDate>Wed, 09 Mar 2011 23:29:00 GMT</pubDate>
  </item>
  <item>
    <title>Radio-controlled HL1606 strips</title>
    <link>http://bleaklow.com:80/2011/01/15/radio_controlled_hl1606_strips.html</link>
    <description>
          &lt;p&gt;
Well, I&#039;ve finally finished the design and implementation of the radio-controlled LED strips I&#039;ve been asked to make for &lt;a href=&#034;http://travellinglightcircus.com/&#034;&gt;The Travelling Light Circus&lt;/a&gt;.  It&#039;s taken far longer than I expected, but I&#039;ve learned an immense amount in the process.  The remaining tasks are to construct some more boards, put the boards into suitable enclosures and to sort out how best to package and connect the strips, so now seems like a good point to write up what was involved in the project.  Some of the items are worthy of posts of their own, but first I&#039;ll give an overview of how everything fits together.  The system is composed of two parts, a single controller and a number of LED strip drivers.  The controller is used to select the required pattern and to synchronise the LED drivers, with the communication being done with 2.4GHz radio transceivers.  I&#039;ve put a video together to show everything in operation, and there are some annotated photos of the controller and LED strip drivers at the start.
&lt;/p&gt;
&lt;p&gt;
&lt;object width=&#034;560&#034; height=&#034;340&#034;&gt;&lt;param name=&#034;movie&#034; value=&#034;http://www.youtube.com/v/BXAnan8zkC0?fs=1&amp;amp;hl=en_GB&amp;amp;color1=0x234900&amp;amp;color2=0x4e9e00&#034;&gt;&lt;/param&gt;&lt;param name=&#034;allowFullScreen&#034; value=&#034;true&#034;&gt;&lt;/param&gt;&lt;param name=&#034;allowscriptaccess&#034; value=&#034;always&#034;&gt;&lt;/param&gt;&lt;embed src=&#034;http://www.youtube.com/v/BXAnan8zkC0?fs=1&amp;amp;hl=en_GB&amp;amp;color1=0x234900&amp;amp;color2=0x4e9e00&#034; type=&#034;application/x-shockwave-flash&#034; allowscriptaccess=&#034;always&#034; allowfullscreen=&#034;true&#034; width=&#034;560&#034; height=&#034;340&#034;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;/p&gt;
&lt;h1&gt;Hardware&lt;/h1&gt;
&lt;p&gt;
As I&#039;ve said, the hardware consists of two parts, the controller and the LED strip driver.  At the moment these are made using discrete parts on a hand-built breadboard, but version 2 will be a PCB with most of the components mounted directly on the PCB.
&lt;/p&gt;
&lt;h2&gt;Controller&lt;/h2&gt;
&lt;p&gt;
The controller consists of the following parts:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#034;http://www.arduino.cc/en/Main/ArduinoBoardProMini&#034;&gt;Arduino Pro Mini&lt;/a&gt;.  This uses a ATMega328p microcontroller and runs the controller software.&lt;/li&gt;
&lt;li&gt;4-digit 7-segment display, from &lt;a href=&#034;http://www.sparkfun.com/products/9767&#034;&gt;SparkFun&lt;/a&gt;.  Whilst this works, getting it to work cause me an inordinate amount of problems, as I documented in an &lt;a href=&#034;/2010/08/28/sparkfun_are_less_than_electrifying.html&#034;&gt;earlier post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Voltage regulator - a 7805, which I&#039;ve discussed in an &lt;a href=&#034;/2010/06/30/characterising_the_7805.html&#034;&gt;earlier post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#034;http://www.nordicsemi.com/index.cfm?obj=product&amp;act=display&amp;pro=94&#034;&gt;nRF24L01+&lt;/a&gt; radio transceiver.  This a a reasonably complicated SPI device, capable of working in several different modes.  I&#039;m using a &lt;a href=&#034;http://www.sparkfun.com/products/691&#034;&gt;breakout board&lt;/a&gt; from SparkFun, but in future revisions the radio chipset will probably be integrated onto the controller PCB.&lt;/li&gt;
&lt;li&gt;A rotary encoder/switch used to select and activate the required pattern.  I&#039;ve already discussed this in an &lt;a href=&#034;/2010/09/23/switch_debouncing_the_hard_and_the_soft_way.html&#034;&gt;earlier post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A simple voltage divider to sense external battery voltage and shut down when the battery is discharged.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;LED strip driver&lt;/h2&gt;
&lt;p&gt;
The LED strip drivers consist of the following parts:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Arduino Pro Mini.  This runs the software that drives the LED strips.&lt;/li&gt;
&lt;li&gt;A nRF24L01+ radio transceiver, which receives the control and timing messages from the controller.&lt;/li&gt;
&lt;li&gt;74125 glue logic to make the HL1606 strips behave like proper SPI devices.  Despite the manufacturer&#039;s claims they aren&#039;t true SPI devices, a topic that I covered at length in an &lt;a href=&#034;/2010/05/27/how_the_hl1606_really_works.html&#034;&gt;earlier post&lt;/a&gt;.
&lt;li&gt;Voltage regulators - two 7805 linear regulators.  Two are needed to provide the 4 amps that is required to drive the 4 LED strips.  In future revisions this will probably be replaced by a switched-mode supply as the 7805s get very hot under high load and are quite inefficient, both of which are issues for portable use.&lt;/li&gt;
&lt;li&gt;A simple voltage divider to sense external battery voltage and shut down when the battery is discharged.&lt;/li&gt;
&lt;li&gt;A thermistor used to sense the temperature between the regulators.  When it reaches 60C the strips are turned off to protect the hardware.  When it drops back below 40C the patterns are resumed.
&lt;/ul&gt;
&lt;h1&gt;Software&lt;/h1&gt;
&lt;p&gt;
The software is the most complicated part of the system, and it&#039;s divided into four main parts, described below.  The various parts of both the controller and LED driver are implemented as tasks, implemented using the task manager described in the library section below.
&lt;/p&gt;
&lt;h2&gt;Library code&lt;/h2&gt;
&lt;p&gt;
This is code that is used in the LED strip project but that is used in other projects as well.
&lt;/p&gt;
&lt;h3&gt;SPI master library&lt;/h3&gt;
&lt;p&gt;
The nRF24L01+ radios, the 7-segment display and the LED strips are all SPI devices, so it seemed useful to abstract the core SPI master functionality into a separate library.
&lt;/p&gt;
&lt;h3&gt;nRF24L01+ driver&lt;/h3&gt;
&lt;p&gt;
This driver builds on top of the SPI master library and provides access to the low-level nRF24L01+ functionality such as device configuration and message transmit/receive.
&lt;/p&gt;
&lt;h3&gt;Task library&lt;/h3&gt;
&lt;p&gt;
This library has been described in an &lt;a href=&#034;/2010/07/20/a_very_simple_arduino_task_manager.html&#034;&gt;earlier post&lt;/a&gt;.  It is a simple non-preemptive task scheduler with fixed priority scheduling and a 1 millisecond timer tick.  It is available for download from &lt;a href=&#034;http://bleaklow.com/files/2010/Task.tar.gz&#034;&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;h2&gt;Common code&lt;/h2&gt;
&lt;p&gt;
This is code that is specific to the LED strip project, but that&#039;s shared between both the controller and the LED strip drivers.
&lt;/p&gt;
&lt;h3&gt;Global configuration and LED strip colours&lt;/h3&gt;
&lt;p&gt;
Some aspects of the system such as the colour definitions for the HL1606 strips, timing intervals, radio channels etc are shared between the master controller and the slave LED strip drivers.
&lt;/p&gt;
&lt;h3&gt;Radio message&lt;/h3&gt;
&lt;p&gt;
This is a simple definition of the control messages that are sent from the master to the slaves.
&lt;/p&gt;
&lt;h3&gt;Pattern animator&lt;/h3&gt; 
&lt;p&gt;
Both the master and the slave units run the same pattern animation code.  In the case of the master, the output is a series of synchronisation radio messages that keep the slaves in synchronisation.  In the case of the slaves, the output is a series of SPI commands that drive the LEDs.  This means that if a slave temporarily loses the radio signal from the master, it will continue to display the pattern.  The resonators used on the Arduino pro Mini boards are not very stable, so in early testing it became apparent that the slaves would have to be kept in synchronisation by the master.  To achieve this, the master sends a constant stream of synchronisation messages no more than 13 milliseconds apart to ensure the pattern generators in the slave remain in step.
&lt;/p&gt;
&lt;h3&gt;Animation output and animation fade clock base classes&lt;/h3&gt;
&lt;p&gt;
As the master and the slave are both running the same animation code, the animation output and fade clock output code were implemented as empty base classes, with the master and slave providing implementations appropriate to their roles in the system.
&lt;/p&gt;
&lt;h3&gt;Pattern definitions&lt;/h3&gt;
&lt;p&gt;
As has been noted, both the master and the slave run the same pattern animation code, so they both need access to the pattern definitions.  Each of the 4 strips on the slave are animated separately, so the pattern definitions are a reasonably complex tree of data structures containing colour, movement and timing information that are interpreted at run-time.  The pattern definitions are too large to fit in the ATmega&#039;s limited 2Kb of SRAM, so they are stored in program memory and the subset necessary for the current pattern step is extracted into SRAM and interpreted at run time.
&lt;/p&gt;
&lt;h2&gt;Master controller&lt;/h2&gt;
&lt;p&gt;
The software in the master is implemented as a set of tasks, implemented using the library descried above.  The main program simply initialises the tasks before transferring control to the task scheduler.  The tasks are as follows:
&lt;/p&gt;
&lt;h3&gt;Display driver task&lt;/h3&gt;
&lt;p&gt;
This manages the 7-segment display described in the hardware section above.  Updating the display is not time-critical, so updates are made by saving the new display contents and scheduling the display update when no other high-priority tasks need to run.
&lt;/p&gt;
&lt;h3&gt;Radio transmitter task&lt;/h3&gt;
&lt;p&gt;
The radio task is responsible for transmitting the synchronisation messages via the nRF24L01+.  Transmitting a message consists of storing the message details and scheduling the transmitter task to run.  When it runs the message is transferred to the radio via SPI and transmitted.  As synchronisation is key to the correct operation of the slaves, this is the highest-priority task.
&lt;/p&gt;
&lt;h3&gt;Four animation synchroniser tasks, one per strip&lt;/h3&gt;
&lt;p&gt;
These are derived from the Animation output base class that is defined in the shared code section.  They are called by the pattern animators when the next step for an animation pattern needs to be output, at which point they queue a synchronisation message that is subsequently send by the transmitter task to the slaves.
&lt;/p&gt;
&lt;h3&gt;Four pattern animator tasks, one per strip&lt;/h3&gt;
&lt;p&gt;
Each strip is animated separately, so each requires its own animator instance.  The animators extract the pattern definitions from &lt;a href=&#034;/2010/09/05/progmem_and_gcc_bug_34734.html&#034;&gt;PROGMEM&lt;/a&gt; and interpret them.  At each new step the animators call the synchronisation tasks to output the appropriate synchronisation message.
&lt;/p&gt;
&lt;h3&gt;Encoder/switch handler task&lt;/h3&gt;
&lt;p&gt;
The rotary encoder and switch need to be read and debounced as described in &lt;a href=&#034;/2010/09/23/switch_debouncing_the_hard_and_the_soft_way.html&#034;&gt;this post&lt;/a&gt;.  This task is responsible for doing that.
&lt;/p&gt;
&lt;h3&gt;Voltage monitor task&lt;/h3&gt;
&lt;p&gt;
The voltage monitor task samples the battery voltage every second via a voltage divider.  Once the battery voltage drops below a certain level, the subcomponents of the master are powered down and the ATMega is put into suspend mode.
&lt;/p&gt;
&lt;h3&gt;Interaction and pattern switching objects&lt;/h3&gt;
&lt;p&gt;
These objects simply marshal and redirect the internal messages between the various tasks.  They are called directly by tasks and call non-blocking operations on other tasks, although they themselves are not implemented as tasks.
&lt;/p&gt;
&lt;h2&gt;Slave LED strip driver&lt;/h2&gt;
&lt;p&gt;
As in the master, the software in the slave is implemented as a set of tasks, implemented using the library descried above.  Again, the main program simply initialises the tasks before transferring control to the task scheduler.  The tasks are as follows:
&lt;/p&gt;
&lt;h3&gt;Four LED strip driver objects, one per strip&lt;/h3&gt;
&lt;p&gt;
These are called by the pattern animators when the next step for an animation pattern needs to be output, at which point they output the new LED settings to the strips via SPI.  They aren&#039;t tasks as they merely transmit the LED setting bytes to the strips.
&lt;/p&gt;
&lt;h3&gt;LED clock object&lt;/h3&gt;
&lt;p&gt;
The LED strips need a fade clock to drive the pattern fades as described in &lt;a href=&#034;/2010/05/26/driving_the_hl1606_using_the_arduinos_hardware_support.html&#034;&gt;this post&lt;/a&gt;.  This object manages the internal ATMega timer that is used to generate the fade timing clock pulses.
&lt;/p&gt;
&lt;h3&gt;Four pattern animator tasks, one per strip&lt;/h3&gt;
&lt;p&gt;
Each strip is animated separately, so each requires its own animator instance.  The animators extract the pattern definitions from &lt;a href=&#034;/2010/09/05/progmem_and_gcc_bug_34734.html&#034;&gt;PROGMEM&lt;/a&gt; and interpret them.  At each new step the animators call the LED strip driver objects and the LED clock object to output the appropriate synchronisation message.
&lt;/p&gt;
&lt;h3&gt;Radio receiver task&lt;/h3&gt;
&lt;p&gt;
This task receives the incoming radio messages from the master, decides which strip they refer to and makes any necessary adjustments.  This could be to switch to a new pattern, to adjust the current pattern step of a strip if it leads or lags the controller, or to adjust the delay until the next pattern step if the clocks on the master and the slave have drifted.
&lt;/p&gt;
&lt;h3&gt;Voltage and temperature monitor task&lt;/h3&gt;
&lt;p&gt;
This task samples the battery voltage and temperature every second via a voltage divider and a thermistor.  Once the battery voltage drops below a certain level, the subcomponents of the slave are powered down and the ATMega is put into suspend mode.  If the temperature exceeds 60C the strips are turned off until the temperature drops below 40C, at which point the pattern output will be resumed.
&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;
This project is reasonably complex for a microcontroller - about 5000 lines of code with the master and slave binaries both being 13K in size.  There are a number of non-obvious design constraints and decisions that I haven&#039;t had space to fully explain in this post, I&#039;m intending to write some follow-ups to explore those areas in more depth.
&lt;/p&gt;</description>
      <category>Arduino</category>
    <category>Tech</category>
    <comments>http://bleaklow.com:80/2011/01/15/radio_controlled_hl1606_strips.html#comments</comments>
    <guid isPermaLink="true">http://bleaklow.com:80/2011/01/15/radio_controlled_hl1606_strips.html</guid>
    <pubDate>Sat, 15 Jan 2011 18:07:19 GMT</pubDate>
  </item>
  <item>
    <title>Waiting for O(1)</title>
    <link>http://bleaklow.com:80/2010/10/19/waiting_for_o1.html</link>
    <description>
          &lt;p&gt;
Due to a misconfiguration the notification emails from my blog weren&#039;t reaching me, so I missed a couple of interesting comments on my earlier &lt;a href=&#034;/tags/hl1606/&#034;&gt;HL1606-related&lt;/a&gt; posts.  The ones from Dan from over at &lt;a href=&#034;http://waitingforbigo.com/&#034;&gt;Waiting for O(1)&lt;/a&gt; were particularly interesting, and he&#039;s written a SPI library for driving the HL1606 as well as other similar LED drivers such as the LPD6803 and WSC2801 - if you are looking for alternatives to the HL1606 he has some links on the &lt;a href=&#034;http://code.google.com/p/fastspi/&#034;&gt;googlecode&lt;/a&gt; page for his project.  Dan is actually doing PMW fading of the strips, so he&#039;s driving them via timer-generated hardware interrupts.  Dan has a lot of useful tips and observations about speed and power limitations he&#039;s run into and how he&#039;s solved them that are well worth checking out, check out &lt;a href=&#034;http://waitingforbigo.com/&#034;&gt;his blog&lt;/a&gt;.
&lt;/p&gt;</description>
      <category>Arduino</category>
    <category>Tech</category>
    <comments>http://bleaklow.com:80/2010/10/19/waiting_for_o1.html#comments</comments>
    <guid isPermaLink="true">http://bleaklow.com:80/2010/10/19/waiting_for_o1.html</guid>
    <pubDate>Tue, 19 Oct 2010 17:14:11 GMT</pubDate>
  </item>
  <item>
    <title>SparkFun are less than electrifying</title>
    <link>http://bleaklow.com:80/2010/08/28/sparkfun_are_less_than_electrifying.html</link>
    <description>
          &lt;p&gt;
As part of my LED strip project I needed a 7-segment display capable of displaying two or more digits.  I could have built something myself, but I&#039;m short of time as it is so the &lt;a href=&#034;http://www.sparkfun.com&#034;&gt;SparkFun&lt;/a&gt; &lt;a href=&#034;http://www.sparkfun.com/commerce/product_info.php?products_id=9767&#034;&gt;kelly green seven-segment serial display&lt;/a&gt; seemed like a good trade-off between cost and speed of implementation.  It can be driven either over a serial link or via SPI.  SparkFun also do the same unit in &lt;a href=&#034;http://www.sparkfun.com/commerce/product_info.php?products_id=9764&#034;&gt;yellow&lt;/a&gt;, &lt;a href=&#034;http://www.sparkfun.com/commerce/product_info.php?products_id=9766&#034;&gt;red&lt;/a&gt; and &lt;a href=&#034;http://www.sparkfun.com/commerce/product_info.php?products_id=9765&#034;&gt;blue&lt;/a&gt;.  The units use a ATMega328 to drive the display, which is the same microcontroller that&#039;s in the &lt;a href=&#034;http://www.arduino.cc/en/Main/ArduinoBoardProMini&#034;&gt;Arduino Pro Mini&#039;s&lt;/a&gt; that I&#039;m using for the project.  I therefore bought two of them from one of SparkFun&#039;s distributors in the UK.
&lt;/p&gt;
&lt;p&gt;
As I&#039;m already using SPI for most of the peripherals, the obvious thing to do was to use the display&#039;s SPI interface to drive it.  I spent an absolute age trying to get the display to work, but no matter what I tried, the output on the display was a seemingly random collection of characters and garbage.  After a &lt;strong&gt;lot&lt;/strong&gt; of wasted time I eventually got it to work &lt;strong&gt;most&lt;/strong&gt; of the time by dropping the SPI clock rate down from the specified 2MHz to 0.5MHz, but even at that it was still glitchy.
&lt;/p&gt;
&lt;p&gt;
I tried unsuccessfully over a period of several weeks to get some help from SparkFun with the problems I was having, first trying the SparkFun IRC channel, then an unanswered question on the &lt;a href=&#034;http://www.sparkfun.com/commerce/product_info.php?products_id=9767#comment_14901&#034;&gt; product page&lt;/a&gt; and then and equally unanswered &lt;a href=&#034;http://forum.sparkfun.com/viewtopic.php?f=14&amp;t=22771&amp;p=105154#p105154&#034;&gt;forum post&lt;/a&gt;.  In the end I emailed their tech support group, and finally got a response.  A 30-mail thread then ensued, with the tech support person playing piggy-in-the-middle between mself and the SparkFun engineer who is responsible for the product.  They had no clue as to what the problem was - initially I suspected that the CLKDIV8 fuse bit had been mis-programmed as the SPI interface would only work at approximately 1/8th of the specified clock rate, but as I didn&#039;t have anything capable of reading them I couldn&#039;t be sure.  Plus, if that was the case I&#039;d expect the serial interface not to work properly either, which wasn&#039;t the case.  The engineer then said he thought that the problem was that the boot loader fuse bits were wrong.  I thought that was hokum as the device doesn&#039;t use a boot loader, but they wanted to send me two new units with the &#039;fixed&#039; fuse bits which they assured me would fix the problem.  I asked instead if they could send me a &lt;a href=&#034;http://www.sparkfun.com/commerce/product_info.php?products_id=8702&#034;&gt;STK500&lt;/a&gt; programmer instead so I could fix the fuse bits myself and end up with something I was probably going to buy anyway but they refused because it was &#034;Too difficult&#034; to arrange.  I wasn&#039;t happy, but agreed to try two new displays.
&lt;/p&gt;
&lt;p&gt;
The displays duly arrived, and to my complete lack of surprise they were just as broken as the original ones.  I fed this back to SparkFun tech support who duly admitted they were completely stumped.  Great.
&lt;/p&gt;
&lt;p&gt;
I then did something I should have done in the beginning, and downloaded the &lt;a href=&#034;http://www.sparkfun.com/datasheets/Components/LED/7-Segment/Serial-7-Seg-v2.zip&#034;&gt;firmware source&lt;/a&gt; for the displays and had a look, at which point the cause of the problems became immediately apparent.  Oh boy, what a complete pile - probably some of the shoddiest code I&#039;ve seen in quite some time.  Here&#039;s a brief description of the issues I found:
&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;
The immediate cause of the problem is the ISR that services the SPI interface.  The ATMega328 is being clocked at 8MHz using the internal oscillator, and when in slave mode the maximum SPI data rate is FCPU/4, i.e. 2Mhz.  Each SPI transaction transfers one byte, which works out at 32 CPU clock cycles per byte.  That means the ISR has to use less than 32 clock cycles if it isn&#039;t to drop data.  The ISR in the code is &lt;/strong&gt;much&lt;/strong&gt; longer than that, not least because it calls a two-page subroutine for each processed byte!
&lt;/li&gt;
&lt;li&gt;
The firmware consists of one .c and one .h file, with all of the global variables and about a quarter of the functions being defined in the .h file rather than the .c file.  Huh?
&lt;/li&gt;
&lt;li&gt;
Globals are shared between the ISRs and the main loop without &lt;strong&gt;any&lt;/strong&gt; of them being declared volatile.  Plus there&#039;s &lt;strong&gt;no&lt;/strong&gt; locking whatsoever around any of the shared multibyte globals - see the &lt;a href=&#034;http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html&#034;&gt;avr-libc documentation&lt;/a&gt; for an explanation of why this is a problem.
&lt;/li&gt;
&lt;li&gt;
Many of the globals are unnecessarily long, e.g. 16 bits to hold a value that ranges from 0 to 4.  Also, multiple variables are used where a single state variable would be sufficient.
&lt;/li&gt;
&lt;li&gt;
The timer delay code is completely bizarre.  There&#039;s a &lt;code&gt;delay_us()&lt;/code&gt; microsecond delay function that takes a delay of up to 2^16 microseconds, yet the &lt;code&gt;delay_ms()&lt;/code&gt; millisecond delay function consists of a string of four &lt;code&gt;delay_us(250)&lt;/code&gt; calls in a loop rather than a single delay_us(1000) call.  No idea why.  Oh, and the comments (such as they are) make absolutely &lt;strong&gt;no&lt;/strong&gt; sense.
&lt;/li&gt;
&lt;li&gt;
There are many other doozies as well, for example &lt;code&gt;switch&lt;/code&gt; statements that only have 1 &lt;code&gt;case&lt;/code&gt;, blocks of code where some members of a set of conditionals are handled by a &lt;code&gt;switch&lt;/code&gt; block and others are handled by &lt;code&gt;if&lt;/code&gt; statements,
&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;
I proved that the ISR overrun was the cause of the problem rather than the SPI data rate by leaving the SPI data rate at 2MHz in the master and inserting a delay between each SPI transaction.  With a 15msec delay, the driver ISR can keep up and the display works correctly.
&lt;/p&gt;
&lt;p&gt;
I fed back the information about the ISR overrun to SparkFun, and included pseudocode for a suggested fix.  The reply I got back was that the engineer had &#034;checked the clock speed again and claimed that the SPI bus was talking at 2MHz&#034;.  Well duh - yeah.  I also asked when I could expect a fix, the reply being that the tech support person had asked the engineer and that &#034;he said it is on his list to review and rewrite the ISR. So no ETA, could take months.&#034;.  I pushed back again, saying that at least the product pages and datasheet should be updated.  As of writing, the product pages still don&#039;t note this issue, but the &lt;a href=&#034;http://www.sparkfun.com/datasheets/Components/LED/7-Segment/SFE-0012-DS-7segmentSerial-v41.pdf&#034;&gt;datasheet&lt;/a&gt; has been updated to say that the SPI interface won&#039;t run above 250kHz, so that&#039;s one small step, at least.
&lt;/p&gt;
&lt;p&gt;
I really don&#039;t think this sorry saga is acceptable.  Yes, SparkFun has offered me a refund, but I&#039;m not quite sure how that&#039;s going to work out when I bought the parts via a distributor - when I asked for a STK500 as compensation, they cited the fact that I&#039;d gone through a distributor as a reason why I couldn&#039;t return the original displays to SparkFun.  I&#039;ve subsequently bought a STK500 anyway so when I eventually find the time I can fix the firmware myself and reprogram the displays, but I really don&#039;t think that having to go down that route is acceptable.  Plus I&#039;ve wasted many hours trying to get these bloody things to work, and in the end &lt;strong&gt;I&lt;/strong&gt; diagnosed the faults in &lt;strong&gt;their&lt;/strong&gt; product - their engineer had absolutely no clue as to why it didn&#039;t work.
&lt;/p&gt;
&lt;p&gt;
As I was still unhappy with the response I&#039;d had, I mailed their customer support manager just under two weeks ago, and as of the date of this post, I&#039;ve still not had a reply, which is just adding insult to injury.
&lt;/p&gt;
&lt;p&gt;
I&#039;ve always been a SparkFun fan in the past, but no more.  Their hardware seems fairly well put together, but if the firmware I&#039;ve looked at is representative, anything with a software component is going to be of extremely dubious quality,  Plus their tech support truly sucks - they had no clue about what the problem was, and as I said I&#039;ve had no reply from the support manager,
&lt;/p&gt;
&lt;p&gt;
Be warned.
&lt;/p&gt;</description>
      <category>Arduino</category>
    <category>Tech</category>
    <comments>http://bleaklow.com:80/2010/08/28/sparkfun_are_less_than_electrifying.html#comments</comments>
    <guid isPermaLink="true">http://bleaklow.com:80/2010/08/28/sparkfun_are_less_than_electrifying.html</guid>
    <pubDate>Sat, 28 Aug 2010 19:10:57 GMT</pubDate>
  </item>
  <item>
    <title>AVR SPI gotcha</title>
    <link>http://bleaklow.com:80/2010/06/13/avr_spi_gotcha.html</link>
    <description>
          I&#039;ve had all sorts of problems getting a SPI radio device to work for the last few days - I wasn&#039;t using the default /SS pin to select the slave as I was reusing some code from another program that already used the default /SS pin for a different device.  For the life of me I couldn&#039;t figure out why I couldn&#039;t get it work reliably unless I used the standard /SS pin - if I used a different pin it sometimes worked, but most of the time didn&#039;t, or it just worked very slowly, or only if I waggled wires - most baffling.  It&#039;s perfectly possible to drive multiple SPI devices using a different /SS pin for each, so I was completely stumped as to what was causing the problem.  Eventually I noticed this in the documentation:
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;blockquote&gt;
If /SS is configured as an output, the pin is a general output pin which does not affect the SPI
system. Typically, the pin will be driving the /SS pin of the SPI Slave. If /SS is configured as an input, it must be held high to ensure Master SPI operation. If the /SS pin is driven low by peripheral circuitry when the SPI is configured as a Master with the /SS pin defined as an input, the SPI system interprets this as another master selecting the SPI as a slave and starting to send data to it.
&lt;/blockquote&gt;
&lt;p&gt;
And then the penny finally dropped - because I wasn&#039;t using the default /SS pin it wasn&#039;t being explicitly configured, which meant it was in the default post-reset state.  The default post-reset state for pins is to be configured for input.  That meant that any noise on the pin would trigger the logic that switched the AVR from SPI master to SPI slave mode, and things would apparently lock up, or generally start behaving oddly.  It was easy enough to confirm this, I simply configured the default /SS pin to be an output pin, even thought I wasn&#039;t using it, and the problem went away.
&lt;/p&gt;
&lt;p&gt;
Moral of the story: When using multiple SPI devices, &lt;strong&gt;always&lt;/strong&gt; use the default /SS pin to control one of them.
&lt;/p&gt;
&lt;p&gt;
Meta-moral of the story: Always re-read the documentation thoroughly when you have unexplained problems :-)
&lt;/p&gt;</description>
      <category>Arduino</category>
    <category>Tech</category>
    <comments>http://bleaklow.com:80/2010/06/13/avr_spi_gotcha.html#comments</comments>
    <guid isPermaLink="true">http://bleaklow.com:80/2010/06/13/avr_spi_gotcha.html</guid>
    <pubDate>Sun, 13 Jun 2010 21:30:00 GMT</pubDate>
  </item>
  </channel>
</rss>

