Archive for December, 2008

Practice 1, Theory 1

Tuesday, December 30th, 2008

As part of getting the new workspace space I moved the toxins related to casting and circuit board fabrication out of my apartment. The theory being that the space is semi industrial.

So as a test of the new space I took one of Alex Normans board designs and etched it.

Since the last time I worked with Alex on his designs he has picked up quite a bit and I only spent about 10 minutes getting his eagle files layed out and printed before going to the office. When I got there I realized that I had forgotten the green trf and bon ami but we were still able to get a reasonable etch and the new space has been broken in on the practice side.

War on Christmas Lights.

Wednesday, December 24th, 2008


War on Christmas Lights from Donald Delmar Davis on Vimeo.

Last year I cast a series of led arrays for thing-a-day but hadnt wired them up. With this in mind I ordered some hc595s in the last group order but the snow canceled the meeting.

I have been thinking about using the avr to drive the arrays directly and control them using i2c. I hacked 4 dorkboards by cutting the traces for pins 5-12 on the top of the board and soldering 220 ohm resistors on the other side. This gives a one chip solution which does not require a constant refresh or other attention.

/*
 Simple 4 node array of leds (8x8).
 */
#include <Wire.h>

int node=0; /* CHANGE THIS BASED ON POSITION OF ARRAY */

volatile int twi_group_offset=128;

volatile int colpins[]={//12,11,10,9,8,7,6,5};
5,6,7,8,9,10,11,12};
volatile int rowpins[]={
17,16,15,14,13,4,3,2};
//2,3,4,13,14,15,16,17};

volatile unsigned long int myTics;

unsigned char pixels[]={0x3E, 0x51, 0x49, 0x45, 0x3E,0,0,node,
0x00, 0x42, 0x7F, 0x40, 0x00,0,1,1,
0x42, 0x61, 0x51, 0x49, 0x46,0,2,2,
0x21, 0x41, 0x45, 0x4B, 0x31,0,3,3
};

void setup()                    // run once, when the sketch starts
{

	int i;
	myTics=millis();
	for(i=0;i<8;i++){
		pinMode(rowpins[i],OUTPUT);
		digitalWrite(rowpins[i],LOW);
		pinMode(colpins[i],OUTPUT);
		digitalWrite(colpins[i],HIGH);
	}    // sets the digital pin as output
	if (node==0) {
		Wire.begin();
		Serial.begin(19200);
		updateSlaveNodes();
	} else {
		Wire.begin(node+twi_group_offset);
		Wire.onReceive(updatePixels); // register event
	}
}

void loop()                    //move most of this into a timer loop.
{
	int r,c;
	int lastcolpin=colpins[0];
	for (c=0;c<8;c++){
		lastcolpin=colpins[c];
		for(r=0;r<8;r++){
			if ((pixels[c]>>r)&0x01){
				//if ((!r)||((7-c)==r)||(c==r)){
				digitalWrite(rowpins[r], HIGH);
			} else {
				digitalWrite(rowpins[r], LOW);
			}
		}
		digitalWrite(colpins[c], LOW);
		if (node==0) {
			updateSlaveNodes();
		} else {
			//delayMicroseconds(1500); //
			delay(3);
		}
		digitalWrite(lastcolpin, HIGH);
	}
}

void updateSlaveNodes() {
	int slavenode, row, pixel8;
	pixel8=8;
	for (slavenode=1;slavenode<4;slavenode++){
		Wire.beginTransmission(slavenode+twi_group_offset);
		for (row=0;row<8;row++) {
			Wire.send(pixels[pixel8++]);
		}
		Wire.endTransmission();
	};
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void updatePixels(int howMany)
{ int r=0;
	while(Wire.available()) //
	{
		pixels[r++] = Wire.receive(); // receive byte as a character
	}
}


The next step is to move the actual refresh into a timer routine so that the body of code for the main node can focus on content.

/*------------------------------------------------------------ xmas timer array
 *
 * This is the program for a 4x8x8 led display using a processor for each segment
 * To program the different nodes set the node variable below. Node 0 is the
 * master node which keeps the pixel memory for the remaining nodes.
 *
 * The master node takes its memory and sends updates to each of the other segments
 * via the i2c buss using the Wire library.
 *
 * Each node takes its 8byte array of data and strobes it onto the display using
 * the 8 bit timer2 overflow interrupt.
 *
 * The first 7 characters are loaded into the display memory using the
 * loadCharacters function. The array is then shifted to the left in the main loop
 * with the next character being loaded a collumn at a time.
 *
 * The character data and the bitmap for the 5x7 array are stored in program
 * memory.
 *
 * Since interrupts are used all of the globals are marked as volatile.
 *
 * CopyLeft 2008 Donald Delmar Davis, Tempus Dictum, Inc.
 * This is free software (GPL)
 */
#include <Wire.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define FREEK 180

int node=0; /* CHANGE THIS BASED ON POSITION OF ARRAY */

unsigned char PROGMEM Font5x7[] = {
0x00, 0x00, 0x00, 0x00, 0x00,// (space)
0x00, 0x00, 0x5F, 0x00, 0x00,// !
0x00, 0x07, 0x00, 0x07, 0x00,// "
0x14, 0x7F, 0x14, 0x7F, 0x14,// #
0x24, 0x2A, 0x7F, 0x2A, 0x12,// $
0x23, 0x13, 0x08, 0x64, 0x62,// %
0x36, 0x49, 0x55, 0x22, 0x50,// &
0x00, 0x05, 0x03, 0x00, 0x00,// '
0x00, 0x1C, 0x22, 0x41, 0x00,// (
0x00, 0x41, 0x22, 0x1C, 0x00,// )
0x08, 0x2A, 0x1C, 0x2A, 0x08,// *
0x08, 0x08, 0x3E, 0x08, 0x08,// +
0x00, 0x50, 0x30, 0x00, 0x00,// ,
0x08, 0x08, 0x08, 0x08, 0x08,// -
0x00, 0x60, 0x60, 0x00, 0x00,// .
0x20, 0x10, 0x08, 0x04, 0x02,// /
0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
0x00, 0x42, 0x7F, 0x40, 0x00,// 1
0x42, 0x61, 0x51, 0x49, 0x46,// 2
0x21, 0x41, 0x45, 0x4B, 0x31,// 3
0x18, 0x14, 0x12, 0x7F, 0x10,// 4
0x27, 0x45, 0x45, 0x45, 0x39,// 5
0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
0x01, 0x71, 0x09, 0x05, 0x03,// 7
0x36, 0x49, 0x49, 0x49, 0x36,// 8
0x06, 0x49, 0x49, 0x29, 0x1E,// 9
0x00, 0x36, 0x36, 0x00, 0x00,// :
0x00, 0x56, 0x36, 0x00, 0x00,// ;
0x00, 0x08, 0x14, 0x22, 0x41,// <
0x14, 0x14, 0x14, 0x14, 0x14,// =
0x41, 0x22, 0x14, 0x08, 0x00,// >
0x02, 0x01, 0x51, 0x09, 0x06,//
0x32, 0x49, 0x79, 0x41, 0x3E,// @
0x7E, 0x11, 0x11, 0x11, 0x7E,// A
0x7F, 0x49, 0x49, 0x49, 0x36,// B
0x3E, 0x41, 0x41, 0x41, 0x22,// C
0x7F, 0x41, 0x41, 0x22, 0x1C,// D
0x7F, 0x49, 0x49, 0x49, 0x41,// E
0x7F, 0x09, 0x09, 0x01, 0x01,// F
0x3E, 0x41, 0x41, 0x51, 0x32,// G
0x7F, 0x08, 0x08, 0x08, 0x7F,// H
0x00, 0x41, 0x7F, 0x41, 0x00,// I
0x20, 0x40, 0x41, 0x3F, 0x01,// J
0x7F, 0x08, 0x14, 0x22, 0x41,// K
0x7F, 0x40, 0x40, 0x40, 0x40,// L
0x7F, 0x02, 0x04, 0x02, 0x7F,// M
0x7F, 0x04, 0x08, 0x10, 0x7F,// N
0x3E, 0x41, 0x41, 0x41, 0x3E,// O
0x7F, 0x09, 0x09, 0x09, 0x06,// P
0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
0x7F, 0x09, 0x19, 0x29, 0x46,// R
0x46, 0x49, 0x49, 0x49, 0x31,// S
0x01, 0x01, 0x7F, 0x01, 0x01,// T
0x3F, 0x40, 0x40, 0x40, 0x3F,// U
0x1F, 0x20, 0x40, 0x20, 0x1F,// V
0x7F, 0x20, 0x18, 0x20, 0x7F,// W
0x63, 0x14, 0x08, 0x14, 0x63,// X
0x03, 0x04, 0x78, 0x04, 0x03,// Y
0x61, 0x51, 0x49, 0x45, 0x43,// Z
0x00, 0x00, 0x7F, 0x41, 0x41,// [
0x02, 0x04, 0x08, 0x10, 0x20,// "\"
0x41, 0x41, 0x7F, 0x00, 0x00,// ]
0x04, 0x02, 0x01, 0x02, 0x04,// ^
0x40, 0x40, 0x40, 0x40, 0x40,// _
0x00, 0x01, 0x02, 0x04, 0x00,// `
0x20, 0x54, 0x54, 0x54, 0x78,// a
0x7F, 0x48, 0x44, 0x44, 0x38,// b
0x38, 0x44, 0x44, 0x44, 0x20,// c
0x38, 0x44, 0x44, 0x48, 0x7F,// d
0x38, 0x54, 0x54, 0x54, 0x18,// e
0x08, 0x7E, 0x09, 0x01, 0x02,// f
0x08, 0x14, 0x54, 0x54, 0x3C,// g
0x7F, 0x08, 0x04, 0x04, 0x78,// h
0x00, 0x44, 0x7D, 0x40, 0x00,// i
0x20, 0x40, 0x44, 0x3D, 0x00,// j
0x00, 0x7F, 0x10, 0x28, 0x44,// k
0x00, 0x41, 0x7F, 0x40, 0x00,// l
0x7C, 0x04, 0x18, 0x04, 0x78,// m
0x7C, 0x08, 0x04, 0x04, 0x78,// n
0x38, 0x44, 0x44, 0x44, 0x38,// o
0x7C, 0x14, 0x14, 0x14, 0x08,// p
0x08, 0x14, 0x14, 0x18, 0x7C,// q
0x7C, 0x08, 0x04, 0x04, 0x08,// r
0x48, 0x54, 0x54, 0x54, 0x20,// s
0x04, 0x3F, 0x44, 0x40, 0x20,// t
0x3C, 0x40, 0x40, 0x20, 0x7C,// u
0x1C, 0x20, 0x40, 0x20, 0x1C,// v
0x3C, 0x40, 0x30, 0x40, 0x3C,// w
0x44, 0x28, 0x10, 0x28, 0x44,// x
0x0C, 0x50, 0x50, 0x50, 0x3C,// y
0x44, 0x64, 0x54, 0x4C, 0x44,// z
0x00, 0x08, 0x36, 0x41, 0x00,// {
0x00, 0x00, 0x7F, 0x00, 0x00,// |
0x00, 0x41, 0x36, 0x08, 0x00,// }
0x08, 0x08, 0x2A, 0x1C, 0x08,// ->
0x08, 0x1C, 0x2A, 0x08, 0x08 // <-
};

unsigned char PROGMEM banner[] = "Happy Holidays!!! Merry Christmas!!! May every man with \"Merry Christmas\" on his lips be boiled in his own blood pudding with a steak of holly driven through his heart! Christmas! BAH! HUMBUG!!!";

volatile int twi_group_offset=128;
volatile int colpins[]={5,6,7,8,9,10,11,12};
volatile int rowpins[]={17,16,15,14,13,4,3,2};

volatile unsigned long int myTics; //counter for timer interrupt.

volatile unsigned char pixels[]={
0x3E, 0x51, 0x49, 0x45, 0x3E,0,0,node,
0x00, 0x42, 0x7F, 0x40, 0x00,0,0,1,
0x42, 0x61, 0x51, 0x49, 0x46,0,0,2,
0x21, 0x41, 0x45, 0x4B, 0x31,0,0,3,
0x00, 0x00, 0x00, 0x00, 0,0,0,0}; //pixel buffer rounded out to another 8 bytes

volatile unsigned int cursorpos=0;
volatile unsigned int charcursor=0;
volatile unsigned int currentcol;
volatile unsigned int charmod;
volatile unsigned char currentchar;
volatile unsigned int currentcharoffset;

/*---------------------------------------------------------------------setup()
 * initialize timer2
 * setup the i/o pins (initialized with everything off);
 * Initialize the i2c buss;
 * if master node then load initial characters into display.
 */
void setup()                    // run once, when the sketch starts
{

    int i;
    currentcol=0;

    /*------------ setting up timer two. ----------------*/
    TCCR2A = 0;                           // normal mode
    TCCR2B = 1<<CS22 | 1<<CS21 | 0<<CS20; // clock selection
    TIMSK2 |= 1<<TOIE2;          // enable overflow interupt
    TCNT2=FREEK;                 // adjustment of period
    ASSR=0; // paranoid
    myTics=0;                    // counter for delays
    sei();                       // enable interrupts

   for(i=0;i<8;i++){
		pinMode(rowpins[i],OUTPUT);
		digitalWrite(rowpins[i],LOW);
		pinMode(colpins[i],OUTPUT);
		digitalWrite(colpins[i],HIGH);
    }

    if (node==0) {            // master node
		Wire.begin();
		Serial.begin(19200);
                loadCharacters();
		updateSlaveNodes();
    } else {
		Wire.begin(node+twi_group_offset);
		Wire.onReceive(updatePixels); // register event
    }
}

/*------------------------------------------------------------ISR(TIMER2_OVF_vect)
 * loads the next collumn into the led array
 *
 */
ISR(TIMER2_OVF_vect) {
int r;
  digitalWrite(colpins[currentcol], HIGH); //turn off the last column.

  if (++currentcol > 7) {
    currentcol=0;
  }
  for(r=0;r<8;r++){
	if ((pixels[currentcol]>>r)&0x01){
		digitalWrite(rowpins[r], HIGH);
	} else {
		digitalWrite(rowpins[r], LOW);
	}
  }
  digitalWrite(colpins[currentcol], LOW);
  myTics++;
  TCNT2 = FREEK;


};

/*--------------------------------------------------------------loadCharacters()
 * load the initial characters into the pixel buffer
 */
void loadCharacters(){
  int ch,i,j;
  cursorpos=0;
  for (charcursor=0;charcursor<7;charcursor++) {
    ch=pgm_read_byte_near(banner+charcursor);
    j= (ch-32) & 0x000000ff;
    j = j*5;
   for (charmod=0;charmod<5;charmod++){
      pixels[cursorpos++]=pgm_read_byte_near(Font5x7+j+charmod);
    }
  }

}

/*------------------------------------------------------------updateSlaveNodes()
 *  send the pixel data to the slave nodes.
 */

void updateSlaveNodes() {
  int slavenode, row, pixel8;

  if (node==0) {
	pixel8=8;
	for (slavenode=1;slavenode<4;slavenode++){
		Wire.beginTransmission(slavenode+twi_group_offset);
		for (row=0;row<8;row++) {
			Wire.send(pixels[pixel8++]);
		}
		Wire.endTransmission();
	};
  }
}
/*------------------------------------------------------------------udatePixels()
 * recieve the pixel data from the master node.
 * executes whenever data is received from master
 * this function is registered as an event, see setup()
 */
void updatePixels(int ignored)
{ int r=0;
	while(Wire.available()) //
	{
		pixels[r++] = Wire.receive(); // receive byte as a character
	}
}

/*-------------------------------------------------------------------------loop()
 *
 */
void loop()
{int c;

 //int head=pixels[0];
 updateSlaveNodes();

 for (c=1;c<35;c++) {
   pixels[c-1]=pixels[c];
 }


  if (charmod==5) {//get next char
    charcursor++;
    charmod=0;
    currentchar=pgm_read_byte_near(banner+charcursor);
    if (currentchar=='\0'){
       currentchar=pgm_read_byte_near(banner);
       charcursor=0;
    }
    currentcharoffset = (currentchar-32) & 0x000000ff;
    currentcharoffset = currentcharoffset*5;
  }

  pixels[34]=pgm_read_byte_near(Font5x7+currentcharoffset+charmod);
  charmod++;

 while (myTics<90) ; myTics=0L; //wait a few hundred millisecconds

}



http://www.dorkbotpdx.org/files/xmastimer-081225b.zip

Testing the Atmel Mega32U4

Tuesday, December 2nd, 2008

Mega 32 U4

While I am wrangling with the appropriate board design, I needed to get started working with the underlying software so I ran up one of the six samples I was able to get from Cascade on a tqfp adapter from measure explorer.

Schematic For Test Board

The AtMega32U4 http://www.atmel.com/dyn/products/product_card.asp?part_id=4317 is the midrange model in the atmel usb chipset. It follows a new standard naming convention that atmel is adapting U for Usb 4 is for the 40 pins 32k, there is another 32K part the U6 which has the same pinouts as the 90usb646/647/1286/1287. The U4 does not have a legacy pinout however the q1000 price for this board is around $2 which makes it a very powerful chip for the money.

Dfu-Programmer.

There is a recent release of dfu-programmer (0.4.6) but it seems that they havent read the atmel doc on the signatures for the dfu recently. http://www.atmel.com/dyn/resources/prod_documents/doc7618.pdf recently.

I need to check the memory and eeprom sizes against the datasheets for the parts. However the table in arguments.c should have the following entries; added new parts, corrected 64x and 82 signatures. (I will resubmit this patch).

/* ----- target specific structures ----------------------------------------- */
/*  { "name",         value,            ,device_type, chipID,VID   , MemSize,FPSize,abt,ifclass,eepgsz,eepmemsz} */
static struct target_mapping_structure target_map[] = {
    { "at89c51snd1c", tar_at89c51snd1c, device_8051, 0x2FFF, 0x03eb, 0x10000, 128, false, true,  0,   0      },
    { "at89c5130",    tar_at89c5130,    device_8051, 0x2FFD, 0x03eb, 0x04000, 128, false, true,  128, 0x03FF },
    { "at89c5131",    tar_at89c5131,    device_8051, 0x2FFD, 0x03eb, 0x08000, 128, false, true,  128, 0x03FF },
    { "at89c5132",    tar_at89c5132,    device_8051, 0x2FFF, 0x03eb, 0x10000, 128, false, true,  0,   0      },
    { "at90usb1287",  tar_at90usb1287,  device_AVR,  0x2FFB, 0x03eb, 0x1F000, 128, true,  false, 128, 0x0FFF },
    { "at90usb1286",  tar_at90usb1286,  device_AVR,  0x2FFB, 0x03eb, 0x1F000, 128, true,  false, 128, 0x0FFF },
    { "at90usb647",   tar_at90usb647,   device_AVR,  0x2FF9, 0x03eb, 0x0F000, 128, true,  false, 128, 0x07FF },
    { "at90usb646",   tar_at90usb646,   device_AVR,  0x2FF9, 0x03eb, 0x0F000, 128, true,  false, 128, 0x07FF },
    { "atmega32U6",   tar_atMega32u6,   device_AVR,  0x2FFB, 0x03eb, 0x07000, 128, true,  false, 128, 0x03FF },
    { "atmega32U4",   tar_atMega32u4,   device_AVR,  0x2FF4, 0x03eb, 0x07000, 128, true,  false, 128, 0x03FF },
    { "atmega16U4",   tar_atMega16u4,   device_AVR,  0x2FF3, 0x03eb, 0x03000, 128, true,  false, 128, 0x01FF },
    { "at90usb162",   tar_at90usb162,   device_AVR,  0x2FFA, 0x03eb, 0x03000, 128, true,  false, 128, 0x01FF },
    { "at90usb82",    tar_at90usb82,    device_AVR,  0x2FF7, 0x03eb, 0x01000, 128, true,  false, 128, 0x01FF },
    { NULL }
};

Then we test.

static
dfu-programmer atMega32U4 get bootloader-version --debug 20
     target: atMega32U4
    chip_id: 0x2ff4
  vendor_id: 0x03eb
    command: get
      quiet: false
      debug: 20
device_type: AVR
------ command specific below ------
       name: 0

Bootloader Version: 0x00 (0)

(after reading the datasheets for the 3 classes of avr usb chips and looking at the way that the avr-gcc library calls the cpu names there are some changes to the above that I will post later.)

Next up some code.

Tried running up the midiGate software that I wrote last week and found my first bug for the chip in avr-libc

UBRR1 is redefined in iom32u4.h

#define UBRR1 _SFR_MEM16(0xCC)

#define UBRR1L _SFR_MEM8(0xCC)
#define UBRR0 0
#define UBRR1 1
...

Which results in lvalue errors errors when trying to set the register to a given value. Setting the bit values as in some of the other registers seems to resolve this issue.

#define UBRR1 _SFR_MEM16(0xCC)

#define UBRR1L _SFR_MEM8(0xCC)
#define UBRR_0 0
#define UBRR_1 1
#define UBRR_2 2
#define UBRR_3 3
#define UBRR_4 4
#define UBRR_5 5
#define UBRR_6 6
#define UBRR_7 7

#define UBRR1H _SFR_MEM8(0xCD)
#define UBRR_8 0
#define UBRR_9 1
#define UBRR_10 2
#define UBRR_11 3

This is a pretty braindead error so I am sure that its been resolved by now. I need to see if it is fixed in 1.6.3 or the current release candidate (since AvrMacPack is out of sync and has 1.6.2) And yes this is the case.

We have a device!!!

Fix(ing) it!

Both of these issues were easy enough to fix within the source of the utilities but to make it possible for everyone else to use the new chips some body needs to Fix it! So I went about looking up the chain to get these issues resolved over the long run.

Dfu Programmer.

dfu-programmer is a source forge project so I logged an error through the sourceforge project page. https://sourceforge.net/tracker2/?atid=767783&group_id=147246&func=browse A new release has been made (0.5.0) which resolves the issue above.

Avr-Libc

Since avr-libc is a savanaha project and so making bug requests is a little different. http://savannah.nongnu.org/bugs/?group=avr-libc Fortunately (sort of) I had already been around the buggier parts of the release in question (1.6.2) when I first ran up the at90usb647. When Eric Weddington released the June rev of WinAvr (with avr-libc 1.6.3) I thought I had seen the last of it as obdev released the coresponding AvrMacPack. The bug noted above was fixed in 1.6.3 and I was able to verify that using my windows vmware session. For some reason this was not the case and AvrMacPack went out with the buggy (for this new chip anyway) libc. I filed a bug report with obdev and followed up with Christian from obdev and Eric until the version descrepency was resolved. The new version of WinAvr just came out and I am waiting to verify that the AvrMacPack version matches WinAvr.

If you are running linux plan on building from source and patching as in the script kept current at avrfreaks (you will need to log in) . http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=42631&start=0&postdays=0&postorder=asc&highlight= This script has not been updated for the latest winavr but it should at least give you a version above 1.6.2.

To Boldly Go…

Tuesday, December 2nd, 2008


I finally got a chance to wire up the first of my ATMega32U4 samples (see atmel doc7766). Like all of atmel’s usb chips it comes up as a bootloader. Now we get to go through the list of things that are probably broken (starting with dfu-programmer which I already know from fixing it for the at90usb647 is broken).

  • dfu-programmer

  • the bootloader itself (as was the case with the 90usb647)
  • avr-gcc
  • avr-libc
  • LUFA (soon to be formarly known as MyUSB)


Let the games begin…