| PICPLD Output | ||
| Related Links PICPLD |
![]() 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 codeUsing 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?
|