Thursday, December 5, 2013

Take Pitty On Your State Insurance Commissioner

I watched President Obama talk today about administrative remedies that his administration is going to make so that he can make good on his promise of "if I (oops, I mean you) like your insurance plan, you can keep your insurance plan, period."

Either Mr. Obama knows nothing about how insurance companies do their business, or, he knows all too well...

Insurance regulation falls within the purview of state government, since it is not an enumerated power of the United States Constitution.  This means that the insurance companies have to re-apply to the state insurance boards where they sell products, to every state where they sell products, and ask for approval to sell the old products.  And most likely, these will not be under the same rates.  I have never seen this process take shorter than months (having been in the insurance industry).

But, Mr. Obama has done his part.  Blame for losing your plan can now be placed on either the state insurance commissioners or the insurance companies if they decided not to re-instate products for which cannot be sold to new customers (a big waste of time and money), or both.

Problem solved and promise kept!

Monday, December 2, 2013

USB Serial Port Adapter and Other USB Problems on Mavericks (OSX 10.9)

I upgraded to Mavericks yesterday and I have to say it went smoothly, except for the Moschip-based 7720 USB to serial port adapter I use to debug AVR embedded projects.  It worked fine on Snow Leopard.

I also noticed several complaints for these kinds of devices (not just Moschip based devices) on Mavericks.  So, beware...

From my syslog, the following errors were noted:

       
Dec  2 06:51:03 charles-benedicts-macbook.local com.apple.kextd[12]: WARNING - Invalid signature -67062 0xFFFFFFFFFFFEFA0A for kext "/System/Library/Extensions/MCS7720Driver.kext"


Dec  2 06:51:03 charles-benedicts-macbook.local com.apple.kextd[12]: Can't load /System/Library/Extensions/MCS7720Driver.kext - no code for running kernel's architecture.


Dec  2 06:51:03 charles-benedicts-macbook.local com.apple.kextd[12]: Load com.MosChip.driver.MCS7720Driver failed; removing personalities from kernel.
I am not sure whether the "no code" error is because the signature was invalid or whether the driver must be recompiled for 10.9.

Further research yields the following:

       
charles-benedicts-macbook:Extensions chuck_benedict$ sudo kextutil -b kextload -t ./MCS7720Driver.kext
Notice: /System/Library/Extensions/MCS7720Driver.kext has debug properties set.
Diagnostics for /System/Library/Extensions/MCS7720Driver.kext:
Warnings: 
    Executable does not contain code for architecture: 
        x86_64


Code Signing Failure: not code signed
Warnings: 
    Executable does not contain code for architecture: 
        x86_64


WARNING - Invalid signature -67062 0xFFFFFFFFFFFEFA0A for kext "/System/Library/Extensions/MCS7720Driver.kext"


Can't load /System/Library/Extensions/MCS7720Driver.kext - no code for running kernel's architecture.

So I did what I usually do in these cases.  I booted up Linux on Virtualbox and the serial port adapter works fine.

Finally, I have a home-built USBasp programmer that I use for hobby micro-controller projects with Atmel chips.  I had this device plugged into a powered Belkin USB hub and under Snow Leopard, it worked fine.  Since upgrading to Mavericks, the only way I can get it to work is to plug it directly into my Macbook.  Hmph...I don't know why this is, yet.

Thursday, November 14, 2013

Republican Stategery

In the Wall Street Journal this morning (and in many news casts), the reports are all about law makers' desires to fix the Affordable Care Act.

Did I miss something?  Republican strategic ineptness is astounding.

The Republicans practically committed political suicide "shutting down" the federal government.  It is truly amazing to me that so many people got so worked up over not being able to go to the park.  The federal park system did seem like the only government program affected by the "Great Shutdown of 2013."  In any case, Republicans went to the mat over shutting down the federal government over a desire to repeal or change the Affordable Care Act.  It was laudable but foolish.  Democrats would not budge on changing it, period.

Now the Obama administration and Democrats generally claim ignorance to the effect of millions of people losing their ability to renew plans in the individual insurance marketplace.  Never mind it was predicted and documented in the federal register back in 2010.  If you think the current situation is bad, just wait until the employer market is impacted.  In the June 17, 2010 Federal Register on page 34553, a Kaiser Foundation employer survey is quoted that predicts between 39% to 69% of employer plans will lose grandfather status (that is the "if you like your plan, you can keep your plan, period" rule) in 2013.


Message to Republicans: Leave the ACA Alone!  You spent so much capital in the shutdown trying to change the ACA.  You showed that you wanted to make changes for the very reasons that are now becoming known.  But that time has now passed.  As Americans in general and independents in particular see the impact of left-winged Democratic socialism, they will flock back to the Republican party.  All you need to say is vote for Republicans in 2014, and change will be on the way.

Friday, November 8, 2013

HHS Wolves Guarding The Privacy and Security Hen House

As a former technology executive of a health and welfare benefits technology company, I am well versed in privacy and security regulations governing the protection of health information.  Those regulations are promulgated by...wait for it...the U.S. Department of Heath and Human Services, or HHS.  Yes, the very same department responsible for the failed rollout of the insurance marketplaces of 34 states.  If the totality of the problem was simply the inability of HHS to sell insurance products through their web site, that would be one thing...

Security and privacy regulations of "protected health information", or PHI, are governed by a law first passed in 1996 called the Health Insurance Portability and Privacy Act (more commonly know as HIPAA).  That law, associated amendments, and the HITECH act enacted as part of the infamous "shovel ready" American Recovery and Reinvestment Act of 2009 (or ARRA) and their associated regulation have transformed the information technology, data handling, and personnel management environment for companies (or their departments) that deal in personal health information.  There are stiff penalties and disclosure requirements for compliance failures.  The Office for Civil Rights (OCR) maintains a "wall of shame" for those covered entities that have faced enforcement action.

In the businesses where I served, our company would sign "business associate" agreements with our clients.  The purpose of those agreements was ensure that our company and those sub-contractors that we hired would appropriately safeguard protected health information of our client's employees.  Those safeguards were stringent and costly.  They ranged from hiring practices (including background checks) to numerous technological investments, to extensive training and finally a rigorous audit regimen.

This leads me to numerous questions now that the federal government is so involved in the procurement of health care:


  1. Is HHS subject to the HIPAA law?
  2. Is HHS a business associate to the health plans to which they are collecting personally identifiable information for the provision of health care?
  3. Have contractors that HHS is using to build the technology for the marketplaces signed business associate agreements with HHS?
  4. Has an independent auditor (not the OIG, which is again...part of HHS) established an opinion on the appropriateness of operational controls (via a Reporting on Controls at a Service Organization of the SSAE16 auditing standard or other established auditing standard) to assure those using the exchange that their information will in fact be safeguarded?
  5. Will HHS disclose their own privacy violations to the OCR, and will those be posted on their own wall of shame?

Wednesday, November 6, 2013

Katy ISD Board of Trustees, Fix THIS: Portable Education vs. Permanent Football

Following up to my earlier posts, I decided to research the portable education infrastructure that Katy ISD is grappling with.  Ask yourself...is this the best we can do for our kids' public education in a district with vast resources?  I believe (I hope) this is why the November 5 bond did not pass.  KISD Board of Trustees - please prioritize the elimination of portable education first prior to providing for more permanent football.

Katy Elementary Schools

Fun Facts: 35 elementary schools, 27 schools with portable buildings representing 77% of the schools with temporary classrooms, and 174 portable buildings in all.  This information derived from pictures from Google Maps.

Fun Conjecture: Each portable building holds two classrooms (this I know because I attended classes with my daughter), each classroom holds ~20 kids, and lets assume 80% occupancy (this is a WAG), so that is 174 * 2 * 20 * 0.8 = 5,568 children in portable education facilities.  Of the 30,602 elementary students (derived from page 35 of this presentation), I estimate ~18% are attending class in portable buildings.  Ask yourself: how many elementary school students participate in extracurricular activities that would be hosted at the new proposed football stadium?  I am going to guess none, zero.  So, $70MM that benefits none of the 30,000 elementary students while 1/5 of them attend class in temporary facilities.  Hmm...




































Katy ISD Board of Trustees: Reset Your Priorities

The voters spoke on November 5th and it was not even close.  Katy ISD voters, by a 55 to 45 margin, said no to extravagance over education.  The area's rapid growth has strained basic infrastructure.  In my last blog, I wrote about my experience in my daughter's overcrowded elementary school.  That school is not an exception.  In the coming weeks, I intend to document, for the benefit of Katy ISD Trustees, the scope of the problem.

This was never a battle over taxes, per se, or whether a new stadium was actually needed, or whether the trustees played loose with the justification.  A new stadium probably is justifiable.  A STEM center IS warranted (the Wall Street Journal just this morning has an article documenting MBA migration away from finance to tech).  The Ag Center is in keeping with the cultural roots of the area.  This is simply a statement about priorities.  Cover the basics first...adequate classrooms and adequate transportation.

I hope Katy ISD Board of Trustees got the message, but lets not rely on one ballot box defeat.

Thursday, October 31, 2013

Open Letter to Katy ISD Board of Trustees: Your priorities are wrong

I live in Grand Lakes, a subdivision in the Katy Independent School District. We could live anywhere, but my wife and I choose to live here with our two daughters because of the outstanding school system in this far west Houston suburb.  My daughters attend Beckendorf Junior High and Alexander Elementary.  Our property taxes are high, but I accept it because I believe that the educational value for the dollar is good.  Both of these schools are outstanding.

On November 5th, 2013 voters will decide on a $99 million bond referendum to build a $69.5 million stadium, a $25 million agriculture science center, and a $4.5 million science, technology, engineering, and math education center.  Mr. Bill Moore, CFO of Katy ISD is quoted in the October 31, 2013 newspaper The Rancher to the effect that taxes will not have to be raised to pay for the bonds.  I have no reason to doubt the assertion.  Set aside for a moment then, that if true, it means that our tax rate is higher than it needs to be...

I walked around the Alexander Elementary campus numerous times yesterday, as I participated in the very rewarding Watch D.O.G.S. program sponsored by our local PTA.  I also sat inside my daughter's classrooms.  The 5th grade is mostly situated in outdoor portable buildings.  Alexander has 11 of them.  They are windowless and cramped.  What struck me the most was the disruption caused by kids having to get in and out of the classroom.  The doors, rightly, because the buildings are outside on the generally unsecured campus grounds, are automatically locked.  You need a key to get in to the classroom and also to the main building.  There is one key in each classroom, and so when kids need to go the the library, or the bathroom, etc., a student "key master" as I called him, goes with the kids so they can be let back in as a group.  Otherwise, someone is constantly opening the door to let students in.  Frankly, it was insane.  But I marveled at how the students managed to focus on their work.

Katy ISD Trustees, on this bond issue, you have your priorities wrong.  Is it really necessary to build a $70 million stadium when our kids' classrooms are like this?  I have a suggestion...allocate money to existing schools to get kids out of portable buildings, build a modest stadium with basic bleachers, and use the existing portables freed up from the schools for any indoor needs at the stadium.  My guess is that this can be done without raising taxes too, and it will delay the need to raise them some time in the future.

I voted no on this bond.  Do not interpret that vote as a failure to acknowledge facility needs (extracurricular needs included).  I voted no because the priorities were wrong.  Forego extracurricular extravagance and favor frugality.  Mr. John Eberlan, stadium design bond committee member, states that "some fans will be turned away during marquee play-off matchups due to capacity issues."  If that happens with something more modest, so be it.  Build facilities for education first and extra curricular activities second.

Wednesday, September 25, 2013

Spoiled Pi

Background

I built what I called a "Cloud Scanner" interface for my older but functional HP Laserjet 3055 multi-function office printer some time ago.  I built it with a Raspberry Pi and a 2-line Hitachi-compatible LCD and some momentary contact push buttons for navigation.  The idea of the device is that I want to be able to easily and rapidly get paper "into the cloud".  No turning on a connected computer (waiting for boot-up...ok, I have a Mac so this is not too big a deal for me, but God help you Windows folks), no finding the typically crummy proprietary scanning application, no figuring out how to convert the scan that results into the universal electronic paper (PDF), no fumbling around with a transfer program (email, Google Docs, or the like).  No, I just want to walk up, put in my papers to the document feeder, push a button, and have my electronic paper show up in the cloud.  One step.

I built it and all was well, until...

My wife came to me and said the scanner was not working.  She became a fan of my little device and grew to rely on it.  She has a vacation rental business and so does a lot of rental agreement processing.  She sends paper to her email all the time.  So off I go to diagnose.  Turns out...corrupt SD RAM card.  After some Googling, it seems that many RPi users are having the same problem.  Secretly, I kinda knew this.  We had a power failure a day or two prior and I don't think it was coincidence.  This has happened to me in the past and all I had to do was eject the card, mount it in a Linux machine, and run fsck on the volume.  This time...ouch.  The card was totally unrecoverable.

This hurt.  Of course I did not have a backup.  Back to the drawing board...

So this time, I start looking for what the Linux router crowd has been doing for years (with read-only Linux'es and busybox, for example).  The only solution I stumbled on, aside from numerous blogs with varying cookbooks to be performed against Raspbarian, is a distro built by NutCom Services Ltd.  This post chronicles my experience and gives you a mini how-to if you want to build your own.  I use a MacBook for development work, so all instructions will be given in that context.

Re-Baking the Pi

Installing IPE

  1. You'll need a command prompt.  On the Mac, it's terminal.
  2. Download the Industrial Perennial Environment (IPE) and unzip it.
  3. Insert your SD card (must be 1GB or greater) and figure out which volume it mounts up as.  I used:
    $ df -lh
  4. If there is already a formatted volume on the card (usually there is), unmount it:
    $ sudo diskutil umount "/Volumes/NO NAME"
  5. From the directory where the ipe_r1.img file is located, type (NOTE - /dev/disk2 is where my SD card was located...ymmv and don't blame me if you wipe out something important.  This command is destructive and unforgiving!):
    $ sudo dd if=ipe_r1.img of=/dev/disk2 bs=1m
  6. Put the card into the Pi and boot it.  Since I did not have a monitor and keyboard hooked up to mine, I used my router to figure out what IP address was given to the Pi.  Note - The IPE distro only starts up with TELNET for remote access!  It took me a while to figure this out.  I had to hook up a monitor and keyboard to learn that sshd was not started (never fear, keep reading).  Log into the Pi using root with password root.
    $ telnet 192.168.1.122
  7. A very nice command script was written by NutCom that resizes your SD card volume to the max it can be (defaults to 1GB upon install) and then generates an SSH private key, turns on sshd, resets the root password, and turns off telnet.  Run TWICE (there is a reboot in between if memory serves).
    $ firstboot
    $ firstboot
  8. I am always in the habit (and one of the reasons I gravitate to Debian-based distros - apt rocks) of updating software upon a new install.  So this step would be to tell you to run apt-get update and apt-get upgrade.  But I ran into problems with this distro.  There is a script you can run that will set of the Pi volume for read-write, which you obviously need to do to update software.  But what it does not do is change to /boot volume.  Therefore, I got the following errors:
    rm: cannot remove `/boot/bootcode.bin': Read-only file system
    dpkg: error processing raspberrypi-bootloader (--configure):
     subprocess installed post-installation script returned error exit status 1
    dpkg: dependency problems prevent configuration of libraspberrypi0:
     libraspberrypi0 depends on raspberrypi-bootloader (= 1.20130617-1); however:
      Package raspberrypi-bootloader is not configured yet.
    dpkg: error processing libraspberrypi0 (--configure):
     dependency problems - leaving unconfigured
    dpkg: dependency problems prevent configuration of libraspberrypi-dev:
     libraspberrypi-dev depends on libraspberrypi0 (= 1.20130617-1); however:
      Package libraspberrypi0 is not configured yet.
    dpkg: error processing libraspberrypi-dev (--configure):
     dependency problems - leaving unconfigured
    dpkg: dependency problems prevent configuration of libraspberrypi-doc:
     libraspberrypi-doc depends on libraspberrypi0 (= 1.20130617-1); however:
      Package libraspberrypi0 is not configured yet.
    dpkg: error processing libraspberrypi-doc (--configure):
     dependency problems - leaving unconfigured
    dpkg: dependency problems prevent configuration of libraspberrypi-bin:
     libraspberrypi-bin depends on libraspberrypi0 (= 1.20130617-1); however:
      Package libraspberrypi0 is not configured yet.
    dpkg: error processing libraspberrypi-bin (--configure):
     dependency problems - leaving unconfigured
    Errors were encountered while processing:
     raspberrypi-bootloader
     libraspberrypi0
     libraspberrypi-dev
     libraspberrypi-doc
     libraspberrypi-bin
    E: Sub-process /usr/bin/dpkg returned an error code (1)
  9. Set the Pi root volume to read/write.
    $ ipe-rw
  10. Modify the /sbin/ipe-rw file as follows:
    #!/bin/sh
    echo Remounting rootFS for R/W! Use \"ipe-ro\" to lock it again!
    mount / -o remount,rw
    mount /boot -o remount,rw
  11. Modify the /sbin/ipe-ro file as follows:
    #!/bin/sh
    echo Remounting rootFS for R/O!
    mount / -o remount,ro
    mount /boot -o remount,ro
    
  12. Now update the distro (need to re-execute read-write script):
    $ ipe-rw
    $ apt-get update
    $ apt-get upgrade
  13. Base Pi install, immune to SD card corruption (at least so far for me), is now good to go!

Caveat

When updating the Pi, I encountered a situation that I cannot reproduce where DHCP assigned DNS addressing no longer worked (it did at initial install).  It may be that the upgrade process overwrote /etc/resolv.conf and because of the read-only nature of the root volume, it could not get reset.  When I manually updated it with my routers' address, everything was fine.  I intend to ping NutCom after authoring this to see if they have any experience with this.

Base Packages and Dependencies

The following base software is needed by the Cloud Scanner device:

$ apt-get install sane libsane sane-utils libsane-hpaio
$ apt-get install libtiff-tools imagemagick
$ apt-get install python-dev python-pip
$ pip install RPIO
$ pip install RPLCD

The Hardware

I used a HD44780 compatible LCD display and 4 momentary push button switches for the user interface.  I used the onboard power supply on the Pi to power these peripherals, which is just enough (and also contingent on how you are powering the device and what else beside a connection to your scanner you may have plugged into the USB port).

Cloud Scanner Schematic

The Software

I have put my project on github.  Instructions on how to install it are located in the github readme.

There are three options from the main menu: Green button =  Scan now, White button = select an email destination, and Blue button = select a paper size.  The program will scan from the first scanner it finds (which may be a limitation I realize...it's on my list).

One additional thing you will need to do, since the scan program will put all working files in /tmp, is to expand the size of the tmpfs volume.  To do that, edit /etc/default/tmpfs, find the TMP_SIZE parameter, uncomment it, and change it to 200M.

Enhancements

Nothing is ever completely done, is it?
  1. Add a More> submenu to the black button so more options can be added.
  2. Add a scanner selector.
  3. Add an automatic document feeder vs. flatbed option (defaults to ADF but I do have a flatbed-only scanner and it will currently work).
  4. Add more destination types, like to Dropbox, Google Docs, Amazon S3, ftps, etc.
  5. Add a duplex assembly option (for double-sided pages).
  6. Add a web interface to manage the settings.

The Result

For the "enclosure", I was inspired by a project that I saw that used discarded CDs and CD protectors.  Since I have plenty of those, I made one myself.  It worked pretty well.


Tuesday, September 24, 2013

Advanced Arduino Sound Synthesis

I read with interest Jon Thompson's skill builder article Advanced Arduino Sound Synthesis in Make: Magazine.  I have always been interested in electronics, sound, amplification, and music of all kinds, and found myself with some time to explore.  So, I broke out my Atmel chips and o'scope and started experimenting.  I write here about the things that I got hung up on while really trying to understand all of the great information presented in the article.

The first thing I had to deal with was that Jon used the Arduino Nano v3.0 board.  I don't have one of those.  The microcontroller on those boards is the Atmel ATmega328.  I tend to do lots of breadboarding (before Arduino became popular) and have a stock of the older ATmega8 chips.  So, no big deal, they are very similar to the 328 chips.

Since the article is about the Arduino, it is natural that all the source code is based on the Arduino libraries.  I am a command line guy, so I typically use avr-gcc and make tools, along with my trusty home-made USBasp programmer.  I often viewed Arduino as eye-candy that got in the way of the "real programming."  But since Arduino has take over the world, I figured now was the time to see what it was all about.  So I downloaded the Mac version of the IDE, and of course went for the V1.5.4 beta.

The first question I asked myself was "how do I get the Arduino bootloader on a blank ATmega8?"  After some quick research, I realized that you don't have to.  The Arduino IDE has an "Upload Using Programmer" option right off the File menu.  And, the USBasp programmer is supported out of the box (Tools/Programmer).  Nice.

Next problem.  How do you target the build for the ATmega8 on a breadboard?  The closest setting I found was "Arduino NG or older".  So I got listing_2 from the article to generate a series of waveforms, slapped it in the IDE, and viola...errors.

I soon realized that the errors were not due to a targeting problem, but instead because the code was written for the 328.  It referenced registers that the ATmega8 did not have.  But the good news is that the two timers needed for the example (Timer1 and Timer2) worked just fine on the ATmega8.  I just had to correct the registers.  The modified listing_2 follows:

       
# define DEBUG 0

/******** Load AVR timer interrupt macros ********/
#include <avr/interrupt.h>

/******** Sine wave parameters ********/
#define PI2     6.283185 // 2 * PI - saves calculating it later
#define AMP     127      // Multiplication factor for the sine wave
#define OFFSET  128      // Offset shifts wave to just positive values

/******** Lookup table ********/
#define LENGTH  256  // The length of the waveform lookup table
byte wave[LENGTH];   // Storage for the waveform

/******** Waveform parameters ********/
#define SINE     0
#define RAMP     1
#define TRIANGLE 2
#define SQUARE   3
#define RANDOM   4

#if DEBUG
volatile byte timer1_start = 0;
volatile byte timer1_end = 0;
#endif

void setup() {

  /******** Populate the waveform lookup table with a sine wave ********/
  waveform(SINE);                      // Replace sine with the different cases to
                                        // Produce the different waves
#if DEBUG
  // Keep this speed low becuase there are not many cycles left
  Serial.begin(2400);
#endif
  
  /******** Set timer1 for 8-bit fast PWM output ********/
  pinMode(9, OUTPUT);       // Make timer's PWM pin an output
  TCCR1B  = (1 << CS10);    // Set prescaler to 1 - full 8MHz
  TCCR1A |= (1 << COM1A1);  // PWM pin to go low when TCNT1=OCR1A
  TCCR1A |= (1 << WGM10);   // Put timer into 8-bit fast PWM mode
  TCCR1B |= (1 << WGM12); 

  /******** Set up timer 2 to call ISR ********/
  TCCR2 = (1 << CS20);      // Set prescaller to divide by 1
  TIMSK = (1 << OCIE2);     // Set timer to call ISR when TCNT2 = OCR2
  OCR2 = 128;               // sets the frequency of the generated wave
                            // 8Mhz / (OCR2 = 128 * 256)...in this case, 244 Hz
  sei();                    // Enable interrupts to generate waveform!
}

void loop() {  // Nothing to do!
#if DEBUG
  static int diff = 0;
  // This might be negative...ignore it
  diff = timer1_end - timer1_start;
  Serial.println(diff);
  delay(1000);
#endif
}

/******** Called every time TCNT2 = OCR2 ********/
// Question here is...what should be the offset time to set
// TCNT2 given that the timing of my chip is different than the author
// (and maybe even the compiler).
ISR(TIMER2_COMP_vect) {  // Called each time TCNT2 == OCR2
  static byte index=0;    // Points to successive entries in the wavetable
#if DEBUG
  timer1_start = TCNT1L;
#endif
  OCR1AL = wave[index++]; // Update the PWM output
  TCNT2 = 33;  // Timing to compensate for time spent in ISR
#if DEBUG
  timer1_end = TCNT1L;
#endif
}


void waveform(byte w) {
 switch(w) {

   case SINE: 
    for (int i=0; i<LENGTH; i++) 
      {float v = OFFSET+(AMP*sin((PI2/LENGTH)*i));
      wave[i]=int(v);
    }
    break;

  case RAMP:
    for (int i=0; i<LENGTH; i++) {
      wave[i]=i;
    }
    break;

  case TRIANGLE:
    for (int i=0; i<LENGTH; i++) {
      if (i<(LENGTH/2)) {
        wave[i]=i*2;
      } else {
        wave[i]=(LENGTH-1)-(i*2);
      }
    }
    break;
    
  case SQUARE:
    for (int i=0; i<(LENGTH/2); i++) {
      wave[i]=255;
    }
    break;

  case RANDOM:
    randomSeed(2);
    for (int i=0; i<LENGTH; i++) {
      wave[i]=random(256);
    }
      break;
  }
}

After I got the coding errors fixed, the sketch compiled and uploaded easily.  You can see my rig here (the board on the left is like the Nano...that I designed years ago, but it plugs directly into the power rails on the breadboard):



There are a couple of enhancements I made along the way.  Notice in the original interrupt service routine (ISR), Jon makes reference to two lines that are designed to account for time spent in the ISR:

       
/******** Called every time TCNT2 = OCR2A ********/
ISR(TIMER2_COMPA_vect) {  // Called each time TCNT2 == OCR2A
  static byte index=0;    // Points to successive entries in the wavetable
  OCR1AL = wave[index++]; // Update the PWM output
  asm("NOP;NOP");         // Fine tuning
  TCNT2 = 6;              // Timing to compensate for time spent in ISR
}

Notice the NOP and TCNT2 = 6 lines.  I had no idea what I should change these values to.  For one thing, I changed the prescale of Timer2 to 1 instead of 8, so that I could get higher frequencies out of the test (this makes the formula 8MHz / (OCR2 * 256)).  Also, my chip is running at 8MHz vs. 16MHz (for the 328).

I always say, if it offends thee, take it out.  So when I set OCR2 = 128 and took the timing lines out, what I got was the following (126 Hz):


This is clearly not right, and expected, as OCR2 is supposed to set the overflow value for the next value in the waveform table.  But that assumes an instantaneous change.  While the ISR routine does not have much in it, it still takes some clock ticks to execute, but how many?  I am expecting to see 244 Hz (8,000,000 / (128 * 256)).

Through trial and error, I got to a setting of TCNT2 = 33:


But I continued to ask myself...how do I make this more scientific?  I might have expected Jon's value of 6 scaled to account for my slower processor (8 MHz / 16 MHz) and scaled up by the prescale factor difference (8 for his vs 1 for mine).  This would yield 24 plus two ticks for the NOPs, or 26.  33 is off by more than 10%, so how can I figure this out (and how did he...it is not in the article)?

One way is to look at the assembler from the compiler and try to discern the number of clock ticks.  This is beyond what I was willing to do.  But after looking at AVR136 Application Note and studying the code, I realized that I could just time the routine by capturing the timer counter before and after the code executed.  So, if you study my code, you will note a DEGUB symbol that causes that timer difference to be written to the UART0 serial console.  So what was the result?  17.

Hmph!  Where is the other missing time?  I occurred to me that the interrupt service routine must have some overhead associated with it, and it may well be compiler specific.  More Googling...

What I found was this AVR Interrupt Response Time posting by an Atmel engineer.  The answer is 8 to 11 cycles plus any extra time preserving registers (which is a compiler specific optimization).  This jives with 33 - 17 = 16 answer I was looking for.

Here is a final side note.  When I put in the console debugging code, I noticed that I could not get the baud rate specified in the sketch to match the setting I needed to put in to my terminal emulator to see expected results.  I had to specify a baud value 1/2 of that in the sketch.  Having run into this in past projects, I recognized that this must be a clock rate problem in the f_cpu compile directive.  So the Arduino board settings are now coming back to haunt me.  The Arduino NG board runs at 16MHz.  Because I was really into using the Arduino IDE, I figured out how (with much difficulty) to create board files for a breadboarded ATmega8 at different clock rates.  You can see (and use if you want) the result of that work at my github project chuckb/atmega.