PICPLD Output
Related Links
PICPLD

GPMPU28 manual

Zip file

As a simple example, let's look at how you'd use the PICPLD to create 32 extra outputs for the PIC. The interface will be a simple 3-wire serial interface. In particular, you'll shift 11 bits to the CPLD. The first bit is always a 1 (think of it as a start bit). The next two bits select which of 4 banks of 8 bits you want to address. Finally, the last 8 bits are the byte you want to write to that 8 bit port (MSB first). In addition, you must pulse the "START" pin before you begin a transfer. This scheme saves some CPLD real estate at the expense of an extra PIC pin.

Of course, there are many other schemes you might use. For example, you could use a giant 32-bit shift register and latch. Then you'd just shift in the 32 bits you wanted to output and pulse the latch line. Or, you might use RA0 to RA3 as a 4 bit data port. RA5 could be a strobe output from the PIC to tell the CPLD to latch the data and you could build up commands and data that way. However, for this example, I'll stick to the original Start/Shift protocol I described first.

AWC provides source code and logic designs to accomplish these tasks with a minimum of fuss. However, in this tutorial, I'll not only show you how to easily use these tools, but what's inside the tools -- this will help you when you want to design something new.

Here is a schematic of the (misnamed) PICIO symbol (click to enlarge):

The CLK20 line is the 20MHz clock from the CPU. DCLK is the data clock. Starting at the DCLK input, notice that there is a synchronizing flip flop and an edge detector (this is separate component included with the design). The edge detector enables the shift register for one clock period and this shifts the data in one bit at a time. An 8- and 4-bit shift register join to provide 12 bits (the top bit isn't used). The lower 8 bits connect to each of the FD8CE registers that drive the outpus.

The upper 3 bits of the 11 bit command wind up in the second shift register. When the topmost bit is set (remember, the PIC has to shift a 1 first) the lower FD flip flop delays it for one clock cycle. This gives the address a chance to be at the inputs of the D2_4E decoder which selects one of the registers. On the next clock cycle the register grabs the data bus (from the lower shift register) and presents it on output.

The START input simply clears the shift registers for another round. It would be possible to add logic to make this happen (and, in fact, you could preset the first bit in the shift register so the PIC didn't have to shift the first 1) but this would require extra real estate on the CPLD.

It is important to realize that the system clock is running at 20MHz and the data clock is running much slower. Since the PIC divides its internal clock by 4, the data clock could hardly be faster than 2.5MHz (since it will take at least 2 instructions to make a full cycle). This gives the CPLD a chance to do multiple things during one data clock. However, if you interfere with the clock frequencies, you'd have to take this into account. The circuit needs the data clock to be on for at least 5 (and 6 would be safer) system clock periods. So, with a 20MHz clock, that works out to about 333nS. However, since the PIC and the CPLD are on the same clock and the PIC divides the clock internally, you don't have to worry about this in practice unless you start using external clocks from another source.

The PIC code

Using the provided library, it is quite easy to send data to the output port:

main
	clrf pshadow
	clrf ui
	bsf STATUS,RP0
    	MOVLW 0x06 ; Configure all pins
    	MOVWF ADCON1 ; as digital inputs
    ; set outputs - These are in bank 1 so really TRIS access
	bcf PORTC,0  ; reset 
	bcf PORTC,1  ; data
	bcf PORTC,2  ; clock 
	bcf STATUS,RP0
	movf pshadow,w
	movwf PORTC
	movlw 3       ; select PORT (channel)
	movwf chan
loop:
	movf ui,w     ; get byte and store it
	movwf dbyte
	call sendpld  ; send to PLD
; this code is good when testing digital I/O	
; it just flips the ui bit so you can see an LED blink, for example
	movlw 0xFF
	xorwf ui,f
; delay in any event
	call dly
	call dly
	goto loop

Of course, this is simple because of the sendpld routine. But that's not much either:

; send data in chan and dbyte to PLD
sendpld:
	call pldreset
	swapf chan,w  ; make 1=0x10, 3=0x30, etc.
	call shift3
	movf dbyte,w
	goto shift8
; reset PLD input
pldreset:
	bsf pshadow,0
	movf pshadow,w
	movwf PORTC
	bcf pshadow,0
	movf pshadow,w
	movwf PORTC
	return
	
; shift 3 bits
; on entry, we assume that W=the bits
; left-justified in the top 4 bits
; So to shift 3, W=0x30
shift3:
	movwf sr
	rlf sr,f  ; adjust for 3 bits   
	bsf sr,7  ; set marker bit
	movlw 3
	goto shift
; This just shifts 8 bits
shift8:
	movwf sr
	movlw 8
shift:
	movwf i
shift0:
	rlf sr,f        ; shift
	btfss STATUS,C  ; copy STATUS to data bit
	bcf pshadow,1
	btfsc STATUS,C
	bsf pshadow,1
	movf pshadow,w
	movwf PORTC
	call clock
	decfsz i,f      ; loop!
	goto shift0
	return
	
; just pulse the clock
clock:
	bsf pshadow,2
	movf pshadow,w
	movwf PORTC
	bcf pshadow,2
	movf pshadow,w
	movwf PORTC
	return	

This code is relatively conservative. It uses a shadow register instead of directly modifying the port registers, for example. In practice, you may be able to speed it up, but for most purposes, the code is plenty fast and conservative code will be more reliable in more situations.

You can find all the code for this page in this zip file.

OK. So what if you want to do something exotic, like PWM?

 

Next Page