brainwagon "There is much pleasure in useless knowledge." — Bertrand Russell

14Jan/122

A phrase I don’t like: “Dumbing down.”

We've all heard it (and most of us have said it): "X is just a dumbed down for the masses." Heck, I came dangerously close to saying it myself in today's earlier rant. But I didn't say it, and I try not to, because I think it's not really very useful.

First of all, if you really are a beginner, you probably need things to be dumbed down, at least a little. For instance, as a relative beginner working to self-educate himself in the field of electronics and RF design, I learned that diodes pass current in one direction, but not the other. This is a "dumbed down" version of diodes: they actually have a forward voltage drop, and it's only when that forward voltage drop is exceeded that current passes. But that too is a dumbed down version of what diodes do. The forward drop isn't constant, it depends on things like temperature. Also, there is actually a curve that relates voltage and current, they don't just snap on. But that too is just a "dumbed down" version of what a diode is. And so on, and so on.

The fact is, these "dumbed down" versions of the diode are very useful: they do convey some bit of useful information and begin to give us some experience and intuition about reasoning about circuits that contain diodes. The only thing that is bad is if we envision that our "dumb" understanding of diodes was a complete understanding of diodes. Then, there would be circuits and behaviors that we simply couldn't understand, because the real diodes are a bit more subtle than our dumb version, whatever level of understanding that might actually be.

But more than that, when we say something is dumbed down, we stray dangerously close (and often well beyond) calling the people who may use these simplified models as "dumb". That simply isn't productive, and runs counter to what I view as the purpose (and mostly successful achievement) of getting people interested in computing and electronics. The Arduino is successful because it does "dumb down" things enough for the people to experience success, who might otherwise have been frustrated and annoyed. When I hear people say that the Arduino is "dumbed down", I really hear them telling people who use them (or even more tragically, might have used them) that they are stupid. I don't want to call people stupid, especially those who might actually try something that I enjoy, and inspire me to do better work.

The problem I was trying to make clear was not that the Arduino was "dumbed down", but that the default development environment was a path that eventually kind of dead ends: to gain any real expertise and fully use the power underlying the $2.50 piece of silicon at it's heart, you almost need to start over: perhaps by using assembler as some has suggested, or perhaps just by using avr-gcc with avr-libc. You have to learn about interrupt vectors, and the hardware resources, because the particular abstractions that the default development enviroment present rob the underyling hardware of its power. To give another example, no less a luminary than Edsger Dykstra scolded a generation of computer science instructors and students that the BASIC programming language was a fatal disease from which they would never recover. It wasn't true. For many, it was the only programming that they ever learned, but that wasn't a bad thing. For many in my generation though, it was a stepping stone to an exciting and profitable career.

Don't bother saying something is "dumbed down". It's pointless. Your understanding of almost anything worth knowing is almost certainly "dumbed down" from its reality. Revel in complexity. Don't be ashamed that you don't understand everything today: you won't understand everything tomorrow either, but with luck, you might understand more than you do today.

Now, if I could develop a slightly less dumbed down idea of how FETs work, I could perhaps understand the behavior of my QRSS beacon a bit better. So that's what I'll work on for the rest of the evening...

14Jan/126

The downside of Arduino…

First of all, I really like the Arduino. There are lots of reasons: great community, relatively inexpensive, wide hardware availability and variety, and often a good "impedance" match to projects. But there are a few design choices (both hardware and software) that can be a nuisance, especially as you try to push the limits of what can be done on such inexpensive and low power hardware.

First of all, there is the basic software philosophy. I love the fact that it is a single download: this simplifies installation, and whether you are an expert or a novice doesn't matter, that's simply more convenient. But using the program editor provided is simply not that desirable for experts who might be more used to Eclipse, or to an old fashioned kind of guy like myself for whom vi and Makefiles is more reasonable. With a little work you can find out where avr-gcc, avr-libc and avrdude are installed and add them to your search path, but you still have some work to build a Makefile which can compile your sketch from the command line. That's a little annoying.

But more annoying are the design choices of the libraries themselves.

High among them are the heavy use of delay and the relative invisibility of interrupts. This may simplify short programs, but it provides no help to more sophisticated programs, and may in fact hinder them. Consider my experiments of last night (which fueled the rant of this morning). I merely wanted to implement a serial terminal using the TVout library and some serial communications library. The idea would be "read from serial, print to TVout", voila, should be simple.

TVout generates NTSC video on the fly, and it basically works great. To do so, it uses regular timer interrupts. and if you dig into the library itself, you might find out that it uses Timer1. At regular interval, the timer 1 counter overflows, and the library knows that it's time to bitbang out the video using some carefully constructed code. It also appears to use Timer2 to generate audio tones. Hmmm. The AVR chip that underlies the normal Arduino has only three timers... is that going to be a problem? How can I tell if another library also uses those timers?

You won't find it in the documentation to any library. Arduino programming is supposed to be easy, and remove the need to understand how the underlying hardware works. Except that when you try to use two libraries together, and they happen to both use the same underlying timer resources, it doesn't work right. There are no compile issues, it's just one or both of the modules fail.

Which it did of course last night. You'd think that a loop like:

void
loop()
{
    TV.print((char)Serial.read()) ;
}

might have a chance of working, but it doesn't. It drops and mangles characters horribly. While you might be able to poll some switches, apparently typing is something that is simply beyond the realm of expectation.

Some of you are probably going to leap to TVout's defense, claiming that "You're not doing it right! There is an example sketch which shows you the right way to do Serial and TVout!" Let's have a look at that little sketch, shall we?

#include <TVout.h>
#include <pollserial.h>
#include <fontALL.h>

TVout TV;
pollserial pserial;

void setup()  {
  TV.begin(_NTSC,184,72);
  TV.select_font(font6x8);
  TV.println("Serial Terminal");
  TV.println("-- Version 0.1 --");
  TV.set_hbi_hook(pserial.begin(57600));
}

void loop() {
  if (pserial.available()) {
    TV.print((char)pserial.read());
  }
}

Okay, we have some new library, which we never heard of before. It's apparently part of the TVout download. Documentation? No. It calls a function I haven't seen before, "set_hbi_hook". Is that documented? No. I am pretty sure it's a hook which will get called at the end (or the beginning?) of a horizontal blanking interrupt (this isn't my first rodeo) but what's really going on here. The pserial.begin call must return a function... time to crack open the source code.

And, it's about what you expect. There is a hook function that gets called on every line, right before the line is rendered. My guess is that it's bad if the timing of the hook function is in anyway indeterminate, because then the rows will start at odd intervals. But each render routine starts with a line which waits... for some length.... maybe there is some amount of time (undocumented, different for PAL/NTSC, maybe just the front part of each scanline, read more code) that if you don't exceed, you'll be fine. What does pollserial do? Well, it snoops at the serial data registers (polling!) to see if a new character has arrived. It then puts it in a ringbuffer, so that it can be made available to the read call later. Okay, I understand.

But did I mention the reason I didn't use this code in the first place? It's that pollserial didn't compile on my Arduino 1.0 setup (most libraries that aren't part of the core don't out of the box yet, in my experience). I could probably figure that out (has something to do with inheriting from the Print class and a prototype mismatch) but in my real, ultimate application, I wanted to read from a PS/2 keyboard. It will of course have the same (but differing in details) issues, and I'll have to tweak their driver code to make it work with TVout too. Sigh.

Ultimately, I guess I disagree with one part of the Arduino philosophy: that programming can ever really be simple. Writing a program to blink an led, or read a switch isn't hard, no matter what language or processor you use. Simple programs are simple, but the virtue of computers is that they can do things which are complex. If your software environment doesn't give you sufficient help in organizing and doing complex actions, then you are missing out a great deal of the purpose of computers.

Addendum: While trying to fix the compile errors in pollserial, I found this fragment:

int pollserial::read() {
        if (rxbuffer.head == rxbuffer.tail)
                return -1;
        else {
                uint8_t c = rxbuffer.buffer[rxbuffer.tail];
                //tail = (tail + 1) & 63;
                if (rxbuffer.tail == BUFFER_SIZE)
                        rxbuffer.tail = 0;
                else
                        rxbuffer.tail++;  
                return c;
        }
}

Can you spot the problem? Hints: BUFFER_SIZE is defined to 64, and rxbuffer.buffer is malloced to be BUFFER_SIZE bytes long.