Adventures in Digital Electronics

Saturday, May 30, 2009

The secret lives of magstripe cards


I love All Electronics, the Van Nuys, CA that buys surplus electronics inventories and offers them to the public at discount prices. One of the items I acquired through them was an assembly from a credit card verification device - it included a circuit board with various ICs (including a DTMF encoder/decoder that I plan to mess with at some point) and a 2-track magnetic stripe reader manufactured by MagTek, Inc. From the datasheet, the interface seemed relatively straight forward: aside from +5v and ground, there were a strobe (clock) and data line for each track, and a common 'card present' line.

My first attempt was just a simple state machine that would run in an infinite loop looking alternatively for the low and high signals from the strobe line, and then assemble the states of the data lines into 7 bit words (6 bits of data plus a parity bit.) While I was making some progress, I couldn't get any consistent results, and the loops within loops started getting unmanageable. I decided to start over using the built-in interrupts. After some research and fiddling, I was able to create an interrupt that fired every time the clock line changed. The Teensy++ has two types of hardware interrupts - Pin-Change interrupts and External interrupts. The Pin-Change interrupts fire whenever there is a change (low->high or high->low) on the pin. The External interrupts can be set to respond to only low or high change event, and are especially useful in any environment where you have a clocked-in data. Since each type of interrupt is only available on a specific port (or set of pins), and I didn't feel like rewiring my breadboard, I used the Pin-Change interrupts on Port B, and just ignored the changes I didn't need to use.


ISR(PCINT0_vect) {

//
// This is the pin-change interrupt that is executed from the STROBE pin
//

cli();

if (STB_LOW) {

if (start || (!start && DAT_LOW)) {

if (!start) {start=1;}

if (DAT_LOW) {
// 1
data[i] |=128;
} else {
// 0
data[i] &=~128;
// parity=(~parity&1);
}

bc++;
if (bc==7) {
data[i]>>=1;
// data[i]|=(parity<<7);
// parity=1;
bc=0;
i++;
} else {
data[i]>>=1;
}


}


}

sei();

}


That code initialized the interrupts the Teensy++ needs to respond to, along with the function that handles the interrupt. It fires whenever there is a Pin Change on the pins we initialized the interrupt with. The rest of the code is an infinite loop that process the data from the interrupt once the card present line goes from low to high, performs a Longitudinal Redundancy Check on the data, then outputs it to debug program (available from ___'s website) via USB.

If I would need to implement this again, I would do it using more interrupts; the series of infinite loops is kinda a kludgey way to do it and was meant more as a proof-of-concept project. All in all I learned a lot from this project and look forward to my next and most ambitious one yet - a 240x64 LCD display with controller chip. My full code for the card reader is below:



//
// Notes
//
// Initally integrated parity, but removed since LRC has been implemented
//
//
// B3 - card present
// B2 - strobe
// B1 - data
//
// ToDo: bi-directional scanning: if fails LRC, try reversing bits and repeat

//

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "print.h"
#include "usb_debug_only.h"

#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))

#define CP_LOW ((PINB & (1<<3))==0)
#define STB_LOW ((PINB & (1<<2))==0)
#define DAT_LOW ((PINB & (1<<1))==0)

#define LED_ON (PORTD &= ~(1<<6))
#define LED_OFF (PORTD |= (1<<6))

unsigned int bc=0;
unsigned int i=0,n=0;
char data[250]={};
char start=0;
char lrc;
char parity=1;
unsigned int decode_mode;


ISR(PCINT0_vect) {

//
// This is the pin-change interrupt that is executed from the STROBE pin
//

cli();

if (STB_LOW) {

if (start || (!start && DAT_LOW)) {

if (!start) {start=1;}

if (DAT_LOW) {
// 1
data[i] |=128;
} else {
// 0
data[i] &=~128;
// parity=(~parity&1);
}

bc++;
if (bc==7) {
data[i]>>=1;
// data[i]|=(parity<<7);
// parity=1;
bc=0;
i++;
} else {
data[i]>>=1;
}


}


}

sei();

}

int main(void) {

unsigned int dstart,dend;


CPU_PRESCALE(0);

usb_init();

DDRD |= (1<<6);


LED_ON;
_delay_ms(1000);
LED_OFF;

// B3 Card Present, B2 Strobe, B1 Data

DDRB &= ~(1<<3);
DDRB &= ~(1<<2);
DDRB &= ~(1<<1);

// Set interrupts

PCMSK0 |= (1<<PCINT2); // PORT B2
PCICR |=(1<<0); // Enable pin external interrupts
sei(); // Turn on interrupts

while (1) {

while (!CP_LOW) {}
while (CP_LOW) {}

// LRC

decode_mode=0;

for (n=0;n<160;n++) {

if (decode_mode==0) {

if ((data[n]&63)==5) {
decode_mode=1;
dstart=n+1;
lrc=5;
}

} else if (decode_mode==1) {

lrc^=(data[n]&63);

if ((data[n]&63)==31) {
dend=n-1;
decode_mode=2;
}

} else if (decode_mode==2) {

lrc^=(data[n]&63);
decode_mode=3;

}

}
lrc&=63;

// Output data iva USB Debug

if (!lrc && decode_mode==3) {

print("Data received.\n");
for (n=dstart;n<=dend;n++) {

pchar((data[n]&63)+32);

}
print("\n\n");

} else {

print("LRC error - rescan\n\n");

}

bc=0;
i=0;
start=0;
parity=1;
}


return 0;

}

Tuesday, May 26, 2009

First projects

This post is to get up to speed on the digital projects I've been experimenting with. Over the years, I've collected various components in the hopes that one day I would bring them to life respectively scanning, displaying, or blinking on my desk. My first project, however, was just to get my feet wet with the unit. It read the input from one of the ADC's (analog to digital converters) and display it's estimated value onto 3 LEDs (light emitting diodes.) I mostly used code examples from the Teensy website.






I suppose this is a good time to talk about my development environment. My computer is just a stock P4 running Windows XP. The code is all written in C, using the AVR Studio 4 available from ATMEL corporation. From the application:

AVR Studio is an Integrated Development Environment (IDE) for writing and debugging AVR applications in Windows 9x/ME/NT/2000/XP/VISTA environments. AVR Studio provides a project management tool, source file editor, simulator,assembler and front-end for C/C++, programming, emulation and on-chip debugging.
If you are using the Teensy, most of the benefits of this software package will not apply - it is most useful for using a dedicated (and costly) prototyping solution. However, it is configured to use the WinAVR compiler by default. Utilizing these two packages, getting the development environment up and running was completely painless.

Since then, I have then interfaced a 4x1 OSRAM PD2437 alphanumeric LED display (this wasn't too difficult - it was pretty lenient to timing, and well documented, a series of 4KB EEPROM ICs (this was difficult, mainly because I origininaly attempted to implement the I2C protocol myself (which was an absolute failure), and then used a buggy code sample I obtained from a website. I eventually got it working using the built-in I2C registers (code upon request)).

These turned out to represent excellent examples to help familiarize myself with aspects of the MCU. I may need to use the EEPROMS in a later project, and the LED display will be very useful for future debugging. So far, asidie from the burned-out LED module, I haven't had any other casualties.

Be sure to check out my next blog, where I detail how I got a mag-stripe reader successfully connected!

Welcome


Hello, and welcome. The purpose of this blog is to document my projects and progress utilizing my newly acquired Teensy++ USB development board. Ever since I've been interested in computers and programming, I have always wanted to explore outside the realm of mere software and try and interface to devices in the outside world. Basically, I've had a few projects that have been bouncing around in my head for the past 15 years or so that I would like to see become a reality. What you will read ahead is my own personal experiments toward that goal. I am no expert, and I have never had a clear grasp of electrical theory, so I am sure my writing will be punctuated with tales of smoking components and misapplied theories.

I purchased the Teensy++ a few weeks ago and I have been very happy with it so far. One of the roadblocks to doing any type of work like this has been the development cycle - I code in small blocks and test/debug frequently (a consequence of my self-taught programming, no doubt) and it seemed to inconvenient to switch to separate program each time I needed to reprogram the microcontroller. I know there are in-circuit programmers and what-not, but given I don't have much experience in electronics to begin with, this seemed like too much of a hurdle. The Teensy solves these problems by combining an ARM MCU with a USB port right onto a DIP package that can plug easily into a breadboard. It comes with a small driver that runs in the background and responds to a button on the package that automatically updates its firmware and resets the MCU, running the new code. That means that after you've compiled your latest version, all it takes is a button-push to have it running the new code. It sounded simple in theory and I can attest that it holds up in practice. Once I had it ordered, my brother graciously gave me a few needed items (a large breadboard, some LEDs (that I have since toasted - oops), a handful of resistors (that I should have used with the LEDs) and other miscellaneous items that have proved to be very useful) and I have been tinkering every chance I get.

I plan to put up pictures, diagrams and code examples every chance I get. If you've ever wanted to get your feet wet with digital interfacing, I hope you stick around and get inspired by the face that if someone with my limited expertise in electronics can do it, you can too!