Short term notice: We’ll have a short talk about the Everykey at the Minikonferenz located at the Startplatz, Mediapark, Cologne, on March 7, 2013. Since we’re hackers (and painters, sort of), we decided to tell some stories. You have been warned. Unlike our other presentations, we might not start it with pictures of cats and babies, you’ll see.

The place will most likely be quite crowded with interesting people and ideas all around – sounds like it’s going to be fun. Have a look at their site – participation is free!

Until now, if you tried to initialize a (non-constant) global or static variable with the Everykey framework, the resulting firmware file turned out to be huge, far too big to fit on the device. Even worse, if you initialized a global or static to zero, you might be able to flash, but the program would randomly not work. The workaround was to initialize only const variables and then to set up everything by hand in your `main` function. Not so beautiful. If you’re not interested in the why and how, here’s the good news in brief: It works now – just update your repository, make clean and make. If you want to get a better understanding about linking and bootstrapping internals, read on – it’s often considered dark magic, but probably far easier than you believe.

The cause of the problem was skipping an essential step that is supposed to happen between compilation and execution for the sake of simplicity: Data Initialization. Let’s see what actually happens:

The makefile first compiles your C code into machine language and data. But any locations that are supposed to refer to an actual, absolute address in memory are intentionally left blank. Why? Because memory locations are not known yet at this point. Instead, gcc classifies the different types of its results (executable code, data, global variables, etc) and adds a special export symbol for each location that might be interesting for others. The symbol does not specify an absolute address, just the location within the compilation unit. Other special import symbols are added for each location that should later on refer to an actual memory address – just the location within the compilation unit and a name where it should point to.

The linker is supposed to glue together all the compilation units generated by the compiler. In principle, this process is rather simple: It scans through all .o object files (the compiler’s results) and collects all the different types of data. After that, it orders the contents of the object files and calculates the location of all the symbols, once the actual location of the symbols is known, the linker can switch the symbols for the actual memory addresses. If one imported symbol could not be matched to an exported one, you get an error. That’s basically it for static linking.

But wait, there’s more: The linker is not only supposed to layout the runtime addresses, it also creates our firmware file! Do they differ? Yes, exactly in situations that initialize a global or static variable. On one hand, the variable must be located in RAM (because your code may modify its contents at runtime). On the other hand, it’s initial value must be stored in FLASH, because that’s the only memory known at startup (hey, that’s why it’s called flashing). In order to solve this problem, we have to do two things:

  1. Tell the linker that these variables should later on have a location in RAM, but initial values should go to a separate region in the firmware file (which goes to the FLASH memory)
  2. Add a step in the startup code that copies the stored initial values from FLASH to their respective location in RAM

Fortunately, it’s quite easy to tell the linker to do the first thing using a special markup in the linker script (which is, by the way, more of a list of rules than a script). The second step has to be done by ourselves, it adds four lines of code to the bootstrap() function in startup.c. But how does the bootstrap code know what to copy from where to where? Nice trick: We intentionally import symbols that are not exported anywhere else in the code. Usually, this would cause a linker error, unless we tell the linker to export these symbols itself. That’s exactly what we do.

Linker scripts can be slightly confusing to read. For readability, all input segments names (stuff classified by the compiler) start with a dot. Output segments (stuff ordered by the linker) don’t start with a dot (at least that’s how we did it) – plus there are now some comments in the linker script (lpc1343.ld).

By default, gcc classifies it output using the following names (don’t ask why, it’s just convention):

  • .text : compiled code. This can go into FLASH (if you want to build self-modifying code, you have to copy it to RAM first)
  • .rodata: globals and static variables declared as const. Since their contents cannot be modified, they can also go into FLASH
  • .data: non-const globals and static variables that are initialized to a value other than zero: These need to be linked to RAM, but we need to store their initial values in a mirror region in FLASH.
  • .bss: non-const globals and static variables that are either initialized to zero or not initialized (which defaults to zero): These need to be linked to RAM, but we don’t need to store their initial values (they are all zero, so there’s no need to waste FLASH memory). The startup code just needs to clear the corresponding RAM region to zeroes.

In addition, we declare a special segment “.vectors” in startup.c, which only contains the vector table (initial stack pointer, start address of the bootstrap code and default addresses of interrupt and fault handlers). The Cortex M3 expects this table to start at memory location 0x0 to properly launch into our code. We use this dedicated segment to ensure that the linker puts it to the right place.

Just for completeness, here’s the rest of the bootstrap story:

The linker will write its results into an .obj file, containing all necessary information. After the linker is done, objcopy will extract a “memory dump” of the linker results – the contents of the .hex file is exactly what should be in the microcontroller’s FLASH memory, starting at address 0x0. One last step is missing: Our specific microcontroller expects a valid checksum to accept the firmware file. There’s an entry in the vector table left empty for this value. The `checksum` tool will calculate the correct value and modify the value in the .bin file.

When flashing, this binary data is written into the microcontroller’s flash memory. Later at runtime, after the controller hardware has finished its internal setup, it initializes the stack pointer (with the value at address 0, part of the vector table) and jumps into our bootstrap code (whose address is stored at memory location 4 – also part of the vector table). Once in software land, we can do the copy trick described above, do some more common initialization (for example, enabling the external quartz oscillator and some basic peripherals) and call main(), which is the starting point of the actual application.

As you see, there are quite a couple of components involved, but no dark magic at all.

Posted in SDK.

I recently found a rare 80’s technology gem on the attic: An (almost) functional Commodore 1520 plotter. This was the only plotter ever sold by Commodore. It was a C64 peripheral, although even back then, it was pretty unknown (and fairly useless).

Surprisingly, after 25 years of deep sleep, the device powered up to self test. Two motor gears needed some glue and the ink in the pens had dried. A bit of water brought at least the blue pen back to life (the plotter has four pens in different colors, for a “perfect multimedia experience”).

Commodore, like just about everyone else back then, used a propietary protocol to drive the plotter. It is a weird serial protocol – in our official Everykey protocol weirdness scale, it beats most other protocols by far, making I2C and SPI look boring and straightforward. There’s even some (partially incorrect) documentation on the web. And you can still buy the 6-pin DIN plugs. There are some projects to control the Commodore 1541 floppy disk drive, but we didn’t find any good approaches on bringing the 1520 back to life. Challenge accepted!

The implementation was surprisingly simple – after categorizing the existing documentation into a) usable,  b) incomplete or c) just plain wrong. The Everykey connects through USB to a computer and shows up as a virtual serial port. It implements a tiny parser which interprets simple commands (such as MOVE, LINE, PRINT or COLOR) typed into the terminal and translates them into something that can be understood by the plotter. Here’s an early result (just blue – as mentioned, the other pens are still dry):

Commodore 1520 plotter
A Commodore 1520 plotter controlled by Everykey

The output quality is not perfect (for example, you can see that the vertical feed is off a little), cleaning the mechanics and replacing the pens should help. Even in perfect condition, the results could not compete even with the cheapest inkjet printer of today. So why did we do it? Because we can.

Code and schematics are not online yet since we decided to stop spamming our base repository. If you’re interested in how it works, let me know. If you have other peripherals waiting for resurrection, we might be able to help – did you know that we are for hire for this sort of stuff?

There’s a video of the plotter in action on youtube.

USB is a rather complex protocol. Its main advantage in computer history was that it promised to offer a useful replacement for legacy parallel and serial ports. In comparison though, USB is terribly complex, but it does not suffer the typical shortcomings of its predecessors and has some nice, built-in advantages: Hot plugging, device self description, automatic driver matching etc.

Keeping that in mind, it’s a bit surprising that the number-one mode of communication in embedded DIY projects that support USB is – a virtual serial port. This approach combines the complexity of USB with the inflexibility of serial ports. The worst of both worlds!

For certain purposes, serial ports are nice: Quick and dirty communication, debugging etc. So we’re happy to announce that our USB software stack now includes a virtual serial port implementation (USB CDC class, Abstract Control Model) – if you’re curious to see one of the weirdest USB class specifications, have a look at the USB CDC specification at

To see it in action, compile and install the cdcleetifier example. Then replug your device. On Macs and Linux systems, it should appear as a serial device in the /dev subdirectory. Connect it to a serial terminal to see the old serial glory of the eighties (on a Mac, you may use “screen /dev/cu.usbserialV1.1” – quit with “ctrl-a k y”). Type some text – the example will turn your text into V3RY C00L l33TSP3AK on the fly.

We haven’t tested it on Windows yet, but it seems to require an additional (quite useless) configuration (*.inf ?) file that basically states that this serial device is a serial device (if someone manages to get it running, we would be happy to hear from you).

Posted in USB.

Oscilloscopes can be very useful. The main problem with oscilloscopes is that many hardware hackers don’t have one – due to a lack of money, space or both. If you want to look at real time signals, you have to improvise. So do I.

If you’re lucky, you can slow down signals to brain speed. Still, looking at them with a multimeter is no fun. Here’s a simple level tester I built using a 1K resistor, a LED (in fact, it’s a deluxe two-pin dual-color LED, so you can even see negative polarity), a piece of wire, an alligator clip and some heat shrink tube – you can see the resistor beneath the tube, the probe is acually one side of the resistor. Just cents of materials, and minutes to build. Of course, it’s pretty dumb by no means accurate, but it can be useful – LED green: High, LED off: Low, LED very dim green: Likely undriven with a pullup somewhere, LED red: Whoops, negative voltage.

This little tool helped me debugging the SPI firmware: The peripheral simply didn’t answer. I turned down the interface speed to a crawl and observed the different signal lines: Chip select was ok and on the MOSI line I could see each bit of my commands, great. But there was no clock. It boiled down to an error in the LPC1343 user manual (the only one I ever saw, and it’s corrected in the latest revision – make sure you have it). However, without this tool, I would never have searched for the culprit there. Did I mention SPI works now?