Scrolling NEOPIXEL Leds

This post brought to you by the letter H, and the dev board Tessel

This post brought to you by the letter H

Scrolling text on NEOPIXEL LEDs is quite a bit easier than on the previous LED panel, as it is part of the out-of-the-box functionality provided by the great and mighty adafruit.  I had the pleasure of working with the adafruit 8×8 neopixel array, as seen above.  These things are BRIGHT.  And unlike the previous LED panel, they don’t have any kind of cover or diffuser.

The result is that there is no dark color to contrast against, and the leds are so bright that they “bleed” into the surrounding space a little.  they also reflect off the glossy PCB.  The result is that at a distance, it can be a little hard to read the text on only an 8×8 panel.  A diffuser and a black mask around the pixels might help provide some contrast, and prevent the reflection problem.

Software:

The code was really simply.  The adafruit libraries take care of all the heavy lifting.  The one caveat is that I had to delete my Arduino Robot library because it caused some kind of error.

Some important but uncommented lines from the example are:

const uint16_t colors[] = {
matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(255, 255, 255) };

This makes an array of values to scroll text in.  Here it goes Red, Green, White.  You can add more or delete some but you may have to change loop iterator values later in the code.

matrix.print(F(“HI, RYAN.  THIS IS A NEOPIXEL BOARD”));
if(–x < -220) {

These lines control what gets printed to the matrix, and how much gets printed.  -220 can be made shorter to print only part of the message, and the string “HI RYAN, THIS IS A NEOPIXEL BOARD” can be changed to whatever you want.

Code dump:

// Adafruit_NeoMatrix example for single NeoPixel Shield.
// Scrolls ‘Howdy’ across the matrix in a portrait (vertical) orientation.

#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
#ifndef PSTR
#define PSTR // Make Arduino Due happy
#endif

#define PIN 6

// MATRIX DECLARATION:
// Parameter 1 = width of NeoPixel matrix
// Parameter 2 = height of matrix
// Parameter 3 = pin number (most are valid)
// Parameter 4 = matrix layout flags, add together as needed:
//   NEO_MATRIX_TOP, NEO_MATRIX_BOTTOM, NEO_MATRIX_LEFT, NEO_MATRIX_RIGHT:
//     Position of the FIRST LED in the matrix; pick two, e.g.
//     NEO_MATRIX_TOP + NEO_MATRIX_LEFT for the top-left corner.
//   NEO_MATRIX_ROWS, NEO_MATRIX_COLUMNS: LEDs are arranged in horizontal
//     rows or in vertical columns, respectively; pick one or the other.
//   NEO_MATRIX_PROGRESSIVE, NEO_MATRIX_ZIGZAG: all rows/columns proceed
//     in the same order, or alternate lines reverse direction; pick one.
//   See example below for these values in action.
// Parameter 5 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic ‘v1′ (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)

// Example for NeoPixel Shield.  In this application we’d like to use it
// as a 5×8 tall matrix, with the USB port positioned at the top of the
// Arduino.  When held that way, the first pixel is at the top right, and
// lines are arranged in columns, progressive order.  The shield uses
// 800 KHz (v2) pixels that expect GRB color data.
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(8, 8, PIN,
NEO_MATRIX_TOP     + NEO_MATRIX_RIGHT +
NEO_MATRIX_COLUMNS + NEO_MATRIX_PROGRESSIVE,
NEO_GRB            + NEO_KHZ800);

const uint16_t colors[] = {
matrix.Color(255, 0, 0), matrix.Color(0, 255, 0), matrix.Color(255, 255, 255) };

void setup() {
matrix.begin();
matrix.setTextWrap(false);
matrix.setBrightness(40);
matrix.setTextColor(colors[0]);
}

int x    = matrix.width();
int pass = 0;

void loop() {
matrix.fillScreen(0);
matrix.setCursor(x, 0);
matrix.print(F(“HI, RYAN.  THIS IS A NEOPIXEL BOARD”));
if(–x < -220) {
x = matrix.width();
if(++pass >= 3) pass = 0;
matrix.setTextColor(colors[pass]);
}
matrix.show();
delay(100);
}

Hardware:

As usual, adafruit provides awesome information on hooking up the LEDs here.  But in case that is down or something, all you have to do to hook this up to an arduino is to hook up pin 6 to the DI pin through a 300-500 ohm resistor, and to supply power with a 5v 4A power supply.  the voltage can go below 5v, but not above 5v, as this will burn out the leds. Any amperage in excess of 4A is fine.

Videos!

 

BlueGene Technical Progress Report

pSHL8 is not the one I have

pSHL8 is not the one I have

In my pursuit of an indigo plasmid, I had two options: straight up synthesis, or getting the original plasmid cloned from the rhodococcus gene.  Back when I started this project, it would have cost about $600 to get the gene synthesized and stitched together, which would leave very little room for improvement.  Fortunately, Dr. Stephen Hart was kind enough to send me the plasmids from his research from 20 years ago.

Unfortunately, the only plasmid that was still intact was labeled pSLH1.  pSLH1 is described the paper “Construction of an insertional-inactivation cloning vector for Escherichia coli using a Rhodococcus gene for indigo production” as “The prototype insertional-inactivation cloning vector pSLH1… level of production appeared to be lower than that of other pigment-producing strains…cells produced only slight amounts of pigment even after several days incubation at room temperature.”  According to my observations, this is accurate- it takes a while for the transformed bacteria to produce indigo.  This seems to be because between the the indigo production gene and the promoter (an in-frame lacZ’a fragment upstream of the gene), there is a stop codon and two rare codons which theoretically prevent the gene from being expressed.

Deletion of stop codon

Deletion of stop codon

Hart and Woods went ahead and deleted the deleterious fragment of the gene by cutting out the undesirable DNA, chewing the ends of the DNA back with exonuclease III, and then blunt-end ligating the ends together.  Amazingly, this deletion keeps everything in-frame, and produces more indigo than without the deletion.  The process is shown in the image above.  First, the gene is cut, then the exoIII blunts the ends, and finally they are re-ligated.

In theory, this is great, and it totally works.  In practice, something was mislabeled or possibly only a mutated version made it to me 20 years later, because the sequence I got was not the sequence from the paper.  It was pretty close, but definitely different.  Lets compare:

Modern read -G TCG ACGG

From paper  -C TGC AGGC GA

Bolded letters show the “wrong” codons for the cut recognition site (CTGCAG) for PstI.  My hypothesis is that the new read is correct, and that the old read was flawed in one way or another.  This is because the new read was duplicated exactly the same across 8 independent samples, and the old read was probably done once.  The new reads were done on a modern sequencing machine, while the old read was done from radioactive sanger sequencing, which can be hard to interpret, leading to easily transposed letters in the sequence.

The authors may have gotten lucky with the enzyme as well.  I was using a recombinant “HF” enzyme, which stands for high fidelity.  This means that it has lower star/non-specific activity, reducing the chance it will make an improper cut.  To give you an idea of how much more specific the HF version is, I took this snippet from the NEB website:

The minimum number of units of PstI-HF required to produce star activity in the recommended NEBuffer 4 is (4000 units). The minimum number of units of PstI required to produce star activity in the recommended NEBuffer 3 is (120 units).The minimum number of units of PstI required to produce star activity in NEBuffer 4 is (8 units)

So the short version is that the HF version is something like 20-500 times more specific.  20 years ago, the PstI may have been even less specific, and allowed for cuts like the one that was made.  Or, somewhere along the line, a lossy polymerase copied the DNA wrong and my copy is mutated.

Either way, what actually seemed to happen was that the double-digest with PstI and SphI turned out to be a single-digest.  If you look at the actual sequence:

CTTGCATGC

it would be cut like this:

CTTGCATG || C

then blunted to this:

CCTG            C

and then ligated to this

CCTGC –> gene

Instead of increasing yield, this introduces a frame-shift mutation, which makes the gene totally useless since it is being translated out of frame.  Transforming the DNA yielded ampicilin resistant colonies with no indigo production ability.

So that was a big waste of material.  However, there is some good news!  The price of DNA synthesis has dropped, and the length of DNA that can be purchased has increased!  In these new and exciting times, the cost of synthesizing the gene is only about $200!  So I think my next steps are to codon-optimize the gene for e. coli, add restriction sites, then to add a promoter to it and stick the whole thing into p2kb to share with people.

Awesome Grant: One year later

IMG_5478

Some nice indigo-producers mixed in with not-nice ampR colonies

Last year I got an awesome grant to work on the bluegene project.  Awesome grants are by definition, awesome. For those who don’t know, an awesome foundation grant is a no strings attached $1k grant. They are granted one a month by decision of the awesome foundation trustees, who each put up $100 towards the grant.  As a result, are very flexible, community oriented, and can support all kinds of projects. In my case, the awesome grant allowed me to work on project bluegene.

Project blugene is a project to increase the yield of indigo from genetically modified e coli. The e coli harbors a plasmid that contains the sequence fpr a monoxygenase from rhodococcus. This enzyme acts on indole, turning it into indoxyl, which spontaneously turns into indigo in the presence of oxygen.

So what happened to the grant money? What has happened in bluegene? The answer is that a lot has been done, but not much has changed. Unlike mechanical or electrical engineering, bioengineering has a much slower and much more expensive turnaround time on prototypes. To make sweeping generalizations, a programming project will generate almost instantaneous feedback when run, and takes hours to iterate on, mostly for free. A pcb design might take a few (2-3) days to fabricate and test. A small mechanical prototype can be cranked out in a week, but feedback can be generated as it is built.  Implicit in all these things are feedback tools built on hundreds of years of innovation and iteration, from compiler debug output, multimeters, and logic analyzers to micrometers, thread gauges and coordinate measuring machines.

Biology has none of this.  Debugging is hard, and the parts are for all intents and purposes, invisible.  Things are getting slightly better (cheap sequencing, qPCR), but its nowhere near the level of ease of a micrometer or o-scope yet.  And with school in session and a 6 hour round trip commute to the lab, the amount of time I have put in is less than I want.  The result is that the gene was modified, with the result of only disrupting and not improving the function of the gene.  This was a result of trusting the sequence from the paper, instead of the more contemporary sequence from the plasmid I had.  It was a stupid error, but it seemed straightforward at the time.

The approximate cost breakdown is :

  • $200 for restriction enzymes and exonuclease
  • $65  for a plasimid prep kit
  • $80 for ligase
  • $80 pcr/gel extraction kit
  • $80 error correcting pcr master mix

That comes out to $500 for one iteration, not including DNA sequencing, PCR primers, lab consumables like DNA stains, agarose, media, pipette tips, petri dishes, or microtubes.  Doing the cutting, pasting, and testing is also incredibly time intensive and pretty boring.  While it is theoretically exciting that your DNA is being copied thousands of times by amazing enzymes, it is not exciting to sit on a couch and wait for it.  The waiting time and the cost make it expensive to iterate and improve designs.

However, there is a technical solution to the problem.  The toolset I was using on the project was based in molecular biology, and fundamentally comes down to cutting, pasting, and copying pieces of DNA.  At the time, it was a cheaper tool-set by maybe $200 compared to DNA synthesis.  But that was a year or so ago.

In the last year the cost of 1kb+ (kilobases, not kilobytes) DNA synthesis has plummeted.  There used to be extra costs associated with genes over 1kb in ligation and in wastage of the ends of the synthesis.  Now, both life and IDT are offering cheap synthesis of genes in excess of 1kb.  Life technologies offers up to 3kb and IDT oferers up to 2kb genes.  IDT even offers MIXED BASES, allowing you to have random mutations in certain portions of your gene.

The price for the gene that I spent $500+ and many hours unsuccessfully modifying now only costs about $210 bucks, and I can have it in a few days instead of after a few weeks.  That price and turn time are about the same price as a small quick-turned PCB.  While the debug tools are not quite there yet, biological prototyping is really catching up to other engineering disciplines.  Clearly the next move is to get the DNA synthesized, and try it out!

Another Bloggable Debug Session: “token too large, exceeds YYLMAX”

Image

This error brought to you by bananas

I was about to go through the thermal camera code today and comment and neaten things up, when my friend walked into the room.  He had brought me a gift- a gift of bananas.  He knows I like bananas, so he brought some to the dorms for me.  We decided to make some coffee, so I put the bananas on my computer for later.  These bananas led me down a long and exhausting rabbit hole by causing a very tricky bug.  By the time I got back to my coding perch, I had somewhat forgotten about the bananas, which were long since consumed along with the coffee.

I made some modifications and hit the build button, and tired to upload the code, but it wouldn’t work.  I found out that I was getting an error during the debug!  The log read:

[builtin](2): Including file ‘C:\Program Files (x86)\Atmel\Atmel Toolchain\AVR Assembler\Native\2.1.39.232\avrassembler\Include\m328Pdef.inc’
C:\Users\alouie\Documents\Atmel Studio\6.1\ThermalApp2\ThermalApp2\ThermalApp2.asm(10): Including file ‘C:\Users\alouie\Desktop\m328Pdef.inc’
token too large, exceeds YYLMAX

I tried everything to fix the situation.  I copied the code into a new project, and it it wouldn’t work, so I hadn’t messed up my build options.  I tried getting a new version of the m328def.inc files, which turned out to be up to date.  I tried commenting out the .inc file (since it looked like it was throwing the error), but I knew the .inc file was good because other projects would build.  The one thing that did work was deleting all the code and just having a loop like:

main

rjmp main

When I did this, I copied the whole file into sublimetext as kind of a giant clipboard.  This turned out to be really important to finding the bug.  Now that I knew I could get blank code to build, I started adding things back into the code.  I knew the bug had something to do with line size, or a missing “, but I couldn’t find anything out of the ordinary.  Once I hit the main loop section of the code, the error became apparent.

There were thousands of space characters, all on one line.

The banana had landed on the space key, and typed out about 28 thousand spaces.  Of all keys, that is the worst one it could have landed on.  Infinite return lines, or a long string of characters is easy to catch, but whitespace is invisible in atmel studio.  In sublime text it is wrapped, which fills up lines, and there is no new line number, so it is easy to see.

What a bizarre bug.

Thermal Camera “Live View”

 

Last time I reported that I could take b/w “stills” with the thermal camera.  This meant that the system would do this:

  1. set up registers
  2. get ambient sensor temperature
  3. initiate i2c start
  4. interrupt driven i2c read of registers
  5. display a lit led if temperature>ambient

Unfortunately, this looked pretty lame, because it never updated.  To fix this, I added a timer interrupt that interrupts every 100ms.  It initiates the i2c transaction that reads the sensor values.  100ms was chosen because the camera updates at 10 fps, so a fresh frame is ready every 100ms.  Doing this cuts down on time spent running i2c transactions, which produces a flicker free display.  A timing diagram of the system would look like this:

0ms start i2c transaction

0-3.5ms read i2c data and output pixel data

3.5-100ms output pixel data

As you can see in the video, it can tell when my hand is hovering over the sensor, as well as what direction it is coming from.  The clarity of how this is displayed should improve when I wire up all the LEDs.

The next steps of the process are to:

  1. wire up the rest of the display such that the micro will not tank if the voltage drops
  2. clean, comment, and publish code
  3. design and build an enclosure

I am excited to get this up and running!

Thermal Camera Progress: Still Images

The thermal camera can now take B/W thermal stills!  If the temperature is higher than ambient, the pixel lights up hot.  Else, it stays dark.  The rough steps in the code are:

start I2C get all pixels

while 1:

output pixels

Now all I need to do is add an interrupt that calls the I2C start every 100ms, which is as fast as the camera updates.  This will start re-writing the image data and let the output be “live”!

Interrupt Driven I2C Assembly on the Atmega328p

Interrupt-driven post here!

The Atmega328 has an I2C interrupt.  This allows I2C processes to interrupt the flow of the code whenever the TWINT bit is toggled by the hardware TWI module.  This means the processor has more clock cycles to deal with the LED display, and I don’t have to read the temperature registers bit by bit while interwoven with LED code.  I did not use interrupts originally because I wanted to do a quick test to make sure everything was hooked up write, and just to see the project work a little to keep me going.  It quickly became apparent that interrupts would be necessary.

The datasheet does a good job explaining exactly what is going on, but code can be really handy for people who are trying to implement this on their own, so I will do an explanation of the important parts.

.org $0000
jmp RESET ; Reset Handler
jmp RESET;EXT_INT0 ; IRQ0 Handler
jmp RESET;EXT_INT1 ; IRQ1 Handler
jmp RESET;PCINT0 ; PCINT0 Handler
jmp RESET;PCINT1 ; PCINT1 Handler
jmp RESET;PCINT2 ; PCINT2 Handler
jmp RESET;WDT ; Watchdog Timer Handler
jmp RESET;TIM2_COMPA ; Timer2 Compare A Handler
jmp RESET;TIM2_COMPB ; Timer2 Compare B Handler
jmp RESET;TIM2_OVF ; Timer2 Overflow Handler
jmp RESET;TIM1_CAPT ; Timer1 Capture Handler
jmp RESET;TIM1_COMPA ; Timer1 Compare A Handler
jmp RESET;TIM1_COMPB ; Timer1 Compare B Handler
jmp RESET;TIM1_OVF ; Timer1 Overflow Handler
jmp RESET;TIM0_COMPA ; Timer0 Compare A Handler
jmp RESET;TIM0_COMPB ; Timer0 Compare B Handler
jmp RESET;TIM0_OVF ; Timer0 Overflow Handler
jmp RESET;SPI_STC ; SPI Transfer Complete Handler
jmp RESET;USART_RXC ; USART, RX Complete Handler
jmp RESET;USART_UDRE ; USART, UDR Empty Handler
jmp RESET;USART_TXC ; USART, TX Complete Handler
jmp RESET;ADC ; ADC Conversion Complete Handler
jmp RESET;EE_RDY ; EEPROM Ready Handler
jmp RESET;ANA_COMP ; Analog Comparator Handler
jmp TWI_ISR;TWI ; 2-wire Serial Interface Handler
jmp RESET;SPM_RDY ; Store Program Memory Ready Handler

This is the Interrupt Service Routine (ISR) table for the atmega 328p.  Not all megas, tinys and xmegas have the same ISR setup, so check your datasheets if you are not on this exact micro.  Basically interrupts, when enabled (more on this later) cause the program counter to jump to a particular address at the beginning of the program (caveat: bootloaders.  see datasheet, but the ISRs may need be be moved in memory if you have a bootloader).  That address can have any instruction in it.  As you can see, most of mine just jump to reset, except for:

jmp TWI_ISR;TWI ; 2-wire Serial Interface Handler

This jumps to the label TWI_ISR, which is what I creatively called my Two Wire Interface Interrupt Service Routine.  This is a peice of code that deals with whatever has to happen when the TWI interrupt is triggered.

But how does it get triggered?  Well, two main things have to happen to trigger the TWI interrupt.  First, Interrupts have to be enabled.  This is done by setting the global interrupt enable (i) bit in the SREG.  This is SO SPECIAL, that it has its own instruction:

sei

Now, it would be crazy town if all of the interrupts were suddenly enabled without being configured.  Since there are tons of interrupts, and you only want some of them enabled, each one has its own special enable bit somewhere in the registers for the module.  For the TWI module, it is the TWIE bit, which you could set like this:

ldi r16, (1<<TWIE)
sts TWCR, r16

Once those are enabled, the interrupt can be triggered.  Once triggered, other interrupts are turned off, and the address that you jumped from is stored in the stack.  You can turn on interrupts within the interrupt with sei- but be careful if you do.  You can put more and more addresses in the stack (nested interrupts), but first you need to initialize the stack with:

ldi temp, high(RAMEND)
out sph,temp
ldi temp, low(RAMEND)
out spl,temp

SPH and SPL stand for stack pointer high and stack pointer low.  This sets the stack pointer register at the end of the SRAM, which is find for me.  Now, at some point the micro will want to return from the interrupt subroutine.  This can be done with

ret

but ret does not set the i bit in the SREG.  This means that interrupts will not be enabled again until the main code calls sei.  This could be a good thing, or not.  In my case, I mostly want to call

reti

which returns and re-enables interrupts.  You could call

sei
ret

but that would leave a chance of being interrupted by another interrupt in between when sei is processed and when the ret is processed.

Now we will take a look at the interrupt handler/service routine, but first a note about this particular application.

I want to quickly read the temperature data for each pixel from my 8×8 thermal camera.  These registers are stored one after another in memory space- a table can be found here.  Each temperature is stored as a 12 bit value across two sequential registers, with the next two registers being the next pixel.  so reading 0×80, 0×81, 0×82, 0×83 would give me pixel 1 high, pixel 1 low, pixel 2 high, pixel 2 low.  Since they are sequential, it seems like it would make sense to have some way to read them without having to ask for each one by name each time.  Hmm.  There is!

The device actually auto-increments the register you are going to read each time you read from it.  In other words, I can just request 128 bytes and I will get all of the temperature data at once!  This is great, and you will see how this plays out in the handler for the interrupt.

TWI_ISR:
;if you are about to read the last pixel, dont.
;instead send a stop condition
cpi   pixel,128
breq  send_stop

These first lines just check and see if the pixel counter has reached the end.  If it has, it sends a stop condition.  Otherwise, the master would just keep reading the memory of the slave.

lds   temp,TWSR
andi  temp,0b11111000

This masks the top 5 bits of the Two Wire Status Register (TWSR).  This will tell us what is happening on the bus, since the main code is not keeping track of it anymore.  The micro will want to send out different signals depending on what this is.

cpi   temp,start
breq  send_addrR

This compares the masked TWSR value and the value of start, which happens to be 0×08.  If the TWSR is set to 0×08, it means that the micro has just sent a start condition.  For this application, this means we should send the Slave addres+read address, to let the slave device know that it is going to be read from.

cpi   temp,MR_SLA_ACK
breq  read_more

cpi   temp,MR_DATA_ACK
breq  read_more

reti

This compares the masked TWSR values to see if they are MR_SLA_ACK, or MR_DATA_ACK.  The former means the slave has just acknowledged it is going to be read from, and the latter means that the slave has sent a data byte and the master has acknowledged receipt.  The last reti just tells the routine to return to the main code if none of these conditions are met.  Some kind of error handling should be put here for robustness, in case of MR_DATA_NACK or other nasty codes.

read_more:
ldi            temp,(1<<TWINT) | (1<<TWEN) | (1<<TWEA) |(1<<TWIE)
sts             TWCR,temp
inc pixel
reti

This snippet reads another byte from the bus.  In the future there will be a few more lines for storing data, but for now it just keeps asking for bytes!  The key parts of this are that TWCR has Two Wire Interrupt Enable set to 1, which enables TW interrupts, and that it returns with reti, so no matter where the code returns to it enables interrupts for later.  We also increment pixel counter, but that is implementation specific. You will notice that this is a lot sleeker than the previous code, because right aver the TWCR is set, it returns to the main program and does not wait for TWSR or TWINT statuses like in the previous poll driven code.  This means the processor can do whatever it wants in the main code, instead of waiting for the bus.  By the time it returns to the main code, about 20 clock cycles (2.5 us) will have passed.  Receiving this data will take 20 us, so this frees up about 18us or 144 clock cycles!

send_addrR:
ldi         data,0xd1
sts         TWDR,data
ldi         temp,(1<<TWINT) | (1<<TWEN) | (1<<TWIE)
sts         TWCR,temp
reti

This is the new code for sending the slave+read address.  0xd1 (0xd0+R) is loaded into temp, and then stored in TWDR, then the module is re-enabled (TWINT=1).

send_stop:
ldi         temp,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)
sts            TWCR,temp
ldi pixel,0×00
reti

Sends a stop condition.  Again, no waiting!

I2C_START_READ:
ldi         temp, (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)
sts         TWCR,temp
reti

Sends a start condition.

 

The main code to read all the registers is then:

sei
call I2C_START_READ
rjmp main

main:
rjmp main

this will read all the registers exactly once.  Calling I2C_START_READ allows the TW interrupt to trigger for the first time, once the start condition is set.

As you can see, this code will free up quite a few clock cycles for dealing with the LEDs and storing and reading data, but it will require some code restructuring form last time.