Everykey was on then road again… We had a small appearance at the wonderful Raspberry Pi Jam hosted by Ordina in Utrecht (NL). The event seemed almost like an embedded hardware jam, with talks by the folks from the Amersfoort Hackspace Bitlair (the guys responsible for the awesome LED lighting at OHM2013 — roughly 1 km of RGB LED strips turned into remote controllable “streetlights”), Gert van Loo, one of the engineers responsible for the Raspberry Pi board and maker of the Gertboard expansion. Finally, Jeremy from Autostatic demonstrated real time audio effects. Only problem was that I was too busy talking to people (and regretting not speaking Dutch) that I forgot to take pictures! Thanks to Ordina for this event and especially to Marco Hebing (@TRexX) for inviting us!
We know you’ve always dreamed of having an electronic foosball table that saves you the tedium of counting and has the added advantage of shooting sparks when you spill beer on it! We started construction with friends at Railslove, got things nearly done at Interactive Cologne and finally finished what we started at the Pirate Hack in Cologne.
The foosball table even has it’s own website. It features automatic goal detection and can even calculate the speed of the ball. It’s got two displays to inform you about the current score. It’s also got Wifi (and an App in the “cloud“!), freeing you from the tedium of having to keep track of your league. It also has buttons that you can press!
Oh, and did we mention that it comes with it’s own lamp that can change the lighting conditions automatically corresponding to game play.
Everykey was on tour in Hungary this summer. Budapest is awesome, they still have actual electronic stores that have an actual inventory of parts that are actually useful:
This is Lomex (walking distance from Nyugati Station). The people from the Hungarian Autonomous Center for Knowledge were kind enough to provide me with a list of stores, which I will share in case you ever have the pleasure to be in Budapest and need some surface mount devices:
- Lomex 1134 Budapest, Lehel utca 17.
- HR Elektronika 1074 Budapest, Vörösmarty utca 5. (has no English,
- homepage open on Monday to Friday, 9.00-17.00)
- – Mikronika 1111 Budapest, Budafoki út 10/B. (has no official homepage, open on Monday to Friday, 10.00-16.00, maybe till 17.00)
Also, the folks at the H.A.C.K. were kind enough to allow me to hold a small introductory workshop. It’s a really cool place, well worth visiting if you are ever in the area.
We’ll be kicking off an Embedded Hardware User Group in Cologne this Saturday in cooperation with Railslove and Dingfabrik.
Drop us a line if you’re coming or are interested in being kept in the loop. Or just come by Railslove, An der Bottmuehle 5 at 14:00.
For the starting session, Matthias and I will be hosting an Introduction to Embedded Programming Workshop that will explain the basics of embedded programming using the Everykey. Bring a microusb cable!
we will be presenting rev2 of the Everykey at Interactive Cologne on June 18th and 19th in Cologne. We’ll be around building an interactive musical instrument based on Everykey together with visitors. Say, write or tweet something nice about us, let us know and you can win a free ticket to this awesome two day event! (it’s a hackathon and startup conference rolled into one…)
Here’s what we built:
A tragic tale of hardships and perils encoutered during the genesis of an embedded hardware platform is being told in current edition of c’t Hardware Hacks. (And will no doubt soon become a compelling motion picture). And guess who wrote it!
Oh the perils of unattended technology! We left two Everykeys alone for a couple of minutes (max!) and look what happend:
We’re happy to announce that we just picked up the first batch of a new revision of the PCB, assembled some keys and … everything seems to work nicely!
- Two buttons! (Both RESET and PROGRAMMING mode pins on buttons, no more re-plugging)
- 30% Smaller: svelte 20×20 mm instead of bovine 24×24 mm
- 0603 component size (“Do these 0805 resistors make my ass look fat?”)
- Large top layer pads and additional diodes to allow easy, safe connection of external power and access to USB voltage
- Readable print on the PCB!
- Of course, we kept all breakout pads on the back side (ribbon cable pitch)
As things seem to work, we’re now getting ready to release the schematics and board files, updating the site and SDK.
If you want to see our baby up close, why not drop by Interactive Cologne? (We’ll provide an update about other upcoming conferences and appearances soon…)
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:
- 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)
- 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.