1
\$\begingroup\$

I am using: Curiosity LPC dev kit, PIC16F15325, MPLABX v5.35 on Mac, XC8 compiler. I am able to blink each LED on the Curiosity.

My goal is to generate a PWM signal on RC5 to drive an LED on the Curiosity board. I want to be able to vary the pulse width to adjust the brightness.

I originally was using the LFINTOSC at 31kHz, but I saw another post that said that you can't run the CCP module when TMR2 is using the LFINTOSC because it's too slow. I am happy to have the PWM at a frequency of <500Hz, so if it's possible to use the LFINTOSC, please let me know. For now I'm using the HFINTOSC at 1MHz.

I also noticed that the steps in the datasheet for configuring the PWM of the CCP module are slightly differently ordered from the steps for configuring the dedicated PWM module. Maybe this discrepancy is part of my issue.

For now I am just trying to enable the PWM in main and then loop on a blinking LED so that I know the MCU hasn't gotten stuck.

Nothing happens to the LED on RC5 when I run this code.

My code is as follows:

void main(void) {
 
 ANSC4 = 0; //disable for analog input
 TRISC4 = 1; //configure PORTC4 for digital input
 
 TRISA = 0x00; //configure all PORTA to digital output
 TRISC5 = 0; //configure PORTC5 to digital output
 ANSA5 = 0; //disable analog inputs for LED pins
 ANSA1 = 0;
 ANSA2 = 0;
 ANSC5 = 0;
 
 LATA = 0x00; //Set all output low
 LATC = 0x00;
 
 IOCAP = 0x00; //Disable interrupts on PORTA
 IOCAN = 0x00;
 IOCAF = 0x00; //Clear PORTA interrupt flags
 
 IOCCP = 0b00000000;
 IOCCN = 0b00010000; //Set PORTC4 to interrupt on negative edge
 IOCCF = 0x00; //Clear PORTC interrupt flags
 
 GIE = 1; //Enable global interrupts
 IOCIE = 1; //Enable interrupts on change
 
 int duty_cycle_reg = 0b0000001100;
 enable_pwm_ccp(duty_cycle_reg);
 
 while(1){ 
 LATA5 = 1;
 delay_ms(100);
 LATA5 = 0;
 delay_ms(100);
 }
}

Enable_PWM_CCP definition:

void enable_pwm_ccp(int duty_cycle_reg){
 
 int lsb = 0b0000000011;
 int msb = 0b1111111100;
 
 lsb &= duty_cycle_reg;
 msb &= duty_cycle_reg;
 
 lsb = lsb << 6;
 msb = msb >> 2;
 
 RC5PPS = 0x09; //set CCP1 output to RC5 via PPS
 TRISC5 = 1; //disable output
 CCP1CONbits.MODE = 0xF; //set CCP1 to PWM mode
 CCP1CONbits.FMT = 1; //set CCP1 format left-aligned
 CCPR1H = msb; //set duty cycle
 CCPR1L = lsb;
 
 PIR4bits.TMR2IF = 0; //clear TMR2IF flag
 T2CONbits.CKPS = 0b111; //set TMR2 prescale to 128
 T2CONbits.OUTPS = 0b000; //set TMR2 postscaler to 1
 T2CLKCON = 0x02;
 PR2 = 0x26; //set PR2 to make PWM freq = 50Hz
 T2CONbits.ON = 1; //enable TMR2
 
 while(!PIR4bits.TMR2IF){} //wait for TMR2 to settle
 
 TRISC5 = 0; //set RC5 for digital output
}
asked Mar 22, 2021 at 17:16
\$\endgroup\$
2
  • \$\begingroup\$ I forgot to mention in the original question that I am using the XC8 compiler. It compiles fine and I can run it on the MCU. I have written other code to use interrupts based on pin input that works fine. I'm not really sure about where to start with the disassembly -- I was hoping to depend on the compiler for that. \$\endgroup\$ Commented Mar 22, 2021 at 18:30
  • \$\begingroup\$ It's best to edit bits that you forgot into the question rather than comment on your own post. Given that it's the first comment below your post most readers will notice it. Welcome to EE.SE. \$\endgroup\$ Commented Mar 23, 2021 at 23:20

1 Answer 1

1
\$\begingroup\$

It looks like you missed setting the enable bit for the CCP1.

Try adding this statement in your Enable_PWM_CCP function:

 CCP1CONbits.CCP1EN = 1; /* Turn on PWM */

This is my test code:

/*
 * File: main.c
 * Author: dan1138
 * Target: PIC16F15325
 * Compiler: XC8 v2.31
 * IDE: MPLABX v5.25
 *
 * Created on March 23, 2021, 1:59 PM
 * 
 * Description:
 * 
 * Blinky LED example for DM164137 - Curiosity LPC Demo Board
 *
 * 
 * PIC16F15325
 * +----------:_:----------+
 * BOARD_VDD -> 1 : VDD VSS : 14 <- GND
 * LED_D4 <> 2 : RA5/T1CKI PGD/RA0 : 13 <> PGD
 * <> 3 : RA4 PGC/RA1 : 12 <> PGC/LED_D5
 * VPP -> 4 : RA3/VPP T0CKI/RA2 : 11 <> LED_D6
 * LED_D7 <> 5 : RC5 RC0 : 10 <> POT1
 * SWITCH_S1 <> 6 : RC4 RC1 : 9 <> 
 * <> 7 : RC3 RC2 : 8 <> 
 * +-----------------------:
 * DIP-14
 */
#pragma config FEXTOSC = OFF, RSTOSC = HFINT32, CLKOUTEN = OFF, CSWEN = ON
#pragma config FCMEN = OFF, MCLRE = ON, PWRTE = OFF, LPBOREN = OFF
#pragma config BOREN = OFF, BORV = LO, ZCD = OFF, PPS1WAY = OFF, STVREN = ON
#pragma config WDTCPS = WDTCPS_31, WDTE = OFF, WDTCWS = WDTCWS_7, WDTCCS = SC
#pragma config BBSIZE = BB512, BBEN = OFF, SAFEN = OFF, WRTAPP = OFF
#pragma config WRTB = OFF, WRTC = OFF, WRTSAF = OFF, LVP = ON, CP = OFF
#include <xc.h>
#define _XTAL_FREQ (32000000ul)
void set_pwm_duty_cycle(int duty_cycle) {
 unsigned char lsb;
 unsigned char msb;
 /* PWM duty cycle registers seup for left aligned operation */
 lsb = 0;
 if(duty_cycle & 1) lsb |= 0b01000000;
 if(duty_cycle & 2) lsb |= 0b10000000;
 msb = (unsigned char )(duty_cycle>>2);
 CCPR1H = msb; //set duty cycle
 CCPR1L = lsb;
}
void enable_pwm_ccp(int duty_cycle){
 
 
 T2CON = 0; /* Stop PWM timer */
 
 RC5PPS = 0x09; //set CCP1 output to RC5 via PPS
 TRISC5 = 1; //disable output
 CCP1CONbits.MODE = 0xF; //set CCP1 to PWM mode
 CCP1CONbits.FMT = 1; //set CCP1 format left-aligned
 set_pwm_duty_cycle(duty_cycle);
 
 PIR4bits.TMR2IF = 0; //clear TMR2IF flag
 T2CONbits.CKPS = 0b111; //set TMR2 prescale to 128
 T2CONbits.OUTPS = 0b000; //set TMR2 postscaler to 1
 T2CLKCON = 0x01; /* Select FOSC/4 as clock source */
 PR2 = 250-1; /* set PR2 to make PWM freq = 250Hz with FOSC = 32MHz */
 TMR2 = 0;
 PIR4bits.TMR2IF = 0;
 T2CONbits.ON = 1; //enable TMR2
 CCP1CONbits.CCP1EN = 1; /* Turn on PWM */
 
 while(!PIR4bits.TMR2IF){}; //wait for TMR2 to settle
 
 TRISC5 = 0; //set RC5 for digital output
}
/*
 * Initialize this PIC
 */
void PIC_Init (void) {
 ANSC4 = 0; //disable for analog input
 TRISC4 = 1; //configure PORTC4 for digital input
 
 TRISA = 0x00; //configure all PORTA to digital output
 TRISC5 = 0; //configure PORTC5 to digital output
 ANSA5 = 0; //disable analog inputs for LED pins
 ANSA1 = 0;
 ANSA2 = 0;
 ANSC5 = 0;
 
 LATA = 0x00; //Set all output low
 LATC = 0x00;
 
 IOCAP = 0x00; //Disable interrupts on PORTA
 IOCAN = 0x00;
 IOCAF = 0x00; //Clear PORTA interrupt flags
 
 IOCCP = 0b00000000;
 IOCCN = 0b00010000; //Set PORTC4 to interrupt on negative edge
 IOCCF = 0x00; //Clear PORTC interrupt flags
 
 GIE = 1; //Enable global interrupts
 IOCIE = 1; //Enable interrupts on change
}
/*
 * Main application
 */
void main(void) {
 int LED_duty_cycle;
 
 PIC_Init();
 
 enable_pwm_ccp(0);
 LED_duty_cycle = ((int)(PR2)+1)*2; /* Set LED at 50% */
 set_pwm_duty_cycle( LED_duty_cycle );
 /*
 * Application loop
 */
 for(;;){
 
 LATA5 = 1;
 __delay_ms(100);
 LATA5 = 0;
 __delay_ms(100);
 /* Vary LED D7 brightness over about a 4 second interval */
 set_pwm_duty_cycle( LED_duty_cycle );
 LED_duty_cycle += 50;
 if(LED_duty_cycle > ((int)(PR2)+1)*4) LED_duty_cycle = 0;
 }
}
void __interrupt() ISR_Handler(void) {
 if(IOCIE) {
 if(IOCIF) {
 IOCIE = 0; /* disable interrupt on change */
 }
 }
}
answered Mar 23, 2021 at 23:12
\$\endgroup\$
3
  • \$\begingroup\$ This got me working. Thank you! I'm curious -- why did you choose to implement the duty cycle lsb & msb bitwise operations in that way? \$\endgroup\$ Commented Mar 24, 2021 at 17:08
  • \$\begingroup\$ @MaximilianCornell, I did the lsb bitwise because I am using the "free" version of XC8 and the code it generates for multiple bit shifts on a PIC16F is awful. \$\endgroup\$ Commented Mar 24, 2021 at 17:55
  • \$\begingroup\$ I'm using the same version of XC8, so I'll probably follow your implementation instead. Seems like I should start learning disassembly! \$\endgroup\$ Commented Mar 24, 2021 at 19:28

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.