PID hbridge random current spikes

My Hbridge consists of 4 nchannel mosfets, high side is driven by basic bootstrap circuit, lowside is directly from mcu. Using PID function to control motor by its position, set by setpoint. And 8-bit pwm is generated by timer/s inside AVR. Current is readed thru shunt res and op-amp fed into ADC. Highest adc value in graph is about 6amps. Tried many different PID libs, issue still remains. What could cause such a random current spikes?


Hbridge schematic:

Code:
main.c

        motor0.output = Compute(motor0.flapPos, motor0.setpoint);
        move_motor((uint16_t) motor0.output);

pwm.c

void PWM_init() {
    // set timer/counter TCA1 in 8-bit PWM mode
    TCA1.SPLIT.CTRLA = TCA_SPLIT_CLKSEL_DIV4_gc | TCA_SPLIT_ENABLE_bm;
    TCA1.SPLIT.CTRLB = TCA_SPLIT_LCMP0EN_bm | TCA_SPLIT_LCMP1EN_bm | TCA_SPLIT_HCMP0EN_bm | TCA_SPLIT_HCMP2EN_bm;
    TCA1.SPLIT.CTRLD = TCA_SPLIT_SPLITM_bm;
    TCA1.SPLIT.LPER = 0xFF;

    //set all values off
    TCA1.SPLIT.HCMP0 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = 0; //LOWSIDE0 PWM

    TCA1.SPLIT.LCMP1 = 0; //HIGHSIDE1 PWM
    TCA1.SPLIT.LCMP0 = 0; //LOWSIDE1 PWM
}

void HBridge_init() {
    //configure the port pins for H-Bridge control and set direction to output
    PORTB.DIRSET |= LOW_SIDE_0 | LOW_SIDE_1 | HIGH_SIDE_0 | HIGH_SIDE_1;
    //invert high side signal
    PORTB.PIN3CTRL = PORT_INVEN_bm;
    PORTB.PIN1CTRL = PORT_INVEN_bm;
//    //invert low side signal
//    PORTB.PIN0CTRL = PORT_INVEN_bm;
//    PORTB.PIN5CTRL = PORT_INVEN_bm;
}

void forward(uint8_t duty) {
    TCA1.SPLIT.HCMP0 = duty - 1; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = 0; //LOWSIDE0 PWM

    TCA1.SPLIT.LCMP1 = 0; //HIGHSIDE1 PWM
    TCA1.SPLIT.LCMP0 = duty + 1; //LOWSIDE1 PWM
}

void reverse(uint8_t duty) {
    TCA1.SPLIT.HCMP0 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = duty - 1; //LOWSIDE0 PWM

    TCA1.SPLIT.LCMP1 = duty + 1; //HIGHSIDE1 PWM
    TCA1.SPLIT.LCMP0 = 0; //LOWSIDE1 PWM
}

void stop() {
    TCA1.SPLIT.HCMP0 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = 0; //LOWSIDE1 PWM

    TCA1.SPLIT.LCMP1 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.LCMP0 = 0; //LOWSIDE1 PWM
}
void move_motor(int16_t input) {
    uint16_t pwm = 0;
    if ((int16_t) input > 255) {
        pwm = 255;
    } else if ((int16_t) input < -255) {
        pwm = 255;
    } else if ((int16_t) input > 0) {
        pwm = input;
        forward(pwm);
    } else if ((int16_t) input < 0) {
        pwm = (65535 + 1 - input);
        reverse(pwm);
    } else {
        stop();
    }
}

pid code is from Improving the Beginner’s PID: Direction « Project Blog

Code?
Schematic?
Pics?

Hbridge schematic:


Code:
main.c

        motor0.output = Compute(motor0.flapPos, motor0.setpoint);
        move_motor((uint16_t) motor0.output);

pwm.c

void PWM_init() {
    // set timer/counter TCA1 in 8-bit PWM mode
    TCA1.SPLIT.CTRLA = TCA_SPLIT_CLKSEL_DIV4_gc | TCA_SPLIT_ENABLE_bm;
    TCA1.SPLIT.CTRLB = TCA_SPLIT_LCMP0EN_bm | TCA_SPLIT_LCMP1EN_bm | TCA_SPLIT_HCMP0EN_bm | TCA_SPLIT_HCMP2EN_bm;
    TCA1.SPLIT.CTRLD = TCA_SPLIT_SPLITM_bm;
    TCA1.SPLIT.LPER = 0xFF;

    //set all values off
    TCA1.SPLIT.HCMP0 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = 0; //LOWSIDE0 PWM

    TCA1.SPLIT.LCMP1 = 0; //HIGHSIDE1 PWM
    TCA1.SPLIT.LCMP0 = 0; //LOWSIDE1 PWM
}

void HBridge_init() {
    //configure the port pins for H-Bridge control and set direction to output
    PORTB.DIRSET |= LOW_SIDE_0 | LOW_SIDE_1 | HIGH_SIDE_0 | HIGH_SIDE_1;
    //invert high side signal
    PORTB.PIN3CTRL = PORT_INVEN_bm;
    PORTB.PIN1CTRL = PORT_INVEN_bm;
//    //invert low side signal
//    PORTB.PIN0CTRL = PORT_INVEN_bm;
//    PORTB.PIN5CTRL = PORT_INVEN_bm;
}

void forward(uint8_t duty) {
    TCA1.SPLIT.HCMP0 = duty - 1; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = 0; //LOWSIDE0 PWM

    TCA1.SPLIT.LCMP1 = 0; //HIGHSIDE1 PWM
    TCA1.SPLIT.LCMP0 = duty + 1; //LOWSIDE1 PWM
}

void reverse(uint8_t duty) {
    TCA1.SPLIT.HCMP0 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = duty - 1; //LOWSIDE0 PWM

    TCA1.SPLIT.LCMP1 = duty + 1; //HIGHSIDE1 PWM
    TCA1.SPLIT.LCMP0 = 0; //LOWSIDE1 PWM
}

void stop() {
    TCA1.SPLIT.HCMP0 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.HCMP2 = 0; //LOWSIDE1 PWM

    TCA1.SPLIT.LCMP1 = 0; //HIGHSIDE0 PWM
    TCA1.SPLIT.LCMP0 = 0; //LOWSIDE1 PWM
}
void move_motor(int16_t input) {
    uint16_t pwm = 0;
    if ((int16_t) input > 255) {
        pwm = 255;
    } else if ((int16_t) input < -255) {
        pwm = 255;
    } else if ((int16_t) input > 0) {
        pwm = input;
        forward(pwm);
    } else if ((int16_t) input < 0) {
        pwm = (65535 + 1 - input);
        reverse(pwm);
    } else {
        stop();
    }
}

pid code is from Improving the Beginner’s PID: Direction « Project Blog

Poor (read: disastrous) H-bridge design. Look up "shoot through", which is a common timing failure mode.

I think i included dead-time in sketch, but mby i dont fully understand it in code...

As im looking 99% of hbridge shematics in internet just doesnt work.
Only one i found that looks promising is this one, but is it true?:

It MUST be included, and you MUST understand the timing, or you will fry the MOSFETS and probably the power supply. You need a scope to make absolutely sure the timing is correct.

Also made this, but it performed somehow much worse than first one :smiley:
First one could easy push 6 amps, this one gets hot @ like 100mA


Can it be true that shoot thru in this one is much worse because of pre-drivers?
P.S i had inverted input ic... thats why pull-up resistors and bootstrap caps was about 1uF

Why not buy a professionally designed H-bridge? They are much cheaper than the scope you need, in order to know what is actually happening.

Need to push about 10 amps @ 13.8v . Have a scope, but looks like i dont fully understand what goes wrong... High side seems like an issue.

The transformer is your load? And L2 (not in your picture) delivers what you are really interested in?

It looks to me like a wicked built-in current limiting feature by PWM.

Or poor PID algorithm with negative signed output interpreted as unsigned.

Load is dc motor. What did you mean by L2?

I have a current limit function which looks if current is greater than 5.5amp for more than 1 second, but at this time its not active.
Will look into signedness

In your picture in post #5 there is L1 marked as transformer... usually transformers have a secondary winding (L2).
But you talk about a motor....
So, will you replace L1 with your motor? Or what is L1 for?

Oh, i think you misinterpreted - what i was asking is if that schematic would work better than what i made. I think nothing changes so drastically if its a transformer or motor

No I did not misinterpret. I tried to get clarity on your idea...

I see a considerable loss of voltage on the high side switches. The transformer (solenoid?) seems to be an essential part of the circuit, elevating the high side gate voltage. The 100µF caps may be guilty of heavy current spikes.

OP uses the scheme in post #3. And thinks of scheme in post #5. To me it seems scheme in post #5 is designed to produce 230V AC from 12 or 24V DC (cigaret lighter in car). But I am no expert on this... if so, it is no good for OP's DC motor.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.