Go here to sign up for The Embedded Muse.
logo The Embedded Muse
Issue Number 252, January 6, 2014
Copyright 2013 The Ganssle Group

Editor: Jack Ganssle, jack@ganssle.com
   Jack Ganssle, Editor of The Embedded Muse

You may redistribute this newsletter for noncommercial purposes. For commercial use contact jack@ganssle.com. To subscribe or unsubscribe go to https://www.ganssle.com/tem-subunsub.html or drop Jack an email.

Editor's Notes

I'd like to wish a Happy New Year to all of the Muse readers, and express thanks for all of the submissions, ideas and critiques you offered in 2013. Keep 'em coming!

Chuck Petras sent this interesting link to a 1965 book about the the development of punch card tabulation.

A couple of readers pointed to The Night Watch by James Mickens, which is a longish but funny and wonderfully-written story about the "joys" of system programming.

Quotes and Thoughts

Pat Little sent this quote from the FORTRAN manual for Xerox computers: The primary purpose of the DATA statement is to give names to constants; instead of referring to pi as 3.141592653589793 at every appearance, the variable PI can be given that value with a DATA statement and used instead of the longer form of the constant. This also simplifies modifying the program, should the value of pi change.

Tools and Tips

Please submit neat ideas or thoughts about tools, techniques and resources you love or hate.

An Ancient Scope

Succumbing to the wiles of eBay, I recently became the owner of a 1946 Philco 7019 oscilloscope, and thought some readers might be interested in how much test equipment has changed.

Targeted originally at hobbyists and repair people, this device offers little in the way of performance. Rated with a 100 kc (kilocycle, used before KHz was common) bandwidth, strangely at -2 dB, and with 1 volt/inch of vertical and horizontal sensitivity.

A Philco 7019 oscilloscope

The Philco 7019 trying to display a 1 KHz sine wave

Notice the lack of any scale on the 2" CRT. It's impossible to make any sort of quantitative measurements. The time base is a free-running ramp. This predates trigger circuits; to freeze the waveform on the screen one adjusts the time base frequency, which is uncalibrated. A sync circuit feeds some of the signal to the time base to try and make the oscillator sync to the signal's frequency, but it can be hard or impossible to get a stable display. Note that there seems to be a DC line below the sine wave. That's because there's no horizontal blanking; that line is the sweep returning from right to left.

The following shows the ramp that drives the beam from left to right.

Philco 7019 scope horizontal oscillator

The Philco's horizontal oscillator.

The ramp is rounded so the sweep isn't constant, as indicated by the squished sine wave display shown previously. I guess there are parasitics causing the nasty little pseudo-ramps. And look at the amplitude! That's over 200 volts, and I think it's the first time my Agilent has measured anything over 15V.


Inside the Philco 7019 scope

Scope guts

The unit has only 4 vacuum tubes: the CRT of course, one in the power supply, one for the time base (a dual triode 6J6) and finally a 6AU6 single pentode for the vertical amplifier. Though the performance is terrible the design is quite ingenious, and uses custom selector switches to minimize the number of capacitors required. Amazingly, the capacitors haven't dried out after 68 years. It's AC coupled so can't display the DC component of a signal.

There are neither vertical nor horizontal position controls. Instead, one moves a magnet around inside the cabinet to direct the electron beam!

It sold for $66 in 1946, which is about $790 in today's shrunken currency. That was probably a good deal back then; today, for the same price, one can get a pretty good Rigol digital scope, or even a decent brand-new 40 MHz Tektronix.

You can find some pretty good eBay deals on used scopes, but other than for historical interest, stay away from anything like this Philco. Triggered sweep and the ability to make amplitude and time measurements are both absolutely required for any sort of serious or even hobbyist work. But this bit of history is certainly fun!

On Cosmic Rays in Embedded Systems

In response to my comments in the last issue about cosmic-ray induced failures, Bruce Wedding sent this:

In 2000, I was writing software for a medical device which used recyclable "cartridges". These cartridges were calibrated in our office in Houston and flown to hospitals worldwide. The calibration data was stored in a 2Mb SRAM module. Soon after commencing operations, we began experiencing CRC errors on the calibration data, requiring the cartridges to be rejected upon delivery and to be returned unused. This was a serious issue because the cartridges contained an expensive-to-manufacture, rapidly-decaying radioactive element which was useless by the time the device was returned.

In the beginning, all we knew was the memory was corrupt. Our leading theory blamed the SRAM manufacturer for faulty memory. It wasn't until I flew to Vienna, Austria to investigate a failure on-site that we got our first clue. I dumped the entire SRAM image to disk and found our data intact. So I examined the unused, but erased, memory. That is when I noticed a single bit flipped in nearly 2M of memory. A little research led me to discover SBU's encountered in space craft. Plotting our failures on a world map provided support for the theory. The farther the shipping destination was from Houston, hence longer time flying at 35,000+ feet, the more likely the occurrence of corrupt memory.

I proposed a Hamming code solution but ultimately we chose to simply save a copy of the calibration data in FLASH (which we had available) and simply restore corrupt memory upon boot up. Problem solved.

As a side note, when I first presented my "cosmic ray" theory, several engineers literally laughed out loud.

Harold Kraus had some interesting information:

I've been looking at newer dual lock step microcontrollers, nominally developed for safety critical (ASIL D) automotive applications. One case is the MPC5643L: (dual lock step e200 cores) . Another is the Hercules series TMS570LSxxx (dual lockstep Cortex-R4F cores) The point of the dual lock step operation is to detect hard or soft upsets or other bit level faults. With this architecture, there is a high degree of confidence that bit errors are detected, but there being only 2 cores, one fault results in loss of function. With this limitation in mind, quad-core, "double dual" lock step 2oo4 microcontrollers are under development. (what I call "pair and a spare") If one lock step pair detects a fault, the other pair carries on.
A feature of these products is end-to-end ECC -- from reading a word from memory, through all internal bus transfers and computations to writing a word to memory, background silicon automatically corrects and reports single upset events and automatically reports dual upset events (cf. Hamming Code). These designs in particular address the concerns of ISO26262 diagnostic coverage of hardware by hardware BIT.

Printing Pi to a Billion Digits

Larry Marks had and engineering analysis of the joke in the last issue about printing pi to a billion digits:

Let's see...

chars per line

80 Typical for 10 pitch Courier

lines per page


chars per page

4400 Typical for 8.5"x11" paper, 1" margins

pages for 1 billion characters


pages per ream


reams for 1 billion characters

454.54 Assumes printer accepts an entire ream

pages per B/W toner cartridge

2500 Typical consumer cartridge

toner cartridges for 10^9 pages


Toner change time (minutes)

1 Assumes unwrapping/reboxing overlapped

Pages per minute

20 Typical consumer printer

Printing time (minutes)


Printing time (hours)


Printing time (days)


If he had thought to send it to the printer, he would have needed 455 reams of paper and would have had to pause to change the toner cartridge 91 times. It would have taken a little over a week to print the value using a consumer-grade laser printer counting printing time and time to change the toner cartridge. I didn't consider time to add paper--maybe assume two alternating trays and loading while printing. He won't get much sleep either, having to load paper every 25 minutes.

Sort of reminds me of the way Lavabit (Edward Snowden's email provider) delivered their SSL key to the NSA in page-printed format.

A Firmware Engineer's New Year's Resolutions

1) I will work hard to elicit correct specifications, insofar as humanly possible, before starting a project.

2) I will work with the hardware people to produce firmware-friendly hardware.

3) I will carefully document all of my code, including tests and prototypes, as prototypes have a nasty habit of becoming products.

4) I will collect metrics about bugs and examine their root causes.

5) I will carefully measure the real-time behavior of real-time code, like interrupt handlers, to ensure adequate margin and to improve my time-domain estimates.

6) My tests will be extremely comprehensive, and will check boundary conditions.

7) I will petition management for funds for high-quality tools.

8) I will write warning-free code.

9) I will not use global variables unless there is no alternative.

10) I will continue to study the fascinating world of software engineering.

11) I'll keep having fun!


Let me know if you’re hiring embedded engineers. No recruiters please, and I reserve the right to edit ads to fit the format and intents of this newsletter. Please keep it to 100 words.

Joke For The Week

Note: These jokes are archived at www.ganssle.com/jokes.htm.

John Black sent in this oldy but goody:

High School/Jr.High:

         10 PRINT "HELLO WORLD"
         20 END

First year in College:

program Hello(input, output)
         writeln('Hello World')

Senior year in College:

(defun hello
         (cons 'Hello (list 'World))))   

New professional:

#include <stdio.h>
         void main(void)
         char *message[] = {"Hello ", "World"};
         int i;
         for(i = 0; i < 2; ++i)
         printf("%s", message[i]);

Seasoned professional:

#include <iostream.h>
         #include <string.h>
         class string
         int size;
         char *ptr;
         string() : size(0), ptr(new char[1]) { ptr[0] = 0; }
         string(const string &s) : size(s.size)
         ptr = new char[size + 1];
         strcpy(ptr, s.ptr);
         delete [] ptr;
         friend ostream &operator <<(ostream &, const string &);
         string &operator=(const char *);
         ostream &operator<<(ostream &stream, const string &s)
         return(stream << s.ptr);
         string &string::operator=(const char *chrs)
         if (this != &chrs)
         delete [] ptr;
         size = strlen(chrs);
         ptr = new char[size + 1];
         strcpy(ptr, chrs);
         int main()
         string str;


         str = "Hello World";
         cout << str << endl;

Master Programmer:

         library LHello
         // bring in the master library
         // bring in my interfaces
         #include "pshlo.idl"
         cotype THello
         interface IHello;
         interface IPersistFile;
         module CHelloLib
         // some code related header files
         // needed typelibs
         coclass CHello
         cotype THello;
         #include "ipfix.hxx"
         extern HANDLE hEvent;
         class CHello : public CHelloBase
         CHello(IUnknown *pUnk);
         HRESULT  __stdcall PrintSz(LPWSTR pwszString);
         static int cObjRef;
         #include <windows.h>
         #include <ole2.h>
         #include <stdio.h>
         #include <stdlib.h>
         #include "thlo.h"
         #include "pshlo.h"
         #include "shlo.hxx"
         #include "mycls.hxx"
         int CHello::cObjRef = 0;
         CHello::CHello(IUnknown *pUnk) : CHelloBase(pUnk)
         HRESULT  __stdcall  CHello::PrintSz(LPWSTR pwszString)
         printf("%ws", pwszString);
         // when the object count goes to zero, stop the server
         if( cObjRef == 0 )
         #include <windows.h>
         #include <ole2.h>
         #include "pshlo.h"
         #include "shlo.hxx"
         #include "mycls.hxx"
         HANDLE hEvent;
         int _cdecl main(
         int argc,
         char * argv[]
         ) {
         ULONG ulRef;
         DWORD dwRegistration;
         CHelloCF *pCF = new CHelloCF();
         hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
         // Initialize the OLE libraries
         CoInitializeEx(NULL, COINIT_MULTITHREADED);
         CoRegisterClassObject(CLSID_CHello, pCF, CLSCTX_LOCAL_SERVER,
         REGCLS_MULTIPLEUSE, &dwRegistration);
         // wait on an event to stop
         WaitForSingleObject(hEvent, INFINITE);
         // revoke and release the class object
         ulRef = pCF->Release();
         // Tell OLE we are going away.
         return(0); }
         extern CLSID CLSID_CHello;
         extern UUID LIBID_CHelloLib;
         CLSID CLSID_CHello = { /* 2573F891-CFEE-101A-9A9F-00AA00342820 */
         { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
         UUID LIBID_CHelloLib = { /* 2573F890-CFEE-101A-9A9F-00AA00342820 */
         { 0x9A, 0x9F, 0x00, 0xAA, 0x00, 0x34, 0x28, 0x20 }
         #include <windows.h>
         #include <ole2.h>
         #include <stdlib.h>
         #include <string.h>
         #include <stdio.h>
         #include "pshlo.h"
         #include "shlo.hxx"
         #include "clsid.h"
         int _cdecl main(
         int argc,
         char * argv[]
         ) {
         HRESULT  hRslt;
         IHello        *pHello;
         ULONG  ulCnt;
         IMoniker * pmk;
         WCHAR  wcsT[_MAX_PATH];
         WCHAR  wcsPath[2 * _MAX_PATH];
         // get object path
         wcsPath[0] = '\0';
         wcsT[0] = '\0';
         if( argc > 1) {
         mbstowcs(wcsPath, argv[1], strlen(argv[1]) + 1);
         else {
         fprintf(stderr, "Object path must be specified\n");
         // get print string
         if(argc > 2)
         mbstowcs(wcsT, argv[2], strlen(argv[2]) + 1);
         wcscpy(wcsT, L"Hello World");
         printf("Linking to object %ws\n", wcsPath);
         printf("Text String %ws\n", wcsT);
         // Initialize the OLE libraries
         hRslt = CoInitializeEx(NULL, COINIT_MULTITHREADED);
         if(SUCCEEDED(hRslt)) {
         hRslt = CreateFileMoniker(wcsPath, &pmk);
         hRslt = BindMoniker(pmk, 0, IID_IHello, (void **)&pHello);
         if(SUCCEEDED(hRslt)) {
         // print a string out
         ulCnt = pHello->Release();
         printf("Failure to connect, status: %lx", hRslt);
         // Tell OLE we are going away.

Apprentice Hacker:

         $msg="Hello, world.\n";
         if ($#ARGV >= 0) {
         while(defined($arg=shift(@ARGV))) {
         $outfilename = $arg;
         open(FILE, ">" . $outfilename) || die "Can't write $arg: $!\n";
         print (FILE $msg);
         close(FILE) || die "Can't close $arg: $!\n";
         } else {
         print ($msg);

Experienced Hacker:

         #include <stdio.h>
         #define S "Hello, World\n"
         main(){exit(printf(S) == strlen(S) ? 0 : 1);}

Seasoned Hacker:

         % cc -o a.out ~/src/misc/hw/hw.c
         % a.out

Guru Hacker:

         % echo "Hello, world."

New Manager:

         10 PRINT "HELLO WORLD"
         20 END

Middle Manager:

         mail -s "Hello, world." bob@b12
         Bob, could you please write me a program that prints "Hello, world."?
         I need it by tomorrow.

Senior Manager:

         % zmail jim
         I need a "Hello, world." program by this afternoon.     

Chief Executive:

         % letter
         letter: Command not found.
         % mail
         To: ^X ^F ^C
         % help mail
         help: Command not found.
         % damn!
         !: Event unrecognized
         % logout

Advertise With Us

Advertise in The Embedded Muse! Over 23,000 embedded developers get this twice-monthly publication. .

About The Embedded Muse

The Embedded Muse is Jack Ganssle's newsletter. Send complaints, comments, and contributions to me at jack@ganssle.com.

The Embedded Muse is supported by The Ganssle Group, whose mission is to help embedded folks get better products to market faster.