This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DRV8850EVM w/ Modified Firmware, Question on VPROPI

Other Parts Discussed in Thread: DRV8850EVM, DRV8834, DRV8850

Attached is a scope plot taken from a DRV8850EVM without any hardware changes. I've modified the firmware to eliminate PWM and change the speed every 400ms. In the scope plot you can see the direction and speed at the top. The yellow trace is on a 0.7 ohm resistor I placed in series before the power supply ground so you have something like this:

[power supply ground] ----[0.7 resistor]---[circuit ground]

The blue trace is the VPROPI signal. VPROPI shows a peak of about 1.6V or 1.6A since the resistor used on the EVM is a 1k?

The yellow shows 616mV which equates to 880mA (0.616/0.7) so about 1/2? I think I'm having a bad day because I think I've seen this before but I can't recall why I would be measuring 1/2 of the current with this setup.

The bigger question is why is the signal clipped? The power supply is set to trip at 7A so I don't think that is causing an issue. According to Eq. 1 in the datasheet:

2000  x (VCC - 1V) / Iout

The current sense resistor needs to be less than this value. I'm applying 3.7V so this should allow 5.4A if I understand the purpose of VPROPI correctly.

Any insights into this would be greatly appreciated!

  • Hi George,

    Are you measuring VPROPI with respect to power supply ground or circuit ground? If power supply ground, you may be creating an additive effect. The sense resistor is causing the device ground to rise 600mV, so VPROPI should be 1.4V - 600mV.

    With respect to the clipping question, that may depend on the motor parameters. Can you provide a little more information? What are the 4 inputs when DIR is high and low? What are your motor parameters? If you have a motor datasheet, can you provide it?
  • Hi Rick:

    Here's the brain-dead code I have for now for testing:

    // end of setup, beginning of main loop
    		TA1CCTL1 = OUTMOD_0 | BIT2;
    		TA1CCTL2 = OUTMOD_0 | BIT2;
    
      for (;;)
        {
    		P2SEL = BIT5 | BIT2;		// Set IN1H and IN2L high
    		P2OUT &= ~(BIT4 | BIT1);	// Set IN1L and IN2H low
    
    		// Delay for 30ms per outer loop or 420ms
    		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
    		{
    		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
    		  {__no_operation();
    		  }
    		}
    		P2SEL = BIT4 | BIT1;		// Set IN2H and IN1L high
    		P2OUT &= ~(BIT5 | BIT2);	// Set IN1H and IN2L low	  
    
    		// Delay for 30ms per outer loop or 420ms
    		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
    		{
    		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
    		  {__no_operation();
    		  }
    		}
    
        }

    All probe grounds are on the power supply ground side of the resistor. This is a left over setup from the DRV8834 I was previously using which doesn't have the VPROPI pin.

    The attached code segment should answer your questions on the condition of the 4 inputs. Attached is the datasheet for the motor I'm working on but it is a custom winding they are working on for me so this might not be 100% accurateSFF-180SHV-3049-R(50% increase in torque).pdf

  • Hi Rick:

    I "cleaned up" my setup, modified the code, and ran some additional tests this weekend on 3 different motor configurations. I consolidated the findings on the attached PDF. If you could take a look and provide some feedback I'd appreciate it. The goal is to get the lowest power consumption so this can be battery operated.

    SFF-180SHV Moto Evaluation.pdf

    Thanks,

    George

  • Hi George,

    It looks like you are using slow decay when PWM'ing the motor. This is typically the most efficient.

    If you have not tried this, PWM'ing at 20 to 25kHz is a good place to start. This is above the audible range and minimizes switching losses in the FETs. From there, you can move up and down to see if you can achieve better results with the motor.

    What is your code doing approximately 250ms after the trigger in the first two images? It appears there is overlap between IN1x and IN2x. Is that intentional?
  • Good Morning Rick.

    I noticed that as well and was a little curious but decided I take another look today. I'm not doing anything intentional but I'm far from a programming expert so I could have messed up the code. I modified it so I could still use the POT and adjust the speed without having to recompile. I've attached the version of code I'm running now so you can see if I missed something. I was using single shot on the scope trigger and trying to record the duty rate but since it's not a constant PWM the scope wouldn't always capture the correct duty cycle. Now that I think of it I didn't zoom in to confirm those values were correct but based on the small movement of the POT from max they probably are.

    I'm curious why the DRV8834 wasn't working especially based on these plots showing peak currents of under 1.5A. I think I may like the DRV8850 better since it has the built-in LDO to power the MSP430 but I did loose quite a bit of time working with the DRV8834 and trying to figure out why the motors weren't working as expected.

    main_g2553_threader_v2.c
    #include "msp430g2553.h"
    
    
    // Port 1 output definitions
    #define STATUS_LED		BIT7				// P1.7
    
    // Port 2 output definitions
    
    #define IN1H			BIT5				// P2.5
    #define IN1L			BIT1				// P2.1
    #define IN2H			BIT4				// P2.4
    #define IN2L			BIT2				// P2.2
    
    // Port 1 REN definitions (set unused to REN)
    #define UNUSED			BIT4 | BIT 3		// P1.4 and P1.3 are unused
    
    //
    #define SPEED_REF		BIT0				// P1.0 is ADC read location
    
    // Port 2 inputs
    #define DIR				BIT7				// P2.7 is direction
    
    // TIMER defines
    // use 8
    #define DUTY_CYCLE_TIMER_MAX 127	// max timer count value  -- total is 256 for up/down
    #define DEADTIME		1			// software deadtime loop
    									// set to 0 to use internal deadtime
    #define MIN_DC 4					// sets the minimum duty cycle threshold to spin the motor
    									// 1 - 50%
    									// 2 - 25%
    									// 3 - 12.5%
    									// 4 - 6.25%
    									// 5 - 3.125%
    #define MAX_DC 5					// sets the maximum duty cycle threshold to spin the motor
    									// 1 - 50%
    									// 2 - 75%
    									// 3 - 87.5%
    									// 4 - 93.75%
    									// 5 - 96.875%
    #define DC_TOLERANCE	1			// Masked ADC value must change by DC_TOLERANCE + 1 before an update will occur
    									// Value to change is ((DC_TOLERANCE + 1) * Vcc)/1024/8) Volts
    
    // direction
    #define FORWARD			0
    
    #define ALL_LOW			0x00
    #define ALL_HIGH		0xFF
    
    volatile unsigned int LEDcounter=0;			// Initialize LED timing counter
    unsigned int loop_counter;
    unsigned int Direction, PriorDirection;
    signed int DutyCycle, PriorDutyCycle;
    
    unsigned int delayloop1;
    unsigned int delayloop2;
    
    
    /// SUBROUTINES
    // this routine is a simple method of using duty cycle
    // it is calculating the duty cycle by using the DUTY_CYCLE_TIMER_MAX number as
    // a multiple of the number of bits (the number of bits is 6 (64 bins), and the
    // the multiple is MULT_FACTOR)
    // by using a multiple of the number of bits, the duty cycle is a math calculation
    // OUTMOD0 is static, uses state of BIT2 to set low or high
    // OUTMOD2 is toggle/reset  -- use on low side
    // OUTMOD6 is toggle/set    -- use on high side
    
     void UpdateSpeed(unsigned int dc)
    {
    // calculate the next high side and low side values, then set them to minimize time
    	 // the truth table for using this section is shown below
    	 // Dir/Speed		IN1L	IN1H	IN2L	IN2H
    	 // 0				H		L		H		L
    	 // FWD < 100%		PWM		PMW		H		L
    	 // FWD - 100%		L		H		H		L
    	 // REV < 100%		H		L		PWM		PWM
    	 // REV - 100%		H		L		L		H
    
    // set up for slow decay mode
    
    // Stop and reset the timers
    //		TA1CCTL1 &= ~CCIE;	// disable the interrupt
    		TA1CTL  |=  TACLR;	// CLR the timer;
    		if (dc < (DUTY_CYCLE_TIMER_MAX >> MIN_DC)) // do not start spinning until 12.5%
    		{
    			// clear IN1H and IN2H
    			// set IN1L and IN2L high to stop motor
    			TA1CCTL1 = OUTMOD_0 | BIT2;
    			TA1CCTL2 = OUTMOD_0;
    			P2SEL = BIT5 | BIT4 | BIT2 | BIT1;
    		}
    		else if (dc < DUTY_CYCLE_TIMER_MAX - (DUTY_CYCLE_TIMER_MAX >> MAX_DC))     // use this up to 88%
    		{
    			// enable interrupts
    //			TACTL |= TAIE;
    			TA1CCR1 = DUTY_CYCLE_TIMER_MAX - dc;
    			TA1CCR2 = DUTY_CYCLE_TIMER_MAX + DEADTIME - dc;
    //			TA1CCTL1 |= CCIE;
    			// clear IN1H and IN2H
    			// set IN1L and IN2L high to stop motor
    			P2SEL = BIT2 | BIT1;
    			TA1CCTL1 = OUTMOD_2;
    			TA1CCTL2 = OUTMOD_6;
    			// need to set bits to clear based on direction
    			if (Direction == FORWARD)
    			{
    				P2SEL = BIT5 | BIT1;		// PWM IN1 and
    				P2OUT = BIT2;				// SET IN2L high
    			}
    			else
    			{
    				P2SEL = BIT4 | BIT2;		// PWM IN2 and
    				P2OUT = BIT1;				// SET IN1L high
    			}
    
    			// restart the timer
    			TA1CTL   =  TASSEL_2 | ID_0 | MC_3 | TACLR;  // Timer Clock = SMCLK;
    
    		}
    		else  // 100%
    		{
    			TA1CCTL1 = OUTMOD_0 | BIT2;
    			TA1CCTL2 = OUTMOD_0 | BIT2;
    			if (Direction == 0)
    			{
    				P2SEL = BIT5 | BIT2;		// Set IN1H and IN2L high
    				P2OUT &= ~(BIT4 | BIT1);	// Set IN1L and IN2H low
    			}
    			else
    			{
    				P2SEL = BIT4 | BIT1;		// Set IN2H and IN1L high
    				P2OUT &= ~(BIT5 | BIT2);	// Set IN1H and IN2L low
    			}
    		}
    }
    
    
    // MAIN Routine
    
    
    
    
    
    int main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;             	// Stop watchdog timer
    
    // Initialization -- First set all GPIO as inputs with pulldown
    
      P1REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
      P2REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
      P3REN  = BIT7 + BIT6 + BIT5 + BIT4 + BIT3 + BIT2 + BIT1 + BIT0;
    
      P1OUT  = ALL_LOW;
      P2OUT  = ALL_LOW;
      P3OUT  = ALL_LOW;
    
    // Now re-configure Port Directions and Peripherals as required
      P1DIR = STATUS_LED;			// Set Port 1 GPIO to output on P1.7
      P1REN &= ~STATUS_LED;			// Disable Resistor
    
    // must clear P2.7 prior to using it as an input
      P2SEL = ALL_LOW;
    
    // Now re-configure Port Directions and Peripherals as required
      P2DIR = IN1H | IN1L | IN2H | IN2L;			// Set Port 1 GPIO to output on P1.1 and P1.2
      P2REN &= ~(IN1H | IN1L | IN2H | IN2L);		// Disable resistors
    //
    
    // Configure ADC10 to supply reference voltage and read value of voltage divider on P1.0
    
      ADC10CTL0 |= ADC10SHT_2 + ADC10ON + ADC10IE;    // VR+ = Vcc, VR- =AVSS, 16x sample and conversion, enable ADC and ADC interrupt
      ADC10AE0 |= INCH_0;						// Enable ADC input on A0
    
    //  BCSCTL3 =  LFXT1S_3;						// Register value that must be set to allow TAI functionality on XIN pin
    
    // Timer count value needs to be load only once
      TA1CCR0 = DUTY_CYCLE_TIMER_MAX;				// set time
      TA1CCTL1 |= OUTMOD_2;							// set mode to toggle/set
      TA1CCTL2 |= OUTMOD_6;							// set mode to toggle/reset
    
    // delay for some time prior to speeding the clock, approximately 250ms per outer loop
      for (delayloop2 = 2; delayloop2 > 0; delayloop2 --)
      {
    	  for (delayloop1 = 20000; delayloop1 > 0; delayloop1--)
          {__no_operation();
    	  }
      }
    
    
    // Set the DCO to calibrated 12MHz, be sure to have MCLK/2 and SMCLK/2 set prior to these commands.
      BCSCTL2  |= DIVM_1 | DIVS_1;				// MCLK is DCO/2, SMCLK is DCO/2
      DCOCTL	= ALL_LOW;						// clear the DCO then read the values
    
      BCSCTL1 	= CALBC1_12MHZ;
      DCOCTL	= CALDCO_12MHZ;					// Now set clock frequency at 6MHz
    
    
    
    //// End of initialization
    
    // Main Body of Code
      _BIS_SR(GIE);								// Global interrupt enable
    
    // set values to force compare
      PriorDirection = 12000;
      PriorDutyCycle = 12000;
    
    
    // initial setup of direction to avoid time delay
      Direction = ((P2IN & DIR) >> 7);	// read direction if 0 -- forward else reverse
      if (Direction != PriorDirection)
      	{
    	  UpdateSpeed(0);					// stop the motor first then restart in new direction
    										//Set Direction
    	  PriorDirection = Direction;
      	}
    
    // end of setup, beginning of main loop
    		TA1CCTL1 = OUTMOD_0 | BIT2;
    		TA1CCTL2 = OUTMOD_0 | BIT2;
    //		UpdateSpeed(DutyCycle);  //Check Speed Wheel once before looping
    
      for (;;)
        {
    	  	  Direction = 0;
    		ADC10CTL0 |= ENC + ADC10SC;		// Read Speed value from ADC -- Sampling and conversion start
    		UpdateSpeed(DutyCycle);  //Check Speed Wheel
    		// Delay for 30ms per outer loop or 420ms
    		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
    		{
    		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
    		  {__no_operation();
    		  }
    		}
    
    		Direction =1;
    		ADC10CTL0 |= ENC + ADC10SC;		// Read Speed value from ADC -- Sampling and conversion start
    		UpdateSpeed(DutyCycle);  //Check Speed Wheel
    
    		// Delay for 30ms per outer loop or 420ms
    		for (delayloop2 = 14; delayloop2 > 0; delayloop2 --)
    		{
    		  for (delayloop1 = 24000; delayloop1 > 0; delayloop1--)
    		  {__no_operation();
    		  }
    		}
    
        }
    }
    
    ///////////////////////////////// Interrupt service routines ////////////////////////
    
    // ADC10 interrupt service routine
    #pragma vector=ADC10_VECTOR
    __interrupt void ADC10_ISR(void)
    {
    	  DutyCycle = (ADC10MEM & 0x3f8) >> 3;	// discard the last 3 bits ~25mV/bit and
    	  	  	  	  	  	  	  	  	  	  	// shift right one to match 511 max
    	  P1OUT ^= STATUS_LED;           		// Toggle LED
    }
    
    
    
    #pragma vector=PORT1_VECTOR, PORT2_VECTOR, USCIAB0TX_VECTOR, USCIAB0RX_VECTOR, \
    		TIMER0_A1_VECTOR, TIMER0_A0_VECTOR, WDT_VECTOR, COMPARATORA_VECTOR, \
    		TIMER1_A1_VECTOR, TIMER1_A0_VECTOR, NMI_VECTOR
    __interrupt void Trap_ISR(void)
    {
    	  // this is a trap ISR - check for the interrupt cause here by
    	  // checking the interrupt flags, if necessary also clear the interrupt
    	  // flag
    }
    

  • Reading through this again I see what you are referring to about the 250ms. The code is supposed to change direction of the motor every 400ms. I'm not quite sure why the scope isn't triggering on the first rising edge though. I do see a little overlap during the transition which isn't expected and also where the peak current is so perhaps the code could be modified to remove that overlap and reduce the current?
  • Hi George,

    I did not see anything in the code provided. It appears as though only two inputs to the DRV8850 should toggle while the other two are static.

    Can you explain what isn't working with the motors on the DRV8834? I think I missed something.

    The DRV8850 does have the built in LDO, which is a nice feature. The DRV8850EVM is available to provide guidance on connections and layout of the device.
  • Hi Rick:

    Yes, I'm using the DRV8850EVM although for the DRV8834 I was using a modified Pololu module based on the DRV8834. When using that the motor would start to whine once I got past about 80% PWM.

    I noticed in the original code that it stopped the motor before changing direction but I eliminated that. I didn't get a chance to work on this today but I'll try again tomorrow and zoom into that section where it changes direction and maybe play with the code a little to see how it impacts the current consumption.

    George
  • Hi George,

    Above 80%, you may have been hitting overcurrent protection. The overcurrent protection can operate at about 800Hz; the retry time is 1.2ms.

    The DRV8850 should not have that problem as it can drive much more current.
  • I think that was what was happening as I saw glitches on the FAULT pin but the current measurements weren't showing that it should be tripped.

    I just ran a quick test where I stop the motor before changing direction and curiously I saw a slight increase in power consumption. Peak voltage went up about 50mV and "power" increased from ~350mAs to ~3780mAs