CPLD’s (Complex Programmable Logic Device)
PLD’s are a programmable replacement for 74HC series logic. They can do all of your basic AND, OR, NAND logic as well as all of the clocked logic gates such as D, JK, L gates, etc. I decided this would be a good thing to understand – one of these on a robot board would likely handle all of my miscellaneous logic requirements. After programming one and running some tests I’m convinced I was right. I very quickly was able to get a CPLD talking SPI to my uC – I could send a serial byte and 8 LED’s would light up. I can see they could be valuable for miscellaneous logic, for extending microcontroller I/O, adding uC functions such as counters, peripheral interfaces and high speed preprocessing.
I selected the Atmel ATF15XX series of CPLD. I decided to go this route rather than the SPLD route (16V8, 20V8, etc.) primarily due to the cost of the programmer. The ATF1500 series has an ISP JTAG interface. Atmel supplies the programming and downloading software for free. I purchased a $30 interface cable (www.minford.ca), a Byteblaster MV compatible, and that was all I needed. Total investment $33.50 including the chip. Atmel even provides a schematic for an interface cable if you want to get in for less.
The SPLD world operates a little differently. The interface is a closely guarded secret and there is a mini industry of PROM programmers that make interfaces that program PROMS, EEPROMs, PLDs and other such devices. The lowest cost programmer I could find was close to $200. So it’s a no brainer as far as I’m concerned.
The only downside with this decision is that CPLD’s with ISP and DIP packages seem to be a no-no. The ATF15XX is only available in PLCC or TQFP packages, not ideal for hobbyists. This seemed to be the same for other manufacturers as well. I decided I could make do and bought a couple ATF1502’s in a 44 PLCC package. I can get a wire wrap on the terminals. I figured I would mount a conventional PLCC socket in a whole through the board, or upside down, or track down wire-wrap sockets. Even then the number pattern on a PLCC is somewhat mind numbing so you have to be careful. But I think I can make it work. Here is my test setup:
I would spend the extra buck next time a get an ATF1504 with 64 macrocells. They can go quickly if you are using lots of latches.
Atmel supplies, for free, WinCUPL, the high level programming language, and Atmel ISP, the programming software. Buy the cable, parallel interface, and you have a complete development environment.
WinCUPL takes a few nights of head knocking before it becomes clear. Atmel supplies a bunch of examples that really helps. You have to get used to thinking instantaneous gates and not sequential logic like in a microcontroller. Programming simple logic is pretty simple. It gets more complex quickly when you try to work through clocked logic. But after a couple evenings I was able to build an SPI interface that compiled and worked first time. I was very impressed. Atmel supplies a number of app notes on PLDs that are very helpful.
Don’t expect to see libraries of 74HCXX replacement software, though. There seems to be a thriving business in the sale of “IP cores” where one can buy such software. The sample collection provided by Atmel is the best I’ve seen so far – it has some functions such as counters, adders and shift register samples.
A few terms that took me a while to figure out:
Macrocell - A combination of simple logic gates and a multipurpose clocked logic D,L,J-K register with lots of programmable features. Normally has one real output and multiple inputs. The ATF1502 has 32 macrocells. The ATF1504 has 64.
Registered – Logic that uses the D,L,J-K register, as opposed to combinatorial, which is just simple logic gates.
Buried - logic used internally that is not expressed on a device pin.
Here, for example, is the guts of a simple CUPL program to demonstrate basic gates. You write programs like this and a “fitter” converts this into code that best fits this into the specific CPLD device.
* Inputs: define inputs to build simple gates from
Pin 4 = a;
Pin 5 = b;
* Outputs: define outputs as active HI levels
Pin 8 = inva;
Pin 9 = invb;
Pin 11 = and;
Pin 12 = nand;
Pin 14 = or;
Pin 16 = nor;
Pin 17 = xor;
Pin 21 = xnor;
* Logic: examples of simple gates expressed in CUPL
inva = !a; /* inverters */
invb = !b;
and = a & b; /* and gate */
nand = !(a & b); /* nand gate */
or = a # b; /* or gate */
nor = !(a # b); /* nor gate */
xor = a $ b; /* exclusive or gate */
xnor = !(a $ b); /* exclusive nor gate */
Here is my SPI program:
/* Assignment based on ATF 1502 44PLCC */
/* SPI Interface pins */
PIN 4 = SS;
PIN 5 = MOSI;
PIN 18 = MISO;
PIN 19 = SCLK; /* OE2/GCLK2 */
PIN 8 = out0; /* MCell 5 */
PIN 9 = out1; /* MCell 6 */
PIN 11 = out2; /* MCell 7 */
PIN 12 = out3; /* MCell 8 */
PIN 14 = out4; /* MCell 10 */
PIN 16 = out5; /* MCell 11 */
PIN 17 = out6; /* MCell 12 */
PIN 21 = out7; /* MCell 16 */
PINNODE 617 = ShiftIn0; /* MCell 17 */
PINNODE 618 = ShiftIn1; /* MCell 18 */
PINNODE 619 = ShiftIn2; /* MCell 19 */
PINNODE 620 = ShiftIn3; /* MCell 20 */
PINNODE 621 = ShiftIn4; /* MCell 21 */
PINNODE 622 = ShiftIn5; /* MCell 22 */
PINNODE 623 = ShiftIn6; /* MCell 23 */
PINNODE 624 = ShiftIn7; /* MCell 24 */
/* ======= SPI incoming data ======== */
/* Make an 8 bit Long Shift Register */
[ShiftIn0..ShiftIn7].ck = SCLK;
ShiftIn0.d = MOSI;
/* Store data from ShiftIn0 to "out" on rising SS signal */
[out0..out7].ck = SS;
[out0..out7].d = [ShiftIn0..ShiftIn7];