• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Pic24E PWM using timer

drkidd22

Member
I'm trying to get a 24kHz pwm signal from a PIC24EP256GP204 using timer5 as the clock source. The output is to be on pin 8 (RB10/RP42), but I have not been successful. I've configured the PPS and set the port pin as output and no luck.

Code:
int main(void)
{
    // Fcy = 60MHz (Instruction Clock)
    // Fosc = 120MHz System Clock
    // Configure Oscillator to operate the device at 60MhHz (Fcy) from Internal FRC
    // Fosc= Fin*[M/(N1*N2)], Fcy=Fp=Fosc/2
    // Fosc= 7.37*[65/(2*2)]~=119.7625Mhz for FRC(7.37MHz) input clock
    // Configure PLL prescaler, PLL postscaler, PLL divisor
   
    PLLFBD = 63;                // M=65
    CLKDIVbits.PLLPOST = 0;     // N2=2
    CLKDIVbits.PLLPRE = 0;      // N1=2
   
    RCONbits.SWDTEN=0;            /* Disable Watch Dog Timer*/
   
    // Initiate Clock Switch to FRC oscillator with PLL (NOSC=0b001)
    __builtin_write_OSCCONH(0x01);
    __builtin_write_OSCCONL(OSCCON | 0x01);
    // Wait for Clock switch to occur
    while (OSCCONbits.COSC!= 0b001);
    // Wait for PLL to lock
    while (OSCCONbits.LOCK!= 1);
   
   
    TRISBbits.TRISB10 = 0x00;       //Set RB10 as output for OC1/PWM
   
    __builtin_write_OSCCONL(OSCCON & 0xbf);     //Unlock PPS Registers    
      RPOR4bits.RP42R = 0x10;                   //Assign OC1 to Pin RP42R //RB10->OC1:PWM
    __builtin_write_OSCCONL(OSCCON | 0x40);     //Lock PPS Registers

//Timer5 Configuration
   T5CONbits.TON = 0;          //Stops 16-bit Timer
    T5CONbits.TSIDL = 0;        //Discontinues module operation when device enters Idle mode
    T5CONbits.TGATE = 0;        //Disable gated timer
    T5CONbits.TCKPS = 0b011;    //Select 1:8 Prescaler
    T5CONbits.TCS = 0;          //Select Internal clock (FP)
    TMR5 = 0x00;                //Clear timer5 register
    PR5 = 0;                    //Set initial period to 0
    
    T5CONbits.TON = 1;          //Enable timer5
   
  //Set OC1
  OC1RS = 312;                  //Duty Cycle
  OC1R = 156;
  OC1CON1bits.OCTSEL = 3;       //Clock source select [0-7]. 3 = TMR5
  OC1CON1bits.TRIGMODE = 1;     //TRIGSTAT is cleared when OCxRS = OCxTMR or in software
  OC1CON1bits.OCM = 7;          //Center-Aligned PWM mode
  OC1CON2bits.OCTRIG = 1;       //Triggers OCx from source designated by SYNCSELx bits
  OC1CON2bits.SYNCSEL = 15;     //Trigger/Synchronization Source Selection bits [0-31]. 15 = TMR5
  OC1CON2bits.OCTRIS = 0;       //Output compare module drives the OCx pin

    while (1)                   // Run Forever...
    {

    }

    return 0;
}
 

mpgMike

New Member
Get rid of "PR5 = 0;"
OC1RS is your PERIOD, not Duty Cycle. OC1R is your Duty Cycle. In context, it appears you're using them that way.
Though for a different processor, here is what I used for PPS:
Code:
    __builtin_write_OSCCONL(OSCCON & ~(1<<6));
    RPOR4       =   0x1000;         //OC1 = HV_Gen, RP80
    __builtin_write_OSCCONL(OSCCON | (1<<6));
Individual pins may have other functions like SOSC, JTAG, etc that is dealt with in the CONFIG Registers. You didn't list your CONFIGs. Check that also.

I don't see where you are configuring RB10 as Digital (ANSEL). Maybe that's hanging you up. It is typical for pins to default to Analog on start-up.

Hope this helps.
 

drkidd22

Member
Ok I got it going with below code, but I'm still having difficult time understanding how to set OC1RS and OC1R.
I can set any PWM frequency and duty cycle I want out of the output compare as long as I leave OC1R = 1 and just adjust the duty cycle based on the OC1RS/PR5 ratio. I'm I missing something here?

Code:
void pwm_InitOC1(void) //Uses TMR5
{
  OC1CON1 = 0;
  OC1CON2 = 0;
 
  OC1CON1bits.OCTSEL = 3; //Clock source select [0-7]. 3 = TMR5
 
  OC1R = 1; //Determines the period
  OC1RS = 5; //Determines the duty cycle
 
  OC1CON1bits.TRIGMODE = 1; //TRIGSTAT is cleared when OCxRS = OCxTMR or in software
  OC1CON1bits.OCM = 7; //Center-Aligned PWM mode
  OC1CON2bits.OCTRIG = 1; //Triggers OCx from source designated by SYNCSELx bits
  OC1CON2bits.SYNCSEL = 15; //Trigger/Synchronization Source Selection bits [0-31]. 15 = TMR5
  OC1CON2bits.OCTRIS = 0; //Output compare module drives the OCx pin
}

void timer5init (void)
{
    T5CONbits.TON = 0; //Stops 16-bit Timer
    
    T5CONbits.TCS = 0; //Select Internal clock (FP)
    T5CONbits.TCKPS = 0b11; //Select 1:256 Prescaler
    T5CONbits.TGATE = 0; //Disable gated timer
    T5CONbits.TSIDL = 0; //Discontinues module operation when device enters Idle mode
    
    TMR5 = 0x00; //Clear timer 5 register
    PR5 = 10; //Set period of timer
    
    IPC7bits.T5IP = 0x01; //Set Timer 5 Interrupt Priority Level
    IFS1bits.T5IF = 0; //Clear Timer 5 Interrupt Flag
    IEC1bits.T5IE = 1; //Enable Timer 5 interrupt
    
    T5CONbits.TON = 1; //Enable timer 5
}
 

mpgMike

New Member
What you are doing is quite different from what I got working. I'm not a dsPIC expert. In fact, I just started playing with them a couple months ago. I experimented like you are. With my qualifications out in the open...

You are using Center Align Mode. One of the effects of that is your PWM Freq is 1/2 what it would be in Edge Aligned Mode. The way I'm using it, the Timer (5 in this case) is just a drum beat, something for the OC to dance to. Using the PR5 shouldn't serve any purpose.

Your PERIOD is the length of OC1RS measured in Timer 5 counts. When OC1TMR = OC1RS, a new Period is started. Within that Period, when OC1TMR = OC1R, the output is toggled. The ratio of OC1R : OC1RS gives your Duty Cycle%.
Code:
OC1CON2bits.SYNCSEL = 0x1F;  //This selects the Synchronization source as itself
An invaluable resource is the Output Compare FRM.

 

drkidd22

Member
Thank you so much. I was taking PR5 into account and that's where my mistake was and I was getting confused. I was thinking that the PERIOD from PR5 after prescaling was what was being fed into OCxTMR, but it's actually being fed whatever the timer is set for after prescaling, not after PR5.
 

Latest threads

EE World Online Articles

Loading

 
Top