The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Tag: Arduino

All things Arduino

  • Fixed Point Arithmetic: Percentages

    Problem: increment or decrement a variable by a fixed percentage, without using floating-point arithmetic routines. This is the sort of problem that crops up in microcontroller projects, because there’s just not enough storage for the floating-point library stuff and your program at the same time.

    Suppose you want to increment the variable BaseNum by 10%. Using floating point, that’s just

    BaseNum = 1.1 * BaseNum;

    In fixed point, it would look like

    BaseNum = (BaseNum * 11) / 10;

    Similarly, to increment by 5%, you’d use

    BaseNum = (BaseNum * 105) / 100;

    The general idea is that you scale the operation to eliminate the fractional part, then chop off the scaling to get the final answer. The parentheses are vital: the multiplication must precede the division.

    The integer division operator truncates any fractional part, it does not round. This becomes a nasty gotcha if you’re expecting the final value to change.

    For example, incrementing 15 by 10% would look like

    15 ->  165 -> 16

    But incrementing 15 by 5% goes like

    15 -> 1575 -> 15

    For obvious reasons, you should make sure the multiplication can’t overflow. If you’re incrementing by 5% (multiplying by 105), then an int BaseNum can’t exceed 312, which might come as a surprise. Casting the operands to long int would be prudent for many problems:

    BaseNum = ((long int)BaseNum * 105) / 100;

    Suppose you want to increment BaseNum several times in succession, with that number stored in Ticks. With floating point, you could use the pow() function

    BaseNum = BaseNum * pow(1.1,Ticks);

    In fixed point, the same thing seems like it ought to work

    BaseNum = (BaseNum * pow(11,Ticks)) / pow(10,Ticks);

    Unfortunately, that idea runs out of gas pretty quickly: pow(11,9) falls just outside the range of a long int, so even if BaseNum is, say, 2, you’re screwed. It’s even worse for smaller percentages, as pow(105,5) is about 13e9.

    One solution, which works well for reasonable values of Ticks, is to iterate the process

    for (Counter = Ticks; Counter; --Counter)
    {
        BaseNum = ((long int)BaseNum * 11) / 10;
    }

    That won’t overflow in the middle. However, if the division truncates away the increment you were expecting, then the loop just whirs for a while and accomplishes exactly nothing.

    That could come as a surprise if you were expecting, say, five 5% increments to add up to a 28% boost: pow(1.05,5) = 1.276, right?

    Bottom line: when you use fixed-point arithmetic, always check the low end of the range for underflow and the high end for overflow.

    Hint: store the numerator and demoninator of the fixed-point percentage fraction in variables. You can’t decrement by the same percentage by just swapping the numerator and denominator, but it might be close enough for human-in-the-loop knob twiddling adjustments.

    Memo to Self: always check for underflow and overflow!

  • Reading a Quadrature Knob

    Most analog projects will benefit from an adjustment knob; the notion of pressing those UP and DOWN arrows just doesn’t give that wonderful tactile feedback. These days “knob” means a rotary encoder with quadrature outputs and some software converting digital bits into an adjustment value.

    Sounds scary, doesn’t it?

    This is actually pretty simple for most microcontrollers and the Arduino in particular. The Arduino website has some doc on the subject, but it seems far too complicated for most projects.

    A quadrature rotary encoder has two digital outputs, hereinafter known as A and B. The cheap ones are mechanical switch contacts that connect to a common third terminal (call it C), the fancy ones are smooth optical interrupters. You pay your money and get your choice of slickness and precision (clicks per turn). I take what I get from the usual surplus sources: they’re just fine for the one-off projects I crank out most of the time.

    How does quadrature encoding work?

    On each falling edge of the A signal, look at the B signal. If it’s HIGH, the knob has turned one click thataway. If it’s LOW, the knob has turned one click the other way. That’s all there is to it!

    Here’s how you build a knob into your code…

    Connect one of the outputs to an external interrupt, which means it goes to digital input D2 or D3 on the Arduino board. The former is INT0, the latter INT1, and if you need two interrupts for other parts of your project, then it gets a lot more complex than what you’ll see here. Let’s connect knob output A to pin D2.

    Connect the other output, which we’ll call B, to the digital input of your choice. Let’s connect knob output B to D7.

    Define the pins and the corresponding interrupt at the top of your program (yeah, in Arduino-speak that’s “sketch”, but it’s really a program):

    #define PIN_KNOB_A 2			// digital input for knob clock (must be 2 or 3!))
    #define IRQ_KNOB_A (PIN_KNOB_A - 2)	//  set IRQ from pin
    #define PIN_KNOB_B 7			// digital input for knob quadrature
    

    The external circuitry depends on whether you have a cheap knob or fancy encoder. Assuming you have a cheap knob with mechanical contacts, the C contact goes to circuit common (a.k.a, “ground”). If you have a fancy knob with actual documentation, RTFM and do what it say.

    The two inputs need resistors (“pullups”) connected to the supply voltage: when the contact is open, the pin sees a voltage at the power supply (“HIGH“), when it’s closed the voltage is near zero (“LOW“).

    Ordinary digital inputs have an internal pullup resistor on the ATmega168 (or whatever the Arduino board uses) that will suffice for the B signal. Unfortunately, the external interrupt pins don’t have an internal pullup, so you must supply your own resistor. Something like 10 kΩ will work fine: one end to the power supply, the other to INT0 or INT1 as appropriate.

    With the knob connected, set up the pins & interrupt in your setup() function:

    attachInterrupt(IRQ_KNOB_A,KnobHandler,FALLING);
    pinMode(PIN_KNOB_B,INPUT);
    digitalWrite(PIN_KNOB_B,HIGH);
    

    The first statement says that the interrupt handler will be called when the A signal changes from HIGH to LOW.

    The Arduino idiom for enabling the chip’s internal pullup on a digital input pin is to define the pin as an input, then write a HIGH to it.

    Set up a variable to accumulate the number of clicks since the last time:

    volatile char KnobCounter = 0;

    The volatile tells the compiler that somebody else (the interrupt handler or the main routine) may change the variable’s value without warning, so the value must be read from the variable every time it’s used.

    The variable’s size depends on the number of counts per turn and the sluggishness of the routine consuming the counts; a char should suffice for all but the most pathological cases.

    Define the handler for the knob interrupt:

    void KnobHandler(void)
    {
        KnobCounter += (HIGH == digitalRead(PIN_KNOB_B)) ? 1 : -1;
    }
    

    KnobHandler executes on each falling edge of the A signal and either increments or decrements the counter depending on what it sees on the B signal. This is one of the few places where you can apply C’s ternary operator without feeling like a geek.

    Define a variable that will hold the current value of the counter when you read it:

    char KnobCountIs, Count;
    

    Now you can fetch the count somewhere in your loop() routine:

    noInterrupts();
    KnobCountIs = KnobCounter;	// fetch the knob value
    KnobCounter = 0;		//  and indicate that we have it
    interrupts();
    

    Turning interrupts off while fetching-and-clearing KnobCounter probably isn’t necessary for a knob that will accumulate at most one count, but it’s vital for programs that must not lose a step.

    Now you can use the value in KnobCountIs for whatever you like. The next time around the loop, you’ll fetch the count that’s accumulated since the previous sample.

    Even if you RTFM, apply painstaking logic, and wire very carefully, there’s a 50% chance that the knob will turn the wrong way. In that case, change one of these:

    • In the interrupt handler, change HIGH to LOW
    • In the attachInterrupt() statement, change FALLING to RISING

    There, now, wasn’t that easy? Three wires, a resistor, a dozen lines of code, and your project has a digital quadrature knob!

    If you have a painfully slow main loop, the accumulated counts in KnobCounter could get large. In that case, this code will give you a rubber-band effect: the accumulated count can be big enough that when the knob starts turning in the other direction it’s just decreasing the count, not actually moving count to the other side of zero. Maybe you need some code in the interrupt handler to zero the count when the direction reverses?

    But that’s in the nature of fine tuning… twiddle on!

  • Changing the Arduino PWM Frequency

    The default PWM frequency for PWM 3, 9, 10, & 11, at least for the Diecimila running at 16 MHz, is 488 Hz. That’s OK for dimming LEDs where you’re depending on persistence of vision, but it’s much too low when you must filter it down to DC.

    The relevant file is hardware/cores/arduino/wiring.c, which is buried wherever your installation put it.

    Turns out that the Arduino runtime setup configures the timer clock prescalers to 64, so the timers tick at 16 MHz / 64 = 250 kHz.

    You can fix that by setting the Clock Select bits in the appropriate Timer Control Register B to 0x01, which gets you no prescaling and a 62.5 ns tick period:

    TCCR0B = 0x01;   // Timer 0: PWM 5 &  6 @ 16 kHz
    TCCR1B = 0x01;   // Timer 1: PWM 9 & 10 @ 32 kHz
    TCCR2B = 0x01;   // Timer 2: PWM 3 & 11 @ 32 kHz

    If you’re finicky, you’ll bit-bash the values rather than do broadside loads. However, it probably doesn’t matter, because Timer 0 runs in Fast PWM mode and Timers 1 & 2 run in Phase-Correct PWM mode, so WGMx2 = 0 in all cases.

    Fast PWM mode means Timer 0 produces PWM at 250 kHz / 256 = 976 Hz. However, the Arduino runtime runs the millis() function from the Timer 0 interrupt, so changing the Timer 0 prescaler pooches millis(), delay(), and any routines that depend on them.

    Phase-correct PWM mode means that Timers 1 & 2 count up to 0xff and down to 0x00 in each PWM cycle, so they run at 250 kHz / 512 = 488 Hz.

    Adroit TCCRxB setting can prescale by 1, 8, 64, 256, or 1024. Or stop the Timer stone cold dead, if you’re not careful.

    Before you fiddle with this stuff, you really should read the timer doc in the ATmega168 datasheet there.

    Memo to Self: don’t mess with Timer 0.

  • Arduino Command Line Programming: Avrdude Puzzlement

    For all the usual reasons, I’d like to compile & download Arduino programs from the command line, rather than through the (excellent!) IDE. That is supposed to work and, for most folks, apparently it does.

    Not here, alas.

    I’ve installed the 0012 Arduino Java IDE (x86 or x86_64 as appropriate) from http://code.google.com/p/arduino/ on three different systems, all with Kubuntu 8.04:

    • Dell Dimension 9150 – x86_64, which seemed like a good idea at the time
    • Dell Inspiron E1405
    • Dell Inspiron 8100

    In all cases the IDE works perfectly, compiles & downloads programs just fine, and behaves exactly as you’d expect. I had a few minor quibbles with sorting out various paths & suchlike, but, on the whole, it has no troubles at all with either a Diecimila or a Sparkfun Arduino Pro (with a Sparkfun FTDI Basic USB gizmo).

    I tweaked ~/.arduino/preferences.txt to include:

    console.auto_clear=false
    build.verbose=true
    upload.verbose=true

    Here’s the final step in the IDE compile-and-download dance. Backslashes indicate continuations of the same line; the original is all on single line:

    hardware/tools/avrdude -Chardware/tools/avrdude.conf -v -v -v -v -pm168
    -cstk500v1 -P/dev/ttyUSB0 -b19200 -D
    -Uflash:w:/mnt/bulkdata/Above the Ground Plane/
    2009-06 Solar Data Logger/Firmware/Logger/applet/Logger.hex:i 
    
    avrdude: Version 5.4-arduino, compiled on Oct 22 2007 at 13:15:12
             Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
    
             System wide configuration file is "hardware/tools/avrdude.conf"
             User configuration file is "/home/ed/.avrduderc"
             User configuration file does not exist or is not a regular file, skipping
    
             Using Port            : /dev/ttyUSB0
             Using Programmer      : stk500v1
             Overriding Baud Rate  : 19200
    avrdude: Send: 0 [30]   [20]
    avrdude: Send: 0 [30]   [20]
    avrdude: Send: 0 [30]   [20]
    avrdude: Recv: . [14]
    avrdude: Recv: . [10]
             AVR Part              : ATMEGA168

    The IDE evidently does the reset-from-USB trick through the standard USB hardware.

    I set up the command-line Makefile from http://www.arduino.cc/en/Hacking/CommandLine, although that’s for the 0011 IDE, then made the recommended tweaks. The make section does exactly what you’d expect: compiles the source program.

    Running make upload fails every time, on every PC, with both boards. Indeed, in all cases, running avrdude on the command line produces the dreaded “not in sync” errors, showing that it’s unable to communicate with the Arduino board. Blipping the reset button on the Arduino board generally makes the USB transfer work fine, with the failures most likely due to my lack of dexterity & timing precision.

    The usual debugging suggestions aren’t relevant, as they all assume there’s a basic communication failure caused by anything from a completely dead board to mysterious library incompatibilities. In this case, however, I have an existence theorem: the IDE works perfectly before and after the command-line failure.

    It turns out that the IDE includes a specially patched avrdude, so I tried running that version from the directory where the IDE lives, using exactly the same command-line flags as the IDE does. Surprisingly, that doesn’t work. Again, backslashes indicate continuations of the same line and I added quotes to the file name to protect the blanks…

    hardware/tools/avrdude -Chardware/tools/avrdude.conf -v -v -v -v -pm168
    -cstk500v1 -P/dev/ttyUSB0 -b19200 -D
    -Uflash:w:"/mnt/bulkdata/Above the Ground Plane/
    2009-06 Solar Data Logger/Firmware/Logger/applet/Logger.hex":i
    
    avrdude: Version 5.4-arduino, compiled on Oct 22 2007 at 13:15:12
             Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
    
             System wide configuration file is "hardware/tools/avrdude.conf"
             User configuration file is "/home/ed/.avrduderc"
             User configuration file does not exist or is not a regular file, skipping
    
             Using Port            : /dev/ttyUSB0
             Using Programmer      : stk500v1
             Overriding Baud Rate  : 19200
    avrdude: Send: 0 [30]   [20]
    avrdude: Send: 0 [30]   [20]
    avrdude: Send: 0 [30]   [20]
    avrdude: Recv: . [1e]
    avrdude: stk500_getsync(): not in sync: resp=0x1e
    avrdude: Send: Q [51]   [20]
    avrdude: Recv: . [0f]
    avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x0f

    There’s no difference between the /opt/arduino/lib/librxtxSerial.so and /usr/lib/librxtxSerial.so libraries, which normally causes some confusion on x86_64 systems. I think that means the x86_64 version of the IDE has the correct library.

    I’ve also tried the stock Kubuntu avrdude, which is at V 5.5, to no avail.

    Given that the IDE works, that I’m running the same avrdude executable, and that the libraries match, I’m not sure where to go from here.

    While I’m generally dexterous enough to run make upload and blip the Arduino board’s reset button with my other hand, I’m bringing up a shield-like board that plugs atop the Arduino and, alas, lacks both a reset button and a hole over the Arduino’s button.

    The board is, of course, that one.

    Update: As a reasonable workaround, I’ve set the IDE up to use an external editor. Then I can tweak the programming, flip to the IDE, click the Download button, and away it goes. Not quite as easy as a full command-line solution, but close enough.

  • Kubuntu “Server” Time Drift

    I just tried compiling a program (for an Arduino) and make grumped about a date in the future:

    make: Warning: File `Makefile' has modification time 1.4e+02 s in the future
    <<< usual compile output snipped >>>
    make: warning:  Clock skew detected.  Your build may be incomplete.

    Turns out that the timestamps really were screwy:

    [ed@shiitake Solar Data Logger]$ date
    Sun Jan 25 10:57:44 EST 2009
    [ed@shiitake Solar Data Logger]$ ll
    total 28
    drwxr-xr-x 2 ed ed 4096 2009-01-25 10:59 applet
    -rw-r--r-- 1 ed ed 1920 2009-01-25 10:35 Logger.pde
    -rwxr-xr-x 1 ed ed 7719 2009-01-25 10:59 Makefile
    -rwxr-xr-x 1 ed ed 7689 2009-01-25 10:53 Makefile~
    -rw-r--r-- 1 ed ed 1880 2009-01-25 10:08 Solar Data Logger.pde~

    Well, now, how can that be?

    The offending files are stored on a file server, not on the machine in front of my Comfy Char. The current dates for the two machines weren’t quite the same: the server was running just slightly in the future.

    I used an ordinary Kubuntu desktop install on our “file server”, which is basically a Dell Inspiron 531s running headless in the basement. All this is behind a firewall router, so I do not have an Internet-facing machine running X, OK?

    Kubuntu has an option that updates the clock automagically, but only once per boot.

    Right now, that box claims an uptime of just over 22 days. It’s run for months at a time without any intervention, which just one of the things I like about Linux:

    uptime
     11:07:08 up 22 days, 19:52,  1 user,  load average: 0.00, 0.02, 0.00

    I think you can see the problem: after three weeks the PC’s internal clock had drifted more than two minutes fast.

    I used the Big Hammer technique to whack the server’s clock upside the head:

    sudo ntpdate pool.ntp.org
    [sudo] password for ed: youwish
    25 Jan 11:01:22 ntpdate[23062]: step time server 66.7.96.2 offset -151.277185 sec

    That’s 7 seconds per day or 151 seconds out of 2 megaseconds: 77 parts per million. It’s in a basement at 55 F right now, so there may well be a temperature effect going on.

    You can set up ntp (www.ntp.org or, better, from a package in your distro) to run continuously in the background and keep the clock in time by slewing it ever so slightly as needed to make the average come out right. I just added an entry to /etc/crontab like this:

    00 01   * * *   root    ntpdate north-america.pool.ntp.org

    That way the clock gets whacked into line once a day when nobody’s looking.

    If you’re running a real server with heavy activity, ntp is the right hammer for the job because you don’t want ntpdate to give you mysterious gaps of a few seconds or, worse, duplicate timestamps. Leap year is bad enough.

    More about ntp at http://en.wikipedia.org/wiki/Network_Time_Protocol.

    Memo to Self: set up ntp on the server and then aim all the desktops at it.

    I used to do that when I was running a GPS-disciplined oscillator to produce a nearly Stratum 1 clock on my server, but then power got too expensive for that frippery.