Tag Archives: pov

RGB LED Graduation Cap Shenanigans, MIT Graduation Report

I present here my derpy graduation cap, based off of http://learn.adafruit.com/rgb-led-strips/overview:

thanks Jamison (http://thevariableconstant.blogspot.com/) for the picture!

Here it is, just finished at MITERS and still tethered to a power supply. Later I electrical taped on a lipo battery,  I kid you not.

From the front it looks normal, which is unfortunate for the graduation video, but whatever, I tried.

Only if you get some height above me can you see the lights.

what it looks like from the side. yea I can’t believe it got through security too, especially after Jordan‘s kawaiicopter cap that she worked on all winter break was rejected :'(

The original plan was to have a spinning RGB POV display, ala the plenitude of persistence of vision clock displays out there.

I even milled out a board for it, based on the fabduino files.

cute non-RGB 7 LED pov board

I can upload the eagle files if anyone wants, but since I haven’t gotten it to work and I can’t be sure there’s nothing wrong with the circuit I don’t want to put the effort into putting it up. This was my first exploration of the autoroute tool, which seemed to work pretty well.

Anyway after pulling two almost-all-nighters working on that project, I gave up when I couldn’t get the arduino bootloader burned onto the atmega (couldn’t get it to program at all, actually — hit a Target not found error). The cap I actually ended wearing was very simple to make and took about 6 hours total, including time spent trying to waterproof it with hot glue and saran wrap. (Most of the letters are stuck on there with the original backing tape that came on the strip). I didn’t have black wires so I used thick brown but still single core wire. I also probably should have done a 6 LED strip for the “I” and just covered up the center portion with electrical tape. Instead, I just skipped the dot on top of the “i”.

I also found this tool supppeerr useful, way more useful than the helping hands, for holding thick and relatively unyielding wires together so that I could solder them:

src: http://www.orangenarwhals.com/wp-content/uploads/2013/06/il_340x270.329862126-300×238.jpg

If you look carefully there are also two burn marks on my cap. I just colored the cardboard underneath with sharpie.

I also would have taken off my cap and showed it to the camera as I was coming down the ramp after getting my diploma if I knew how graduation worked.

I should have sanded down all the wires because I think a lot of the joints were cold solder joints (this bit me when I was repositioning the letters), but it worked okay and is probably the most robust of all the projects I’ve done so far because the circuit is encased in hot glue. Sorry arduino mini! (I potted that into the breadboard). The circuit itself is super straightforward, 3 FETs directly driven by the arduino. See http://learn.adafruit.com/rgb-led-strips/overview.

This is what graduation looked like for the parents.

Graduation itself was simply wet and miserable. I was on-and-off shivering by midway through and the list of names seemed endless. I’m sure they were rushing toward the end.

APPENDIX: Milling circut boards on a Roland modela mill (in the IDC)

Ultimate lesson learned: Make your traces at least 16 mil, 12 mil does not work!

It’s a 5 LED font.

The fabduino I will be running (a waste to use it for just 7 LEDs, but I don’t have the time to deal with not just reusing other people’s POV code)
How to use the roland modela mill
Eagle libraries
modela@ubuntu:~/Documents/nouyang$ sh eagle-lin-6.4.0.run 
1/tmp/eagle-setup.4298/eagle-6.4.0/bin/eagle: error while loading shared libraries: libssl.so.1.0.0: cannot open shared object file: No such file or directory
ugh, let’s try troubleshooting this
sudo apt-get install libssl-dev
modela@ubuntu:~/Documents/nouyang$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Uhmm… okay nope. Switching back to a windows computer. A shame. : / I really ought to switch over to something more happy running on ubuntu someday.

Pin mapping

FTDI headers:

How to create board outline in eagle:

Eagle MAS.863 documentation


Design rules:

5V 1A regulator is in a SOT-223 package
Fab lab inventory
input gnd output

hmm tangent about IC naming (78xx = vreg)

Hmmm eagle files for this vreg
gnd out in, so pin assignments are wrong, should be easy fix
MAke sure to download zip file! OTherwise file does not download properly (adds some html comments at the beginning)
Currently the Vreg-LM1117 package is
3 IN
4 OUT@1
which matches the datasheet https://www.sparkfun.com/datasheets/Components/FAN1117A.pdf 1:GND, 2:OUT, 3:IN.

However for the LM2940 I want
1:IN 2:GND 3:OUT

Steps ish (very incomplete)
Connect> Disconnect all of them
Create new device

Grid dimensions in autorouting:

Export dpi?

then export as a png (file — export — image)
settings should be MONOCHROME and 500 DPI – this will export a image with white traces.
Make sure the color mode is set to greyscale: image > mode > greyscale
then export Dimenson layer for milling the outside of the board
Remember: the Modela cuts out the DARK and leaves white!

Correction! It should be both the top and pads layer.

just type in
~$ fab

… upon trying to make path:
      distance 0.800000, 140873 exterior points remain
Segmentation fault (core dumped)

must run as sudo
~$ sudo fab

Nyancat cake mold, working PoV [not so yoyo], vending corkscrew test (mod servo for continuous rotation)

Uhh I’ve been doing a lot of blogging and neglecting my other work, so here is minimalist style ftw.

nyancake? nyangummi?

My hall’s thanksgiving (putzgiving, alums come back for this) was two Saturdays ago. I tested out the nyancat cake mold:

for ease of “parameter optimization” runs, I used even-simpler-cake-recipe: cake mix and sprite as the only ingredients (apparently a dieting trick. comes out fine, although for molds probably want to let bubbles settle for a bit after pouring and before intensive mixing).
apply release agent, aka cooking spray / pam — otherwise doesn’t come out well. also,  sprite+cakemix mixture should not be too gloopy. add flour if accidentally pour too much sprite.

many fail results. Here, did not let bake long enough. (much longer than box says — I baked a bit lower temp based on silicone mold research, ~325deg C, and for say 1 or 2 hours)
demolded too quickly, also did not cover in saran wrap to retain moisture afterward
nyancake party~! nyan nyan nyan
probably the best of all my nyancakes. you can see that the minimum mold feature size — the sprinkles — were too small for the resolution of the cake mix and actually resulted in holes.
speed cooling jello in freezer. recipe used: the lego gummies from instructables
nyanjello = almost perfect mold replica. you can see the sprinkles are supposed to stand out, as opposed to how the nyancakes turned out. however, more limited / difficult coloring opportunities with jello than with cake (which you can just apply frosting / food coloring to)
Persistence of Vision Yoyo
I also figured out the issue with the MAS.863 makefiles causing my weird “compiler” bug (actually, compiler options / makefile bug):

Class-based makefile includes:
avr-objcopy -j .text -O ihex ./v0.1.45.out ./v0.1.45.c.hex
man avr-objcopy
       -j sectionname
  Copy only the named section from the input file to the output file.
  This option may  be  given more than once.  Note that using this
  option inappropriately may make the output file unusable. >__> <__<
So the class makefiles should be fixed to include “-j .data”The internet says
“The makefile above DOES NOT create a proper HEX image and is a bad example. When creating an  image, not only does the text section (which holds the code) need to be included but the data section (which holds any initialized data) also needs to be included.
The remedy for this is correct .hex rule to to copy the data setion as well
$(OBJCOPY) -j .text -j .data -O ihex $(PROJECT).out $(PROJECT).hex

bmayton: that actually explains a lot of odd bugs that I’ve been seeing with people

using constant arrays, since the array data is never getting copied into the

So the actual model of what was causing my bug was, I believe, without calling another function the compiler goes ahead and uses the array to insert the correct commands into the compiled code. But when I used a subfunction, the compiler loads the subfunction which the microcontroller calls, but the ucontroller does not have the array data to look up what to set DDRB and PORTB to.

Anyway, then I proceeded to hack together terrible!code and get PoV working. I used oloepede’s sample image ‘cos I’m all about the laziest and quickest tests and ‘cos olopede is awesome.

eheh derp ripped off ISP traces / headers
works fine waving it by hand (without camera extended exposure time, hard to see entire “olopede” message — can see maybe three letters at a time. dead reckoning PoV timing — no sensors.) 

Doesn’t do so hot on the drill. Mess with timing? Although I spun it slow and fast (and in-use yoyo spins quite fast). May require sensors (fan pov as seen on dealextreme — product designer has better idea of speed of motor while yoyo has more variable speed. maybe they used hall effect sensors, ‘cos it was resilient to me slowing down the blades.) to get stable image.

See video:

Vending machine
Right, essentially two weeks until final projects due. Aka time to start cramming on vending machine.

What do I have on hand? Arduino uno, extra servos leftover from when I bought out all the old 2.007 servos., zipties, handheld drill, a corkscrew. Found some rectangular metal thing to act as guiderails lying around MITERS scrap pile. Also found a block of wood lying around the floor.

Mod a servo  to be
continuous rotation servo
(essentially turn it into a cheap RC motor that comes with motor speed controller in a convenient package for mounting) —
aka remove mechanical stop on gear 

apply flush cutters to stop on gear

and remove pot, which like all pots doesn’t turn infinitely — make sure to be gentle ‘cos pot is held in by internal screw, why it doesn’t just fall out normally

see blurry screw at bottom. Also, I wasn’t gentle and cracked the PCB. Maybe it is inevitable for these servos (motor is soldered onto pcb so not much flexibility there) to get to pot screw. Surprisingly the servo still works…
stick pot on outside, chew a hole for it in the casing — i abused flush cutters

see How to Hack a Servo by Daniela Faas http://stellar.mit.edu/S/course/2/sp11/2.007/courseMaterial/topics/topic12/other/Servo_Hack_large/Servo_Hack_large.pdf)

springs / coils
Attach to corkscrew (from real vending machine) I bought off of ebay to see what real mass manufactured ones are like so I can make fake ones DIY like http://www.instructables.com/id/Make-your-own-springs-in-seconds/

Drill out servo horns (1/8” bit fits zipties I found) and attach to corkscrew with zipties

it vends a block! haha. terrible setup is terrible.

Video here:

Yea, not a very interesting proof-of-concept (a “duh are you an idiot” one), but it was very satisfying to me.

Oh right, I tried to use hot glue to hold the pot in one place, since that affects how the servo reacts to servo.write() (pot adjusts when it goes fwd/reverse) — I just used
myServo.write(50) with a 0.5 sec delay
myServo.write(90) with a 3 sec delay
myServo.write(130) with a 0.5 sec delay
to calibrate the pot so that servo was completely still at 90. And then attempted to hot glue. a bit flaky– not good enough for long-term banging around but good enough for dirty proto.

yes, i stole arduino from hexarideablepod. arduino uno with a small breadboard on top and 3 male header pins to connect arduino (Vcc, Gnd, and SIG — arbitrarily pin 2 in my case) and servo. unplugged in this pic.

Not clear from pics, but to test it I’m holding the servo still with my hand.

PoV Yoyo update: v0.1 and failcode (also, Hello World in microcontrollers)

PoV yoyo update:
v0.1: 6 leds (3 pins), attiny45, phototrans, button, isp header (no battery) — board done.
v0.1 — code is the fails. I’ve been chasing this weird compiler bug for many days now.

So I milled and populated my eagle circuit and it works (well, the LEDs at least, haven’t tested buttons / phototransistor). https://github.com/nouyang/pov-yoyo and http://fab.cba.mit.edu/classes/4.140/people/nancy.ouyang/Week11/Week11.html

eagle schematic
I’m using the ng.lbr, fab.lbr, and the sparkfun libraries. More info here: http://academy.cba.mit.edu/tutorials/eagle/eagle_resources.html and the list of parts in fab.lbr:
board layout
slightly cleaned up, colors inverted, for milling out on the roland modella in the MIT Media Lab shop. I export at 1000 dpi to be safe, and clean it up in the open-source and free GIMP image editor.
powered off of USB for now. 

The yoyo is 3d printed, but it’s designed to be injection molded. I’m working with Laura Shumaker and Dan Fourie, and it’s based off of lshu’s 2.008 group’s yoyo design from last year. I’ll upload the Solidworks files when I get permission. Here’s what the CAD files look like (there are three parts. The PCB should pressfit inside the inner body, which fits inside the outer body, and the retaining ring goes on top, pressfitting into the outer body and making sure the inner body doesn’t come out).

The three parts that I 3d printed
So yea, you can poke the eagle file on github and see that I simply drew a rectangle starting at the origin and then set the x2 and y2 coordinates according to the 2d solidworks measurements. (For more on spatial constraints and pcb layout, see http://www.orangenarwhals.com/?p=163)

inner body determines dimensions of board. Corners filleted due to concern over injection molding mold machinability, but turns out to be unwarranted (I think), next version will have sharp corners.

I ended up approximating in Eagle the dimensions from the CAD file that I would need to fit inside the 

After that I devolved into code misery at the down point of which I was wondering why I couldn’t even copy code correctly. Turns out to be a makefile issue. See: http://www.orangenarwhals.com/?p=162

Anyway, so now I’m at the point where I can turn each LED on individually, I’m still trying to figure out my code bugs.

Oh right, this is after my realization last week that I don’t understand any codes. Not even hello world codes.  0b000? 0x000? 0? char? int? huh?

So, I read up on bit operations stuff -^-^-
I recommend these for explaining the hello world code, which seems straightforward now (turn LED on! turn off!) but seemed completely foreign when I was trying to debug my code / write my own / mash together code from other people.
[1] http://fab.cba.mit.edu/content/tools/microcontrollers/c_for_microcontrollers.html
[2] http://www.arduino.cc/playground/Code/BitMath
[3] http://iamsuhasm.wordpress.com/tutsproj/avr-gcc-tutorial/

My code’s here:
and I’ll run over some things I hadn’t found clearly explained here.
0x designates hexadecimal, while 0b designates binary. These are fixed flags, similar to a plus or minus sign in front of a number. The actual values that matter come afterward.
So 0b0010 translates to, in decimal, two. And the compiler will assume that there are infinity zeros to the right (well, until ’till the size of the variable or constant at least, eg 0b00000010 for a byte = 8 bits), just as in decimal “2” and “00[…]002” are equivalent.

#define LINE_A 0
#define LINE_B 1
#define LINE_C 2

//DDRB direction config for each LED (1 = output) //in or output
const char led_dir[6] = {
  ( 1<<LINE_B | 1<<LINE_A & ~(1<<LINE_C)), //LED 0
  ( 1<<LINE_A | 1<<LINE_B & ~(1<<LINE_C)), //LED 1

//PORTB output config for each LED (1 = High, 0 = Low) //hi or lo
const char led_out[6] = {
  ( 1<<LINE_B & ~(1<<LINE_A)), //LED 0

What do these lines mean? Well,
1 << LINE_A means 1 << 0 according to the #defines : This means “put a 1 shifted over 0 bits”, aka 0b1 or 0b00000001
1 << 1 : 0b10, or 0b00000010
The “|” means bitwise OR, aka I add the two numbers together to get
0b00000011 — that is, DDRB pins 1 and 2 are both outputs and everything else is in high impedance mode. To be safe, since I am using 6 LEDs on 3 pins

3 Pin Charlieplexing.png
http://en.wikipedia.org/wiki/Charlieplexing for more info

and therefore cannot have uncertainty about whether the unused pin is in high impedance (input) mode or output mode, I explicitly state with
& ~(1<<LINE_C) that pin 7 (on the attiny45, see datasheet which tells me that pin7 corresponds to index 2 on DDRB — hence #defines LINE_C 2) must be in high impedance mode.
See [1] for an explanation of what & ~(a 1 at the appropriate index)
I’m not certain this is necessary, since in my case I explicitly say “DDRB = 0b011” later in the code rather than saying “DDRB |= 0b011” which would have left high any unspecified pins that were originally high, but I’d rather put it in here than risk wondering if my bugs are because of this.

Thus, an equivalent led_dir array could have said led_dir = {0b001, 0b011, […]}.

C Resources:

My code 

is based off of:

Charlieplexing code:

Most PoV code appears to be in asm:

Crazy compiler bugs, AVR Studio’s avr-gcc commands explained, and makefiles

[Edit: solved, the error was in the fab hello world makefile line
$(OBJCOPY) -j .text -O ihex $(PROJECT).out $(PROJECT).hex
To fix, add -j data or drop the -j option altogether)
See http://www.micahcarrick.com/avr-tutorial-digital-output.html. also, man avr-objcopy.
What was actually happening was in one example the compiler replaces the code with the array data and then loads it into the microcontroller, while for the other example it loads the compiled code into the micro, and in both cases the constant array never makes it into the microcontroller.]

The surface symptoms of crazy compiler bug which appears to eat variables (NOT an optimization issue! — check out this awesome thread for more about that http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=97382 )

Me: I’m getting bugs where the exact symptom in simplest form is

void light_led(char led_num) {
   DDRB = led_dir[2];
   PORTB = led_out[2];
void main(void) {
   while (1) {
      light_led(2); //obviously I am ignoring the argument given here
works as expected but
void light_led(char led_num) {
   DDRB = led_dir[led_num];
   PORTB = led_out[2];
void main(void) {
   while (1) {

doesn’t. (tested and doesn’t work: char, volatile char, int and now int8_t and uint8_t).

Based on this code: https://github.com/benbrandt22/TinyLife5/blob/master/TinyLife5.c
(full file here: https://github.com/nouyang/pov-yoyo/blob/master/v0.1.45.c)

Yes, I tried int instead if char in case C arrays wanted int indices. And volatile char in case the compiler was like “You, variable! You are a useless waste of memory. OPTIMIZED.” (sfx notes: that should sound like RECTIFIED in Tron).

Okay, so why doesn’t AVR Studio 5 Debugger work?

Turned out AVR Studio debugger is straightforward, but it doesn’t work if you have a

void main (void) {}
function instead of a
int main … (return 0; )

Also, AVR Studio 5 is amazing. I can peer at all the DDRB and PORTB and all the pins — even with an oscilloscope I would need like 8 arms to do this.

Oh right, back from worshiping AVR for making AVR Studio freely available (the Gobsmacking Glory of which is only slightly diminished by my sadness that it’s not open-source / doesn’t run on linux (haven’t tried WINE yet)) and on to compiler issues.

Re: linux avr toolchains, Pranjal Vachaspati, hallmate and 2014, in yet-another-spam-thread-I-started, writes:

If you’re using AVR eclipse (and I strongly recommend you do, as AVR development has way too many steps to comfortably manage manually), make sure you change the build target from “Debug” to “Release” or else it won’t create the appropriate binary. Also if you’re not using AVR eclipse it’s awesome! http://avr-eclipse.sourceforge.net/wiki/index.php/The_AVR_Eclipse_Plugin

In the meantime, I will continue my terrifying toolchain of Desktop > AVR Studio > Compile > attach *.hex file to email > Netbook > download file > run avrdude > Debug in AVR studio > … =/ Maybe AVR Studio works with Wine.

I grabbed the avr-gcc commands from the terminal output at the bottom of AVR Studio 5, edited the filenames, and used it to compile C code on ubuntu. (Note that choosing “Release” uses -Os, full optimization, while choosing “Debug” uses -O0, no optimization. For my code this results in 3 kilobytes flashed versus 150 bytes! — 3kb = almost 90% of available mem on attiny45)

I’m writing some C code for the attiny45 microcontroller for how to make anything,  and I’m debugging a problem where for the exact same C code,  AVR Studio creates a happy .hex file but the class-derived makefile creates a “I’m-going-to-half-work-and-drive-you-crazy-debugging” .hex file (see C code above for the symptoms).

 ~~~AVR Studio commands
avr-gcc -funsigned-char -funsigned-bitfields -Os -fpack-struct -fshort-enums -g2 -Wall -c -std=gnu99  -mmcu=attiny45   -MD -MP -MF”v0.1.45.d” -MT”v0.1.45.d” -o”v0.1.45.o” “v0.1.45.c”
avr-gcc -mmcu=attiny45  -Wl,-Map=v0.1.45.map -o v0.1.45.elf  v0.1.45.o
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  “v0.1.45.elf” “v0.1.45.hex”
avr-objdump -h -S “v0.1.45.elf” > “v0.1.45.lss”
avr-objcopy -j .eeprom –set-section-flags=.eeprom=alloc,load –change-section-lma .eeprom=0 –no-change-warnings -O ihex “v0.1.45.elf” “v0.1.45.eep” || exit 0
avrdude -p t45  -c usbtiny -U flash:w:v01.45.hex
~Results  as run on Ubuntu 11.10 in 435 bytes .hex file / 146 bytes flashed. And results in a bunch of magical files.

~~~Class-derived Makefile
avr-gcc -mmcu=attiny45 -Wall -Os -DF_CPU=8000000 -I./ -o ./v0.1.45.out ./v0.1.45.c
avr-objcopy -j .text -O ihex ./v0.1.45.out ./v0.1.45.c.hex;
avr-size –mcu=attiny45 –format=avr ./v0.1.45.out
avrdude -p t45  -c usbtiny -U flash:w:v0.1.45.c.hex

~Results as run on Ubuntu 11.10 in 443 bytes .hex file / 150 bytes flashed. (it takes up more memory and it doesn’t work right! :/)

So, I emailed out to the MAS.863 and one of the TAs promptly spent almost an hour writing an essay in reply. o__o Yay awesome people. Directly copied:

Brian Mayton (bmayton):

Here’s what some of this means.  First, starting with the compiler command (avr-gcc).

> avr-gcc   -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums

The -f options change the behavior of the compiler.  -funsigned-char tells it that the ‘char’ type is by default unsigned (that is, cannot represent negative numbers, but can store numbers twice as large.)  Normally in C ‘char’ is signed, and if you want an unsigned one you have to say ‘unsigned char’.  This flag swaps it around, so that ‘char’ is unsigned by default and you have to say ‘signed char’ if you want a signed one.  Generally, when writing microcontroller code, I very much prefer to be explicit, never assuming what the compiler is going to do.  <stdint.h> is part of the C standard library and defines types like ‘uint8_t’ (an unsigned 8-bit integer, same as ‘unsigned char’) and ‘int8_t’ (a signed 8-bit integer, same as ‘signed char.’)  I prefer these over the char, short, int, long types because I know exactly what I’m getting.

-funsigned-bitfields says that bitfields are also unsigned.  If you don’t know what bitfields are, you’re probably not using them.  (Most code for avr-gcc doesn’t use them.)

-fpack-struct says that all structs should be packed.  (Look up C structs if you’re not sure what these are.)  On some processor architectures, memory is addressed a ‘word’ at a timeβ€”on a 32-bit x86 processor, for example, a word is 32 bits (or four bytes) long.  The instructions for accessing a word of memory tend to be faster when the word being accessed is ‘aligned’ to a word boundary, i.e. its address in memory is a multiple of four bytes.  In a struct, if you were to have, for example, three fields that were each one byte long (uint8_t), and then one field that was four bytes long (uint32_t), and the beginning of the struct is aligned to a word boundary, then the 32-bit variable won’t be, and accessing it will be slower than if it were.  So sometimes the compiler will insert ‘padding’ to make sure that all multi-byte fields in a struct are aligned to word boundaries; in this case, it might insert one byte of padding in between our three single-byte variables and the four-byte variable to push it over onto the word boundary.  Telling the compiler that a struct should be ‘packed’ tells it *not* to insert this padding.  On a microcontroller with limited memory, you might prefer the slower access to unaligned fields to the ‘wasted’ memory that padding creates, or if you’re implementing a network protocol that needs the fields to be at specific locations.

-fshort-enums tells the compiler that enums (again, look this up if you don’t know what they are) should be stored as a ‘short’ rather than an ‘int’.

My guess is that it’s likely one of the above flags that makes your code work, but without seeing your code I couldn’t say for sure.

>   -Os

This sets the optimization level.  -Os means that the compiler should optimize to make things faster, but try to produce the smallest program possible.  -O0 means don’t optimize, -O1 means some optimizations, -O2 enables more optimizations, and -O3 turns on optimizations that might also result in a larger program. http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=71862
>   -g2

This tells the compiler to include debugging information in the code it generates; if you use a debugger later, it uses this information to map between which instruction in the compiled program corresponds to which line of the C files.

>   -Wall

This tells the compiler to enable all warnings.  There are some warnings that aren’t enabled by default (such as you defined a variable but didn’t use it, there’s nothing wrong with that, but it might be a mistake.)  This can sometimes help point out programming bugs that compile fine but might not be what you meant to write.

>   -c

This tells the compiler that it’s going to build an object file instead of a complete program.  Object files contain compiled functions, but they’re not yet ‘linked’ together into a complete program.  When you use a C compiler, one way to do it is to just give it all of your C files at once and have it produce a complete program all in one go (this is how Neil’s example Makefiles do it).  In more complex programs, it’s often useful to produce the intermediate object files first, and then link them together into the complete program at the end.  If you have lots of .c files, and only change one, then you only need to rebuild the .o object file corresponding to the .c file that changed.  For a big project with lots of code, that can be faster.

You can read more about what ‘compiling’ and ‘linking’ mean (lots of info online) if you want to get a better understanding of what’s happening.

>   -std=gnu99

This tells the compiler to use the GNU99 standard.  There are a couple of different variants of C.  There’s ‘ANSI C’ or C89 (the ’89’ corresponds to 1989, the year the standard was ratified.)  C99 is a newer revision to the standard that adds some extra features to the language (like being able to declare varaibles at other places than the top of a block.)  GNU99 adds in a handful of GCC-specific extensions.

>   -mmcu=attiny45

This, of course, tells the compiler what processor to produce code for.

>   -MD -MP -MF”v0.1.45.d” -MT”v0.1.45.d”

These are all dependency-tracking options, that tell the compiler to save information about which header files are used by each .c file, which can be used later to determine, if a header changes, which source files need to be rebuilt.  This is useful for large projects, but not terribly useful for small microcontroller stuff.

>   -o”v0.1.45.o”

This specifies the output filename.  Usually the convention for object files is whatever the name of the .c file was, but with .o instead.

>   “v0.1.45.c”

And finally, this is the .c file to compile.  And that’s it for the compilation step.  If you had multiple .c files in the program, this would be repeated for each one.

Now, the linking step:

> avr-gcc -mmcu=attiny45  -Wl,-Map=v0.1.45.map -o v0.1.45.elf  v0.1.45.o

This also uses the avr-gcc command, but since there’s no -c flag, it’s going to build a complete program instead.  The linker will take all of the object files (in this case, only one) and assemble them together into a complete program, figuring out where everything fits in memory.  The object files have ‘notes’ in them that say things like ‘here I want to call function foo()’; it’s the linker’s job to decide where function ‘foo()’ is actually going to be in memory, and replace that ‘note’ with the actual address for the program to jump to.  The -Wl,-Map= flag tells the linker to also produce a file that says where it’s putting things, which can be helpful to reference when debugging sometimes.

The -o flag, like before, specifies the output file; for a complete program, this will be in ‘elf’ format.  (This is a standard format for executable programs, you can read more about it if you want.)  Finally, a list of all of the .o files to include in the program follows (in this case, again, we only have the one.)

Now some objcopy/objdump stuff:

> avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature  “v0.1.45.elf” “v0.1.45.hex”

Mostly for historical reasons, a lot of programming tools won’t read an elf file directly.  Customarily, the file format that’s used is Intel HEX (ihex, or simply .hex.)  (Some embedded systems also use Motorola S-record or srec files).  The objcopy command here is basically copying the compiled code from the elf file into a hex file.  It’s told (via the -R flags) to ignore the .eeprom, .fuse, .lock, and .signature sections (so this hex file will basically only contain the program code, or the .text (in executable parlance, ‘text’ often means compiled code) section.)

> avr-objdump -h -S “v0.1.45.elf” > “v0.1.45.lss”

objdump here is generating a file with the disassembly listing of the compiled program.  This is completely unnecessary to generating working code, but sometimes looking at the disassembled program to see what instructions the compiler generated can be a useful debugging tool.

> avr-objcopy -j .eeprom –set-section-flags=.eeprom=alloc,load –change-section-lma .eeprom=0 –no-change-warnings -O ihex “v0.1.45.elf” “v0.1.45.eep” || exit 0

Finally, this is creating another hex file that would contain any ‘.eeprom’ section you defined in your program.  You’re quite likely not using the EEPROM on the chip, and don’t need this.

That ended up being a bit long-winded and I went off on a few tangents, but maybe that helps a little?

Also, perhaps the reason why avr-gcc install with neither manpages nor info files is the length of the avr-gcc manual: http://linux.die.net/man/1/avr-gcc

Then my email to my hall course-6 list sidetracked into a rant about makefiles. The main takeaway was that to learn about makefiles I should read the GNU Make manual.

Here’s the gist of the email thread, if it’s interesting to others:

Marti Bolivar (of leaflabs! http://leaflabs.com/ yay open source hardware startups):

if at any point, you find the experience of writing a nontrivial
makefile akin to swimming upstream in a river of tepid molasses, don’t
despair. that is the expected behavior. make sucks, that’s life :(.

if your class requirements don’t forbid it, you may wish to try scons
(http://www.scons.org/) out.

RJ Ryan (of open-source DJ software mixxx http://www.mixxx.org/ and mobile health Sana Mobile http://sana.mit.edu/) says:

SCons is good for projects where everyone knows Python. If nobody knows Python, it’s a really terrible idea. πŸ™‚ Just look at Mixxx’s SConstructs. I’ve attempted to bring some sanity to them, but they’re mostly crap.

And that’s only like 70% of the SCons files we have. After dealing with this long enough, I coined this addage: Give a person a turing-complete build system and they will find a way to club a baby seal.

In my experience, you have two options if you are stuck with make:

1) Spend years learning by example and eventually understand most of what is going on but still be utterly confused 10% of the time (e.g. dealing with autoconf-generated makefiles).

2) Spend a couple hours reading the GNU make manual straight through. Everything will make a lot more sense.

Reid Kleckner writes:

Build systems are like the ultimate doomed project area.  There are so many systems that reinvent the wheel in slightly different ways and don’t provide a bulletproof solution for everyone.

Every user has completely different requirements and is always migrating from some other system where xyz was easy, and so they just grow and grow features that make them incomprehensible at the end of the day.

Projects in this area that haven’t solved all your problems yet:

  • make
  • autoconf/automake
  • cmake (we use this for DynamoRIO and DrMemory)
  • Boost’s jam
  • jom
  • eclipse
  • visual studio
  • ninja
  • scons
  • rake
  • BSD make
  • Ant
  • Maven and all the *other* Java build systems
  • gyp (we use this for Chrome, go NIH)
  • the new LLVM build system ddunbar proposed

It’s just…  I ** hate build systems.  They all suck.  They’re too slow, don’t run on platform x, can’t crosscompile, mess up the deps so you have to do a clean build…

Maybe we ask too much of them. 

marti picks up on the topic of turing complete baby seal clubbers:





that second one reminds me of duff’s quote about his device (with respect to whether fall-through was ok), “This code forms some sort of argument in that debate, but I’m not sure whether it’s for or against.”

 then perry huang, some hall alum I have never met I think:

from the creator of make:

“Why the tab in column 1? Yacc was new, Lex was brand new. I hadn’t tried either, so I figured this would be a good excuse to learn. After getting myself snarled up with my first stab at Lex, I just did something simple with the pattern newline-tab. It worked, it stayed.  And then a few weeks later I had a user population of about a dozen, most of them friends, and I didn’t want to screw up my embedded base. The rest, sadly, is history.”– Stuart Feldman

So yea. I’m waiting for when microcontrollers get so powerful and cheap that I can run python on them. >__> <__<