2020/11/06 17:41:29
I need a 4MHz clock output on a PIC18F66K80 design I'm doing, and I'd like to get it from the PIC18F instead of setting up separate clock hardware. The PIC18F is already running from a 16MHz clock with its PLL enabled, so Fosc/4 internally is running at 16MHz and all I need to do is divide by 4 and emit the result.
Dividing down the clock and emitting it from a pin is a very common thing to do, and the CCP modules seem perfect for this. I've used them for dozens of other things and they've always impressed me with their flexibility. But I've never tried to generate a downsampled clock with them before, and I'm starting to believe it's not possible.
The (E)CCPx pin can be an output in Compare mode. However, it appears that one, and only one, Compare mode clears the associated Timer and this gives you a programmable period: Special Event Trigger (SET) mode. And it does not appear that SET mode controls the output pin.
I first tried this on a couple of standard CCP modules, without success. I also tried it on the ECCP1 module in case its "enhanced" operation supported this - no luck.
The very clear block diagrams in the spec sheet VERY STRONGLY suggest that the CCP modules can control their output pins in any Compare mode. However, it's looking like the only Compare modes that actually control the output pin are 0x02 (toggle output on match), 0x08 (init low, go high on match), and 0x09 (init high, go low on match). Testing reveals:
* Compare mode 0x02 (toggle on match) generates a 50% duty cycle output but always at TimerClock/64K regardless of the value written into the CCP's Period register. I suspect this is because this mode does not clear the associated Timer, so the Timer just free-runs and a match occurs once per overflow.
* Compare modes 0x08 and 0x09 (init one way, go the other on match) do indeed init properly, and then they flip the pin one time where it stays forever. I suspect what's happening is the Timer upcounts to the Period value, a match occurs so the pin is flipped, but then the pin just stays there because the Timer and pin aren't cleared to yield repeating action.
So what is needed is a Compare mode which both controls the pin (which 0x02, 0x08, and 0x09 do) and clears the Timer (which 0x0B SET mode does). Unfortunately, testing shows that 0x0B SET mode does not control the pin (though the block diagrams do not indicate this) and the other three Compare modes do not clear the Timer.
Is there some magic trick I'm missing here? Dividing down the clock and emitting it from a pin is a very common thing to do so you can share a single crystal-based clock in the system. It's hard to believe the otherwise super-flexible CCP's cannot do this.
2020/11/06 18:00:51
Maybe you could use Reference Oscillator output to RC3?
See REFOCON register in the datasheet
If you need RC3 for other peripherals, such as I2C, then it should be possible to use PWM mode to get 4MHz output. I have achieved 4MHz on RD4 from 16 MHz crystal x4PLL using mikroC compiler and library, so presumably same can be done with microchip compiler... 
2020/11/06 18:37:38
Ahh... thank you! I completely missed that feature despite reading the oscillator section multiple times.
Looks like I can base REFOCON off the system clock of 16MHz, then divide it by 4 to get 4MHz. Excellent!
I will prototype that immediately and confirm that it works. Thanks again, multiple pairs of eyes are definitely helpful!
EDIT: Works PERFECTLY! I just knew there had to be a way to get a divided-down clock out of an MCU but despite lots of searching the 598 page spec sheet managed to elude me. {grin} Thank you so much!
2020/11/06 19:01:23
Hmm... I just read your edit and yes, I will need SPI on this device which consumes that pin for SCK. Drat. I was really appreciating the simplicity of your solution.
I did ponder trying a PWM mode to get a constant 4MHz clock but didn't dig into it yet. If by "RD4" you mean Port D bit 4, this is the 28QFN package and it doesn't expose Port D. But ECCP1 P1A is exposed on pin 22 (ECCP1's normal I/O pin), so presumably I should be able to get one phase of PWM there if you could. Same 16MHz crystal + x4 PLL so the numbers match. I haven't checked but I wonder if ECCP1 is configured in PWM mode, does it force you to commit all four pins (phases) even if you only need one? Obviously you could override to an input via TRIS but it may not be possible to use those pins as digital outputs for any other purpose.
It may be possible to get 4MHz out of a "standard" CCP module in PWM mode, too, in which case only a single pin would be committed. PWM mode specifically discusses clearing the associated Timer, so basically this would bring me full circle back to what I was trying to do in the first place: Use a CCP module to divide down the system clock. I'll play with that and report back.
Drat, drat, drat... that REFOCON solution was just so clean.
2020/11/06 19:15:13
So you are using PIC18F25K80 or PIC18F26K80 (or LF) - not PIC18F66K80.
Don't have either of those PICs, so I cannot verify that PWM works at 4MHz on 28-pin device, but presumably it does. Single output should be achievable I would think, but I don't know how to do it with XC8. 
2020/11/06 19:46:04
Yes, sorry, I was describing the family and not the specific part. This is a PIC18F26K80. 5V, not LF.
I'm playing with PWM mode right now and cannot get it to emit a signal. Have tried all combinations of CCP2, CCP3, Timer2, and Timer4 without success. Setting longish period and shortish duty cycle just to get things working on the scope, figuring "get it running and then dial in the values we actually want", but so far no luck. The pin sits cleared, which suggests (according to the spec sheet) the Timer is never equal to its PR register. Still playing around.
2020/11/06 20:01:03
Here's the code I'm using:

    TRISCbits.TRISC6 = 0;        // configure CCP3/pin 14 as digital output

    CCPTMRSbits.C3TSEL = 1;      // associate CCP3 with T2/4 (and PWM mode forces T4)
    PR4 = 0xF0;                  // PWM period (longish)
    CCPR3L = 0x01;               // PWM duty cycle (shortish)
    PIE4bits.CCP3IE = 0;         // disable interrupts from CCP3
    T4CON = 0b00000100;          // 1:1 postscaler, Timer4 enabled, 1:1 prescaler
    CCP3CON = 0x0C;              // enable CCP3 in PWM mode, clear duty cycle LSB's

I've confirmed that if I manually strobe RC6 (same pin as CCP3, pin 14) I get a pulse train, so nothing weird with the hardware. But with the code above, nothing happens.
2020/11/06 20:01:35
Please post the code you tried it with.
It's always better to see what you have done, rather than a description of what you think you've done... ;)
2020/11/06 20:23:38
ricPlease post the code you tried it with.

Our messages crossed... see above.
2020/11/06 23:27:10
Got it!
The error was a swapped nybble in CCP3CON. I've fixed the code above. Then I tuned the values to get a 4MHz 50% duty cycle clock out. Here's the final code:

     TRISCbits.TRISC6 = 0;        // configure CCP3/pin 14 as digital output

    CCPTMRSbits.C3TSEL = 1;       // associate CCP3 with T2/4 (and PWM mode forces T4)
    PR4 = 0x03;                   // PWM period (divide (Fosc/4) by 4, yielding 4MHz)
    CCPR3L = 0x02;                // PWM duty cycle (half of PR4's value, yielding 50%)
    PIE4bits.CCP3IE = 0;          // disable interrupts from CCP3
    T4CON = 0b00000100;           // 1:1 postscaler, enabled, 1:1 prescaler
    CCP3CON = 0x0C;               // enable in PWM mode

Thanks for the feedback, it got me there!
© 2021 APG vNext Commercial Version 4.5

Use My Existing Forum Account