PWM on pic10f322

Discussion in 'Embedded Systems and Microcontrollers' started by Setanta, Mar 1, 2014.

  1. Setanta

    Thread Starter New Member

    Mar 12, 2012
    17
    4
    Hi Guys

    I'm trying to enable PWM on the pic10f322.I've gotten it up and running but I'm having trouble setting the duty cycle.

    It's outputting at 38khz as it should but the duty cycle is stuck at 90%. In fact no matter what I put in PWM2DCH and PWM2DCL, even if i zero those out, it's still 90% so i assume I've made a screwed on the initialization.

    It's a basic setup, this is what I have:



    Code ( (Unknown Language)):
    1. #include    <htc.h>
    2.  
    3.  
    4. #define _XTAL_FREQ 8000000
    5.  
    6. //__CONFIG (FOSC_INTOSC & BOREN_OFF &  WDTE_OFF & PWRTE_OFF & MCLRE_OFF & CP_OFF & LVP_OFF & LPBOR_OFF & BORV_HI & WRT_OFF);
    7.  
    8. #pragma config FOSC = INTOSC    // Oscillator Selection bits (INTOSC oscillator: CLKIN function disabled)
    9. #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    10. #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    11. #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
    12. #pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
    13. #pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
    14. #pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)
    15. #pragma config LPBOR = OFF      // Brown-out Reset Selection bits (BOR disabled)
    16. #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    17. #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    18.  
    19.  
    20.  
    21.  
    22. void InitPWM();
    23.  
    24.  
    25.  
    26. void main()
    27. {
    28.  
    29.     PORTA = 0b00000000;
    30.     TRISA = 0b00000111;
    31.     ANSELA = 0b00000000;
    32.  
    33.      InitPWM();
    34.  
    35.  
    36.  
    37.       while(1)
    38.       {
    39.    
    40.       }
    41.      
    42.  }
    43.  
    44.  
    45.  
    46. void InitPWM()
    47. {
    48.  
    49.    
    50.     PWM2CON = 0b00000000;   // Clear PWM1CON
    51.     PR2   = 0b00110100;     // Set period to  52
    52.  
    53.  
    54.  
    55.     PWM2CON = 0b11000000;   //Enable PWM Module Enable and Module Output Enable bit
    56.  
    57.     PWM2DCH = 0b00000000;   // Clear duty cycle registers
    58.     PWM2DCL = 0b00000000;
    59.  
    60.  
    61.     TMR2IF = 0;             //Clear the timer 2 interrupt flag
    62.     T2CON = 0b00000000;     //Set prescaler to 1 (T2CKPS<1:0>), enable to off(TMR2ON)
    63.                             //and postscaler to 1:1(TOUTPS 3:0)
    64.  
    65.    TMR2ON = 1;              //Now enable timer 2
    66.  
    67.  
    68.     TRISA = 0b00000000;     //Enable the pwm pin output driver on RA1 (and also make all other pins outpouts.)
    69.  
    70.  
    71.  
    72. //Set duty cycle to 50%
    73.  
    74.     PWM2DCH = 0b11010000 ;
    75.     PWM2DCL = 0b10000000;
    76.    
    77.  
    78.     return;
    79.  }
    80.  
    81.  
    82.  }

    It's probably something simple, but I've been staring at this for a couple of hours and I'm starting to go cross eyed. Anyone point out what I'm doing wrong?
     
  2. tracecom

    AAC Fanatic!

    Apr 16, 2010
    3,869
    1,393
    I can't give you specific help, but I would look at all the registers on page 112 of the datasheet that are associated with PWM.
     
  3. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,388
    1,605
    Oops... seems you've tried this already. Dang Never mind (left it here anyway)

    Well since you linked to the data sheet I just had to help <s>

    You set the duty cycle to 110100001 = 0x1A1 = 417, which is about 82% of 511 (max duty cycle setting)

    Try making the duty just 511/2 = 255 = 0xFF or

    Code ( (Unknown Language)):
    1.  
    2.     PWM2DCH = 0b01111111;
    3.     PWM2DCL = 0b10000000;
    4.  
     
    Last edited: Mar 1, 2014
  4. Setanta

    Thread Starter New Member

    Mar 12, 2012
    17
    4
    Thanks for the input. Yeah 417 was just the last value I happened to have in there, but the output is 90% regardless of the value.
     
  5. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    I think its this.

    At 8MHz, Tosc is 125ns, Tcyc=4*Tosc=500ns.
    With PR2=52decimal, prescaler=1, the PWM period is Tcyc(PR2+1) = 500ns*53 = 26.5us.
    For 50% duty cycle, the duty cycle registers must count off 26.5us/2=13.25us.
    PulseWidth = PWMxDCH/L (10bits) * Tosc * 1(prescaler) giving
    13.25us/125ns=PWMxDCH/L = 106decimal = 0001101010 to 10 bits. Splitting this gives
    PWMxDCH = 00011010 and PWMxDCL = 10xxxxxx. So:
    PWMxDCH = 1ah
    PWMxDCL = 80h

    Checking:
    Duty Cycle Ratio = PWMxDCHL / 4(PR2+1) = 104/212 = .4905 ~=50%

    You might want to play around with PR2 to get it it exact.

    Hope this works for you, I just got my 10F322 stuff yesterday and need the pwm too.
    EDIT: Rechecked it on the spreadsheet and the numbers match other midrange PWMs. Should be good to go.
    EDIT2: It also says you are getting only 7.73 bits of resolution due to the small PR2 value.

    EDIT3: PWM2 goes to RA1 but you have it TRIS'd to an input. Also, review the port setup to make sure you don't have the pin assigned to any of the several other functions that it can have (CLC, CWG1B etc.). Especially ensure that the complementary waveform generator is disabled. It has a higher pin priority than the PWM. Since its a weird problem and this is a new chip, I would look at the disassembled compiler output to ensure that it is properly setting the banks etc.
     
    Last edited: Mar 1, 2014
  6. Setanta

    Thread Starter New Member

    Mar 12, 2012
    17
    4
    Well, got it working.

    John, your math looked similar to what I had initially calculated but to be sure I ran through the setup again with your numbers but it made no difference, nor did explicitly disabling the other functions on the pins.

    In the end I just threw away the program and started again and did it line by line checking everything as i went - and it worked. I guess I must have had a bit transposed somewhere despite all my checking.

    When I finish banging my head off my desk I'll continue with the program!


    Thanks for the help guys.
     
  7. Setanta

    Thread Starter New Member

    Mar 12, 2012
    17
    4
    Oh and just in case anyone is looking for a working example in the future:

    Code ( (Unknown Language)):
    1. /*  38khz pwm on RA1 with 50% duty cycle.
    2.    
    3.    Timer 2 is is 52 decimal
    4.    Prescaler is 1
    5.    Duty cycle value is 106 decimal                 */
    6.  
    7. #include    <htc.h>
    8.  
    9.  
    10. #define _XTAL_FREQ 8000000
    11.  
    12. //__CONFIG (FOSC_INTOSC & BOREN_OFF &  WDTE_OFF & PWRTE_OFF & MCLRE_OFF & CP_OFF & LVP_OFF & LPBOR_OFF & BORV_HI & WRT_OFF);
    13.  
    14. #pragma config FOSC = INTOSC    // Oscillator Selection bits (INTOSC oscillator: CLKIN function disabled)
    15. #pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
    16. #pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
    17. #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
    18. #pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD)
    19. #pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
    20. #pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)
    21. #pragma config LPBOR = OFF      // Brown-out Reset Selection bits (BOR disabled)
    22. #pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
    23. #pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
    24.  
    25.  
    26.  
    27.  
    28. void InitPWM();
    29.  
    30.  
    31. void main()
    32. {
    33.  
    34.     PORTA = 0b00000000;
    35.     TRISA = 0b00000000;
    36.     ANSELA = 0b00000000;
    37.     CLC1CON = 0b00000000;
    38.     CWG1CON0 = 0b00000000;
    39.  
    40.    
    41.      InitPWM();
    42.  
    43.       while(1)
    44.       {
    45.    
    46.       }
    47.      
    48.  }
    49.  
    50.  
    51.  
    52. void InitPWM()
    53. {
    54.  
    55.     PWM2CON = 0b00000000;   // Clear PWM1CON
    56.     PR2   = 0b00110100;     // Configure the Timer2 period - decimal 52
    57.  
    58.  
    59.  
    60.     PWM2CON = 0b11000000;   //Enable PWM Module, Module Output
    61.  
    62.     PWM2DCH = 0b00000000;   // Clear duty cycle registers
    63.     PWM2DCL = 0b00000000;
    64.  
    65.  
    66.     TMR2IF = 0;             //Clear the timer 2 interrupt flag
    67.     T2CON = 0b00000000;     //Set prescaler to 1
    68.                            
    69.     TMR2ON = 1;             //Enable timer 2
    70.  
    71.  
    72.     TRISA=0b00000000; =     //Enable the pwm pin output
    73.  
    74.  
    75.     //Set duty cycle to 106
    76.     PWM2DCH = 0b00011010;
    77.     PWM2DCL = 0b10000000;
    78.  
    79.    
    80.  
    81.     return;
    82.  }
    83.  
    84.  
     
  8. JohnInTX

    Moderator

    Jun 26, 2012
    2,347
    1,029
    Not sure whether its transposed bits or not but the resulting math wasn't right in the original code. Glad we agree on the new figures.

    To dispel any mysteries, in the second code I do see that there are important differences compared to the original. Notably, TRISA is set for outputs. Sometimes, enabling a peripheral configures the pin direction but other times it doesn't - depends on the peripheral, the PIC and the documentation (which can be confusing and on occasion incorrect). While some may argue the point, I always set the directions to match the peripherals. The bonus is that if you ever have to disable/re-enable the peripheral (sometimes necessary to recover from errors) you don't lose control of the pin.

    You've also explicitly disabled the other functions that share the pin rather than rely on the power-up defaults. A few times on these boards, such fixes have resolved problems similar to yours. I personally think it's always a good idea and always do it in my own code. Explicitly initializing all things is also necessary if you need to be able to do a warm restart.

    Glad you got it working. If you get a chance, it might be instructive to revert to the original code step by step to see what the root of the problem was. I'd be interested in knowing what you find.

    Have fun!
     
Loading...