ATmega328P-PU 12MHz bootloader

It took me an embarrassingly long time to get a 328 with a 12MHz crystal working so that it would allow a normal (serial / FTDI) upload from the Arduino IDE.

There are a few older guides around but I didn’t find one that used the newer optiboot bootloader.

If you don’t want to compile the bootloader yourself, you can download the compiled optiboot_at328mega_12.hex file from this link (right-click and and Save (link) as…) just copy it to your optiboot folder before editing your “boards.txt” file as described below.

If you want to compile the hex file yourself here’s how:

Edit the Makefile in your optiboot folder. On my (Windows 7 64bit) machine using Arduino 1.0.5-r2 this folder was C:\Program Files (x86)\Arduino\hardware\arduino\bootloaders\optiboot

Add this section. I put it in after the existing atmega328 sections and before the Sanguino section  (note that the -W1, … shouldn’t be on a separate line – it’s a continuation of the LDSECTIONS line, but this blogging software seems to want to wrap it onto a new line):

atmega328_12: TARGET = atmega328
atmega328_12: MCU_TARGET = atmega328p
atmega328_12: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=115200'
atmega328_12: AVR_FREQ = 12000000L
atmega328_12: LDSECTIONS  = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_12: $(PROGRAM)_atmega328_12.hex
atmega328_12: $(PROGRAM)_atmega328_12.lst

atmega328_12_isp: atmega328
atmega328_12_isp: TARGET = atmega328
atmega328_12_isp: MCU_TARGET = atmega328p
# 512 byte boot, SPIEN
atmega328_12_isp: HFUSE = DE
# Low power xtal (12MHz) 16KCK/14CK+65ms
atmega328_12_isp: LFUSE = FF
# 2.7V brownout
atmega328_12_isp: EFUSE = 05
atmega328_12_isp: isp

This is just a copy of the atmega328. section with:

  • the name changed from atmega328. to atmega328_12.
  • the f_cpu parameter changed from 16000000L to 12000000L
  • the two (PROGRAM) lines changed so that the .hex and .lst filenames also have the “_12” addition
  • the comment about the 16MHz crystal frequency changed to 12MHz

Run a command shell as administrator and navigate to the optiboot folder.  Enter the following command to compile the new 12MHz optiboot bootloader:

omake atmega328_12

Now edit your boards.txt file.  On my machine this was located at C:\Program Files (x86)\Arduino\hardware\arduino  Add this new section at the end – again this is just a copy of the ‘uno’ section with the few obvious edits for frequency and bootloader file.

##############################################################

atmega328bb12.name=ATmega328 12MHz crystal
atmega328bb12.upload.protocol=arduino
atmega328bb12.upload.maximum_size=32256
atmega328bb12.upload.speed=115200
atmega328bb12.bootloader.low_fuses=0xff
atmega328bb12.bootloader.high_fuses=0xde
atmega328bb12.bootloader.extended_fuses=0x05
atmega328bb12.bootloader.path=optiboot
atmega328bb12.bootloader.file=optiboot_atmega328_12.hex
atmega328bb12.bootloader.unlock_bits=0x3F
atmega328bb12.bootloader.lock_bits=0x0F
atmega328bb12.build.mcu=atmega328p
atmega328bb12.build.f_cpu=12000000L
atmega328bb12.build.core=arduino
atmega328bb12.build.variant=standard

Now launch Arduino, select “ATmega328 12MHz crystal” as your board and “Burn Bootloader” from the Tools menu.

That’s it, and you should be up and running with the normal hardware serial port working correctly with the ‘Serial’ commands and serial uploading from the Arduino IDE also working correctly.  I’ve seen comments that not all of the timing functions (microsecond delays etc.) work accurately when using a 12MHz crystal and the standard Arduino libraries.  I’ve not investigated that yet; and so far I’ve not tried using software serial with a 12MHz crystal – that also may require some tweaking…

 

 

Controlling the Raspberry Pi camera from C

I wanted to be able to stop and start the camera driven by events instead of just calling raspivid to record for a preset time.

My code is really just a simple wrapper around raspivid using the SIGUSR1 option to stop the video under program control rather than after a preset time.

The example main() function starts the video, sleeps for five seconds and then stops it.  For demo purposes I included the options for black and white inverted video.  To record with the normal raspivid defaults you just call startVideo with an empty options string:

startVideo(“filename.h264”, “”);

Obviously you can put any of the normal raspivid options in the string – but you should avoid -t, -n, -o, and -s as the code fills those in for you.  If you want to enable preview/monitoring then make the obvious change to remove the -n (no preview) option.

Save code as, say, video.c and compile with gcc -o video video.c

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static pid_t pid = 0;

void startVideo(char *filename, char *options) {
    if ((pid = fork()) == 0) {
        char **cmd;

        // count tokens in options string
        int count = 0;
        char *copy;
        copy = strdup(options);
        if (strtok(copy, " \t") != NULL) {
            count = 1;
            while (strtok(NULL, " \t") != NULL)
                count++;
        }

        cmd = malloc((count + 8) * sizeof(char **));
        free(copy);

        // if any tokens in options, 
        // copy them to cmd starting at positon[1]
        if (count) {
            int i;
            copy = strdup(options);
            cmd[1] = strtok(copy, " \t");
            for (i = 2; i <= count; i++)
                cmd[i] = strtok(NULL, " \t");
        }

        // add default options
        cmd[0] = "raspivid"; // executable name
        cmd[count + 1] = "-n"; // no preview
        cmd[count + 2] = "-t"; // default time (overridden by -s)
                               // but needed for clean exit
        cmd[count + 3] = "10"; // 10 millisecond (minimum) time for -t
        cmd[count + 4] = "-s"; // enable USR1 signal to stop recording
        cmd[count + 5] = "-o"; // output file specifer
        cmd[count + 6] = filename;
        cmd[count + 7] = (char *)0; // terminator
        execv("/usr/bin/raspivid", cmd);
    }
}

void stopVideo(void) {
    if (pid) {
        kill(pid, 10); // seems to stop with two signals separated
                       // by 1 second if started with -t 10 parameter
        sleep(1);
        kill(pid, 10);
    }
}

int main(int argc, char **argv) {
    printf("Recording video for 5 secs...");
    // example options give an upside-down black and white video
    startVideo("temp.h264", "-cfx 128:128 -rot 180"); 
    fflush(stdout);
    sleep(5);
    stopVideo();
    printf("\nVideo stopped - exiting in 2 secs.\n");
    sleep(2);
    return 0;
}

Decoding 6 servo channel inputs with an Arduino UNO

Standard radio control receivers drive their connected servos by outputting a train of pulses.  The pulses usually repeat at a 50 Hz rate but the pulse width is the important thing – the standard is a 1.5 ms pulse width for a servo at its center position varying from about 1.0 ms up to 2.0 ms for servo’s nominal travel range. The pulses are positive going, usually about 5V in amplitude.

Searching on the web finds lots of examples of code to read the pulse widths for several servo channels, but for my application the Arduino is looking after several sensors besides the servo signals and also running software serial ports.  The examples I found all gave too much jitter and inaccuracy.

I wired the six channels to the Arduino digital pins 2 to 7.  Pins 0 and 1 are used by the UART (serial communication to PC or other device) so it’s best to avoid those.  Conveniently this means that all six channels are contained on a single Arduino input port, (Port D) so this makes the code to capture the pulse widths very clean.

We enable an interrupt that occurs when any of the 6 pins change state. To do this we set one bit for each of the 6 channels in the PCMSK register.  Then to allow changing input states on Port D to generate interrupts there is just one bit in the PCICR register to set:

PCMSK2 |= 0xFC;
PCICR |= 0x04;

The interrupt handler, declared as ISR(PCINT2_vect) checks each of the six pins. If a pin has changed state since the previous interrupt, we do one of two things:  If the pin has gone high we just remember the current time; if the pin has gone low we store the pulse width by subtracting the remembered time from the current one.  The Arduino has a function that returns microseconds (with a resolution of 4 microseconds on the UNO) convenient for this task.  The microsecond timer wraps around back to zero roughly every 70 minutes but this doesn’t cause any problems – by doing the subtractions using unsigned long integers the pulse widths are still correct even when a ‘wrap around’ occurs.  Here’s the complete program including interrupt handler and simple test output that just prints the current pulse widths to the serial port (PC).

volatile uint8_t prev; // remembers state of input bits from previous interrupt
volatile uint32_t risingEdge[6]; // time of last rising edge for each channel
volatile uint32_t uSec[6]; // the latest measured pulse width for each channel

ISR(PCINT2_vect) { // one or more of pins 2~7 have changed state
  uint32_t now = micros();
  uint8_t curr = PIND; // current state of the 6 input bits
  uint8_t changed = curr ^ prev;
  int channel = 0;
  for (uint8_t mask = 0x04; mask; mask <<= 1) {
    if (changed & mask) { // this pin has changed state
      if (curr & mask) { // +ve edge so remember time
        risingEdge[channel] = now;
      }
      else { // -ve edge so store pulse width
        uSec[channel] = now - risingEdge[channel];
      }
    }
    channel++;
  }
  prev = curr;
}

void setup() {
  Serial.begin(9600);

  for (int pin = 2; pin <= 7; pin++) { // enable pins 2 to 7 as our 6 input bits
    pinMode(pin, INPUT);
  }

  PCMSK2 |= 0xFC; // set the mask to allow those 6 pins to generate interrupts
  PCICR |= 0x04;  // enable interupt for port D
}

void loop() {
  Serial.flush();
  for (int channel = 0; channel < 6; channel++) {
    Serial.print(uSec[channel]);
    Serial.print("\t");
  }
  Serial.println();
}

 

Flash Rubik Cube Simulator

Snapshot of Flash Rubik Cube Simulator

Above is a snapshot image.  Here’s the real thing.

It works for any size of cube from 2 x 2 x 2 up to 11 x 11 x 11.  Actually, 11 is an arbitrary limit – the same code would work for any size of cube.  Use the little + and – buttons up in the top left hand corner to select the size of the cube.

Turning a face or slicing a layer is pretty intuitive – just click somewhere on the cube, hold down the mouse button and drag.

Turning the whole cube around is the same but you have to double-click, hold the mouse button down on the second click and then drag.

There’s a bug in the turning of the whole cube which causes the orientation to jump occasionally.  I think I can fix it by using quaternions to do the whole-cube rotation, but with the demise of Flash I’m thinking this would be a good project to migrate to HTML5 – and then I could patch in the quaternion stuff at the same time.

You can also use the keyboard to turn layers (there’s a sort of agreed way of doing this among speed-cubers, and the simulation mostly uses the agreed keys),

The Minimum Attack Problem

Place five queens on a chess board so that every square on the board is attacked.  It’s an old and famous problem; there are lots of solutions and it’s pretty easy to find one.  Try it for yourself and see!

Now try using just three queens and two rooks.  Not so easy this time; the solution is unique if you ignore trivial rotations and reflections of the whole board.  What about other attacking forces? Four queens and two pawns maybe?

The image above is a snapshot of my solver.  Click here to go to the solver itself. I wrote it over ten years ago when Java applets were flavor of the month.  Most modern computers and tablets don’t have Java available by default and most tablets won’t let you install Java at all; you can still install Java as a free plug-in in most PC browsers though.