Friday, June 1, 2012

RDM6300 RFID with PIC18 Dev Board

After getting a simple LED-blink program working, I moved on to the RFID portion of my project.  It seemed to be the simplest of the three major parts (RFID, SD card, and MP3) because it's basically just configuring the UART to receive and check the card IDs.  I'm using the RDM6300 UART RFID Module from ITeadStudio, which cost $11 for the reader and $0.50 per card.  The datasheet is posted and it describes both the pinout of the module and the data format.  I started out by wiring up the power, ground, and TX line to an FTDI breakout board to verify that the RFID reader worked correctly by reading the data into Docklight.  The data format is 9600bps 8N1 serial.  The datasheet listed 13 bytes (0x02, 10 data bytes, checksum, 0x03), yet I consistently received 14 bytes.  I'm not totally sure what's going on, but I always get the same 14 bytes, so I just recorded those for each of the 10 cards I purchased.  The table below shows the hex values I receive for each of the cards.


The datasheet for the RFID module lists the operating current as <50 mA, which is high enough that I want to be able to turn the module on and off from the PIC instead of just leaving it on all the time.  To do this, I used a 2N3906 PNP transistor in between the board 5V supply and the RFID 5V supply, with the base connected to a GPIO with a 1k resistor.  Turning the GPIO high turns the RFID module on;  setting it low turns the RFID module off.  Using the transistor dropped the supply from 5V to 4.87V, but this is still within the +/-5% of 5V listed on the datasheet spec, and it appears to be working just fine.  I also added a resistor divider to the UART TX line of the RFID module to bring the 5V output down below 3.3V.  The following two pictures show a circuit diagram of this, and then what it looks like soldered onto my development board (some parts/wires were soldered underneath the RFID module).



The PIC C18 compiler comes with a set of peripheral libraries, including one for the USART, which made it very easy to configure the USART and had a good example of using it to send and receive data.  Once I verified that I could receive a single card's data, I set up a demo with three RFID tags programmed into the PIC so that it would toggle an LED based on which card was swiped.  I initially tried to use the "gets1USART" function to read a 14 characters off of the USART, but every once and a while the RFID unit spits out a random bad character (sometimes at power up) that was causing me issues.  Instead, the USART reception is handled using an interrupt service routine, and I pulled the basic setup for it from an Example #6 in an older copy of the C18 Getting Started Guide.  The code is below, followed by a video of the demo.  Note that the code assumes a 16 Mhz clock speed, like my previous post.  You'll need to adjust the USART initialization line and delay line if you're using a different clock speed.

#include <p18lf26j11.h>
#include <delays.h>
#include <usart.h>
#include <string.h>

#pragma config OSC = HS //High speed crystal
#pragma config WDTEN = OFF //Disable watchdog timer
#pragma config XINST = OFF //Disable Extended CPU mode

//LED Pin Configuration
#define LED1Pin LATAbits.LATA0
#define LED1Tris TRISAbits.TRISA0
#define LED2Pin LATAbits.LATA1
#define LED2Tris TRISAbits.TRISA1
#define LED3Pin LATAbits.LATA2
#define LED3Tris TRISAbits.TRISA2

#define RFIDVCCPin LATBbits.LATB4 //Define RFIDVCCPin as PORT B Pin 4
#define RFIDVCCTris TRISBbits.TRISB4 //Define RFIDVCCTris as TRISB Pin 4

//Flags & Data Reception Variables
volatile char tagRecdFlag;
volatile char tagComingFlag;
volatile char tagCounter;
volatile char tagRX[14] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

//RFID Tag IDs
char rfidTag1[14] = {0x02, 0x30, 0x35, 0x30, 0x30, 0x41, 0x44, 0x44, 0x38, 0x46, 0x46, 0x43, 0x3f, 0x03};
char rfidTag2[14] = {0x02, 0x30, 0x35, 0x30, 0x30, 0x41, 0x44, 0x42, 0x46, 0x35, 0x37, 0x36, 0x30, 0x03};
char rfidTag3[14] = {0x02, 0x30, 0x35, 0x30, 0x30, 0x41, 0x45, 0x33, 0x46, 0x36, 0x35, 0x44, 0x33, 0x03};

//Function Prototypes
void rx_handler(void);
//Function Prototypes

#pragma code rx_interrupt = 0x8
void rx_int(void)
{
    _asm goto rx_handler _endasm
}
#pragma code

#pragma interrupt rx_handler
void rx_handler(void)
{
    unsigned char rxByte;
    rxByte = RCREG1; //Read character received from USART

    if (tagComingFlag == 0 && rxByte == 0x02)
    {
        tagRX[tagCounter] = rxByte;
        tagComingFlag = 1;
        tagCounter++;
    }   else if (tagComingFlag == 1)
        {
            tagRX[tagCounter] = rxByte;
            tagCounter++;
            if (tagCounter == 14)
            {
                tagCounter = 0;
                tagComingFlag = 0;
                tagRecdFlag = 1;
            }
        }   else
            {
                tagComingFlag = 0;
                tagCounter = 0;
            }
    PIR1bits.RCIF = 0; //Clear interrupt flag
}

void main()
{
        //Set LED Pins data direction to OUTPUT
        LED1Tris = 0;
        LED2Tris = 0;
        LED3Tris = 0;
        //Set LED Pins to OFF
        LED1Pin = 0;
        LED2Pin = 0;
        LED3Pin = 0;

        tagRecdFlag = 0; //Set in ISR if new RFID tag has been read
        tagComingFlag = 0; //Indicates if a tag is partially received
        tagCounter = 0; //Counts byte index
        
        //USART1 Initialization
        Open1USART(USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_LOW, 25);

        //Interrupts
        RCONbits.IPEN = 1;  //Enable interrupt priority
        IPR1bits.RC1IP = 1;  //Make receive interrupt high priority
        INTCONbits.GIEH = 1; //Enable all high priority interrupts
        
        //Turn on RFID Module
        RFIDVCCTris = 0; //Set to output
        RFIDVCCPin = 1; //Turn on RFID Module

        while(1)
        {
            if (tagRecdFlag)
            {                 
                //Toggle LED corresponding to which card was read
                if (memcmp(tagRX, rfidTag1, 14) == 0)
                {
                    LED1Pin = ~LED1Pin;
                }
                if (memcmp(tagRX, rfidTag2, 14) == 0)
                {
                    LED2Pin = ~LED2Pin;
                }
                if (memcmp(tagRX, rfidTag3, 14) == 0)
                {
                    LED3Pin = ~LED3Pin;
                }

                //Delay 1/2 sec & clear flags to prevent repeated card read
                Delay10KTCYx(200);
                tagRecdFlag = 0; 
                tagComingFlag = 0; 
                tagCounter = 0; 
                }
        }
}

Wednesday, May 30, 2012

PIC18 Getting Started

Now that I have my development boards in hand, I'm getting set up to work with Microchip PIC18 microcontrollers.  My first step (detailed here) is to just get an LED to blink and confirm that I can compile and run code on the microcontroller.  Going forward, I'll do a post each on testing of the other functional parts of my project as I get them working:  the UART interface to an RFID module, working with an SD card and working with the VS1003 MP3 chip.  I don't get much time to play with this stuff, so it'll probably be a few months before I'm done.

I'm going to be using the new MPLAB X IDE, which you can download for free at the MPLAB X IDE download page.  There's video on that page that describes everything you need to do to download and install the IDE.  There are several options to download different compilers.  I selected the "MPLAB IDE X v1.10", "MPLAB X IDE Release Notes/User' Guide", and "MPLAB C18 Lite Compiler for PIC18 MCUs".  The other compiler option for the PIC18 series is the HITECH C compiler, and you can also download a Lite version of this from the same page.  From the research I've done, it looks like the C18 compiler is a better option for compatibility with the application libraries provided by Microchip.  It also looks like both of these compilers will be combined and migrated to the new XC8 compiler from Microchip very soon (or maybe will already be by the time I actually post this), but I'm going to stick with the C18 compiler for now.

For a programmer/debugger, I'm using the PICkit 2, which runs about $35.  Microchip offers several packages that come with the PICkit 2 plus a development board (or the newer PICkit 3 with a development board), but since I have my own board, I bought only the programmer.  There are several other options for programmers from Microchip, and many more from third party sources.  Microchip offers a Development Tool Selector where you can put in the microcontroller you want to use and it will show you which of their development tools are compatible with it.  There's also a device support list for the PICkit 2 specifically, which shows the microcontroller I'm using, PIC18LF26J11, is supported.


After installing the IDE and PICkit 2 driver, I populated enough of my circuit board to start testing with the PIC.  I added the LDO regulators for 5V, 3.3V, and 2.5V, a power LED, the reset circuit, crystal, LEDs, and DIP socket.  My first mistake was soldering on a 48 MHz crystal when I saw 48 MHz as the max clock speed.  I started up the LED blink program, and the timing wasn't even close.  After some digging, I figure out that 48 MHz was the max clock speed, but to get that you either need an external clock or a 12 MHz crystal with the 4x PLL activated.  I'm not finding it in the datasheet right now, but I seem to recall 25 MHz was about the max crystal frequency the PIC could drive.  I'm using 16 MHz for now.


When you download the Microchip C18 compiler, be sure to check out the included documentation.  It's located in the install directory in a "doc" folder (for me it is at C:\Program Files (x86)\Microchip\mplabc18\v3.40\doc).  The "Getting Started" document and "User Guide" are obviously helpful, but the "hlpPIC18ConfigSet.chm" and "PIC18F Peripheral Library Help Document.chm" are also extremely useful.  The first one lets you select your microcontroller and then list all of the configuration settings and possible values.  The configuration settings do similar things as fuses in AVRs, but it seems to be a little smoother with PICs to use them.  The issue I had at first is that the configuration settings names between chips vary, so if you're trying to get sample code for a different PIC to work with yours and are seeing compiler issues it'd be a good idea to reference this document.  For example, the sample LED blink program I found in the user guide used "WDT" to set the watchdog timer to off, but for the  PIC18LF26J11 , I needed to use "WDTEN" instead.  The library help document shows all of the functions available in the C18 library, and again they're broken down by what's available for your specific microcontroller.

The following code is what I wrote as a sample program to make sure I had everything working correctly and could program the PIC.  I wired an LED each to pins 2, 3, & 4 on the PIC (PORTA0-2), and set them blinking at a 1, 2, & 4 Hz rate.  This is where I figured out about the crystal frequency being off, because the blink rate was much slower than in should have been.  I'm using two of the libraries that come with the C18 compiler, and had to add them to the project to get it to work (though I just referenced them from their default location).

#include <p18lf26j11.h>
#include <delays.h>

#pragma config OSC = HS //High speed crystal
#pragma config WDTEN = OFF //Disable watchdog timer
#pragma config XINST = OFF //Disable Extended CPU mode

#define LED1hzPin LATAbits.LATA0
#define LED1hzTris TRISAbits.TRISA0
#define LED2hzPin LATAbits.LATA1
#define LED2hzTris TRISAbits.TRISA1
#define LED4hzPin LATAbits.LATA2
#define LED4hzTris TRISAbits.TRISA2

char i;

void main()
{
        //Set LED Pins data direction to OUTPUT
        LED1hzTris = 0;
        LED2hzTris = 0;
        LED4hzTris = 0;
        //Set LED Pins to OFF
        LED1hzPin = 0;
        LED2hzPin = 0;
        LED4hzPin = 0;

        i = 0;
        while(1)
        {
            Delay10KTCYx(50);//Delay 1/8 sec
            LED4hzPin = ~LED4hzPin;//Toggle LED Pin
            if (i%2==0)
                LED2hzPin = ~LED2hzPin;//Toggle LED Pin
            if (i%4==0)
                LED1hzPin = ~LED1hzPin;//Toggle LED Pin
            i++;
        }
}

This step was pretty simple, but it's one that can take some time tracking down silly errors when you're starting with something new, and now I'm ready to move on to my actual project.  Next up will be getting the RFID module working.

Thursday, April 26, 2012

28 Pin PIC18F Development Board



The next project I'm working on incorporates several things I've never worked with before, and instead of buying breakout boards for some parts and breadboarding the rest, I decided to design my own development board that was tailored specifically to my project.  While this board is designed with a particular project in mind, I still tried to add generic features and as much flexibility as I could.  I'm trying to learn how to use a variety of different microcontrollers (I've mostly used AVRs and MSP430s up til now), and this project seemed like a good fit to try out PICs.  The MSP430F/G chips I have are 14 pin with 2KB flash, and I needed more than that for my project.  The AVRs I have are in the ATmegaXX8 line, which certainly could have worked, but looking through the Microchip 28pin options, I saw a lot more flexibility with peripherals.  Having multiple SPI and USART ports would be useful for this project, and USB could work well for other projects to avoid using an FTDI or MCP2200.  In the end, it was mostly the chance to learn something new that made me decide to go with a PIC18 for this project.

Several sites offer a 10 copies of 10x10 cm pcb for ~$25 deal, so I initially planned on that size, but I'm using the freeware version of Cadsoft Eagle for the PCB layout, so board size was limited to 10x8 cm.  I upgraded to Eagle 6 for this layout, but I didn't notice too many changes from version 5 on the user interface side.  My goal was to essentially make a simple breakout board for the VS1003 MP3 chip, SD card, and PIC18 on a single board, add a power supply, and then leave the rest as a prototyping area.  The prototyping area is just big enough for an RFID module from ITeadStudio with two extra rows, but also makes the space more useful in projects that don't use RFID.

Most of the eagle parts I used came from the default libraries, but I also made use of the Sparkfun library and Adafruit library.  In theory, the Sparkfun library is nice because it contains part numbers so you can order straight from them and know that your parts will match the footprint, but it's not foolproof. While Sparkfun only gives you Sparkfun part numbers, Adafruit goes further and gives part numbers for multiple major distributors (Digikey, Mouser, etc.), so I used Adafruit's library whenever a part was in both.

For the power supply, I used separate MCP1702 low dropout regulators.  This regulator is available in a variety of voltages (1.20V, 1.5V, 1.8V, 2.5V, 2.8V, 3.0V, 3.3V, 4.0V, 5.0V)  and has a typical active current of 2uA, making it a good fit for battery operated projects.  They have a typical voltage drop of 625 mA, compared to 2V for an LM7805, so the power supply input doesn't need to be as high.  I used separate regulators for each of the 3 supplies for the VS1003 chip (IOVDD, CVDD, AVDD), a regulator for the PIC CVDD, and then 3.3V and 5V generic supplies for the PIC and other parts.  There is a PTC fuse for protection, and the power input is pretty flexible and can come from USB, a barrel plug wall adapter, or two wires from a battery pack.  I used solder jumpers throughout the board so that I can configure the board as needed for each project.  In addition to the jumpers selecting the power input, there's one that allows selection of 3.3V or 5V power to the PIC.


I looked at the pinouts for the two PIC18F series chips I had on hand as samples from Microchip (PIC18LF26J11 and PIC18LF26J50) and added the basic support circuit.  This included the ICSP connector for programming/debugging, reset circuitry, a crystal, and decoupling capacitors.  One of the chips has USB built in, so I routed those pins to a mini-B connector, but solder jumpers are used so that is a select-able feature.  I will not be using USB for the project I'm working towards right now, but I'd like the option to use it in the future.


The circuit for the VS1003 mp3 chip is straight out of page 15 of the datasheet, and is definitely the part of this board in which I am the least confident.  I left out the microphone input portion of the circuit because I didn't need it, but everything else is included.  I didn't route any of the pins to the PIC, but I broke out the pins required for interfacing, so it's basically a breakout board for the VS1003 on the same PCB.   I used a Sparkfun part for a headphone jack that had a part number, but it was a mistake in their library and it wasn't until I got the board and was starting to order parts that I realized the problem.  I'll probably end up getting a separate breakout board for just the headphone jack of the part of my project.


The SD card portion of the PCB is also essentially just a breakout board.  There's a jumper that allows it to use the PIC's Vcc (which should only be selected if it's 3.3V).  I used the Adafruit SD card socket footprint, which was only available at 4UCON or Newark, but I found one that looked similar on Digikey and decided to get it, and it ended up being a match.


I put footprints for 5 LEDs on the board, mostly for status and testing as I'm developing.


I used the Open PCB service from iTeadStudio when I had my boards made, which for just $0.10 you get two random PCBs that someone else designed, and two copies of your boards are sent to random people.  The chances I'd get something useful were slim, but for ten cents it was worth it.  One of the boards I got looks like one of iTead Studio's Arduino Mega Sensor Shield.  I don't have an Arduino mega, and don't plan on getting one, so this one isn't really useful to me.  The other board was a breakout board for a TQFP-32 ATmega8.  Someone used the 5cm x 5cm service and put three copies of a simple breakout board onto a single PCB.  It looks like there's enough room that I could use my dremel to cut out 3 separate breakout boards.  This one looks more useful, and I actually have some TQFP ATmega88's on hand that I can use with it.  If anyone out there ended up with a copy of my board and happens to read this, I'd love to hear from you and see if it can be of any use to you.  Here's a picture of the two boards I received.


This is first PCB I've made where I've used silkscreen, and it was a lot easier than I thought...but it didn't turn out too well.  The first PCB I designed I used a company that didn't offer free silkscreen, so I left it off, and didn't bother with the next couple either.  Because I'm intending this to be more of a development board and will be doing quite a bit of wiring after all the components are soldered on, I realized that having labels on the rows of broken out pins would be very helpful.  The eagle "smash" command, in particular, was very helpful in laying out the board so that the text was not overlapping from different parts.  I resized a lot of the text, but didn't really have a good idea of what it would look like on the actual PCB.  A lot of it ended up being really tiny...way too small to read, and some of it didn't show up at all.  I always have the eagle files up on my computer while I'm working anyway, but it would've been nice to have better labeling on the board than I ended up with.  I'll have to pay more attention to text size in the future.  Here's a picture of the how the boards turned out.



I got all of the parts I needed from Digikey except for the VS1003 chip and the headphone jack, which I'll from Sparkfun, and the RFID module from ITeadStudio.  My end goal is to make a book reader for my daughter.  The basic idea is that I'll have extended family record themselves reading books to my daughter.  I'll put the files on an SD card, and have each one tied to an RFID tag taped inside the books so that she can swipe the book over the device and it will start reading the book to her.  My Sourceforge page for this project (https://sourceforge.net/projects/pic18devboard/) has the board design files and an Excel workbook with a (mostly complete) bill of materials with part numbers.  I'll add additional files to it as I get some of the firmware tested out and working.  My next few posts will go through getting started with PICs and implementing the different pieces needed to complete my project, assuming all goes as planned.  

Saturday, February 18, 2012

Baby Star Lights

My daughter just turned 3 months old, and she is completely fascinated by lights and things that move.  I got the idea to make a star projector from seeing one of these stuffed animals that puts a star pattern on the ceiling, although mine is a little different.  My project uses an MSP430 to control an LED inside of a ping pong ball that's mounted on the end of a servo to rotate it.


I started out by taking a ping pong ball and drilling holes all over it with a 1/16" bit, the smallest in my set.  I used a 3/16" bit to make hole for an LED and I spray painted the ball black to avoid having the ball glow.  To test it out, I wired up a quick LED circuit and when I went into a dark closet it was clear that 1/16" was too big of holes--the light was not near focused enough on the ceiling, and  it'd look even worse in the baby's room.  I started over with a new ping pong ball and used a hot sewing needle to poke tiny holes and got closer to the look I wanted.




 Switching over to the electronics, I used an MSP430G2211, which is one of the chips that comes with the MSP430 Launchpad.  Any of the small MSP430's would work just as well...the firmware's really simple.  Basically when you switch it on, the LED turns on, and then the servo rotates slowly one way to the max and then goes back the other way, and repeats.  It runs for a set amount of time (15 minutes right now...it can be varied based on how long it takes for my daughter to calm down and go to sleep), and then shuts everything down and goes to sleep (LPM3).  The servo control is on P1.1, and the LED is on P1.2.  I got a servo for $2.50 that works great.  I tried to use a red-yellow two color LED, but the one I had was too dim, so I used a bright bluish-white LED instead.  I might use an RGB LED in the future if I come back to this and clean it up.  It's powered by a 4xAA holder from Radio Shack with a power switch built in, and an L78L33 provides 3.3V for the MSP430.  The PCB I used is a spare from a stalled project (a Wii Nunchuk controlled RC car...the same board is used as the controller/transmitter and receiver/motor driver and also serves as a simple breakout board for 14 pin MSP430F/Gs) that I had made at Seeed Studio.


The most frustrating part of this project was when I tried to package it up.  I used a small Sparkfun box as a case, and once I put everything inside the box I realized that the wires I was using from the PCB to the LED at the end of the servo arm were way too thick and there wasn't enough give.  The servo was straining really hard and not moving much, so I reduced the swing range to only a few degrees, but that still didn't fix it.  I had to cut out that wire and use the thinnest I could find, which was some wire I snipped off of a spare battery holder.  It works...but I may decide to start over with the whole enclosure (maybe use this as a chance to try out a laser cutting service) and use thinner wire yet so that it works more like I'd initially planned.


The picture here is a longer exposure, so its fuzzy because of the movement, but you get the idea of how it looks on the ceiling.  The source code is very simple, but it's available at https://sourceforge.net/projects/babystarlights/.  The project didn't turn out quite like I'd planned, but it's tons of fun to see my daughter staring at the lights and following them as they move around the room, and my wife even asked to help me solder it.  My camera wouldn't pick up the light on the ceiling, but here's a quick clip of the light in action.

Wednesday, December 7, 2011

Star Wars Christmas Tree...Now with Sound

A few days ago I posted a set of Christmas tree lights that flashes to the Star Wars theme song.  I initially did not include a sound output intentionally because the tree sits in our dining room and it'd be annoying to have a song playing whenever we had the tree lit.  I decided later that as long as I could turn the sound off, it'd be a fun addition to the project, so I added a small piezo buzzer between pins 8 & 9 of the MSP430 and made the software changes necessary to output the song on the buzzer as well as on the lights.  I soldered a couple female headers onto my protoboard so that I can plug the buzzer in (to have sound) or take it out (for lights only).


In order to add the sound, I had to go back to the music and re-transcribe it with the actual note values (I ignored flats/sharps before because you couldn't really distinguish them on the lights...but it matters more with the sound).  I looked up the frequencies of those notes here.  The notes in the song range in frequency from ~294 Hz to 880 Hz.  I tried to keep the structure of my code as similar to the first version as possible, so the audio PWM is handled in software in the interrupt routine that fires when Timer A reaches the end of its period for the LED PWM.  I bumped up the DCO frequency from 1Mhz to 8Mhz to provide finer resolution for the musical notes, but the rest of the changes are pretty minor.  An updated version of the source code is available at https://sourceforge.net/projects/starwarsxmasled/.

Sunday, December 4, 2011

Star Wars Christmas Tree

In addition to all of the Christmas trees, ornaments, stockings, garlands, and other decorations that fill our house for the Christmas season, my wife lets me have one small tree of Star Wars Ornaments.  For the past few years it has been unlit, and she decided that it needed some lights this year.  She found a battery operated strand of 30 white LEDs on sale at Target last week, but I figured we could do better than just plain lights.....we needed Star Wars lights.  I built a small controller for the light strand that makes it flash in the pattern of the Star Wars theme song.  The basic concept is that the note durations are how long the lights are on, and the pitch translates to light intensity.  The lowest note in the song corresponds to the dimmest light setting, and the highest note to the brightest. 


I first cut the strand and measure that it draws ~70 mA with a new set of 4xAA batteries, which is way more than a mcu gpio can output, so I started with a 2n3904 transistor to turn the strand on and off.  I really only needed 1 pin from an mcu, so I went to my parts box and dug around for small microcontrollers.  The two options I had on hand were an AVR ATTINY85 and a handful of MSP430 microcontrollers.  I had a couple of ez430 thumbsticks that TI was giving away a while ago, along with a pack of the extra target boards, and this project was well suited to the small form factor and ease of use that those provide.  I ended up using one of the MSP430F2012 target boards.  It has a built in LED, which I did my initially firmware testing with to get  the note lengths and song pace working right, and then I used PWM output from the Timer A module to control the intensity of the LEDs on the actual strand.  

I'm not really a musical person, and all of the notes on the piano sheet music I was finding just confused me, so I found a violin arrangement (so only 1 note is being played at a time) and set about transcribing that into code for my microcontroller.  I broke the song down into repeating chunks so that I wouldn't have to code in every single note and could reuse the chunks.  Each note is represented by a single byte, where the lower three bits represent the length of the note, and the upper bits represent the pitch.  I went through and labeled the notes 1-12 from lowest to highest, and store those values, which are mapped to the range of PWM duty.  I recorded the note duration and pitch by hand for the whole song, and then used an Octave script to combine the values into my chosen representation of the information.


In the next picture you can see the circuit board a little closer.  I'm using an LM317 with a couple resistors and capacitors to provide 3.3V for the MSP430, and then the LED strand is switched on my a 2n3904 transistor with a 1k resistor on the gate.  Using the ez430 target board makes it easy to connect to the programmer/debugger, and it's not much more expensive than the bare chip (~$3.30 vs ~$2.70).  One of the value line (MSP430G series) chips would certainly have worked, but I had a few of these target boards lying around and it did the job just fine.


Below you can see a video of the tree in action.  The tree plays the full Star Wars Theme, but this is just the intro.  It looks better in person than on my camera, but you at least can get the idea.  My wife was kind enough to play violin along with the tree for the accompaniment.  You can download the source code here if you want it.

Friday, August 26, 2011

Hacking an LED POV Fan



The company where I work has recently been doing a big push for safety, and last week they passed out small POV fans with sayings like, “Thx 4 Being Safe”, “Being Safe is Cool”, “I'm a Safety Fan”, etc. The fan has clear, flexible plastic blades, and one of the blades has a strip of 7 LEDs in it which are used to display the messages. The fan itself is pretty cool....but I wanted to see if I could make it say something else.  The box it came in says "Programmable Message Fan: Model 45 Series".  I searched online and found similar fans that were re programmable, but those had 4 buttons for programming in messages, and mine only has an on/off button.  This was a very simple project, but it was fun to figure out how something worked and then make it do something else.
There is a removable cap that reveals a 5 pin port, but there was no documentation with the fan indicating what the port was or how to reprogram it. Removing the entire front of the fan reveals a circular PCB.


Whatever microcontroller is being used is under a black blob, but the SOIC-8 IC with a marking on it was a CAT24C04, which is a 4kbit (512 byte) I2C EEPROM. On the back side of the PCB, the 5 pin port was labeled: [DATA, VCC, CLK, GND, PA0], and I confirmed that these pins were connected to the I2C SDA and SCL pins on the EEPROM.  The PA0 pin threw me for a little bit, but it is connected to what would be the A0 address pin on the EEPROM for smaller chips in the same line.  I'm assuming they use the same fan PCB with the smaller EEPROMs and use the other address bit for some reason.  The 512 byte version leaves the A0 pin unconnected and that bit in the EEPROM slave address is reserved for the high bit of the memory address.  The smaller EEPROMs can address their entire memory in a single byte, but the 4kbit (and larger) versions require part of the device address for the higher values.  The table below (from the EEPROM datasheet) shows how to figure out the I2C slave address.  The first 4 bits are fixed, and then A2 and A1 are determined by the state of the corresponding pins.  Those pins were connected to ground, so both values were zero.  For the CAT24C04, the a8 bit is 0 for bytes 0-255 of the EEPROM, and 1 for bytes 256-511.


The first thing I tried to do was read the data stored on the EEPROM. I have used the Bus Pirate from Dangerous Prototypes in the past for initial I2C prototyping with new chips, but I didn't have any luck with this one....I may have done something bad to my Bus Pirate. After wasting a couple hours on that dead end, I pulled out my Arduino and was immediately able to read the EEPROM. I wrote a short sketch that read out each page of memory and sent it over the serial port to my PC, and then copied all of the data to Excel as a single column. I converted the values to decimal numbers so I could make more sense of them and then tried to figure out the data format. I wrote out each of the messages displayed on the screen and counted their characters. The very first byte of memory contained the number of screens, and the second byte contained the number of characters in that screen. From another post about a similar fan I'd seen that the data was probably stored with 5 bytes per character, and I confirmed that this was the case. So, the first screen initially read “Thx 4 being safe”, which contains 16 characters. The second byte of memory contained the number 16 (0x10), and the following 5x16=80 bytes contained the character codes to display. The very next byte contained the length of the second screen, and that pattern continued to the end.  Below you can see the beginning of the data dump.


Once I had read and stored all the data (so I could presumably restore it if I totally messed up the fan), I started experimenting with writing data to the fan. The first thing I did was change the first byte of memory to 1 instead of 6, which caused the fan to only display the first screen. This was what I expected to see. Rather than try to pull the alphabet out of all the character codes on the fan (which would have yeilded an incomplete set anyways), I decided to just figure out how the characters are stored and then create my own set. I changed the second byte of the fan to 1 so that the first screen only displayed a single character, and then experimented with different values until I figured out how they mapped to the LEDs. My basic process was to write all 1's or 0's to different rows/columns, record what happened, and then write new values.  After 2 or 3 tests I figured out what was going on.  What I found was that each character is 5 LEDs wide and 7 LEDs tall. Each byte of the 5 character bytes represents a single column. In each byte, the LSB is the bottom of the screen, and the MSB is the top. The 8th bit is unused, so I set it to 1 in all of my codes. In each byte, a 1 means the LED is off, and a 0 means an LED is on. The screen also prints from right to left, which means that everything has to be entered in the reverse order to display correctly. To create the characters I drew each letter backward in OOCalc using 1's and 0's, and then converted to the corresponding hex values. I wrote a single test screen to the Arduino by copying each byte by hand into my sketch and sending the appropriate start/stop conditions, and it worked, but it was very tedious and I would not want to enter multiple screens worth of data that way.  The example below shows how I created the letter Z.  0's represent an ON LED, and the MSB is ignored.  The bottom row automatically converts to the hex value, so all I had to do was enter the 1's and 0's, and I ended up with a table of the alphabet.  Once I had the full alphabet, I started trying to write new phrases to the fan.


I probably could have put the character map into my Arduino sketch and had someway to enter words and convert them there, but I thought it would be easier to do the character conversion in some kind of script on my computer first. The result is ugly (and unneccesarily long) Arduino code, but it makes it much faster and easier to input new words. I use Matlab frequently at work for quick data processing scripts, so that was the first thing my mind jumped to. I don't have Matlab at home, but Octave is an open source clone that has most of the major functionality and I decided to give it a try. Basically, all my Arduino sketch does is load/enable the I2C library, send the data, and then blink an LED forever to say that it is done. I cut the sketch into three parts: header, body, and footer. The header and footer are always the same, and the body of the sketch (which sends the data) comes from Octave. The Octave script has a user input section to enter the screen information, and it converts the words to the 5 byte character codes, reverses the order, and then writes them a page at a time to the EEPROM, with the correct # of screen and # of characters bytes as well.  I was running on Linux, and the Octave script uses the Linux cat command to combine the header, Octave output, and footer into a single file.  If you want to run this on Windows, you'll need to manually combine the files.


Running the Octave script creates a finalPDE.pde file which is what I load onto the Arduino. Only 4 wires are needed (PA0 is unused) for programming: Vcc to 3.3v, GND to GND, DATA to Analog 4, and CLK to Analog 5. The amount of data you can display is limited to 6 screens maximum with 20 characters (including spaces) per screen. The screens wipe across the display in different patterns, and as far as I can tell there is no way to control these from the EEPROM....it's dictated by the MCU. Here's a video of the fan in action (before and after):



I've posted the Octave script, OOCalc file with character codes, and a sample Arduino sketch at https://sourceforge.net/projects/povfan/ if anyone wants to try this for themselves.

July 4, 2015 UPDATE: The software I was using in this post no longer works with the current version of Arduino and Octave.  I have an update available here.