• AVR Freaks

Hot!12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x

Author
AlanMcR
New Member
  • Total Posts : 14
  • Reward points : 0
  • Joined: 2018/07/26 10:42:22
  • Location: 0
  • Status: offline
2019/09/09 10:55:35 (permalink)
0

12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x

This processor has a rather nice triple PWM block that can easily be synchronized to produce three phase output.  This is a very attractive feature for a project that I am working on that needs to produce a variety of phased outputs, often with varying phase lengths.  The one requirement is that the total of the three phases must be 100% of the phase period.
There is where the problem comes in.  If I set up the registers such that A+B+C=Period, there is still a single PWM tick of off time. If I shorten up the PWM period, then whichever phase is high when the period ends loses its initial low period.  See scope traces & simplified (actual) code.
 
Perhaps I'm setting it up wrong.  Advice appreciated.
 
Scope traces and code below:
 





#define _XTAL_FREQ 16000000 //Frequency 16MHz
#include
#pragma config FOSC = INTOSC // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN
#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
#pragma config LVP = OFF // High Voltage on MCLR/VPP must be used for programming. (frees RA3 for use as input)

#pragma config CP = ON // Code Protection bit (Program memory code protection is enable)
#pragma config BOREN = ON // Brown Out Detect (BOR enabled)

void main() {
    // Oscillator setup
    OSCCONbits.SCS1 = 1; // internal clock
    OSCCONbits.IRCF = 0b1111; // 16 MHz

    // Port setup
    LATA = 0;
    TRISA = 0b00111000; // RA0, RA1, RA2 as output
    ANSELA = 0b00000000; // all pins to digital.
    
    // Setup up the PWM machinery
    PWM3CLKCON = PWM2CLKCON = PWM1CLKCON = 0b01110000; // ~4KHz
    PWM3INTE = PWM2INTE = PWM1INTE = 0; // No Interrupts.
    PWM3OF = PWM2OF = PWM1OF = 0;
    
    // PWM setup for synchronized operation on all 3 PWM modules
    PWM3LDCON = PWM2LDCON = PWM1LDCON = 0;
    PWM3OFCON = PWM2OFCON = PWM1OFCON = 0; // independent, NO_match, match_incrementing
    PWM3CON = PWM2CON = PWM1CON = 0b01000000; // Module disabled, output enabled
    PWMEN = 0b111; // Enable all three modules at the same time to maintain sync

    unsigned short int periodA = 10;
    unsigned short int periodB = 10;
    unsigned short int periodC = 10;
    PWM3PR = PWM2PR = PWM1PR = periodA + periodB + periodC; // PWM Period
    
    // Settings for periodA
    PWM1PH = 0; // phase is always 0
    PWM1DC = PWM1PH + periodA;
    // Settings for periodB
    PWM2PH = PWM1DC; // phase starts just after A
    PWM2DC = PWM2PH + periodB;
    // Settings for periodC
    PWM3PH = PWM2DC; // phase start just after B
    PWM3DC = PWM3PH + periodC;
    // end of C should be the end of the PWM period
    while(1) {
        // Clear the watch dog timer
        CLRWDT();
    }
}

 
post edited by AlanMcR - 2019/09/09 10:58:18
#1

5 Replies Related Threads

    davekw7x
    Entropy++
    • Total Posts : 1828
    • Reward points : 0
    • Joined: 2012/01/16 12:01:07
    • Location: Second star on the right, straight on till morning
    • Status: offline
    Re: 12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x 2019/09/09 22:18:25 (permalink)
    +2 (2)
    Here's the thing:  To get a period of 30 you have to set the PR register to 29.  Look carefully at Equation 22-1 in the Data Sheet!
    This off-by-one error is very common, and is easy to overlook for lots of applications.
     
    Anyhow, with PR = 29 you might think that your Your 3-phase setup would be the following:
     
    • Offset for phase A is 0, DC is 10.
      That is, Phase A goes high at zero, low at 10.
      OK!  This works.
    • Offset for phase B is 10, DC is 20.
      That is, Phase B goes high at 10, low at 20.
      OK!  This works.
    • Offset for phase C is 20, DC is 30.
      Phase C goes high at 20, low at 30.
      Oops---this doesn't work!  Phase C goes high and stays high.

    So here's the problem with Phase C: When the PR register reaches 29, it rolls over to zero and never gets to 30, so Phase C remains stuck at 1

    Then, here's the trick:
    • Invert phase 3
    • Set phase equal to 0
    • Set DC equal to 20.

    So: It goes low at zero and high at 20 then back to zero at the end of the period (i.e. at what would have been 30).

    Badda-bing, Badda-boom!


    // All of your setup up to this point is unchanged

        unsigned short int periodA = 10;
        unsigned short int periodB = 10;
        unsigned short int periodC = 10;
        PWM3PR = PWM2PR = PWM1PR = periodA + periodB + periodC - 1; // PWM Period

        // Settings for periodA
        PWM1PH = 0; // phase is always 0
        PWM1DC = PWM1PH + periodA;

        // Settings for periodB
        PWM2PH = PWM1DC; // phase starts just after A
        PWM2DC = PWM2PH + periodB;

        // Settings for periodC
        // Invert phase 3 and set its inverted state to go high at the end of B
        PWM3CONbits.POL = 1;    
        PWM3PH = 0; // It goes low at zero
        PWM3DC = PWM2DC; // It goes high when B goes low
        // End of C will be the end of the PWM period, where it goes low again


    Tested on my PIC12F1572 on my Curiosity board.  (Same approach used by numerous projects over the years.)

    Regards,

    Dave


    post edited by davekw7x - 2019/09/09 22:28:43

    Sometimes I just can't help myself...
    #2
    AlanMcR
    New Member
    • Total Posts : 14
    • Reward points : 0
    • Joined: 2018/07/26 10:42:22
    • Location: 0
    • Status: offline
    Re: 12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x 2019/09/10 09:04:44 (permalink)
    0
    Dave,
    Thanks for the detailed reply.
     
    I also tried that as a solution, however this is just one of the waveforms I need to produce, and the others cannot use an inverted 3rd channel.  Flipping the channel generates glitches that the project can't tolerate.
     
    So, after pounding my head against the data sheet for a while longer, I accidentally ran across the correct incantations to get the offset mechanism to work. 
     
    This setup actually does what I wanted, which is to run the PWM registers as offsets of each other.  Phase A leading, then Phase B, then Phase C. 
     
        // Setup up the PWM machinery
        PWM3CLKCON = PWM2CLKCON = PWM1CLKCON = 0b01110000;  // ~4KHz
        PWM3INTE = PWM2INTE = PWM1INTE = 0;                 // No Interrupts.
        PWM3OF = PWM2OF = PWM1OF = 0;
        PWM3CON = PWM2CON = PWM1CON = 0b01000000; // Module disabled, output enabled
        PWM3PH = PWM2PH = PWM1PH = 0;             // phase is always 0

        // PWM setup for synchronized operation on all 3 PWM modules  
        PWM1LDCON = 0b10000000;     // Load armed, no trigger
        PWM2LDCON = 0b11000001;     // Load armed, trigger on PWM1
        PWM3LDCON = 0b11000010;     // Load armed, trigger on PWM2
        PWM1OFCON = 0; // independent, NO_match, match_incrementing
        PWM2OFCON = 0b01000001; // One-shot slave, matching PWM1
        PWM3OFCON = 0b01000010; // One-shot slave, matching PWM2
        PWMEN = 0b111; // Enable all three modules at the same time to maintain sync
        PWM3PR = PWM2PR = PWM1PR = PERIOD_LENGTH-1; // PWM Period


     
    Then when changing phase values:
     
        PWMEN = 0;  // Critical to disable and renable the PWMs (otherwise the output is undefined)
        PWM1OF = PWM1DC = PhaseA;
        PWM2OF = PWM2DC = PhaseB;
        PWM3DC =  PhaseC;
        PWMEN = 0b111; // Must be more than one instruction between disable and enable


    I had gone down this path before but not had success, the scope trace was a mess of random transitions.  I went back to one of those examples and noticed that the very glitchy scope trace would occasionally show the right waveform.  Disabling and re-enabling the PWM block cured that and the waveform is clean.  None of that is documented in the data sheet, of course.  Also, you can't disable, and re-enable the PWM block in successive instructions.  Doesn't work.
    #3
    AlanMcR
    New Member
    • Total Posts : 14
    • Reward points : 0
    • Joined: 2018/07/26 10:42:22
    • Location: 0
    • Status: offline
    Re: 12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x 2019/09/10 15:18:32 (permalink)
    0
    Follow up:
    The waveforms are perfect ... BUT ...
    I need to change them relatively rapidly.  Sometimes after only a few 100 complete PWM cycles. When I do change them there is a statistical chance that the transition is really poorly done.  Every time that I have caught it on the scope it appears that the offset trigger missed and thus B & C never happen.  This is true even if I load the registers with the values that they had last time.  Truly strange. 
     
    Addendum: Just for fun I turned off interrupts during the PWM change code, no difference.
     
    post edited by AlanMcR - 2019/09/10 15:51:29
    #4
    ric
    Super Member
    • Total Posts : 25117
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: 12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x 2019/09/10 15:25:37 (permalink)
    0
    Are you making any attempt to synchronise your loading with the base timer?
     

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #5
    AlanMcR
    New Member
    • Total Posts : 14
    • Reward points : 0
    • Joined: 2018/07/26 10:42:22
    • Location: 0
    • Status: offline
    Re: 12F1572 Unable to achieve 100% PWM and still use phase delay feature 12F1571 12F157x 2019/09/10 15:35:37 (permalink)
    0
    No.  I did try disabling the PWM, resetting the timer, then re-enabling the PWM.  No change in behavior.    It seems very glitchy, as though it only happens at the beginning (or more likely the end) of the PWM cycle.  I don't have another output to trigger the scope, so very frustrating.
    #6
    Jump to:
    © 2020 APG vNext Commercial Version 4.5