PWM output appears to falter at 100%

Discussion in 'Embedded Systems and Microcontrollers' started by urb-nurd, Feb 15, 2015.

  1. urb-nurd

    Thread Starter Member

    Jul 9, 2014
    269
    3
    Hey guys, i am having an issue with my pwm output.
    It appears that when the duty should be at 255, it is more like 254 or 253.
    This can be seen on the gate drive waveform of my MOSFET that i am controlling via the PWM output of my Ready for Pic board.
    [​IMG]


    When i change the input for my opto-coupler from the Pwm output to VCC i get a solid dc level at my gate.
    From this test, i assume the problem is with the code or micro-controller rather than the circuit.

    Code (Text):
    1. //LCD module connections
    2. sbit LCD_RS at LATD4_bit;
    3. sbit LCD_EN at LATD5_bit;
    4. sbit LCD_D4 at LATD0_bit;
    5. sbit LCD_D5 at LATD1_bit;
    6. sbit LCD_D6 at LATD2_bit;
    7. sbit LCD_D7 at LATD3_bit;
    8.  
    9. sbit LCD_RS_Direction at TRISD4_bit;
    10. sbit LCD_EN_Direction at TRISD5_bit;
    11. sbit LCD_D4_Direction at TRISD0_bit;
    12. sbit LCD_D5_Direction at TRISD1_bit;
    13. sbit LCD_D6_Direction at TRISD2_bit;
    14. sbit LCD_D7_Direction at TRISD3_bit;
    15. // End Lcd module connections
    16. unsigned short current_duty, new_duty, duty_cycle;
    17. unsigned int  oldstate, oldstate2, adc_rd;
    18. double adc, adc1;
    19. char txt1[4];
    20. char txt2[] = "Duty =";
    21. char txt4[] = "Temp =";
    22. char txt3[14];
    23. void InitMain() {
    24.    ANSELA.B0  = 1;  // configure port a pin 0 as analogue (disable digital buffer)
    25.    PortA = 255;
    26.    TRISA = 255;                      // Configure AN pins
    27.   ANSELB = 0;
    28.   ANSELC = 0;
    29.   ANSELD = 0;
    30.   PORTB = 255;            // Set RB0 pin as input
    31.   TRISB = 255;            // Set RB1 pin as input
    32.   C1ON_bit = 0;               // Disable comparators
    33.   C2ON_bit = 0;               // (for pwm function)
    34.   PORTD = 0;
    35.   TRISD = 0;
    36.   PORTC  = 0;                          // set PORTC to 0
    37.   TRISC = 0;                          // designate PORTC pins as output
    38.  
    39. PWM1_Init(25000);                    // Initialize PWM1 module at 5KHz
    40. }
    41. void LCD(){
    42.     Lcd_Init();                        // Initialize Lcd
    43.     Lcd_Cmd(_LCD_CLEAR);               // Clear display
    44.     Lcd_Cmd(_LCD_CURSOR_OFF);          // Cursor off
    45.     }
    46.  
    47.  
    48.  
    49. void main() {
    50.   InitMain();
    51.   LCD();
    52. current_duty  = 0;                 // initial value for new_duty
    53.   duty_cycle = 0;
    54.  PWM1_Start();                       // start PWM1
    55.  PWM1_Set_Duty(current_duty);        // Set current duty for PWM1*
    56.  
    57.  
    58.   do {
    59.       adc_rd = ADC_Read(1);
    60.       adc = (adc_rd);
    61.       adc1 = ((((adc)/1024)*3.3)-1.25)/0.005;
    62.  
    63.  
    64.       BYTEToStr(current_duty, txt1);
    65.      // wordtostr(adc_rd, txt3);
    66.        floattostr(adc1,txt3);
    67.  
    68.       Lcd_Out(1,7,txt1);                 // Write text in first row
    69.       Lcd_Out(1,1,txt2);
    70.       Lcd_Out(2,7,ltrim(txt3));                  // Write text in second row
    71.       Lcd_Out(2,1,txt4);
    72.  
    73.     if (Button(&PORTB, 0, 100, 1)) { // detect logical one to logical zero transition
    74.       current_duty++;          // Incremenet Duty
    75.      PWM1_Set_Duty(current_duty);        // Set new duty for PWM1
    76.       Delay_ms(3);
    77.     }
    78.     if (Button(&PORTB, 1, 100, 1)) { // detect logical one to logical zero transition
    79.       current_duty--;                          // set current duty
    80.       PWM1_Set_Duty(current_duty);        // Set new duty for PWM1
    81.       Delay_ms(3);
    82.     }
    83.   } while(1);
    84. }
    Any help is greatly appreciated!
    Thanks
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,395
    1,607
    Lots of code. LOTS! Way to much.

    Just give your PWM a fixed number of 255 and see what happens.

    I'm not a big fan of MikroC as it hides too much stuff (like what chip you are using and what libraries have been selected) so I don't know who good the PWM1_Set_Duty() function works. Later day PICs use a 10 bit period to set 8 bits here and 2 bits there; I would expect MikroC to get this correct but may be a glitch.

    I'd also turn on the debugger to see if the proper period bits make it to the register(s).
     
  3. JohnInTX

    Moderator

    Jun 26, 2012
    2,348
    1,029
    Its hard to tell from the scope pic what the freq/duty is but some observations:
    PWM1_Init parameter is 25000Hz but the comment says 5000Hz - which is it.
    You are running the PWM output through an opto? A schematic would be nice but if the collector of the opto out is what you are measuring, it looks like you need more pullup resistor (slow rise time). Need a schematic to be sure.
    I echo ErnieM's comments about MikroC. Which PIC are you running, what's the oscillator?

    If you are splitting hairs between 253-254 is your scope setup accurate enough? I would have a hard time with the trace shown.

    Me too. Set a breakpoint after changing current_duty, inspect the register value then work backwards using the PIC datasheet to confirm that the PICs raw period and duty registers are correctly set. Its not unlikely that some rounding error skins an LSB off here and there. You can also inspect the listing file to see how the library uses the hardware PWM and check its numbers.

    Good luck.
     
  4. GopherT

    AAC Fanatic!

    Nov 23, 2012
    6,073
    3,856
    If you are resetting your PWM frequency or duty cycle at the end of each Pwm interval, there may be a glitch as it resets. Also, check the datasheet. It may always go back to ground after each roll-over of the Pwm clock.

    Try a short segment of code where you turn on 255 duty cycle only.
     
Loading...