Prime Number Generator Rapid Prototype

In my quest to build a hardware-based binary prime number generator I decided to build a demonstration model / rapid prototype to prove to myself (and the world) that I can reliably (and quickly) generate prime numbers. This code needs a lot of work, but it’s functional. Instead of messing with tons of little LEDs, it just dumps the output to a LCD. Of note, the library to run the LCD takes up about 90% of the memory of the chip leaving only a handful of free bytes to write the actual code in!
img_1984

Keep in mind this is a PROTOTYPE and that the full version will have over 80 LEDs to represent every number in binary form (up to 2^25, 33.5 million, with 25 LEDs/number). For now, this version (which dumps data to a HD44780 LCD screen) serves as a proof of concept. Powered by an ATTiny2313.

Here’s some video:

Here’s the code responsible:

#define F_CPU 1E6
#include <stdlib.h>
#include <avr/io.h>
#include <math.h>
#include <util/delay.h>
#include "lcd.h"
#include "lcd.c"

const unsigned long int primeMax=pow(2,25);
unsigned long int primeLast=2;
unsigned long int primeTest=0;
unsigned int primeDivy=0;

void wait(void);
void init(void);
void updateDisplay(void);
char *toString(unsigned long int);

int main(void){
    init();
    short maybePrime;
    unsigned int i;
    //for(primeTest=3;primeTest<sqrt(primeMax);primeTest=primeTest+2){
    for(primeTest=2;primeTest<sqrt(primeMax);primeTest++){
        maybePrime=1;
        //for (i=3;i<=(sqrt(primeTest)+1);i=i+2){
        for (i=2;i<=(sqrt(primeTest)+1);i++){
            primeDivy=i;
            updateDisplay();
            if (primeTest%primeDivy==0){maybePrime=0;break;}
        }
        if (maybePrime==1){primeLast=primeTest;updateDisplay();}
    }
    return 0;
}

void updateDisplay(void){
    lcd_gotoxy(12,0);lcd_puts(toString(primeLast));
    lcd_gotoxy(5,1);lcd_puts(toString(primeTest));
    lcd_gotoxy(16,1);lcd_puts(toString(primeDivy));
    //_delay_ms(1000);
    return;
}

void init(void){
    lcd_init(LCD_DISP_ON);
    //lcd_clrscr();
    lcd_puts("PRIME IDENTIFICATIONn");
    //lcd_puts("MAX PRIME: ");
    //lcd_puts(toString(primeMax));
    //lcd_puts("nsquare root: ");
    //lcd_puts(toString(sqrt(primeMax)+1));
    _delay_ms(2000);
    lcd_clrscr();
    lcd_puts("LAST PRIME:n");
    lcd_puts("TRY:");
    lcd_gotoxy(14,1);lcd_puts("/");
    return;
}

char *toString(unsigned long int x){
    char s1[8];
    ltoa(x,s1,10);
    return s1;
}

In other news, I’ve seen the new Star Trek movie and found it enjoyable. My wife liked it too (perhaps more than I did). Here’s a relevant news story I found informative:


     

Exhaustion, Steering, and Primes

I’m completely drained of energy. I visited my wife’s family in Tennessee last week. I left Thursday and came back Tuesday (yesterday). I drove a total of 2,180 miles. That averages to over 213 . The drive to Humboldt, TN (the destiation) and back is only 1,658 miles. That means that I drove over 520 miles over the 3 days while at my destination. That’s about 174 miles a day. At 50mph (average speed) that’s about 4 hours in the car. So, 13 hour drive (each way) to get there, then 4 hours in the car every day I was there. That’s a lot of car time!

While speaking with my brother-in-law (who just got a BS in computer science with a minor in mathematics) I learned that a faculty member at the university challenged him to write a computer program which could find the n’th prime number (up to 10^15) for a graduate school project. Being fluent in several programming languages myself and having a little mathematics background as well, I was fascinated by the project (and the various algorithms, techniques, and workarounds related to it.) After working on the theory behind the software (which I tested in Python) for a few hours, I had the idea to attempt to perform a similar task at the microcontroller level.

Here’s the project I want to begin: I want to build a microcontroller (ATTiny2313) powered prime number generator which displays results in binary form. The binary-encoded output is similar to the binary clocks which are nothing new. My project will calculate prime numbers up to 2^25 (33,554,432) and display the results in binary using long strips of 20 LEDs. There will be 3 rows of LEDs. The middle row (red) will simply count from 0 to 2^25. Every time it gets to a new number, the bottom row (blue) counts from 0 to the square root of the middle row. For every number on the bottom row, the remainder (modulus) of the middle/bottom is calculated. If the remainder is 0, the middle (red) number is divisible by the bottom (blue) therefore it is not prime. If the bottom number gets all the way to the square root of the middle number, the middle number is assumed to be prime and it is copied to the top row (green). The top row displays the most recent number determined to be prime.
prime_binary
Technical details of the project further reveal its dual simplicity/complexity nature. I’ll add some buttons/switches for extra features. For example, I want to be able to start the program at a number of my choosing rather than forcing it to start at 0. Also, I want to be able to adjust the speed at which it runs (I don’t want the blue row to just flicker forever). The ATTiny2313 (my microcontroller of choice because I have a few extra of them) has 18 IO pins. If I get creative with my multiplexing techniques, I can probably run 81 LEDs from 18 pins (9 rows of 9 LEDs). I’ve specifically chosen against charlieplexing because I will be lighting many LEDs “simultaneously” and I think the degree of flicker would be far too great to satisfy my sensitive eyes, even though I could do it all with only 10 pins.

I’ve decided to transistorize the entire project to provide a greater and more constant current to the LEDs. I’ll use a set of 9 transistors to set the row that gets power (when the microcontroller powers the base, the row gets power) and another set of 9 transistors to set the LEDs in each row that light up (when the microcontroller powers the base, the LED gets grounded and lights up). To have consistently-bright, non-flickering LEDs which don’t dim as more LEDs illuminate, I will add a resistor to every LED. Maybe I can get creative and utilize 10-pin resistor networks (one for each row) immediately after the row-selecting transistor! That will save me so much time. (I just came up with that idea – just now!) Anyway, that’s my project idea.

I’d love to make this project look nice. All of my other projects were housed in junky plastic or cardboard boxes (if they were housed at all!) and this is something I want to keep. I start dental school soon, and I’ve love to have a fancy-looking piece of artsy/geeky/electrical memorabilia so I’ll never forget who I am, my roots, and my true interests. Plus, it will give me something groovy to stare at when I come home after a long day cleaning the teeth of manikins and wondering why I went to dental school [sigh].

Update (nextday): I’ve been toying over some various layouts for the LEDs. I most like the rectangle and hex-rectangle configurations, and am already working on assembly of the “mini” (prototype). Here are some random images of my thinking process.
prime_layout_2
g12684
rect7887


     

Graphing Computer Usage

I’m a big fan of writing Python scripts to analyze huge volumes of linear data. It’s a sick addiction. One of my favorite blog entries is Linear Data Smoothing with Python, developed for my homemade electrocardiogram project. Anyway, I installed the free Windows program TimeTrack.exe on my work computer. I can’t remember why I installed it – this looks like pretty crappy software – but I did nonetheless. It basically logs whenever you open or close a program. The data output looks like this:

"Firefox","Prototype of a Digital Biopsy Device - Mozilla Firefox","05/19/2009  9:45a","05/19/2009  9:45a","766ms","0.0"
"Firefox","Dual-Channel Mobile Surface Electromyograph - Mozilla Firefox","05/19/2009  9:46a","05/19/2009  9:46a","797ms","0.0"
"Windows Explorer","","03/24/2008  9:30a","05/19/2009  9:48a","49d 6h 9m","20.7"
"Windows Explorer","09_04_07_RA_SA_AV","05/19/2009  8:48a","05/19/2009  8:48a","1.0s","0.0"
"Windows Explorer","Image003.jpg - Windows Picture and Fax Viewer","05/18/2009  4:03p","05/18/2009  4:03p","1.2s","0.0"

I have a 13mb file containing lines like this which I parse, condense, analyze, re-parse, and graph with a Python script I just wrote. Briefly it finds the first and last entry time and creates a dictionary object whose keys are the hours between the 1st and last log lines, parses the log, determines which time block each entry belongs to, and increments the integer (value of the dictionary) for its respective key. Something similar is repeated, but with respect to days rather than hours. The result is:
compusage_white
I’d like to thank Python, Numpy, and of course my all-time-favorite software in the world, MatPlotLib. The code I used to generate the graph above is here:

# This script analyzes data exported from "TimeTrack" (a free computer usage
# monitoring program for windows) and graphs the data visually.
import time, pylab, datetime, numpy

# This is my computer usage data.  Generate yours however you want.
allHours = ['2008_10_29 0', '2009_03_11 5', '2009_04_09 5', '2008_07_04 10',
'2008_12_18 9', '2009_01_30 12', '2008_09_04 7', '2008_05_17 1',
'2008_05_11 5', '2008_11_03 3', '2008_05_21 3', '2009_02_19 11',
'2008_08_15 13', '2008_04_02 4', '2008_07_16 5', '2008_09_16 8',
'2008_04_10 5', '2009_05_10 1', '2008_12_30 4', '2008_06_07 2',
'2008_11_23 0', '2008_08_03 0', '2008_04_30 4', '2008_07_28 9',
'2008_05_19 0', '2009_03_30 7', '2008_06_19 3', '2009_01_24 3',
'2008_08_23 6', '2008_12_01 0', '2009_02_23 6', '2008_11_27 0',
'2008_05_02 5', '2008_10_20 13', '2008_03_27 5', '2009_04_02 9',
'2009_02_21 0', '2008_09_13 1', '2008_12_13 0', '2009_04_14 11',
'2009_01_31 7', '2008_11_04 10', '2008_07_09 6', '2008_10_24 10',
'2009_02_22 0', '2008_09_25 12', '2008_12_25 0', '2008_05_26 4',
'2009_05_01 10', '2009_04_26 11', '2008_08_10 8', '2008_11_08 6',
'2008_07_21 12', '2009_04_21 3', '2009_05_13 8', '2009_02_02 8',
'2008_10_07 2', '2008_06_10 6', '2008_09_21 0', '2009_03_17 9',
'2008_08_30 7', '2008_11_28 4', '2009_02_14 0', '2009_01_22 6',
'2008_10_11 0', '2008_06_22 8', '2008_12_04 0', '2008_03_28 0',
'2009_04_07 2', '2008_09_10 0', '2008_05_15 5', '2008_08_18 12',
'2008_10_31 5', '2009_03_09 7', '2009_02_25 8', '2008_07_02 4',
'2008_12_16 7', '2008_09_06 2', '2009_01_26 5', '2009_04_19 0',
'2008_07_14 13', '2008_11_01 5', '2009_01_18 0', '2009_05_04 0',
'2008_08_13 10', '2009_02_27 3', '2009_01_16 12', '2008_09_18 8',
'2009_02_03 7', '2008_06_01 0', '2008_12_28 0', '2008_07_26 0',
'2008_11_21 1', '2008_08_01 8', '2008_04_28 3', '2009_05_16 0',
'2008_06_13 5', '2008_10_02 11', '2009_03_28 6', '2008_08_21 7',
'2009_01_13 6', '2008_11_25 4', '2008_06_25 1', '2008_10_22 11',
'2008_03_25 6', '2009_02_07 6', '2008_12_11 4', '2009_01_01 4',
'2008_09_15 2', '2009_02_05 12', '2008_07_07 9', '2009_04_12 0',
'2008_04_11 5', '2008_10_26 4', '2008_05_28 3', '2008_09_27 14',
'2009_05_03 0', '2008_12_23 5', '2009_05_12 10', '2008_11_14 3',
'2008_07_19 0', '2009_04_24 8', '2008_04_07 1', '2008_08_08 11',
'2008_06_04 0', '2009_05_15 12', '2009_03_23 13', '2009_02_01 10',
'2008_09_23 11', '2009_02_08 3', '2008_08_28 4', '2008_11_18 9',
'2008_07_31 7', '2008_10_13 0', '2008_06_16 9', '2009_03_27 6',
'2008_12_02 0', '2008_05_01 7', '2009_04_05 1', '2008_08_16 9',
'2009_03_15 0', '2008_04_16 6', '2008_10_17 4', '2008_06_28 5',
'2009_01_28 10', '2008_04_18 0', '2008_12_14 0', '2008_11_07 6',
'2009_04_17 7', '2008_04_14 7', '2008_07_12 0', '2009_01_15 7',
'2009_05_06 8', '2008_12_26 0', '2008_06_03 7', '2008_09_28 0',
'2008_05_25 4', '2008_08_07 8', '2008_04_26 7', '2008_07_24 1',
'2008_04_20 0', '2008_11_11 4', '2009_04_29 0', '2008_10_04 0',
'2009_05_18 9', '2009_03_18 4', '2008_06_15 8', '2009_02_13 6',
'2008_05_04 5', '2009_03_04 2', '2009_03_06 3', '2008_05_06 0',
'2008_08_27 11', '2008_04_22 0', '2009_03_26 6', '2008_03_31 9',
'2008_06_27 5', '2008_10_08 4', '2008_09_09 4', '2008_12_09 3',
'2008_05_10 0', '2008_05_14 5', '2009_04_10 0', '2009_01_11 0',
'2008_07_05 8', '2009_01_05 7', '2008_10_28 0', '2009_02_18 11',
'2009_03_10 7', '2008_05_30 3', '2008_09_05 7', '2008_12_21 6',
'2009_03_02 6', '2008_08_14 5', '2008_11_12 5', '2008_07_17 8',
'2008_04_05 6', '2009_04_22 11', '2009_05_09 0', '2008_06_06 0',
'2009_01_03 0', '2008_09_17 6', '2009_03_21 3', '2009_02_10 7',
'2008_05_08 4', '2008_08_02 0', '2008_11_16 0', '2008_07_29 12',
'2008_10_15 5', '2008_06_18 5', '2009_03_25 2', '2009_01_10 0',
'2009_04_03 5', '2008_08_22 7', '2009_03_13 11', '2008_10_19 0',
'2008_06_30 8', '2008_09_02 9', '2008_05_23 4', '2008_12_12 7',
'2008_07_10 11', '2008_11_05 8', '2008_04_12 4', '2009_04_15 7',
'2008_12_24 1', '2008_09_30 0', '2008_05_27 2', '2008_08_05 10',
'2008_04_24 6', '2009_04_27 6', '2008_07_22 3', '2008_11_09 1',
'2008_06_09 6', '2008_10_06 14', '2009_03_16 7', '2008_05_22 5',
'2009_01_29 12', '2008_11_29 4', '2008_04_09 7', '2008_08_25 12',
'2009_02_15 0', '2008_03_29 7', '2008_06_21 7', '2008_10_10 9',
'2008_05_12 6', '2009_02_16 10', '2008_09_11 11', '2008_12_07 0',
'2008_07_03 6', '2009_04_08 3', '2009_01_23 7', '2009_01_27 5',
'2008_10_30 0', '2009_03_08 0', '2009_01_21 8', '2008_12_19 0',
'2008_05_16 2', '2009_01_25 1', '2009_02_26 5', '2008_09_07 2',
'2008_04_03 1', '2008_08_12 6', '2008_04_13 10', '2008_11_02 0',
'2008_07_15 0', '2009_04_20 3', '2009_02_24 10', '2009_05_11 8',
'2008_12_31 8', '2008_04_15 7', '2008_09_19 10', '2009_01_19 0',
'2008_11_22 3', '2008_07_27 2', '2009_02_04 7', '2009_03_31 1',
'2008_05_24 3', '2008_10_01 8', '2008_06_12 6', '2009_01_12 11',
'2008_11_26 8', '2009_04_01 10', '2009_02_28 0', '2008_08_20 6',
'2008_10_21 10', '2008_06_24 4', '2008_03_26 4', '2008_12_10 0',
'2008_09_12 0', '2008_05_09 7', '2009_02_17 7', '2008_07_08 6',
'2008_10_25 5', '2009_04_13 9', '2009_05_02 0', '2008_12_22 8',
'2008_09_24 9', '2009_01_20 5', '2008_11_15 6', '2009_04_25 10',
'2008_08_11 9', '2008_04_06 8', '2008_07_20 1', '2009_03_22 3',
'2008_06_11 6', '2008_09_20 3', '2009_05_14 10', '2008_11_19 0',
'2008_08_31 2', '2009_02_09 8', '2008_10_12 0', '2008_04_25 5',
'2008_06_23 4', '2009_01_07 8', '2008_08_19 0', '2008_12_05 2',
'2008_07_01 8', '2008_10_16 6', '2009_04_06 3', '2009_03_14 5',
'2008_09_01 2', '2008_12_17 14', '2008_05_18 7', '2008_04_01 2',
'2009_04_18 0', '2008_04_17 0', '2008_07_13 0', '2008_06_02 10',
'2008_09_29 6', '2008_12_29 0', '2009_05_05 8', '2008_04_19 0',
'2009_04_30 8', '2008_08_06 4', '2008_11_20 0', '2008_07_25 6',
'2009_02_06 6', '2009_03_29 3', '2009_05_17 0', '2009_03_19 7',
'2008_10_03 1', '2008_06_14 3', '2008_05_07 5', '2008_08_26 3',
'2008_11_24 9', '2008_04_21 8', '2008_04_23 4', '2008_10_23 11',
'2008_06_26 4', '2008_03_24 8', '2008_12_08 5', '2008_09_14 2',
'2009_01_02 6', '2008_04_08 0', '2008_10_27 6', '2009_04_11 0',
'2008_07_06 0', '2008_12_20 3', '2009_04_23 6', '2008_09_26 9',
'2008_05_31 0', '2008_07_18 4', '2008_11_13 6', '2008_08_09 2',
'2008_04_04 0', '2009_03_20 5', '2008_09_22 7', '2009_05_08 9',
'2008_06_05 7', '2008_07_30 7', '2008_11_17 10', '2008_05_03 0',
'2008_08_29 3', '2009_02_11 12', '2009_01_08 8', '2008_06_17 0',
'2008_10_14 7', '2009_03_24 11', '2008_08_17 6', '2008_12_03 0',
'2009_01_09 4', '2008_05_29 5', '2008_06_29 9', '2008_10_18 5',
'2009_04_04 0', '2008_12_15 10', '2009_03_12 0', '2009_03_05 7',
'2008_05_20 4', '2008_09_03 7', '2009_03_07 8', '2009_01_14 6',
'2008_05_05 5', '2008_11_06 7', '2008_07_11 6', '2009_04_16 9',
'2009_02_20 0', '2008_12_27 0', '2009_01_17 0', '2009_05_07 7',
'2008_11_10 5', '2008_07_23 11', '2009_04_28 0', '2008_04_27 2',
'2008_08_04 0', '2009_03_01 11', '2008_10_05 0', '2008_06_08 8',
'2009_05_19 5', '2008_04_29 4', '2008_11_30 0', '2009_01_06 8',
'2009_02_12 3', '2008_08_24 2', '2009_03_03 10', '2008_10_09 6',
'2008_06_20 2', '2008_05_13 10', '2008_12_06 0', '2008_03_30 7']

def genTimes():
    ## opens  exported timetrack data (CSV) and re-saves a compressed version.
    print "ANALYZING..."
    f=open('timetrack.txt')
    raw=f.readlines()
    f.close()
    times=["05/15/2009 12:00am"] #start time
    for line in raw[1:]:
        if not line.count('","') == 5: continue
        test = line.strip("n")[1:-1].split('","')[-3].replace("  "," ")+"m"
        test = test.replace(" 0:"," 12:")
        times.append(test) #end time
        test = line.strip("n")[1:-1].split('","')[-4].replace("  "," ")+"m"
        test = test.replace(" 0:"," 12:")
        times.append(test) #start time

    times.sort()
    print "WRITING..."
    f=open('times.txt','w')
    f.write(str(times))
    f.close()

def loadTimes():
    ## loads the times from the compressed file.
    f=open("times.txt")
    times = eval(f.read())
    newtimes=[]
    f.close()
    for i in range(len(times)):
        if "s" in times[i]: print times[i]
        newtimes.append(datetime.datetime(*time.strptime(times[i],
                                        "%m/%d/%Y %I:%M%p")[0:5]))
        #if i>1000: break #for debugging
    newtimes.sort()
    return newtimes

def linearize(times):
    ## does all the big math to calculate hours per day.
    for i in range(len(times)):
        times[i]=times[i]-datetime.timedelta(minutes=times[i].minute,
                                             seconds=times[i].second)
    hr = datetime.timedelta(hours=1)
    pos = times[0]-hr
    counts = {}
    days = {}
    lasthr=pos
    lastday=None
    while pos<times [-1]:
        daypos=pos-datetime.timedelta(hours=pos.hour,
               minutes=pos.minute,seconds=pos.second)
        if not lastday==daypos:
            lastday=daypos
            print daypos
        counts[pos]=times.count(pos)
        if counts[pos]>1:counts[pos]=1 #flatten
        if not daypos in days: days[daypos]=0
        if not lasthr == pos:
            if counts[pos]>0:
                days[daypos]=days[daypos]+1
                lasthr=pos
        pos+=hr
    return days #[counts,days]


def genHours(days):
    ## outputs the hours per day as a file.
    out=""
    for day in days:
        print day
        out+="%s %in"%(day.strftime("%Y_%m_%d"),days[day])
    f=open('hours.txt','w')
    f.write(out)
    f.close()
    return

def smoothListGaussian(list,degree=7):
    ## (from an article I wrote) - Google "linear data smoothing with python".
    firstlen=len(list)
    window=degree*2-1
    weight=numpy.array([1.0]*window)
    weightGauss=[]
    for i in range(window):
     i=i-degree+1
     frac=i/float(window)
     gauss=1/(numpy.exp((4*(frac))**2))
     weightGauss.append(gauss)
    weight=numpy.array(weightGauss)*weight
    smoothed=[0.0]*(len(list)-window)
    for i in range(len(smoothed)):
     smoothed[i]=sum(numpy.array(list[i:i+window])*weight)/sum(weight)
    pad_before = [smoothed[0]]*((firstlen-len(smoothed))/2)
    pad_after  = [smoothed[-1]]*((firstlen-len(smoothed))/2+1)
    return pad_before+smoothed+pad_after

### IF YOU USE MY DATA, YOU ONLY USE THE FOLLOWING CODE ###

def graphIt():
    ## Graph the data!
    #f=open('hours.txt')
    #data=f.readlines()
    data=allHours
    data.sort()
    f.close()
    days,hours=[],[]
    for i in range(len(data)):
        day = data[i].split(" ")
        if int(day[1])<4: continue
        days.append(datetime.datetime.strptime(day[0], "%Y_%m_%d"))
        hours.append(int(day[1]))
    fig=pylab.figure(figsize=(14,5))
    pylab.plot(days,smoothListGaussian(hours,1),'.',color='.5',label="single day")
    pylab.plot(days,smoothListGaussian(hours,1),'-',color='.8')
    pylab.plot(days,smoothListGaussian(hours,7),color='b',label="7-day gausian average")
    pylab.axhline(8,color='k',ls=":")
    pylab.title("Computer Usage at Work")
    pylab.ylabel("hours (rounded)")
    pylab.legend()
    pylab.show()
    return

#times = genTimes()
#genHours(linearize(loadTimes()))
graphIt()
</times>

In other news, I managed to locate the patent for the Nintendo 64 Video Game Console – how funny is that?


     

Audio and Video on an ATMega88 Microcontroller!

At least 99% of my blog entries contain original content I created. However, I was so impressed by something I stumbled upon tonight that I absolutely cannot resist sharing it. It’s a project which aims to output audio and video simultaneously from a single microcontroller. The author’s site has all the details, but if you watch the video below you’ll be amazed. (Just get through the 30 second narration at the beginning) Apparently the guy rendered video in horizontal lines from the software and outputted audio signals between horizontal lines! Amazing!

On second thought, this was no big deal in the 80’s, so why am I so impressed by it now? The 8-bit microcontrollers this guy is programming is likely on par with the PCs of the 80’s. I guess that in the 70’s this would have been amazing because it was cutting edge. In the 80’s this would have been boring because it was commonplace. In the 2000’s, this is amazing because no one in my generation is old enough to remember how amazing this was in the 70’s and 80’s!

After researching some similar projects I realized I’m becoming fascinated with chiptune synthesizing code, hardware, and music. It’s basically a type of code to tell a synthesizer how to synthesize the music, rather than having it play pre-recorded music. It’s like a merge of a programming language and MIDI. For non-technical people, it’s like giving a microchip the sheet music for all the different instruments of an orchestra and having the microchip play everything from the sheet music, rather than giving it a CD to play. Here’s some video of a PC-based front-end to the audio creation process. Notice how each line represents a time, and how certain codes in certain channels represent notes (hence the MIDI aspect). Numbers on the far right represent the location of the memory, and notice also how it goes back and forth, replaying certain areas when necessary (to safe space, hence the coding aspect).

I can’t describe my emotional state right now. It’s like I have an extreme nostalgia for an era I never even lived in. This chip level audio synthesis stuff sounds amazingly fun to me. (I’ve already bookmarked nolife-radio.com and 8bitFM.com) I feel drawn toward it… but I’m scared to get sucked in.

I wish more than anything I were a college student in the 80’s studying electrical engineering. Here I am, having just gotten a master’s in molecular biology and microbiology, and I feel like I wasted six years of my life in the process. I’m about to start dental school in August. Hopefully when I look back from the future I won’t feel like I wasted another four years doing that.

Either way, I have an endless supply of possible projects to do this summer (not even going into the small list of projects I’m trying/expected to complete in the cardioneurophysiology lab I work in). I feel like I’m running out of time. I start dental school in August, and I dread the date. Not necessarily because I expect it to be difficult, but because I feel [however illogical, irrational, or ridiculous] that I’m actually doing something significant, working with my hands and working with my brain to do things that [almost] no one has done before, and doing things in a way that no one has ever thought of doing them. I feel like when I start resume classes, it’s another four years of people telling me how I should do things so I can be exactly like everyone else. How can you exercise creativity as a dental student? I’m sure there are ways, but it’s certainly leagues away from the projects engineering college students work on. As far as the career goes, if you’re an engineer the best case scenario is that you do something no one has ever done before. If you’re a dentist, the best case scenario is to do things exactly as everyone else does them. Maybe I’ll go crazy and change the wallpaper in my office every few months.


     

ATTiny2313 Controlling a HD44780 LCD via AVR-GCC

After a day of tinkering I finally figured out how to control a HD44780-style LCD display from an ATTiny2313 class ATMEL AVR microcontroller. There are a lot of websites out there claiming to show you how to do this on similar AVRs. I tried about 10 of them and, intriguingly, only one of them worked! I don’t know if it’s user error, or an incompatibility of the ATTiny2313 running code written for an ATMega8, but since it took me so long to get this right I decided to share it on the internet for anyone else having a similar struggle. First, the results:
attiny_2313_lcd_hd44780
You might recognize this LCD panel from some PC parallel port / LCD interface projects I worked on about 5 years ago. It’s a 20-column, 2-row, 8-bit parallel character LCD. This means that ranter than telling each little square to light up to form individual letters, you can just output text to the microcontroller embedded in the display and it can draw the letters, move the cursor, or clear the screen.
attiny_2313_lcd_hd44780_2
As you can see this thing is pretty easy to wire-up to the ATTiny2313. These are the connections I made:

  • LCD1 -> GND
  • LCD2 -> +5V
  • LCD3 (contrast) -> GND
  • LCD4 (RS) -> AVR D0 (pin2)
  • LCD5 (R/W) -> AVR D1 (pin3)
  • LCD6 (ES) -> AVR D2 (pin6)
  • LCD 11-14 (data) -> AVR B0-B3 (pins 12-15)

The code I used to FINALLY allow me to control this LCD from the ATTiny2313 was found on Martin Thomas’ page. [HIS CODE] I included the .h and .c files and successfully ran the following program (with great results) on my AVR. The internal RC clock works, and supposedly any external clock (<8MHz) should work too.

// THIS THE TEST PROGRAM "main.c"
// ATTiny2313 / HD44780 LCD INTERFACE
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
#include "lcd.c"

int main(void)
{
    int i=0;
    lcd_init(LCD_DISP_ON);
    lcd_clrscr();
    lcd_puts("ATTiny 2313 LCD Demo");
    lcd_puts("  www.SWHarden.com  ");
    _delay_ms(1000);
    lcd_clrscr();
    for (;;) {
        lcd_putc(i);
        i++;
        _delay_ms(50);
    }
}
// THIS IS PART OF MY INCLUDED "lcd.h"
// THE WIRING CHART DESCRIBED IN THIS BLOG ENTRY
// IS MATCHED TO THE VALUES DISPLAYED BELOW
#define LCD_PORT         PORTB        /**< port for the LCD lines   */
#define LCD_DATA0_PORT   LCD_PORT     /**< port for 4bit data bit 0 */
#define LCD_DATA1_PORT   LCD_PORT     /**< port for 4bit data bit 1 */
#define LCD_DATA2_PORT   LCD_PORT     /**< port for 4bit data bit 2 */
#define LCD_DATA3_PORT   LCD_PORT     /**< port for 4bit data bit 3 */
#define LCD_DATA0_PIN    0            /**< pin for 4bit data bit 0  */
#define LCD_DATA1_PIN    1            /**< pin for 4bit data bit 1  */
#define LCD_DATA2_PIN    2            /**< pin for 4bit data bit 2  */
#define LCD_DATA3_PIN    3            /**< pin for 4bit data bit 3  */
#define LCD_RS_PORT      PORTD     /**< port for RS line         */
#define LCD_RS_PIN       0            /**< pin  for RS line         */
#define LCD_RW_PORT      PORTD     /**< port for RW line         */
#define LCD_RW_PIN       1            /**< pin  for RW line         */
#define LCD_E_PORT       PORTD     /**< port for Enable line     */
#define LCD_E_PIN        2            /**< pin  for Enable line     */

// AND A LITTLE LOWER, I CHANGED THIS LINE TO 4-BIT MODE
#define LCD_FUNCTION_8BIT     0      /*   DB4: set 8BIT mode (0->4BIT mode) */

And some video of the output… Notice how this display can show English (lowercase/uppercase/numbers) as well as the Japanese character set! Sweet!


     

Removing Textile From WordPress

I realized that the C code from yesterday wasn’t showing-up properly because of textile, a rapid, inline, tag-based formatting system. The app converted blog code from [“text”:http://www.SWHarden.com/ *like* _this_] to [text like this. ] While it’s fun and convenient to use, it’s not always practical. The problem I was having was that in C code, variable names (such as _delay_) were becoming irrevocably italicized, and nothing I did could prevent textile from ignoring code while styling text. The kicker is that I couldn’t disable it easily, because I’ve been writing in this style for over four years! I decided that the time was now to put my mad Python skills to the test and write code to handle the conversion from textile-format to raw HTML.
I accomplished this feat in a number of steps. Yeah, I could have done hours of research to find a “faster way”, but it simply wouldn’t have been as creative. In a nutshell, I backed-up the SQL database using PHPMyAdmin to a single “x.sql” file. I then wrote a pythons script to parse this [massive] file and output “o.sql”, the same data but with all of the textile tags I commonly used replaced by their HTML equivalent. It’s not 100% perfect, but it’s 99.999% perfect. I’ll accept that. The output? You’re viewing it! Here’s the code I used to do it:

## This Python (1.0) script removes *SOME* textile formatting from WordPress
## backups in plain text SQL format (dumped from PHP MyAdmin). Specifically,
## it corrects bold and itallic fonts and corrects links. It should be easy
## to expand if you need to do something else with it.
## Enjoy! --Scott Harden (www.SWHarden.com)

infile = 'x.sql' # < < THIS IS THE INPUT FILE NAME!

replacements=   ["r"," "],["n"," n "],["*:","* :"],["_:","_ :"],
                ["n","<br>n"],[">*","> *"],["*< ","* <"],
                [">_","> _"],["_< ","_ <"],
                [" *"," <b>"],["* "," "],[" _"," <i>"],["_ ","</i> "]
                #These are the easy replacements

def fixLinks(line):
    ## replace ["links":URL] with [<a href="URL">links</a>]. ##
    words = line.split(" ")
    for i in range(len(words)):
        word = words[i]
        if '":' in word:
            upto=1
            while (word.count('"')&lt;2):
                word = words[i-upto]+" "+word
                upto+=1
            word_orig = word
            extra=""
            word = word.split('":')
            word[0]=word[0][1:]
            for char in ".),'":
                if word[1][-1]==char: extra=char
            if len(extra)>0: word[1]=word[1][:-1]
            word_new='<a href="%s">%s</a>'%(word[1],word[0])+extra
            line=line.replace(word_orig,word_new)
    return line

def stripTextile(orig):
    ## Handle the replacements and link fixing for each line. ##
    if not orig.count("', '") == 13: return orig #non-normal post
    line=orig
    temp = line.split
    line = line.split("', '",5)[2]
    if len(line)&lt;10:return orig #non-normal post
    origline = line
    line = " "+line
    for replacement in replacements:
        line = line.replace(replacement[0],replacement[1])
    line=fixLinks(line)
    line = orig.replace(origline,line)
    return line

f=open(infile)
raw=f.readlines()
f.close
posts=0
for raw_i in range(len(raw)):
    if raw[raw_i][:11]=="INSERT INTO":
        if "wp_posts" in raw[raw_i]: #if it's a post, handle it!
            posts+=1
            print "on post",posts
            raw[raw_i]=stripTextile(raw[raw_i])


print "WRITING..."
out = ""
for line in raw:
    out+=line
f=open('o.sql','w')
f.write(out)
f.close()

I certainly held my breath while the thing ran. As I previously mentioned, this thing modified SQL tables. Therefore, when I uploaded the “corrected” versions, I kept breaking the site until I got all the bugs worked out. Here’s an image from earlier today when my site was totally dead (0 blog posts)

hostingwork


     

PHP-Generated Access.log is a Success

THIS CODE HAS BEEN UPDATED!
THIS CODE HAS BEEN UPDATED!
THIS CODE HAS BEEN UPDATED!

>>> CHECK OUT THE NEW CODE < << [Generate Apache-Style HTTP Access Logs via SQL and PHP]

OBSOLETE CODE IS BELOW…

A few months ago I wrote about a way I use PHP to generate apache-style access.log files since my web host blocks access to them. Since then I’ve forgotten it was even running! I now have some pretty cool-looking graphs generated by Python and Matplotlib. For details (and the messy script) check the original posting.

This image represents the number of requests (php pages) made per hour since I implemented the script. It might be a good idea to perform some linear data smoothing techniques (which I love writing about), but for now I’ll leave it as it is so it most accurately reflects the actual data.


     

Simple Case AVR/PC Serial Communication via MAX232

UPDATE: I found a method of PC/microcontroller communication which I feel is simpler, easier, and definitely cheaper than this! It’s not good for everything, but worth looking at. It’s a way to communicate with a PC using your sound card and zero components!

Another page HERE has more info on how to do this with an intermediate IC if yours doesn’t have RX/TX pins…

I recently had the desire to be able to see data from an ATMEL AVR microcontroller (the ATTiny2313) for development and debugging purposes. I wanted an easy way to have my microcontroller talk to my PC (and vise versa) with a minimum number of parts. The easiest way to do this was to utilize the UART capabilities of the ATTiny2313 to talk to my PC through the serial port. One problem is that the ATTiny2313(as with most microcontrollers) puts out 5V for “high” (on) and 0V for “low” (off). The RS-232 standard (which PC serial ports use) required -15V for high and +15v for low! Obviously the microcontroller needs some help to achieve this. The easiest way was to use the MAX232 serial level converter which costs about 3 bucks at DigiKey. Note that it requires a few 10uF capacitors to function properly.

Here’s a more general schematic:

I connected my ATTiny2313 to the MAX232 in a very standard way. (photo) MAX232 pins 13 and 14 go to the serial port, and the ATTiny2313 pins 2 and 3 go to the MAX232 pins 12 and 11 respectively. I will note that they used a oscillator value (3.6864MHz) different than mine (9.216MHz).

Determining the speed of serial communication is important. This is dependent on your oscillator frequency! I said I used a 9.216Mhz oscillator. First, a crystal or ceramic oscillator is required over the internal RC oscillator because the internal RC oscillator is not accurate enough for serial communication. The oscillator you select should be a perfect multiple of 1.8432MHz. Mine is 5x this value. Many people use 2x this value (3.6864Mhz) and that’s okay! You just have to make sure your microchip knows (1) to use the external oscillator (google around for how to burn the fuses on your chip to do this) and (2) what the frequency of your oscillator is and how fast it should be sending data. This is done by setting the UBRRL value. The formula to do this is here:

The datasheet of your microcontroller may list a lot of common crystal frequencies, bandwidths, and their appropriate UBRR values. However my datasheet lacked an entry for a 9.216MHz crystal, so I had to do the math myself. I Googled around and no “table” is available! Why not make one? (picture, below). Anyway, for my case I determined that if I set the UBRR value to 239, I could transmit data at 2800 baud (bits/second). This is slow enough to ensure accuracy, but fast enough to quickly dump a large amount of text to a PC terminal.

>>> IMPORTANT UPDATE!

This will make your life easier. The page wormfood.net/avrbaudcalc.php has a chart of common crystals and the baud rates they work best with! Try to pick a combination that provides the least error possible...

This is the bare-minimum code to test out my setup. Just load the code (written in C, compiled with avr-gcc) onto your chip and it’s ready to go. Be sure you set your fuses to use an external oscillator and that you set your UBRRL value correctly.

  

  #include <avr/io.h>  

  #include <avr/interrupt.h>  

  #include <util/delay.h>  

   

 int main (void)  

 {  

   unsigned char data=0;  

   UBRRL = 239;  

   UCSRB = (1 < < RXEN) | (1 << TXEN);  

   UCSRC = (1 < < UCSZ1) | (1 << UCSZ0);  

   for (;;)  

     {  

     if (data>'Z'||data< 'A')  

     {  

       UDR = 10; UDR = 13; data='A';_delay_ms(100);  

     }  

     UDR = data;  

     data += 1;  

     _delay_ms(100);  

     }  

 }  

 

Once you load it, it’s ready to roll! It continuously dumps letters to the serial port. To receive them, open HyperTerminal (on windows, under accessories) or minicom (on Linux, look it up!). Set your baud rate to 2800 (or whatever you selected) and you’re in business. This (picture below) is the output of the microcontroller to HyperTerminal on my PC. Forgive the image quality, I photographed the LCD screen instead of taking a screenshot.

This is the circuit which generates the output of the previous image. I have a few extra components. I have an LED which I used for debugging purposes, and also a switch (labeled “R”). The switch (when pressed) grounds pin 1 of the ATTiny2313 which resets it. If I want to program the chip, I hold “R” down and the PC can program it with the inline programmer “parallel port, straight-through, DAPA style. One cable going into the circuit is for the parallel port programmer, one cable is for the serial port (data transfer), and one is for power (5v which I stole from a USB port).

I hope you found this information useful. Feel free to contact me with any questions you may have, but realize that I’m no expert, and I’m merely documenting my successes chronologically on this website.


     

Random Junk In'da Mail!

I placed another online order to DigiKey yesterday. They have virtually every electronic component available for next-day delivery. How awesome is that? The frustrating thing is that I’m always trying to get my order in before 6pm CMT so that my package will ship same day, so I rush, and I always forget something! It never fails. 30 minutes after I place an order, I always remember something else I wish I’d added to the order (to save on shipping). So, instead of buying it when I want it (now) I wait a few more days to think of some more stuff to add. The last couple weeks I’ve placed 3 orders totaling about $30. You never think you’re spending a lot, but all the sudden you realize that all these 40-cent parts add up when you go to check out. Shipping is usually under $3, which makes me happy. What did I get? I got a couple MAX232 chips so I can easialy shuffle data back and forth from my PC to an AVR chip using the serial port using a simple terminal application like hyperterminal. This will allow me to do some pretty fancy stuff and certainly help with the prototyping/debugging/development steps of my various microcontroller-based projects.

Some of the things which I forgot to order include a few 1F supercapacitors for my solar-powered QRSS beacon project and a random collection of parts needed to build a DIY AVR microcontroller programmer with a USB PC interface and I also wanted to buy at least one ATMega8 microcontroller because they seem to be a good step above the ATTiny 2313 chips I already have and are at the center of so many microcontroller projects. I’m sure there are are few more items I need, but can’t think of them right now, so they don’t make the list.

A little random, but worth noting is a cool website I found earlier which details (in a very basic way) the various types of HF antennas and does a good job (IMHO) of explaining the basic theory behind them. The page can be found at deltadx.net.

Let’s see, what have I been up to? Today’s work (similar to much of last week) involves “damage control” of scientific images. Today’s project is recovering images from a project that cost hundreds of thousands of dollars to complete. Hundreds of animals were killed. Hundreds of man hours went into this project. Numerous animal surgeries on old and sick mice. This project was one of the most massive, time-consuming, and resource-consuming projects ever undertaken by this laboratory. The results (significant) are represented numerically (some graphs) and visually (some representative microscope scans of neurons innervating tissue). But wait! What’s this? The only representative images we have are in highly-compressed JPEG format! (extremely damaged from the start) Holy crap, some are even in 256-color GIF format! To add to the frustration, scale bars, labels, arrows, and titles (some of then incorrect and requiring modification) are permanently burned into the images. Yet, these are all that remain from the project. I’ve got my work cut out for me huh? Check out this example image. This (originally) was a gorgeous TIFF file showing an axon gracefully innervating its target tissue. However, the conversion to extremely-poor-quality JPEG format caused the image to be fragmented into thousands of small squares which (due to the compression algorithm) no longer line up. If you want to get technical, one might be able to argue that since they no longer line-up, it demonstrates that they no longer reflect accurate, actual signals. In other words, this is no longer a scientifically-valid image. In some pixels you’re not seeing things were originally there, and not seeing some things that were originally there. Supposedly backups of the original images were never made, and this is all we have to work with. It’s certainly a challenge!

On that note I encourage everyone to take a couple minutes out of your day and browse the Wikipedia entry describing the JPEG compression algorithm. Seriously, it’s an educational, enlightening, and entertaining read.


     

Proofing Scientific Literature

Man, what a long day! Work is so tedious sometimes. This week I’ve been proofing scientific literature (revising scientific manuscripts in an attempt to improve them as much as possible to increase their probability of acceptance and timely publication). I’ve been using Office 2003 (with “track changes”) to do this. I make changes, my boss makes changes, I make more changes, and it goes back and forth a few times. I wonder why office 2007 is so bad. Does anybody truly like it, and find it to be a significant improvement upon 2003? … or Vista over XP? [sigh] Maybe I’m just getting old, inflexible, and grumpy.

Here, take a look at what I’m working on [snapps screenshot]. I had to blur the content for intellectual property protection and to avoid possible future copyright violations. The light bubbles on the right are deletions. The dark bubbles on the right are comments. The red text is insertions/modifications I made. Pretty intense, huh? Pages and pages of this. And, upon successful completion of a manuscript, my reward is to begin working on another one! Luckily we’re almost caught-up on manuscripts… but that means we get to start writing grants… I’m starting to grasp the daunting amount of time a scientist must spend writing in the laboratory as opposed to performing actual experiments or even doing literature research.

Last night I assembled a Pixie II circuit similar to the one pictured here. I must say that I’m a little disappointed with the information available on the internet regarding simple RF theory in relation to transceiver circuits. I’m probably just not looking in the right places though. (Yes, I know about the ARRL handbook.) The thing is that I’m just now starting to get into RF circuitry and the concept looking at solid-state circuits and imagining a combination of AC and DC flowing through it is warping my brain. I have everything I need to build an ultra-simple Pixie II transceiver (which is supposedly capable of morse code transmissions over 300 miles, and QRSS applications over 3,000 miles) but I refuse to use it. No, it’s not because of moral obligations preventing me from powering it up before I get a general class radio license (shhhh). It’s because building something is useless unless you understand what you’re building.

I’m trying to break this circuit down into its primary components. I understand the role of the lowpass pi filter (before antenna). I understand the role of the 1st transistor and related circuitry in amplifying the output of the oscillator (left side). I totally get the audio amplifier circuitry (bottom). It’s that center transistor (which supposedly handles signal amplification, receiving, and mixing) that I can’t get my mind around. Every time I think figure it out for one mode (sending or receiving), I lose the other one, and visa versa. It has me very frustrated (and a little depressed about the whole thing) because this should be much easier than I’m making it. There’s no thourough documentation on this circuit! I selected it because it was extremely simple and I assumed I’d be smart enough to figure it out. I guess I was wrong. I wish I had an oscilloscope so I could probe the RF passing through various stages of this circuit [sigh]. Back to the ARRL handbook. Maybe if I read chapters 5-11 a couple more times I’ll magically understand it.