PIC18 burned output

Thread Starter

adrenalina

Joined Jan 4, 2011
78
Hello everyone. I have a circuit to control a dc motor using a DRV8837 and a PIC18F13K22. I am using the ECCP peripheral to output 2 pwm signals to control the motor speed and direction.

The circuit was working perfectly until one output stopped working. It won't output the pwm signal (RC2) and I tried writing to the bit in the latch register and port register, but it won't output a 1.

Does anybody know what could've cuased this issue? It has happened on 2 boards, I'm assuming there is some kind of voltage spike on that pin somehow.

I attach a schematic. Thanks in advance.
 

Attachments

tshuck

Joined Oct 18, 2012
3,534
I can't imagine a spurious voltage on those input pins.

One thing that sticks out is that you have a series resistor with Vpp, and no pullup to Vdd- which can (will) lead to problems (though it may not explain what you are seeing).

Also, there are sometimes problems with relying on reset values as default values for variables and registers - explicitly initialize them if you need them a specific value.

Without seeing your code, it's impossible to say you've initialized things properly.
 

Thread Starter

adrenalina

Joined Jan 4, 2011
78
In the image the pull up on reset is not there, but on the circuit it is there.

In the ISR its simply reading the bytes coming in from the I2C communication.
The ECCP registers are initialized int PWM_Init and PWM_Set is to change the pwm and direction.
The main loop is reading the data received through I2C and writing the PWM values.
Code:
#include "Config.h"
#include <p18f13k22.h>


/*
* Outputs:
* - RC4 - PWM1 (Pin 3) (P1B)
* - RC2 - PWM2 (Pin 11) (P1D)
*
* Communication:
* - RB6 - SCL (I2C) (Pin 8)
* - RB4 - SDA (I2C) (Pin 10)
*/
//#define TEST
volatile unsigned char i2c_reg_address;
volatile unsigned char i2c_data;
volatile unsigned char I2C_byte_count;
volatile unsigned char i2c_data_count;
volatile unsigned char i2c_data_ready;

void I2C_Init(void);
void PWM_Set(unsigned char duty_cycle, unsigned char direction);
void PWM_Init(void);

#pragma interrupt high_isr
void high_isr(void){
    unsigned char x = 0;

    // Check if interrupt was caused by I2C
    if(PIR1bits.SSPIF == 1) {
        if(!SSPSTATbits.D_NOT_A) {
            I2C_byte_count = 0;
            if(SSPSTATbits.BF){
                x = SSPBUF;
            }
        }
        else {
            I2C_byte_count++;

            if(SSPSTATbits.BF) {
                if(I2C_byte_count == 1){
                    i2c_reg_address = SSPBUF;
                }
                else if(I2C_byte_count == 2) {
                    i2c_data = SSPBUF;
                    PIE1bits.SSPIE= 0;      // Disable MSSP Interrupt
                }
                else {
                    x = SSPBUF;
                }
            }
        }
        SSPCON1bits.SSPOV = 0;

    }
    PIR1bits.SSPIF = 0;     // Clear interrupt flag
    SSPCON1bits.CKP = 1;
    //INTCONbits.GIEH = 1;    // Renable interrupts
}

#pragma code high_vector = 0x08
void high_interrupt(void) {
    _asm GOTO high_isr _endasm
}
#pragma code


void main(void) {
    unsigned char register_address = 0;
    unsigned char data = 0;
    unsigned int i =0;
    unsigned char motor_duty_cycle = 0;
    unsigned char motor_direction = 0;
  
    ANSELHbits.ANS11 = 0;   // Analog function disabled
    TRISBbits.TRISB5 = 1;   // RB5 set as input

    TRISCbits.RC4 = 0;      // RC4 set as output

    ANSELbits.ANS6 = 0;     // Analog function disabled
    TRISCbits.RC2 = 0;      // RC2 set as output

    TRISBbits.TRISB7 = 1;    // RB7 set as input

    LATCbits.LATC2 = 0;
    LATCbits.LATC4 = 0;

    I2C_Init();
    PWM_Init();

    PWM_Set(60, 1);
    for(i = 0; i < 1000; i++){}
    PWM_Set(60, 2);
    for(i = 0; i < 1000; i++){}
    PWM_Set(0,0);
  
    while(1){
        // If a stop bit was last detected transmission is over
        // and data can be read.
        if(!PIE1bits.SSPIE) {
            INTCONbits.GIEH = 0;    // Disable interrupts
            register_address = i2c_reg_address;
            data = i2c_data;
            INTCONbits.GIEH = 1;    // Enable interrupts
            PIE1bits.SSPIE= 1;      // Enable MSSP Interrupt
        }

        if(register_address == 0x01) {
            motor_duty_cycle = data;
            PWM_Set(motor_duty_cycle, motor_direction);
        }
        else if(register_address == 0x02) {
            motor_direction = data;
            PWM_Set(motor_duty_cycle, motor_direction);
        }
        else{
        }
    }
}

void I2C_Init() {
     // I2C Configuration
    ANSELHbits.ANS10 = 0;   // Analog function disabled
    TRISBbits.TRISB4 = 1;   // RB4 set as input

    TRISBbits.TRISB6 = 1;   // RB6 set as input

    SSPCON1bits.SSPM = 0x6; // I2C Slave mode, 7-bit address
    SSPADD = 0b1011110 << 1;     // Slave address (0x5E)
    SSPCON1bits.CKP = 1;
    SSPCON2bits.SEN = 1;    // Clock stretching enabled

    // Interrupt configuration
    PIR1bits.SSPIF = 0;     //Clear MSSP interrupt flag
    IPR1bits.SSPIP = 1;     // MSSP interrupt is high priority
    RCONbits.IPEN  = 1;     // Enable Interrupt priority
    PIE1bits.SSPIE= 1;      // Enable MSSP Interrupt
    INTCONbits.GIEH = 1;    // Enable High priority interrupts


    SSPCON1bits.SSPEN = 1;   // Enable I2C
}

void PWM_Init(){
    // CCPR1L pwm duty cycle
    //PWM Configuration
    CCP1CONbits.CCP1M = 0b1100; // PWM mode, all outputs active high
    CCP1CONbits.P1M = 0b00;     // Single output, ouputs controlled by steering
    CCP1CONbits.DC1B = 0;       // LSBs of 10-bit PWM are 0, using 8-bit PWM
    PSTRCONbits.STRSYNC = 1;    // Output steering update on next PWM period
    //PSTRCONbits.STRB = 1;       // Output PWM on P1B(RC4)

    // PWM Period = 4 * Tosc * (PR2+1) * (TMR2 prescale value)
    // PWM period = 4 * 16MHz * 250 * 16
    // PWM period = .001s or 1000kHz
    //T2CONbits.T2CKPS = 0b10;    // Prescaler 16

    // Setting right now prescaler to 1 because clock is running at 1 MHz
    T2CONbits.T2CKPS = 0b00;
    PR2 = 249;
    T2CONbits.TMR2ON = 1;       // Turn on timer 2

    CCPR1L = 0;
}

void PWM_Set(unsigned char duty_cycle, unsigned char direction){
    if(direction == 0){
        CCPR1L = 0;
    }
    else if(direction == 1){
        PSTRCONbits.STRB = 0;
        CCPR1L = duty_cycle;
        PSTRCONbits.STRD = 1;
    }
    else {
        PSTRCONbits.STRD = 0;
        CCPR1L = duty_cycle;
        PSTRCONbits.STRB = 1;
    }
}
 

tshuck

Joined Oct 18, 2012
3,534
Your initializations look fine.

How are you verifying that the output is not working? Oscilloscope? Multimeter? LED?

In your cycle through the PWM outputs after initialization, the PWM period is longer than the time than you allow the PWM output to be steered to a particular pin. Since you've also set the steering to update on the next PWM period (STRSYNC=1), you'd never see it with this testbench.

Is this the code that was intermittently failing in a board?

Have you verified the I2C comms independently?

Did you try separate code to validate the output of the pins in question?
 

Thread Starter

adrenalina

Joined Jan 4, 2011
78
Your initializations look fine.

How are you verifying that the output is not working? Oscilloscope? Multimeter? LED?

In your cycle through the PWM outputs after initialization, the PWM period is longer than the time than you allow the PWM output to be steered to a particular pin. Since you've also set the steering to update on the next PWM period (STRSYNC=1), you'd never see it with this testbench.

Is this the code that was intermittently failing in a board?

Have you verified the I2C comms independently?

Did you try separate code to validate the output of the pins in question?
I did the following to measure the outputs using a multimeter. RC2 does measure the 1, but C2 is at 0. I also tried by writing directly to the port register, but it stills outputs 0. I also looked at the pwm using an oscilloscope and RC4 does give the pwm, but RC2 does not.

Code:
 ANSELHbits.ANS11 = 0;   // Analog function disabled
    TRISBbits.TRISB5 = 1;   // RB5 set as input

    TRISCbits.RC4 = 0;      // RC4 set as output

    ANSELbits.ANS6 = 0;     // Analog function disabled
    TRISCbits.RC2 = 0;      // RC2 set as output

    TRISBbits.TRISB7 = 1;    // RB7 set as input

    LATCbits.LATC2 = 1;
    LATCbits.LATC4 = 1;
 

tshuck

Joined Oct 18, 2012
3,534
I did the following to measure the outputs using a multimeter. RC2 does measure the 1, but C2 is at 0. I also tried by writing directly to the port register, but it stills outputs 0. I also looked at the pwm using an oscilloscope and RC4 does give the pwm, but RC2 does not.[...]
Was this from a fresh configuration (e.g. brand new code)? It's possible that the ECCP module will override any LATx I/O function while it's active.

I don't suppose you have a bare breakout board for your QFN package that you can test on, separate from the populated boards, do you?
 
Top