I've got a project where I'm using a PIC 16f877 to make calculations based on user settings and realtime data and come up with 8*8bit numbers which represent the desired duty cycles (percentage of 256) for 8 PWM outputs. The PWM has to be fairly high frequency, so doing it in software is out, and the pic only has 2 dedicated PWM outputs. I've decided to use a CPLD to do my PWM for me, and transfer the numbers into it from the PIC. My only problem is the best way to transfer the data to the CPLD without using too many pins on the PIC (I'm strapped as it is). Serial transfer is obviously a good idea then, but I don't want to use a whole lot of clock cycles transferring the data across one bit at a time. A compromise that's occurred to me is that I do it one nibble at a time, and use one or two more pins for control. example pseudocode is as follows:
The CPLD will count rising edges on portA(3) and use the counter to address 16*4bit registers, which will be parallel loaded from portA(7:4). Is this sufficient to transfer the data? Possible problems I see with it are that if the CPLD misses a nibble for whatever reason, it will permanently be off by one register, completely stuffing the pwm output. Also, the CPLD might miss the pulse on the control pin without a delay, but the CPLD will be running at a much higher clock frequency than the PIC, so this should be fine.Another possible problem is that the the comparator will be confused if we try to load data while the clock counter is close to the stored value for each channel. I've checked this one out though, and it could only mean that the pwm remains high for one clock cycle more than it should, or drop low for one cycle when it shouldn't - not a problem in this application, as the pwm output will be filtered. The synchronisation does concern me though. I could dedicate another pin to control, but I'd prefer not to. Perhaps I could give it a "start" pattern - eg, if the cpld gets a sustained low followed by a sustained high on portA(3) it knows to clear the address register and start from the first one again. For this to work though I'd need to have the timings worked out between the two devices. I could dedicate another pin to it, but I'd prefer not to. Can anyone see a better way?
Code:
for i=0 to 7
load duty_cycle[i] into w
copy w(7:4) to portA(7:4)
set portA(3)=1
set portA(3)=0
copy w(3:0) to portA
set portA(3)=1
set portA(3)=0
next i