PIC18f2431 PCPWM module help

(instructions, reset, WDT, specifications...) PIC17Cxx, PIC18Fxxx

PIC18f2431 PCPWM module help

Postby Cantafford » Tue Jun 21, 2016 8:40 am


I'm trying to generate 6 PWM signals with the PCPWM(power controlled pwm module) of PIC18F2431(to drive a BLDC motor).

I have read the datasheet and configured the module to my needs. I have calculated a frequency of 1.5Khz which will give me a duty cycle resolution of 14 bits.

In the datasheet is specified that by setting the specific bit in OVDCOND register, the state of the pin will be determined by the duty cycle which is set by setting the value in the PDCx register. So basically if OVDCOND is 0x01 setting a value in the PDC1H and PDC1L will give me a specific duty cycle for the transistor on PWM0(RB0).

I used the ADC to read a value from 5V to 0V and use that value as the duty cycle by using a potentiometer.

This is the schematic from Proteus:

And this is the code:
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#include "header.h"
int HALL;
int HALLvalue[6] = { 0b00000101, 0b00000001, 0b00000011, 0b00000010, 0b00000110, 0b00000100 };
unsigned int dch;
unsigned int dcl;
// Capture Interrupt Service Routine
void interrupt CheckHallValue()
while(GODONE==1); // wait till conversion is
dch = ADRESH>>2; // set the
dcl = (ADRESH<<6) || (ADRESL>>2); // duty cycle with the pot

IC1IF = 0; IC2QEIF = 0; IC3DRIF = 0;
HALL = (PORTA >> 2) & 0x7; // read the capture pins to get hall sensor state
if(HALL == HALLvalue[0]) {OVDCOND = 0b00100100; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; OVDCONS = 0b00000000;}
else if(HALL == HALLvalue[1]) {OVDCOND = 0b00000110; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; OVDCONS = 0b00000000;}
else if(HALL == HALLvalue[2]) {OVDCOND = 0b00010010; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; OVDCONS = 0b00000000;}
else if(HALL == HALLvalue[3]) {OVDCOND = 0b00011000; PDC2H = dch; PDC2L = dcl; PDC1H = dch; PDC1L = dcl; OVDCONS = 0b00000000;}
else if(HALL == HALLvalue[4]) {OVDCOND = 0b00001001; PDC1H = dch; PDC1L = dcl; PDC0H = dch; PDC0L = dcl; OVDCONS = 0b00000000;}
else if(HALL == HALLvalue[5]) {OVDCOND = 0b00100001; PDC2H = dch; PDC2L = dcl; PDC0H = dch; PDC0L = dcl; OVDCONS = 0b00000000;}
void ConfigureADC()
ADCON0 = 0b00100000; // continuous loop mode, single channel mode
VCFG1 = 0; // VDD and VSS as ref
VCFG0 = 0;
ADCON2 = 0b10001000; // right justified, 2TAD, conversion clock: Fosc/2
ADCON3 = 0b11000100; // input capture 1 starts the a/d sequence!!(check here the first two bits)
GASEL1 = 0; // select AN0
GASEL0 = 0;
ANSEL0 = 0b00000001;
ADON = 1; // start ADC
void main()
//OSCCON = 0b01001111; // frequency is 1Mhz
SCS1 = 0;
SCS0 = 0;
TRISA = 0b11111111; // PORTA is input(CAP's + POT)
TRISB = 0b11000000;
GIE = 1; // enable global interrupts
GIEH = 1;
PEIE = 1;
// Initialize the Input Capture Module
CAP1CON = 0b00000000; // disable input capture 1 module
CAP1CON = 0b00001000; // enable input capture 1 module; interrupt on every state change
CAP2CON = 0b00000000; // disable input capture 2 module
CAP2CON = 0b00001000; // enable input capture 2 module; interrupt on every state change
CAP3CON = 0b00000000; // disable input capture 3 module
CAP3CON = 0b00001000; // enable input capture 3 module; interrupt on every state change
// Enable Capture Interrupt and configure TMR5
IC1IE = 1; // enable IC1 interrupt
IC1IP = 1; // IC1 interrupt on high priority
IC1IF = 0; // clear IC1 interrupt status flag
IC2QEIE = 1; // enable IC2 interrupt
IC2QEIP = 1; // IC2 interrupt on high priority
IC2QEIF = 0; // clear IC2 interrupt status flag
IC3DRIE = 1; // enable IC3 interrupt
IC3DRIP = 1; // IC3 interrupt on high priority
IC3DRIF = 0; // clear IC3 interrupt status flag
PTCON0 = 0b00000000; // 1:1 postscale, 1:1 prescale, PWM in free-running mode
PTCON1 = 0b10000000; // pwm time base is on, the time base counts up
PWMCON0 = 0b01001111; // pwm0-5 configured as pwm output in independent mode
SEVOPS3 = 0; // 1:1 postscale
SEVOPS2 = 0;
SEVOPS1 = 0;
SEVOPS0 = 0;
OSYNC = 1; //Output overrides via the OVDCON register are synchronized to the PWM time base(NOT SURE HERE)
PTPERH = 0x4F; // frequency is 1.5Khz
PTPERL = 0xFF; // 0xFF here
//T5SYNC = 0;
//T5CON = 0b01011001;
//TMR5CS = 0;
T5CON = 0b00000101;
//LATB = 0b00100100; // in order to start input capture must see a change
OVDCOND = 0b00100100; // start(needs a change on input capture)
PDC2H = 0xFF; PDC2L = 0xFF; PDC1H = 0xFF; PDC1L = 0xFF;
OVDCONS = 0b00000000;
ADON = 1;

And header file.
Code: Select all
// PIC18F2431 Configuration Bit Settings
// 'C' source line config statements
#include <xc.h>
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#pragma config OSC = XT         // Oscillator Selection bits (XT oscillator)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = ON        // Internal External Oscillator Switchover bit (Internal External Switchover mode enabled)
#pragma config PWRTEN = OFF     // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled)
// BORV = No Setting
#pragma config WDTEN = OFF      // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDPS = 32768     // Watchdog Timer Postscale Select bits (1:32768)
#pragma config WINEN = OFF      // Watchdog Timer Window Enable bit (WDT window disabled)
#pragma config PWMPIN = OFF     // PWM output pins Reset state control (PWM outputs disabled upon Reset (default))
#pragma config LPOL = HIGH      // Low-Side Transistors Polarity (PWM0, 2, 4 and 6 are active-high)
#pragma config HPOL = HIGH      // High-Side Transistors Polarity (PWM1, 3, 5 and 7 are active-high)
#pragma config T1OSCMX = ON     // Timer1 Oscillator MUX (Low-power Timer1 operation when microcontroller is in Sleep mode)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (Disabled)
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low-Voltage ICSP Enable bit (Low-voltage ICSP enabled)
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000200-000FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (001000-001FFF) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (002000-002FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (003000-003FFFh) not code-protected)
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000200-000FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (001000-001FFF) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (002000-002FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (003000-003FFFh) not write-protected)
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000200-000FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (001000-001FFF) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (002000-002FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (003000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from table reads executed in other blocks)
#define _XTAL_FREQ 25000000

When I run this code the motor just starts spinning with a random speed without respecting the position of the potentiometer which is odd because the duty cycle in my program is equal to the value read by the ADC.

This is how I calculated everything:
From the datasheet -> TABLE 17-2:
I have used those values to get a frequency of 1.5Khz. AKA: Set PTPER to 0xFFF; FOSC is 25Mhz. PTMR prescaler value = 1. For this values in the table it says that PWM resolution is 14 bits. However the ADC has a resolution of 10 bits so my PWM resolution would actually be 10 bits not 14 bits(at least that's the way I think it is).
Though, I'm not quite sure if my frequency is actually 25Mhz. This is the first time I'm using an external oscillator and not the internal one. In Proteus I put a crystal, set it's value to 25Mhz and used 2 capacitors of 30pF each. Any way I can verify if this gives me a frequency of 25Mhz? I used a rule of thumb formula I found for the capacitors values.

Now that 10 bit value from the ADRESH and ADRESL given by the ADC I must put in PDCH and PDCL(14 bit value).
I have chosen the result of ADRES to be right justified so I can have the result as the ADRESH and 2lsb's from ADRESL.

The PDC value is on 14 bits(ADRESH<6,7> are not used). So in PDC I must have something like:

x x AH7 AH6 AH5 AH4 AH3 AH2 AH3 AH2 AL7 AL6 0 0 0 0

So I tried setting like this:
PDCH = ADRESH >> 2; //
PDCL = (ADRESH<<6) || (ADRESL>>2)

If AH7 - AL6 are all 1 the result is 16368 in decimal.
My period is: 4095 in decimal(0x0F on low and 0xFF) on high. So I think this is where my problem is as you said: the pwm duty cycle is bigger than the period. I tried changing the period to 0x3FFF so period is bigger than duty cycle but still same thing(motor spins without taking value from ADC into account).

Also the datasheets specifies:
"The upper 12 bits of PDCn hold the actual duty cycle value from PTMRH/L<11:0>, while the lower 2 bits control which internal Q-clock the duty cycle match occurs.". I didn't completely understand what these two bits actually do(to my understanding they allow for a finer resolution of the PWM signal) but the way I set it up they will always stay on 00(for which: "duty cycle match occurs on Q1").

Also I'm not sure if my frequency is actually 25Mhz. It's the first time I'm using an external oscillator. I have connected the XTAL in Proteus simulator as shown in that snapshot and set it's value to 25Mhz. The values of the two capacitors were determined by using a rule of thumb formula I found in a tutorial.

Please help me correct this issue and get the motor running properly in the simulation :). Thank you for reading!
Posts: 1
Joined: Tue Jun 21, 2016 8:35 am
PIC experience: EE Student

Return to 16-Bit Core

Who is online

Users browsing this forum: No registered users and 1 guest