Over this weekend I have been working on faerii, a USB controlled RGB LED based around the ATtiny85.

Here is a picture of the breadboard prototype

faerii breadboard prototype
The ATtiny85 is mid centre, and immediately above it is the ISP header. To the left of the ISP header, near the centre, is a 4 pin header that provides USB connectivity. Obscuring it is two filter capacitors, pull resistors, and zener diodes. Finally on the far left edge is a common-anode RGB LED.

Here is a video of it in operation:

The project is based around the hid-data example from vusb. The EEPROM contains control blocks, consisting of 4 bytes. The first 3 bytes specify the red, green and blue intensities, in that order. The last byte specifies a duration. Upon reading a control block, the LED transitions, over the specified duration, from its current colour to the new colour. Currently the duration specified in multiples of 20ms.

Lists of control blocks, which I call a control sequence, can be delimited using delimiter blocks. These blocks have a specified duration value of 0xff. When such a block is encountered, the sequence is restarted  from the beginning. Multiple sequences can be programmed into EEPROM.

The host software performs the job of programming sequences into EEPROM. It also provides additional commands, such as RESET and GOTO. The latter allows a collection of sequences to be stored in EEPROM, and activated individually. This feature was provided to minimise the amount of EEPROM writes required to change patterns. For example, sequences might be stored for an idle and new mail state. Activation then simply requires sending the correct GOTO command, without rewriting the EEPROM which as a limited write/erase cycle.

Currently a total of 62 control blocks can be stored. This is due to incomplete support for writing to arbitrary EEPROM address, and the fact the first block is reserved. It should be no great difficulty to fix this.

Two major features I have no implemented yet are REVERSE and MODIFY-ON-READ. These are animation options, where REVERSE specifies that upon reaching the end of a sequence, instead of starting again from the beginning, control blocks should be read backwards. MODIFY-ON-READ is more interesting. The intention is that after reading and executing a control block, the block's RGB  values should be modified. This allows free-running random colour cycling without explicit programming.

The firmware and commandline utility source code is hosted at github. I will add proper schematics next weekend, though you can probably figure most of it by googling and looking at the photo above.


GNU readline with System Python (OS X 10.7)

By default system python loads "fake" readline (fake because it actually uses libedit) from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/readline.so. Even if you install readline (which goes into /Library/Python/2.7/site-packages), it will still load it, even if you fiddle with sys.path.

The one solution I have found, which I am not terribly proud of, is to rename readline.so to readline.so.bak. This forces the GNU readline installed via pip/easy_install to be loaded.

Now I have nice things in the python interpreter again.



Notes on x86 Opcodes

Here are some notes I made while trying to understand the opcodes in this fun article on generating small elf binaries. Hopefully they will be of use.

  00000000 B801000000        mov        eax, 1
  00000005 BB2A000000        mov        ebx, 42
  0000000A CD80              int        0x80

In the above snippet:
  • B8 is the move instruction, in which the destination register is encoded into the opcode itself. The mov instruction is B8+r where r = 0..7, 0 being al/ax/eax depending on the data size. 
    • One might naively expect then that the next opcode to move 42 into ebx would be B9, and one would be wrong. The registers are not numbered alphabetically. The next 2 registers in sequence is cl/cx/ecx for r=1 and dl/dx/edx for r=2, and finally we get to bl/bx/ebx for r=3. This explains why the next mov instruction has value BB.
      • Note also the little endian encoding of bytes in the operand.

  00000000 31C0              xor        eax, eax
  00000002 40                inc        eax
  00000003 B32A              mov        bl, 42
  00000005 CD80              int        0x80

In the above snippet:
  • 31 encodes xor
    • C0 is the MOD-REG-R/M byte, which has the format:
      • 0..2: R/M (register or memory, 0..7)
      • 3..5: REG (register, 0..7)
      • 6..7: MOD (addressing mode, 0..4)
    • In this case, we have:
      • MOD=11
      • REG=0
      • R/M=0
      • Which says: addressing mode is register addressing mode, and the destination and source registers are eax (REG=0) and eax (R/M=0).
  • 40 is an instruction like B8, where the register to modify is encoded in the opcode itself. 
  • B3 is B0+r with r=3. This is like B8+r except B8+r deals with 16/32bit data while B0+r deals with 8bit data.
    • Recall again that the bl/bx/ebx is the 4th register, not the second.
Instruction information was sourced from the very useful X86 Opcode and Instruction Reference.