Other Parts Discussed in Thread: TMS570LS1227, INSTASPIN-BLDC, DRV8301
Hello,
I had posted on this forum before regarding using the DRV8301 Kit with the Instaspin-BLDC solution and avoiding the use of a GUI. However, I have gone through two different TMS570LS1227 control cards, both of which have become unresponsive (
) and am wondering whether the issue is with my modified code or some other factor.
Essentially what I had done in the code is modify it to remove the gGUIObj object and graphing modules, and in all instances where the the GUI object values are assigned to DRV object values, I have replaced this with hardcoded values to simulate a specific configuration of the GUI that a user could select.
The files I modified were Sys_main.c, drv.c, and drv.h.
One thing I suspect (but cannot test as I don't have any working MCU with me yet) is that in DRV_init, commenting out the while loop that waits for the TPS flag might have affected the TPS65381 power supply, but as the code did not brick the device during the debug session itself, this may not be the case.
The most notable change was replacing the DRV_run function with the GUI_run function with a custom_run function that is defined the drv.h file.
I also changed the adc_notification interrupt so that it calls custom_run instead of gui_run.
I have attached all three files here with comments regarding changes and would greatly appreciate any insights about obvious errors or oversights that may be breaking the TMS570 boards. I would go through and uncomment various lines to test again myself, but as each board is quite expensive it would be best to have another opinion on what the issue could be before I try again.
/*
*
* Omkar Version 7/7/16
*
* This file contains the main function, for FOC motor control
*/
/* (c) Texas Instruments 2009-2012, All rights reserved. */
/* USER CODE BEGIN (0) */
//! \file ~/solutions/instaspin_bldc/boards/drv8301kit_revD/hercules/tms570ls1227/projects/ccs5/project01/src/sys_main.c
//!
//! \brief Main system file for the three phase sensored speed SMO project
//!
//! (C) Copyright 2012, Texas Instruments, Inc.
// **************************************************************************
// the includes
#include "sys_main.h"
/* USER CODE END */
#include "sys_common.h"
#include "system.h"
/* USER CODE BEGIN (1) */
// **************************************************************************
// the globals
DRV_Handle drvHandle; // Handle to the Inverter driver object
//GUI_Handle guiHandle; // Handle to the GUI object //***
//GRAPH_DATA graph; //Omkar
//GRAPH_Handle graphHandle = &graph;//Omkar
//float32_t DlogCh1 = 0;//Omkar
//float32_t DlogCh2 = 0;//Omkar
//float32_t DlogCh3 = 0;//Omkar
//float32_t DlogCh4 = 0;//Omkar
//int32_t GraphInput = 0;//Omkar
/* USER CODE END */
/** @fn void main(void)
* @brief Application main function
* @note This function is empty by default.
*
* This function is called after startup.
* The user can use this function to implement the application.
*/
/* USER CODE BEGIN (2) */
// **************************************************************************
// the functions
/* USER CODE END */
void main(void)
{
/* USER CODE BEGIN (3) */
_mpuInit_();
(*(volatile unsigned int *)(0xFFFFEA38))=0x83E70B13;
(*(volatile unsigned int *)(0xFFFFEA3C))=0x95A4F1E0;
(*(volatile unsigned int *)(0xFFFFEB88))=0x00000002;//ADC Alternate Trigger
//enable all ePWM s + TZ + ECAP1,2,3,4 + EQEP1+EQEP2
*(volatile unsigned int *) 0xFFFFEBA4 = 0x01010102; // Enable TBCLK 37[1]
*(volatile unsigned int *) 0xFFFFEB10 = 0x08010801; // nTZ1 0[19], nTZ2 0[27],
*(volatile unsigned int *) 0xFFFFEB18 = 0x04010110; // ETPWM1A 2[26], EQEP2I 2[4]
*(volatile unsigned int *) 0xFFFFEB1C = 0x01040101; // ETPWM1B 3[18]
*(volatile unsigned int *) 0xFFFFEB20 = 0x20200104; // ETPWM2A 4[2], EQEP2A 4[21], EQEP2B 4[29]
*(volatile unsigned int *) 0xFFFFEB24 = 0x01080404; // ETPWM2B 5[2], ETPWM3A 5[10], ETPWM3B 5[19]
*(volatile unsigned int *) 0xFFFFEB2C = 0x01040101; // ETPWM5A 7[18]
*(volatile unsigned int *) 0xFFFFEB30 = 0x01040104; // ETPWM5B 8[2], ECAP1 8[18]
*(volatile unsigned int *) 0xFFFFEB34 = 0x01010801; //EQEP1B 9[11], SPI3CS0/EQEP1I 9[16/19]
*(volatile unsigned int *) 0xFFFFEB40 = 0x20100101; // ECAP4 12[20],ECAP5 12[29]
*(volatile unsigned int *) 0xFFFFEB40 = 0x04010101; // ECAP6 13[26]
*(volatile unsigned int *) 0xFFFFEB54 = 0x01010110; // nTZ3 17[4]
*(volatile unsigned int *) 0xFFFFEB5C = 0x01010801; // EQEP2S 19[11]
*(volatile unsigned int *) 0xFFFFEB60 = 0x01100101; // EQEP1S 20[20]
*(volatile unsigned int *) 0xFFFFEB7C = 0x01010104; // ETPWM4A 27[2]
*(volatile unsigned int *) 0xFFFFEB94 = 0x01010102; // ETPWM4B 33[1], SPI3SOMI/ECAP2 33[8/10], SPI3SIMO/ECAP3 33[16/18],SPI3CLK/EQEP1A 33[24/26]
*(volatile unsigned int *) 0xFFFFEB98 = 0x01020201; // ETPWM6A 34[9], ETPWM6B 34[17]
*(volatile unsigned int *) 0xFFFFEB8C =0x01010102;//SRC=110, A2 31[1]
(*(volatile unsigned int *)(0xFFFFEA38))=0x0;
(*(volatile unsigned int *)(0xFFFFEA3C))=0x0;
// guiHandle = GUI_init(&gGUIObj,sizeof(gGUIObj)); //***
// initialize the driver
drvHandle = DRV_init(&drv,sizeof(drv), T);
// initialize the graph module (data logger)
// graph.ch1Ptr = &DlogCh1; //***
// graph.ch2Ptr = &DlogCh2;//***
// graph.ch3Ptr = &DlogCh3;//***
// graph.ch4Ptr = &DlogCh4;//***
// graph.trigValue = 0.0;//***
// graph.size = 0x00FF;//***
// graph.holdoff = 3;//***
// graph.prescalar = 5;//***
// Graph_Data_Init(graphHandle); //***
// initialize the gui
// GUI_setup(guiHandle, drvHandle) // GUI_setup(guiHandle, drvHandle, graphHandle); //***
// Send SPI commands to DRV8301 to set it up
spiREG3->DAT1 = 0x13D0;
while((spiREG3->FLG & 0x100)!=0x100);
drv.SPI3_RXDATA[0] = (spiREG3->BUF) & 0xFF;
spiREG3->DAT1 = 0x8000;
while((spiREG3->FLG & 0x100)!=0x100);
drv.SPI3_RXDATA[1] = (spiREG3->BUF) & 0xFF;
spiREG3->DAT1 = 0x180D;
while((spiREG3->FLG & 0x100)!=0x100);
drv.SPI3_RXDATA[2] = (spiREG3->BUF) & 0xFF;
spiREG3->DAT1 = 0x8000;
while((spiREG3->FLG & 0x100)!=0x100);
drv.SPI3_RXDATA[3] = (spiREG3->BUF) & 0xFF;
while((GetChar(drv.ecmpHandle) != '2') && (!drv.tpsFlag));
drv.enableFlag = 1; //*** modified to skip the if statement
/* if(!gGUIObj.TPSFlag) //***
{
gGUIObj.DutyCmd = 0;
gGUIObj.TorqueCmd = 0;
gGUIObj.SpdCmd = 0;
gGUIObj.EnableFlg = 1;
PutText(drv.ecmpHandle, "Motor Enabled\r\n");
} *
// Endless loop to wait for start command from either GUI or button
//while(DRV_get_Enable(drvHandle) != 1){ //*** commented in order to allow automation and avoid need for GUI or button command
//custom_run(drvHandle); // GUI_run((GUI_Handle)&gGUIObj, drvHandle); //GUI_run((GUI_Handle)&gGUIObj, drvHandle, graphHandle); //***
//}
// Start the PWMs and Interrupt
DRV_Motor_start(drvHandle);
// Enable the peripheral interrupt notifications
gioEnableNotification(0);
gioEnableNotification(1);
adcEnableNotification(adcREG1, adcGROUP1);
adcEnableNotification(adcREG1, adcGROUP2);
// Drop into main while loop
drv.ADC_INT_ENA=1; // this is where the interrupts are enabled
while(1)
{
drv.SCI_Command = '3'; //drv.SCI_Command = GetChar(drv.ecmpHandle); ////*** modified such that the switch statement will default to voltage mode
switch (drv.SCI_Command)
{
case '3':
drv.controlMode = 0; // gGUIObj.CtrlType = 0; //***
drv.ref = 0.5; // gGUIObj.DutyCmd = 0.3; //***
PutText(drv.ecmpHandle, "Duty Cycle Mode Enabled\r\n");
break;
/*case '4':
gGUIObj.CtrlType = 1;
gGUIObj.TorqueCmd = 0.3;
PutText(drv.ecmpHandle, "Current Mode Enabled\r\n");
break;
case '5':
gGUIObj.CtrlType = 2;
gGUIObj.SpdCmd = 0.3;
PutText(drv.ecmpHandle, "Velocity Mode Enabled\r\n");
break;
case '6':
gGUIObj.CtrlType = 3;
gGUIObj.SpdCmd = 0.3;
PutText(drv.ecmpHandle, "Cascade (Current + Velocity) Mode Enabled\r\n");
break;
case '7':
gGUIObj.DutyCmd = 0;
gGUIObj.CtrlType = 0;
gGUIObj.SpdCmd = 0;
gGUIObj.TorqueCmd = 0;
PutText(drv.ecmpHandle, "Motor Stopped\r\n");
break;
case '8':
drv.ecmpHandle->DiagFlag = !drv.ecmpHandle->DiagFlag;
PutText(drv.ecmpHandle, "Watchdog Diagnostics Flag Toggled\r\n");
break;*/
}
if(drv.Process_WDA==1)
{
ecmpWdQaSendAnswer(drv.ecmpHandle, 0, 0, 0);
drv.Process_WDA = 0;
}
// Run the GUI interface
custom_run(drvHandle); // GUI_run((GUI_Handle)&gGUIObj, drvHandle);// GUI_run((GUI_Handle)&gGUIObj, drvHandle, graphHandle); //***
}
/* USER CODE END */
}
/* USER CODE BEGIN (4) */
/********************************************************************************
ADC Notification
********************************************************************************/
void adcNotification(adcBASE_t *adc, uint32_t group)
{
//Run the Motor
DRV_EnableMotor(drvHandle);
custom_run(drvHandle); //*** modified to replace GUI_run
//Log data
/* switch (GraphInput) {
case 0:
default:
DlogCh1 = (float) drv.mod6Handle->counter;
DlogCh2 = (float) drv.instaHandle->vInt;
DlogCh3 = (float) drv.iqVaIn;
DlogCh4 = (float) drv.iDCFdbk;
// ------------------------------------------------------------------------------
// Update data logger
// ------------------------------------------------------------------------------
// Graph_Data_Update(graphHandle);
*/
} // end of the interrupt
// Here are dummy functions for the HALCoGen generated drivers
/********************************************************************************
RTI Notification (a dummy-function for the compiler, no affects)
********************************************************************************/
void rtiNotification(uint32_t notification)
{
switch(notification)
{
case 4 :
if(drv.ADC_INT_ENA==0)
{
ecmpWdQaSendAnswer(drv.ecmpHandle, 0, 0, 0);
}
else
{
drv.Process_WDA = 1;
}
break;
}
return;
}
/********************************************************************************
ESM Notification (a dummy-function for the compiler, no affects)
********************************************************************************/
void esmGroup1Notification(uint32_t channel){return;}
void esmGroup2Notification(uint32_t channel){return;}
void hetNotification(hetBASE_t *het, uint32_t offset){return;}
/* USER CODE END */
/* --COPYRIGHT--,BSD
* Copyright (c) 2012, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --/COPYRIGHT--*/
//! \file ~/solutions/instaspin_bldc/boards/drv8301kit_revD/hercules/tms570ls1227/src/drv.c
//! \brief Contains the various functions related to the DRV object
//!
//! (C) Copyright 2011, Texas Instruments, Inc.
// **************************************************************************
// the includes
#include "solutions/instaspin_bldc/boards/drv8301kit_revD/hercules/src/drv.h"
//#include "solutions/instaspin_bldc/boards/drv8301kit_revD/hercules/src/gui.h"
// **************************************************************************
// the defines
// **************************************************************************
// the globals
DRV_Obj drv;
MOD6CNT gMod6;
RMP3 gRMP3;
SPEED_MEAS_CAP gSpeed;
INSTASPIN_BLDC gInstaSPIN;
IMPULSE gImpulse;
PID_Obj gPIDSpd;
PID_Obj gPIDIDC;
RMPCNTL_Obj gRMPCntl;
STATEFILTER gStateFilter;
ECMP_Obj gECMP;
// **************************************************************************
// the functions
//! \brief Initializes the driver (DRV) object
//! \param[in] pMemory A pointer to the memory for the driver object
//! \param[in] numBytes The number of bytes allocated for the driver object, bytes
//! \param[in] period interrupt period
//! \return The driver (DRV) object handle
DRV_Handle DRV_init(void *pMemory,const size_t numBytes, const float32_t period)
{
DRV_Handle drvHandle;
DRV_Obj *drv;
if(numBytes < sizeof(DRV_Obj))
return((DRV_Handle)NULL);
// assign the handle
drvHandle = (DRV_Handle)pMemory;
// assign the object
drv = (DRV_Obj *)drvHandle;
// Initializations
gioInit(); //Initialize GIO module
spiInit(); //Initialize SPI module
adcInit(); //Initialize ADC module
rtiInit(); //Initialize RTI module
//delay 50ms while HET starts up
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
while(rtiGetCurrentTick(rtiCOMPARE0) < 50000);
rtiStopCounter(rtiCOUNTER_BLOCK0);
drv->ecmpHandle = ECMPInit(&gECMP, sizeof(gECMP));
ECMPSetup(drv->ecmpHandle);
(*(volatile unsigned int *)(0xFFFFFF0C))=1;
(*(volatile unsigned int *)(0xFFFFFF04))=1;
/* avoid TPS65381 to transit to ACTIVE operating state */
while(!ecmpStayinDIAGState(drv->ecmpHandle));
// while(wait); /* set cursor to next line to continue - prevents reset chain */
while(!ecmpGetWriteAccess(drv->ecmpHandle));
sciInit();
if(ecmpReadRegister(drv->ecmpHandle, RD_SAFETY_STAT5) == 0x04)
{
PutText(drv->ecmpHandle, "TPS65381 is NOT in DIAG state, toggle IGN!\n\r");
while(1);
}
PutText(drv->ecmpHandle, "1 - Enable Watchdog\n\r");
PutText(drv->ecmpHandle, "2 - Enable Motor\n\r");
PutText(drv->ecmpHandle, "3 - Start Motor in Duty Cycle Mode\n\r");
PutText(drv->ecmpHandle, "4 - Start Motor in Current Mode\n\r");
PutText(drv->ecmpHandle, "5 - Start Motor in Velocity Mode\n\r");
PutText(drv->ecmpHandle, "6 - Start Motor in Cascade (Current + Velocity) Mode\n\r");
PutText(drv->ecmpHandle, "7 - Stop Motor\n\r");
PutText(drv->ecmpHandle, "8 - Toggle Watchdog Diagnostics Flag\n\r");
//delay 50ms
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
while(rtiGetCurrentTick(rtiCOMPARE0) < 500000);
rtiStopCounter(rtiCOUNTER_BLOCK0);
// Set IO to enable DRV8301
gioSetDirection(gioPORTA, 0x00000010U);
gioSetBit(gioPORTA, 4, 1);
//wait until a command from HyperTermal to force the TPS65381 device into active mode
//while((GetChar(drv->ecmpHandle)!='1') && (!drv.tpsFlag));// *** commented because there is no manual toggling of the TPS Flag in automatic mode. The TPS flag is set to 1 in the run function. This is the code I suspect may be causing an issue.
PutText(drv->ecmpHandle, "Start Watchdog\r\n");
//delay 50ms
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
while(rtiGetCurrentTick(rtiCOMPARE0) < 500000);
rtiStopCounter(rtiCOUNTER_BLOCK0);
/* select desired WD mode - time in mu seconds */
ecmpWdQaInit(drv->ecmpHandle, 45000, 18000);
ecmpWdStart(drv->ecmpHandle);
//delay 50ms
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
while(rtiGetCurrentTick(rtiCOMPARE0) < 500000);
rtiStopCounter(rtiCOUNTER_BLOCK0);
while(gioGetBit(gioPORTA, 4)==0);
(*(volatile unsigned int *)(0xFFFFFF0C))=0;
//delay 50ms while DRV8301 powers up
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
while(rtiGetCurrentTick(rtiCOMPARE0) < 500000);
rtiStopCounter(rtiCOUNTER_BLOCK0);
drv->ecmpHandle->DiagFlag = 0;
// initialize connection between the CTRL and PWM modules
drv->gPwmData.Tabc.value[0] = 0;
drv->gPwmData.Tabc.value[1] = 0;
drv->gPwmData.Tabc.value[2] = 0;
// initialize pwm module
drv->pwmHandle[0] = PWM_init((void *)PWM_ePWM2_BASE_ADDR,sizeof(PWM_Obj));
drv->pwmHandle[1] = PWM_init((void *)PWM_ePWM3_BASE_ADDR,sizeof(PWM_Obj));
drv->pwmHandle[2] = PWM_init((void *)PWM_ePWM4_BASE_ADDR,sizeof(PWM_Obj));
// Setup drv object
DRV_setup(drvHandle, period);
return(drvHandle);
} // end of DRV_init() function
//! \brief Setup the driver module to default values
//! \param[in] handle The driver (DRV) handle
//! \param[in] period FOC, period
void DRV_setup(DRV_Handle handle, const float32_t period)
{
DRV_Obj *drv = (DRV_Obj *) handle;
// setup the PWMs
DRV_setupPwms(handle, T, vCNT_SCALE);
// // Setup current calibration constants
drv->cal_offset_A = 0x7FF0;
drv->cal_offset_B = 0x7FF0;
drv->ref = 0.3;
drv->currentDisplay = 0.0;
drv->dFuncStartup = 0.1;
drv->currentStartup = 0.1;
drv->threshold = 0.10;
drv->currentKp = 0.08982;
drv->velocityKp = 0.75;
drv->iMax = 0.95;
drv->rampUpTime = 25;
drv->commErrorMax = 1.0;
drv->tripCnt = 3;
drv->advancedStartup = 0;
drv->speedRPM = 0;
drv->beginStartRPM = 50;
drv->endStartRPM = 100;
drv->currentMode = 0;
drv->velocityMode = 0;
drv->controlMode = drv->currentMode + drv->velocityMode;
drv->resetFault = 0;
drv->poles = 8;
drv->currentKi = 100;
drv->velocityKi = 3;
drv->currentKd = 0;
drv->velocityKd = 0;
drv->prescaler = 1;
drv->runBLDCInt = 0;
drv->overVoltage = 0;
drv->drvFaultFlag = 0;
drv->drvOTWFlag = 0;
drv->enableFlag = FALSE;
drv->vDCBus = 0;
drv->maxVDC = 2880; //1302
drv->minVDC = 1920;
drv->floatCounter = 0.0;
drv->baseFreq = 200; // Base electrical frequency (Hz)
drv->rampStartRate = (PWM_FREQUENCY*1000)*60.0/drv->beginStartRPM/COMMUTATES_PER_E_REV/(drv->poles/2.0);
drv->rampEndRate = (PWM_FREQUENCY*1000)*60.0/drv->endStartRPM/COMMUTATES_PER_E_REV/(drv->poles/2.0);
drv->cmtnPeriodTarget = drv->rampEndRate;
drv->cmtnPeriodSetpt = drv->rampStartRate;
drv->virtualTimer = 0;
drv->speedLoopFlag = FALSE;
drv->rampDelay = 1;
drv->speedRef= 0.0;
drv->iDCOffset = 0.5;
drv->iRef = 0.0;
drv->isrTicker = 0;
drv->calibrateFlag = 0;
drv->calibrateTime = 0x7FFF;
drv->dLogCurrElementIndex = 0;
drv->bemfTrigCnt = 0;
drv->bemfLastTrigCnt = 0;
drv->goodTrigCnt = 0;
drv->goodTrigCntTrip = 20;
drv->closedCommutationFlag = 0;
drv->mod6Handle = &gMod6;
drv->rmp3Handle = &gRMP3;
drv->impulseHandle = &gImpulse;
drv->pidSpdHandle = &gPIDSpd;
drv->pidIDCHandle = &gPIDIDC;
drv->instaHandle = &gInstaSPIN;
drv->speedHandle = &gSpeed;
drv->rmpCntlHandle = &gRMPCntl;
drv->instaHandle->stateFilter = &gStateFilter;
drv->ecmpHandle = &gECMP;
MOD6CNT_Setup(drv->mod6Handle);
PID_setGains(drv->pidIDCHandle, drv->currentKp, (drv->currentKi * T), (drv->currentKd / T));
PID_setMinMax(drv->pidIDCHandle, -0.95, 0.95);
PID_setGains(drv->pidSpdHandle, drv->velocityKp, (drv->velocityKi * T), (drv->velocityKd / T));
PID_setMinMax(drv->pidSpdHandle, -0.71, 0.71);
RMP3_Setup(drv->rmp3Handle);
IMPULSE_Setup(drv->impulseHandle);
INSTASPIN_Setup(drv->instaHandle);
SPEED_MEAS_CAP_Setup(drv->speedHandle);
RMPCNTL_Setup(drv->rmpCntlHandle);
// Initialize the SPEED_PR module
drv->speedHandle->inputSelect = 0;
drv->speedHandle->baseRPM = 120*(drv->baseFreq / drv->poles);
drv->speedHandle->speedScaler = (uint32_t)(PWM_FREQUENCY / (1 * (float32_t)drv->baseFreq * 0.001));
SPEED_MEAS_CAP_Calc(drv->speedHandle);
// Initialize RMPCNTL module
drv->rmpCntlHandle->rampDelayMax = 1;
drv->rmpCntlHandle->rampLowLimit = -1.0;
drv->rmpCntlHandle->rampHighLimit = 1.0;
RMPCNTL_Calc(drv->rmpCntlHandle);
// Initialize RMP3 module
drv->rmp3Handle->desiredInput = drv->cmtnPeriodTarget;
drv->rmp3Handle->ramp3Delay = (uint32_t)(((float32_t)drv->rampUpTime * 0.001)/((float32_t)(drv->cmtnPeriodSetpt - drv->cmtnPeriodTarget) * T));
drv->rmp3Handle->out = drv->cmtnPeriodSetpt;
drv->rmp3Handle->ramp3Min = drv->cmtnPeriodTarget;
RMP3_Calc(drv->rmp3Handle);
//Initialize the INSTASPIN_BLDC module
drv->instaHandle->vaOffset = 0;
drv->instaHandle->vbOffset = 0;
drv->instaHandle->vcOffset = 0;
drv->instaHandle->intThreshold = drv->threshold;
drv->pidIDCHandle->refValue = drv->ref;
drv->pidSpdHandle->refValue = drv->ref;
// Initialize the current offset calibration filter
drv->calFiltGain = (T / (T + TC_CAL));
drv->spdFiltGain = (T / (T + TC_SPD));
}
//void DRV_setupPwms(DRV_Handle handle,const uint_least16_t systemFreq_MHz,const float32_t pwmPeriod_usec)
void DRV_setupPwms(DRV_Handle handle, const float32_t ISRperiod, const int32_t het_vCNT_SCALE)
{
DRV_Obj *obj = (DRV_Obj *)handle;
uint16_t halfPeriod_cycles = ((ISRperiod*het_vCNT_SCALE)/2)*128;
uint8_t cnt;
PWM_setOneShotTrip(obj->pwmHandle[0]);// Disable PWM A leg
PWM_setOneShotTrip(obj->pwmHandle[1]);// Disable PWM B leg
PWM_setOneShotTrip(obj->pwmHandle[2]);// Disable PWM C leg
for(cnt=0;cnt<3;cnt++)
{
// setup the Time-Base Control Register (TBCTL)
PWM_setCounterMode(obj->pwmHandle[cnt],PWM_CounterMode_UpDown);
PWM_disableCounterLoad(obj->pwmHandle[cnt]);
PWM_setPeriodLoad(obj->pwmHandle[cnt],PWM_PeriodLoad_Immediate);
PWM_setSyncMode(obj->pwmHandle[cnt],PWM_SyncMode_EPWMxSYNC);
PWM_setHighSpeedClkDiv(obj->pwmHandle[cnt],PWM_HspClkDiv_by_1);
PWM_setClkDiv(obj->pwmHandle[cnt],PWM_ClkDiv_by_1);
PWM_setPhaseDir(obj->pwmHandle[cnt],PWM_PhaseDir_CountUp);
PWM_setRunMode(obj->pwmHandle[cnt],PWM_RunMode_FreeRun);
// setup the Timer-Based Phase Register (TBPHS)
PWM_setPhase(obj->pwmHandle[cnt],0);
// setup the Time-Base Counter Register (TBCTR)
PWM_setCount(obj->pwmHandle[cnt],0);
// setup the Time-Base Period Register (TBPRD)
// set to zero initially
PWM_setPeriod(obj->pwmHandle[cnt],0);
// setup the Counter-Compare Control Register (CMPCTL)
PWM_setLoadMode_CmpA(obj->pwmHandle[cnt],PWM_LoadMode_Zero);
PWM_setLoadMode_CmpB(obj->pwmHandle[cnt],PWM_LoadMode_Zero);
PWM_setShadowMode_CmpA(obj->pwmHandle[cnt],PWM_ShadowMode_Shadow);
PWM_setShadowMode_CmpB(obj->pwmHandle[cnt],PWM_ShadowMode_Shadow);
// setup the Action-Qualifier Output A Register (AQCTLA)
PWM_setActionQual_CntUp_CmpA_PwmA(obj->pwmHandle[cnt],PWM_ActionQual_Set);
PWM_setActionQual_CntDown_CmpA_PwmA(obj->pwmHandle[cnt],PWM_ActionQual_Clear);
// setup the Dead-Band Generator Control Register (DBCTL)
PWM_setDeadBandOutputMode(obj->pwmHandle[cnt],PWM_DeadBandOutputMode_EPWMxA_Rising_EPWMxB_Falling);
PWM_setDeadBandPolarity(obj->pwmHandle[cnt],PWM_DeadBandPolarity_EPWMxB_Inverted);
// setup the Dead-Band Rising Edge Delay Register (DBRED)
PWM_setDeadBandRisingEdgeDelay(obj->pwmHandle[cnt],DRV_PWM_DBRED_CNT);
// setup the Dead-Band Falling Edge Delay Register (DBFED)
PWM_setDeadBandFallingEdgeDelay(obj->pwmHandle[cnt],DRV_PWM_DBFED_CNT);
// setup the PWM-Chopper Control Register (PCCTL)
PWM_disableChopping(obj->pwmHandle[cnt]);
// setup the Trip Zone Select Register (TZSEL)
PWM_disableTripZones(obj->pwmHandle[cnt]);
}
// setup the Event Trigger Selection Register (ETSEL)
PWM_disableInt(obj->pwmHandle[0]);
PWM_setSocAPulseSrc(obj->pwmHandle[0],PWM_SocPulseSrc_CounterEqualZero);
PWM_enableSocAPulse(obj->pwmHandle[0]);
// setup the Event Trigger Prescale Register (ETPS)
PWM_setSocAPeriod(obj->pwmHandle[0],PWM_SocPeriod_FirstEvent);
// setup the Event Trigger Clear Register (ETCLR)
PWM_clearIntFlag(obj->pwmHandle[0]);
PWM_clearSocAFlag(obj->pwmHandle[0]);
// since the PWM is configured as an up/down counter, the period register is set to one-half
// of the desired PWM period
PWM_setPeriod(obj->pwmHandle[0],halfPeriod_cycles);
PWM_setPeriod(obj->pwmHandle[1],halfPeriod_cycles);
PWM_setPeriod(obj->pwmHandle[2],halfPeriod_cycles);
return;
} // end of DRV_setupPwms() function
// end of file
/* --COPYRIGHT--,BSD
* Copyright (c) 2012, Texas Instruments Incorporated
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* --/COPYRIGHT--*/
//NEW WORKSPACE VERSION- SANS GUI
#ifndef _DRV_H_
#define _DRV_H_
//! \file ~/solutions/instaspin_bldc/boards/drv8301kit_revD/hercules/tms570ls1227/src/drv.h
//! \brief Contains public interface to various functions related
//! to the DRV object
//!
//! (C) Copyright 2011, Texas Instruments, Inc.
// **************************************************************************
// the includes
// **************************************************************************
// the modules
#include "modules/types/src/32b/controller_data_types.h"
#include "modules/instaspin_bldc/src/float32/hercules/champion/InstaSPIN_BLDC.h"
#include "modules/mod6/src/float32/hercules/mod6_cnt.h"
#include "modules/rmp3/src/float32/hercules/rmp3cntl.h"
#include "modules/speed_pr/src/float32/hercules/speed_pr.h"
#include "modules/impulse/src/float32/hercules/impulse.h"
#include "modules/rmpcntl/src/float32/hercules/rmp_cntl.h"
#include "modules/dlog/src/float32/hercules/DLOG.h"
#include "modules/pid/src/float32/hercules/pid.h"
#include "modules/ecmp/src/float32/champion/ecmp.h"
// **************************************************************************
// the drivers
#include "drivers/gio/src/32b/hercules/champion/gio.h"
#include "drivers/adc/adc_bldc/src/32b/hercules/champion/adc.h"
#include "drivers/rti/src/32b/hercules/champion/rti.h"
#include "drivers/pwm/pwm_bldc/src/32b/hercules/champion/epwm.h"
#include "drivers/het/pwm_bldc/src/32b/hercules/champion/het.h"
#include "drivers/spi/src/32b/hercules/champion/spi.h"
//!
//! \defgroup DRV
//!
//! \ingroup DRV
//@{
#ifdef __cplusplus
extern "C"
{
#endif
// **************************************************************************
// the defines
#define VOLTAGE 0 //open-loop volage mode only
#define CURRENT 1 //closed-loop current control
#define VELOCITY 2 //closed-loop velocity control
#define CASCADE 3 //cascaded closed-loop velocity->current control
#define DISABLED 4 //disabled mode, all PWMs off
#define fs 20000.0 //Interrupt
#define PWM_FREQUENCY 20 //PWM Frequency
#define COMMUTATES_PER_E_REV 6.0 //Commutations per electrical revolution
#define T 1.0/fs //Interrupt period
#define WC_CAL 100.0 //Calibration filter cutoff
#define TC_CAL 1/WC_CAL //Time constant for cutoff
#define WC_SPD 1200.0 //Cutoff for speed display filter
#define TC_SPD 1/WC_SPD //Time constant for speed display filter
#define vCNT_SCALE 610000 //scaling constant based on system clock divided by 128
// HET States for PWM logic
#define ALL_PHASES_OFF 0x401BA000
#define PHASE_A_OFF 0x401BA550
#define PHASE_B_OFF 0x401BA505
#define PHASE_C_OFF 0x401BA055
//! \brief Defines the PWM deadband falling edge delay count (system clocks)
//!
#define DRV_PWM_DBFED_CNT 10 //
//! \brief Defines the PWM deadband rising edge delay count (system clocks)
//!
#define DRV_PWM_DBRED_CNT 10 //
// **************************************************************************
// the typedefs
//! \brief Defines the PWM data
//!
typedef struct _DRV_PwmData_t_
{
MATH_vec3 Tabc; //!< the PWM time-durations for each motor phase
} DRV_PwmData_t;
//! \brief Defines the driver (DRV) object
//!
typedef struct _DRV_Obj_
{
//PWM_Handle pwmISync;
PWM_Handle pwmHandle[3];
//PWM_SYNC_Handle pwmSyncHandle;
float32_t currentSync;
uint32_t hetIOstate;
DRV_PwmData_t gPwmData;
ADC_Data_t adcData;
adcData_t AdcResults1[16];
adcData_t AdcResults2[16];
int32_t cal_offset_A;
int32_t cal_offset_B;
float32_t iqVaIn;
float32_t iqVbIn;
float32_t iqVcIn;
float32_t iDCFdbk;
uint32_t rtiCounterValue;
float32_t rtiBenchmarkTime;
uint32_t gdFaultStatus;
uint32_t bridgeFaultFlg;
uint32_t overVoltageFlg;
uint32_t overTempFlg;
uint32_t firstFaultRstEval;
uint32_t faultDisableFlag;
H_MOD6CNT mod6Handle;
RMP3_handle rmp3Handle;
SPEED_MEAS_CAP_handle speedHandle;
H_INSTASPIN_BLDC instaHandle;
IMPULSE_handle impulseHandle;
PID_Handle pidSpdHandle;
PID_Handle pidIDCHandle;
RMPCNTL_handle rmpCntlHandle;
ECMP_handle ecmpHandle;
int8_t SCI_Command;
int32_t ADC_INT_ENA;
int32_t Process_WDA;
uint16_t SPI3_RXDATA[4];
int32_t isrTicker;
uint32_t virtualTimer;
uint16_t previousState;
uint16_t speedLoopFlag;
uint32_t cmtnPeriodTarget;
uint32_t cmtnPeriodSetpt;
uint32_t rampDelay;
uint16_t closedCommutationFlag;
uint32_t bemfTrigCnt;
uint32_t bemfLastTrigCnt;
uint16_t goodTrigCnt;
uint16_t goodTrigCntTrip;
uint16_t controlMode;
uint16_t currCtrlType;
uint16_t prevCtrlType;
uint16_t calibrateFlag;
uint16_t calibrateTime;
uint16_t runBLDCInt;
float32_t rampStartRate;
float32_t rampEndRate;
int16_t dLogCurrElementIndex;
float32_t iDCOffset;
float32_t speedRef;
float32_t calFiltGain;
float32_t spdFiltGain;
float32_t dFuncTesting;
float32_t iqDuty;
float32_t iRef;
float32_t dFuncRun;
float32_t commErrorMax;
float32_t ref;
float32_t currentDisplay;
float32_t dFuncStartup;
float32_t currentStartup;
float32_t threshold;
float32_t currentKp;
float32_t velocityKp;
float32_t iMax;
float32_t speed;
int32_t speedRPM;
int32_t beginStartRPM;
int32_t endStartRPM;
uint16_t currentMode;
uint16_t velocityMode;
uint16_t resetFault;
uint16_t poles;
uint16_t currentKi;
uint16_t velocityKi;
uint16_t currentKd;
uint16_t velocityKd;
uint16_t prescaler;
uint16_t baseFreq;
uint16_t rampUpTime;
uint16_t tripCnt;
uint16_t advancedStartup;
int16_t overVoltage;
int16_t drvFaultFlag;
int16_t drvOTWFlag;
int16_t enableFlag;
float32_t vDCBus;
float32_t maxVDC;
float32_t minVDC;
float32_t floatCounter;
float32_t pidSpdValue;
float32_t pidIDCValue;
int16_t tpsFlag;
} DRV_Obj;
//! \brief Defines the DRV handle
//!
typedef struct DRV_Obj *DRV_Handle;
// **************************************************************************
// the globals
//! \brief Defines the DRV object
//!
extern DRV_Obj drv;
// **************************************************************************
// the function prototypes
//! \brief Initializes the driver (DRV) object
//! \param[in] pMemory A pointer to the memory for the driver object
//! \param[in] numBytes The number of bytes allocated for the driver object, bytes
//! \param[in] period FOC, period
//! \return The driver (DRV) object handle
DRV_Handle DRV_init(void *pMemory, const size_t numBytes, const float32_t period);
//! \brief Sets up the driver module to default values
//! \param[in] handle The driver (DRV) handle
//! \param[in] period FOC, period
void DRV_setup(DRV_Handle handle, const float32_t period);
/*!
* @ingroup Generate_Outputs
* @fn void Generate_Outputs(DRV_Handle drvHandle)
* @brief Function to determine the duty cycle and output necessary PWMs
* @param [in] drvHandle The Handler for the DRV System
* @param [in] drvHandle The Handler for the DRV System
* @param [in] duty The commanded duty cycle for the pwm
* @param [in] state The commutation state
* @param [out] pwmData_out The switching waveforms in duty cycle
* @param [out] currentSyncOut The duty cycle of the current sampling (used if ADC2 is used for Itotal sampling)
* @param [out] hetIOstateOut The active IO for the PWM signals (one phase has to be disabled)
*/
void Generate_Outputs(DRV_Handle drvHandle, float32_t duty, int32_t state, MATH_vec3 *pwmData_out, float32_t *currentSyncOut, uint32_t *hetIOstateOut);
//! \brief Updates the gate driver fault status
//! \param[in] handle The drv handle
inline void DRV_update_gdFaultStatus(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
drv->gdFaultStatus = (gioGetPort(gioPORTB) >> 2);
drv->gdFaultStatus &= 0x00000003; //BIT 1: Faultn, BIT 0: OCTWn
// Latch in fault conditions
switch(drv->gdFaultStatus){
case 0: //Over temperature latched shutdown
drv->bridgeFaultFlg = 0;
drv->overVoltageFlg = 0;
drv->overTempFlg = 1;
break;
case 1: //Over current or undervoltage latched shutdown
drv->bridgeFaultFlg = 1;
drv->overVoltageFlg = 0;
drv->overTempFlg = 0;
break;
case 2: //Over temperature warning
drv->bridgeFaultFlg = 0;
drv->overVoltageFlg = 0;
drv->overTempFlg = 1;
break;
case 3: //No fault condition
drv->bridgeFaultFlg = 0;
drv->overVoltageFlg = 0;
drv->overTempFlg = 0;
break;
default:
break;
}
}
//! \brief Resets gate driver and clears gate driver fault
//! \param[in] handle The drv handle
inline void DRV_gdFaultReset(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
// Dessert EN_GATE for 5uS to reset gate driver
gioSetBit(gioPORTA, 4, 0);
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
while(rtiGetCurrentTick(rtiCOMPARE0) < 4); //1 ticks = 1uS
rtiStopCounter(rtiCOUNTER_BLOCK0);
gioSetBit(gioPORTA, 4, 1);
// Clear fault flags
drv->bridgeFaultFlg = 0;
drv->overVoltageFlg = 0;
drv->overTempFlg = 0;
drv->faultDisableFlag = 0;
}
//! \brief Handles resets and stopping the motor.
//! \param[in] handle The drv handle
inline void DRV_EnableMotor(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
if(drv->enableFlag == FALSE)
{
drv->runBLDCInt=0;
//shut down all PWMs
PWM_setOneShotTrip(drv->pwmHandle[0]);// Disable PWM A leg
PWM_setOneShotTrip(drv->pwmHandle[1]);// Disable PWM B leg
PWM_setOneShotTrip(drv->pwmHandle[2]);// Disable PWM C leg
//hetREG1->DIR = ALL_PHASES_OFF; JPB
// Reset any falts
DRV_gdFaultReset(handle);
//zero all displayed variables when disabled
drv->speedRPM = 0;
drv->speedHandle->speedRPM = 0;
drv->speedHandle->speed = 0;
drv->currentDisplay = 0;
drv->calibrateFlag = 0;
drv->instaHandle->vaOffset = 0;
drv->instaHandle->vbOffset = 0;
drv->instaHandle->vcOffset = 0;
drv->iDCOffset = 0.5;
drv->speedLoopFlag = FALSE;
}
// if motor type is not defined
if((drv->enableFlag == TRUE) && (drv->runBLDCInt == FALSE))
{
// Read drv_SpeedRef Only when you have enabled the motor
drv->speedRef = drv->ref;
if((drv->runBLDCInt == 0) && (drv->drvFaultFlag == 0))
{
drv->speedHandle->inputSelect = 0;
drv->speedHandle->baseRPM = 120 * (drv->baseFreq / drv->poles);
drv->speedHandle->speedScaler = (uint32_t)(PWM_FREQUENCY / (1 * (float32_t)drv->baseFreq * 0.001));
drv->speedHandle->inputSelect = 0;
drv->speedHandle->newTimeStamp = 0;
drv->speedHandle->oldTimeStamp = 0;
drv->speedHandle->eventPeriod = 0;
drv->speedHandle->speed = 0;
drv->virtualTimer = 0;
drv->rmpCntlHandle->equalFlag = 0;
drv->rmpCntlHandle->rampDelayCount = 0;
drv->rmpCntlHandle->targetValue = 0;
//The speed at the end of the ramp should always be greater than the speed at the beginning of the ramp
if(drv->endStartRPM > drv->beginStartRPM)
{
drv->rampStartRate = (PWM_FREQUENCY * 1000) * 60.0 / drv->beginStartRPM /
COMMUTATES_PER_E_REV / (drv->poles / 2.0);
drv->rampEndRate = (PWM_FREQUENCY * 1000) * 60.0 / drv->endStartRPM /
COMMUTATES_PER_E_REV / (drv->poles / 2.0);
}
else
{
drv->rampStartRate = (PWM_FREQUENCY * 1000) * 60.0 / 50 / COMMUTATES_PER_E_REV / (drv->poles / 2.0);
drv->rampEndRate = (PWM_FREQUENCY * 1000) * 60.0 / 100 / COMMUTATES_PER_E_REV / (drv->poles / 2.0);
}
drv->cmtnPeriodTarget = drv->rampEndRate;
drv->cmtnPeriodSetpt = drv->rampStartRate;
drv->rmp3Handle->ramp3Delay = (uint32_t)(((float32_t)drv->rampUpTime * 0.001) /
((float32_t)(drv->cmtnPeriodSetpt - drv->cmtnPeriodTarget) * T));
drv->rmp3Handle->desiredInput = drv->cmtnPeriodTarget;
drv->rmp3Handle->out = drv->cmtnPeriodSetpt;
drv->rmp3Handle->ramp3Min = drv->cmtnPeriodTarget;
drv->rmp3Handle->ramp3DelayCount = 0;
drv->rmp3Handle->ramp3DoneFlag = 0;
drv->impulseHandle->counter = 0;
drv->impulseHandle->out = 0;
drv->mod6Handle->counter = 0;
drv->speedLoopFlag = FALSE;
drv->pidIDCHandle->Ui = 0;
drv->pidIDCHandle->refValue = 0;
drv->pidIDCHandle->fbackValue = 0;
drv->pidSpdHandle->Ui = 0;
drv->pidSpdHandle->refValue = 0;
drv->pidSpdHandle->fbackValue = 0;
drv->dFuncRun = drv->dFuncStartup;
drv->bemfTrigCnt = 0;
drv->bemfLastTrigCnt = 0;
drv->goodTrigCnt = 0;
drv->closedCommutationFlag = 0;
drv->instaHandle->vInt = 0;
//set control_mode based on check box settings from drv object
//VOLTAGE 0 //open-loop volage mode only
//CURRENT 1 //closed-loop current control
//VELOCITY 2 //closed-loop velocity control
//CASCADE 3 //cascaded closed-loop velocity->current control
//DISABLED 4 //Motor is disabled
//velocity loop check box writes either 0 (disabled) or 2 (enabled)
//current loop check box writes either 0 (disabled) or 1 (enabled)
drv->controlMode = drv->velocityMode + drv->currentMode;
drv->runBLDCInt=1;
}
}
}
//! \brief Runs the DRV object
//! \param[in] handle The driver (DRV) handle
inline void DRV_run(DRV_Handle handle)
{
DRV_Obj *obj = (DRV_Obj *) handle;
// ------------------------------------------------------------------------------
// Reset and Start the RTI for the control loop time measurement
// ------------------------------------------------------------------------------
rtiResetCounter(rtiCOUNTER_BLOCK0);
rtiStartCounter(rtiCOUNTER_BLOCK0);
// Update ADC object
adcGetData(adcREG1, adcGROUP1, obj->AdcResults1);
//adcGetData(adcREG1, adcGROUP2, obj->AdcResults2);
// ------------------------------------------------------------------------------
// Update gate driver fault status and protect system
// ------------------------------------------------------------------------------
DRV_update_gdFaultStatus(handle);
if (obj->faultDisableFlag == 0) {
obj->controlMode = DISABLED;
obj->faultDisableFlag = 1;
}
// ------------------------------------------------------------------------------
// Check for change in control mode from disabled to torque control/speed control
// ------------------------------------------------------------------------------
// Latch in change of control mode
if (obj->prevCtrlType != obj->currCtrlType ) {
// Attempt to clear motor fault condition
if ((obj->gdFaultStatus != 3) && (obj->firstFaultRstEval == 0)) {
DRV_gdFaultReset(handle);
obj->firstFaultRstEval = 1;
}
else if ((obj->gdFaultStatus != 3) && (obj->firstFaultRstEval == 1)) {
obj->prevCtrlType = obj->currCtrlType;
}
obj->prevCtrlType = obj->currCtrlType;
}
else {
obj->prevCtrlType = obj->controlMode;
obj->currCtrlType = obj->controlMode;
obj->firstFaultRstEval = 0;
}
//Get the DC Bus Volage
obj->vDCBus = (((float32_t)obj->AdcResults1[2].value) * 0.00024414);
// ------------------------------------------------------------------------------
// Run the InstaSpin Algorithm
// ------------------------------------------------------------------------------
if (obj->runBLDCInt == 1)
{
if (obj->calibrateFlag)
{
/* From TMS570_InstaSPIN */
// Get BEMF Values
obj->iqVaIn = (((float32_t)obj->AdcResults1[5].value) * 0.00024414) - obj->instaHandle->vaOffset;
obj->iqVbIn = (((float32_t)obj->AdcResults1[1].value) * 0.00024414) - obj->instaHandle->vbOffset;
obj->iqVcIn = (((float32_t)obj->AdcResults1[3].value) * 0.00024414) - obj->instaHandle->vcOffset;
// LPF to average the calibration offsets
// Use the offsets calculated here to initialize BemfA_offset, BemfB_offset
// and BemfC_offset so that they are used for the remaining build levels
obj->instaHandle->vaOffset = (obj->calFiltGain * obj->iqVaIn) + obj->instaHandle->vaOffset;
obj->instaHandle->vbOffset = (obj->calFiltGain * obj->iqVbIn) + obj->instaHandle->vbOffset;
obj->instaHandle->vcOffset = (obj->calFiltGain * obj->iqVcIn) + obj->instaHandle->vcOffset;
obj->iDCOffset = (obj->calFiltGain * obj->iDCFdbk) + obj->iDCOffset;
// Turn Off All PWMs
PWM_setOneShotTrip(obj->pwmHandle[0]);// Disable PWM A leg
PWM_setOneShotTrip(obj->pwmHandle[1]);// Disable PWM B leg
PWM_setOneShotTrip(obj->pwmHandle[2]);// Disable PWM C leg
//hetREG1->DIR = ALL_PHASES_OFF; JPB
obj->calibrateFlag++;
obj->calibrateFlag &= obj->calibrateTime;
}
else
{
/* From TMS570_InstaSPIN */
// Get BEMF Values
obj->iqVaIn = ((float32_t)obj->AdcResults1[5].value) * 0.00024414;
obj->iqVbIn = ((float32_t)obj->AdcResults1[1].value) * 0.00024414;
obj->iqVcIn = ((float32_t)obj->AdcResults1[3].value) * 0.00024414;
// Connect inputs of the MOD6 module and call the Modulo 6 counter function.
if (obj->ref > (0.0))
{
obj->mod6Handle->cntDirection = (1.0);
}
else
{
obj->mod6Handle->cntDirection = (-1.0);
}
obj->previousState = obj->mod6Handle->counter;
MOD6CNT_Calc(obj->mod6Handle);
// Connect inputs of the SPEED_PR module and call the speed calculation function.
// While counting up we want positive speed
if ((obj->mod6Handle->counter == 5) && (obj->previousState == 4) && (obj->mod6Handle->trigInput))
{
obj->speedHandle->curTimeStamp = obj->virtualTimer;
SPEED_MEAS_CAP_Calc(obj->speedHandle);
obj->speedLoopFlag = TRUE;
}
// While counting down we want negative speed
else if ((obj->mod6Handle->counter == 0) && (obj->previousState == 1) && (obj->mod6Handle->trigInput))
{
obj->speedHandle->curTimeStamp = obj->virtualTimer;
SPEED_MEAS_CAP_Calc(obj->speedHandle);
obj->speedHandle->speed = (obj->speedHandle->speed * (-1.0));
obj->speedHandle->speedRPM = (obj->speedHandle->speedRPM * (-1.0));
obj->speedLoopFlag = TRUE;
}
// Connect inputs of the INSTASPIN_BLDC module and call the INSTASPIN_BLDC function.
obj->instaHandle->vag = obj->iqVaIn - obj->instaHandle->vaOffset; // Adjust for offset of Va_in
obj->instaHandle->vbg = obj->iqVbIn - obj->instaHandle->vbOffset; // Adjust for offset of Vb_in
obj->instaHandle->vcg = obj->iqVcIn - obj->instaHandle->vcOffset; // Adjust for offset of Vc_in
obj->instaHandle->state = obj->mod6Handle->counter; // Update the state
InstaSPIN_BLDC_Calc(obj->instaHandle);
obj->mod6Handle->trigInput = obj->instaHandle->commTrig;
if ((obj->closedCommutationFlag == 0) || (obj->speedLoopFlag == FALSE))
{
// Connect inputs of the RMP3 module and call the Ramp control 3 function
RMP3_Calc(obj->rmp3Handle);
// Connect inputs of the IMPULSE module and call the Impulse function.
obj->impulseHandle->period = obj->rmp3Handle->out;
IMPULSE_Calc(obj->impulseHandle);
// Connect inputs of the MOD6 module and call the Modulo 6 counter function.
obj->mod6Handle->trigInput = obj->impulseHandle->out;
if (obj->advancedStartup)
{
// When the BEMF signals it's time to commutate, compare against the forced commutation period
if (obj->instaHandle->commTrig)
{
obj->bemfLastTrigCnt = obj->bemfTrigCnt;
obj->bemfTrigCnt = 0;
// Check if the forced commutation period and the BEMF commutation period
// are within the allowed error window
if (labs(obj->bemfLastTrigCnt - obj->impulseHandle->period) < obj->goodTrigCntTrip)
{
obj->goodTrigCnt++;
}
else
{
obj->goodTrigCnt = 0;
}
obj->bemfLastTrigCnt = 0;
}
else
{
obj->bemfTrigCnt++;
}
// Check if there are enough commutation matches to switch to closed commutation mode
if (obj->goodTrigCnt > obj->tripCnt)
{
obj->closedCommutationFlag = 1;
}
}
// If we're not using advanced startup just switch to closed commutation mode at the end of the startup ramp.
else if (obj->rmp3Handle->ramp3DoneFlag != 0)
{
obj->closedCommutationFlag = 1;
}
}
switch (obj->controlMode)
{
case VOLTAGE:
if (obj->closedCommutationFlag == 0)
{
obj->speedLoopFlag = 1; //no need to wait for speed feedback update in this mode.
obj->rmpCntlHandle->setpointValue = (obj->dFuncStartup * obj->mod6Handle->cntDirection);
}
else
{
// Connect inputs of the RMP module and call the Ramp control function.
obj->rmpCntlHandle->targetValue = obj->ref;
RMPCNTL_Calc(obj->rmpCntlHandle);
}
// Connect inputs of the PWM_DRV module and call the PWM signal generation update function.
Generate_Outputs(handle, obj->rmpCntlHandle->setpointValue, obj->instaHandle->state, &obj->gPwmData.Tabc, &obj->currentSync, &obj->hetIOstate);
break;
case CURRENT:
obj->iRef = obj->ref;
if (obj->closedCommutationFlag == 0)
{
obj->speedLoopFlag = 1;
// Use startup current during initial ramp
obj->iRef = (obj->currentStartup * obj->mod6Handle->cntDirection);
}
// Connect inputs of the PID_REG3 module and call the PID current controller function.
PID_run(obj->pidIDCHandle, obj->iRef, obj->iDCFdbk, &obj->pidIDCValue);
Generate_Outputs(handle, obj->pidIDCValue, obj->instaHandle->state, &obj->gPwmData.Tabc, &obj->currentSync, &obj->hetIOstate);
break;
case VELOCITY:
obj->speedRef = obj->ref;
// Connect inputs of the PID_REG3 module and call the PID current controller function.
// Switch from fixed duty-cycle or controlled Speed duty-cycle by SpeedLoopFlag variable
if ((obj->closedCommutationFlag == 0) || (obj->speedLoopFlag == FALSE))
{
obj->iqDuty = (obj->dFuncStartup * obj->mod6Handle->cntDirection); // Fixed duty-cycle
}
else
{
PID_run(obj->pidSpdHandle, obj->speedRef, obj->speedHandle->speed, &obj->pidSpdValue);
obj->iqDuty = obj->pidSpdValue;
}
// Generate the PWM and Reset outputs
Generate_Outputs(handle, obj->iqDuty, obj->instaHandle->state, &obj->gPwmData.Tabc, &obj->currentSync, &obj->hetIOstate);
break;
case CASCADE:
obj->speedRef = obj->ref;
if ((obj->closedCommutationFlag == 0) || (obj->speedLoopFlag == FALSE))
{
PID_run(obj->pidIDCHandle, (obj->currentStartup * obj->mod6Handle->cntDirection), obj->iDCFdbk, &obj->pidIDCValue);
}
else
{
// Connect Speed PID output to IDC PID input
PID_run(obj->pidSpdHandle, obj->speedRef, obj->speedHandle->speed, &obj->pidSpdValue);
PID_run(obj->pidIDCHandle, obj->pidSpdValue, obj->iDCFdbk, &obj->pidIDCValue);
}
Generate_Outputs(handle, obj->pidIDCValue, obj->instaHandle->state, &obj->gPwmData.Tabc, &obj->currentSync, &obj->hetIOstate);
break;
default:
// Connect inputs of the PWM_DRV module and call the PWM signal generation update function.
Generate_Outputs(handle, OFF, obj->instaHandle->state, &obj->gPwmData.Tabc, &obj->currentSync, &obj->hetIOstate);
break;
}
// convert pwm values from float to int16 and write the PWM data
PWM_write_CmpA(obj->pwmHandle[0],(int16_t)(obj->gPwmData.Tabc.value[0]*32768));
PWM_write_CmpA(obj->pwmHandle[1],(int16_t)(obj->gPwmData.Tabc.value[1]*32768));
PWM_write_CmpA(obj->pwmHandle[2],(int16_t)(obj->gPwmData.Tabc.value[2]*32768));
//PWM_write_Cmp(obj->pwmHandle[0], (int16_t) (obj->gPwmData.Tabc.value[0] * 32768));
//PWM_write_Cmp(obj->pwmHandle[1], (int16_t) (obj->gPwmData.Tabc.value[0] * 32768));
//PWM_write_Cmp(obj->pwmHandle[2], (int16_t) (obj->gPwmData.Tabc.value[1] * 32768));
//PWM_write_Cmp(obj->pwmHandle[3], (int16_t) (obj->gPwmData.Tabc.value[1] * 32768));
//PWM_write_Cmp(obj->pwmHandle[4], (int16_t) (obj->gPwmData.Tabc.value[2] * 32768));
//PWM_write_Cmp(obj->pwmHandle[5], (int16_t) (obj->gPwmData.Tabc.value[2] * 32768));
//PWM_write_Cmp(obj->pwmISync, (int16_t) (obj->currentSync * 32768));
//sync the PWMs and ADC
//PWM_Sync(obj->pwmSyncHandle);
//hetREG1->DIR = obj->hetIOstate;
//DC bus current
switch (obj->instaHandle->state) {
case 0:
case 1:
// positive current in A
obj->iDCFdbk = ((obj->AdcResults1[0].value << 4) - obj->cal_offset_A) * 0.0000305176;
break;
case 2:
case 3:
// positive current in B
obj->iDCFdbk = ((obj->AdcResults1[4].value << 4) - obj->cal_offset_B) * 0.0000305176;
break;
case 4:
// negative current in A
obj->iDCFdbk = ((obj->AdcResults1[0].value << 4) - obj->cal_offset_A) * -0.0000305176;
break;
case 5:
// negative current in B
obj->iDCFdbk = ((obj->AdcResults1[4].value << 4) - obj->cal_offset_B) * -0.0000305176;
break;
default:
obj->iDCFdbk = 0.0;
}
//Filter the displayed speed
obj->speed = (obj->spdFiltGain * (obj->speedHandle->speed - obj->speed)) + obj->speed;
obj->speedRPM = (obj->speedHandle->baseRPM * obj->speed);
obj->floatCounter = (float) obj->mod6Handle->counter;
// Increase virtual timer and force 15 bit wrap around
obj->virtualTimer++;
obj->virtualTimer &= 0x00007FFF;
obj->currentDisplay = obj->iDCFdbk;
obj->instaHandle->intThreshold = obj->threshold;
}
}
// ------------------------------------------------------------------------------
// Stop the RTI for the control loop time measurement
// ------------------------------------------------------------------------------
rtiStopCounter(rtiCOUNTER_BLOCK0);
obj->rtiCounterValue = rtiGetCurrentTick(rtiCOMPARE0);
obj->rtiBenchmarkTime = obj->rtiCounterValue * 0.001; // 1 tick corresponds to 1ms
return;
} // end of DRV_run() function
/*!
* @ingroup Generate_Outputs
* @fn void Generate_Outputs(DRV_Handle drvHandle)
* @brief Function to determine the duty cycle and output necessary PWMs
* @param [in] drvHandle The Handler for the DRV System
* @param [in] drvHandle The Handler for the DRV System
* @param [in] duty The commanded duty cycle for the pwm
* @param [in] state The commutation state
* @param [out] pwmData_out The switching waveforms in duty cycle
* @param [out] currentSyncOut The duty cycle of the current sampling (used if ADC2 is used for Itotal sampling)
* @param [out] hetIOstateOut The active IO for the PWM signals (one phase has to be disabled)
*/
inline void Generate_Outputs(DRV_Handle drvHandle, float32_t duty, int32_t state, MATH_vec3 *pwmData_out, float32_t *currentSyncOut, uint32_t *hetIOstateOut)
{
float32_t posDuty = duty;
float32_t negDuty = duty * -1;
static int32_t prevState;
// center the current sample pulse in the center of the PWM on time
*currentSyncOut = (float32_t)(posDuty*0.5);
//Ensure there is no cross talk when switching states
if(state != prevState)
{
PWM_setOneShotTrip(drv.pwmHandle[0]);// Disable PWM A leg
PWM_setOneShotTrip(drv.pwmHandle[1]);// Disable PWM B leg
PWM_setOneShotTrip(drv.pwmHandle[2]);// Disable PWM C leg
}
else
{
switch (state)
{
case (0):
// Phase C is off
PWM_clearOneShotTrip(drv.pwmHandle[0]);// Enable PWM A leg
PWM_clearOneShotTrip(drv.pwmHandle[1]);// Enable PWM B leg
PWM_setOneShotTrip(drv.pwmHandle[2]);// Disable PWM C leg
pwmData_out->value[1] = posDuty; // Phase B
pwmData_out->value[0] = negDuty; // Phase A
break;
case (1):
// Phase B is off
PWM_clearOneShotTrip(drv.pwmHandle[0]);// Enable PWM A leg
PWM_setOneShotTrip(drv.pwmHandle[1]);// Disable PWM B leg
PWM_clearOneShotTrip(drv.pwmHandle[2]);// Enable PWM C leg
pwmData_out->value[2] = posDuty; // Phase C
pwmData_out->value[0] = negDuty; // Phase A
break;
case (2):
// Phase A is off
PWM_setOneShotTrip(drv.pwmHandle[0]);// Disable PWM A leg
PWM_clearOneShotTrip(drv.pwmHandle[1]);// Enable PWM B leg
PWM_clearOneShotTrip(drv.pwmHandle[2]);// Enable PWM C leg
pwmData_out->value[2] = posDuty; // Phase C
pwmData_out->value[1] = negDuty; // Phase B
break;
case (3):
// Phase C is off
PWM_clearOneShotTrip(drv.pwmHandle[0]);// Enable PWM A leg
PWM_clearOneShotTrip(drv.pwmHandle[1]);// Enable PWM B leg
PWM_setOneShotTrip(drv.pwmHandle[2]);// Disable PWM C leg
pwmData_out->value[0] = posDuty; // Phase A
pwmData_out->value[1] = negDuty; // Phase B
break;
case (4):
// Phase B is off
PWM_clearOneShotTrip(drv.pwmHandle[0]);// Enable PWM A leg
PWM_setOneShotTrip(drv.pwmHandle[1]);// Disable PWM B leg
PWM_clearOneShotTrip(drv.pwmHandle[2]);// Enable PWM C leg
pwmData_out->value[0] = posDuty; // Phase A
pwmData_out->value[2] = negDuty; // Phase C
break;
case (5):
// Phase A is off
PWM_setOneShotTrip(drv.pwmHandle[0]);// Disable PWM A leg
PWM_clearOneShotTrip(drv.pwmHandle[1]);// Enable PWM B leg
PWM_clearOneShotTrip(drv.pwmHandle[2]);// Enable PWM C leg
pwmData_out->value[1] = posDuty; // Phase B
pwmData_out->value[2] = negDuty; // Phase C
break;
}
}
prevState = state;
} // end of Generate_Outputs() function
//! \brief Gets the status of the controller enable flag
//! \param[in] handle The controller (CTRL) handle
//! \return EnableFlg Current value of enable flag
inline uint16_t DRV_get_Enable(DRV_Handle handle)
{
DRV_Obj *obj = (DRV_Obj *) handle;
return (obj->enableFlag);
}
//! \brief Starts the Motor Controller
//! \param[in] handle The drv handle
inline void DRV_Motor_start(DRV_Handle handle)
{
DRV_Obj *obj = (DRV_Obj *)handle;
//QEP_Clear_Index(obj->qepIndexHandle);
adcStartConversion(adcREG1, adcGROUP1);
PWM_clearOneShotTrip(obj->pwmHandle[0]);// Enable PWM A leg
PWM_clearOneShotTrip(obj->pwmHandle[1]);// Enable PWM B leg
PWM_clearOneShotTrip(obj->pwmHandle[2]);// Enable PWM C leg
//if ((hetREG1->GCR & 1) == 0)
// hetREG1->GCR = 0x00030001U; // Start HET
return;
}
//! \brief Stops the Motor Controller (Not used in this project)
//! \param[in] handle The drv handle
inline void DRV_Motor_stop(DRV_Handle handle)
{
DRV_Obj *obj = (DRV_Obj *) handle;
//hetREG1->GCR = 0x00030000U; // Stop HET
//hetREG1->DOUT = 0x000A0000U; // Set PWM signals
adcStopConversion(adcREG1, adcGROUP1); // Stop ADC
adcStopConversion(adcREG1, adcGROUP2);
//QEP_Clear_Index(obj->qepIndexHandle);
//obj->gPwmData.Tabc.value[0] = 31 << 7; // Clear the PWM Compares
//obj->gPwmData.Tabc.value[1] = 31 << 7; // Clear the PWM Compares
//obj->gPwmData.Tabc.value[2] = 31 << 7; // Clear the PWM Compares
PWM_setOneShotTrip(obj->pwmHandle[0]);// Disable PWM A leg
PWM_setOneShotTrip(obj->pwmHandle[1]);// Disable PWM B leg
PWM_setOneShotTrip(obj->pwmHandle[2]);// Disable PWM C leg
return;
}
//! \brief Gets adcData
//! \param[in] handle The drv handle
//! \return adcData (phase current and voltage data)
inline ADC_Data_t DRV_get_adcData(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
return (drv->adcData);
}
//! \brief Gets rtiBenchmarkTime value
//! \param[in] handle The drv handle
//! \return rtiBenchmarkTime Current value of rti based FOC isr service time
inline float32_t DRV_get_rtiBenchmarkTime(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
return (drv->rtiBenchmarkTime);
}
//! \brief Gets the status of the driver bridgeFaultFlg
//! \param[in] handle The drv handle
//! \return EnableFlg Current value of bridgeFaultFlg
inline uint32_t DRV_get_bridgeFaultFlg(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
return( drv->bridgeFaultFlg);
}
//! \brief Gets the status of the driver overVoltageFlg
//! \param[in] handle The drv handle
//! \return EnableFlg Current value of overVoltageFlg
inline uint32_t DRV_get_overVoltageFlg(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
return( drv->overVoltageFlg);
}
//! \brief Gets the status of the driver overTempFlg
//! \param[in] handle The drv handle
//! \return EnableFlg Current value of overTempFlg
inline uint32_t DRV_get_overTempFlg(DRV_Handle handle)
{
DRV_Obj *drv = (DRV_Obj *) handle;
return( drv->overTempFlg);
}
inline void custom_run(DRV_Handle drvHandle){ // This is modeled after GUI_run but does not involve any gui related objects. **** This is the only edit made to the file
DRV_Obj *drv = (DRV_Obj *)drvHandle;
// Data Transfers happen here
// Change parameters
PID_setGains(drv->pidSpdHandle, PID_getProportionalGain(drv->pidSpdHandle), PID_getIntegralGain(drv->pidSpdHandle), PID_getDerivativeGain(drv->pidSpdHandle));
PID_setMinMax(drv->pidSpdHandle, -(PID_getSaturation(drv->pidSpdHandle)), PID_getSaturation(drv->pidSpdHandle));
PID_setGains(drv->pidIDCHandle, PID_getProportionalGain(drv->pidIDCHandle), PID_getIntegralGain(drv->pidIDCHandle),PID_getDerivativeGain(drv->pidIDCHandle));
PID_setMinMax(drv->pidIDCHandle, -(PID_getSaturation(drv->pidIDCHandle)), PID_getSaturation(drv->pidIDCHandle));
drv->threshold = 0.1;
drv->controlMode = 0; //Duty Cycle mode
drv->enableFlag = TRUE; //Always on
// Graph_set_prescalar(graphHandle, gui->LogScalar); //Omkar
switch( drv->controlMode )
{
case(CURRENT):
drv->ref = 0.3;
drv->currentMode = 1;
drv->velocityMode = 0;
break;
case(VELOCITY):
drv->ref = 0.3;
drv->currentMode = 0;
drv->velocityMode = 2;
break;
case(CASCADE):
drv->ref = 0.3;
drv->currentMode = 1;
drv->velocityMode = 2;
break;
default:
drv->ref = 0.3; //from sys_main.c in voltage mode
drv->currentMode = 0;
drv->velocityMode = 0;
break;
}
drv->dFuncStartup = 0.1;
drv->rampUpTime = 25;
drv->beginStartRPM = 50;
drv->endStartRPM = 100;
drv->advancedStartup = 0;
drv->commErrorMax = 1.0;
drv->tripCnt = 3;
drv->currentStartup = 0.1;
drv->iMax = 0.95;
drv->minVDC = 1920;
drv->maxVDC = 2880;
drv->tpsFlag = 1; //TPS Flag is set here but may be too late
return;
}
//! \brief Sets up the PWMs (Pulse Width Modulators)
//! \param[in] handle The driver (DRV) handle
//! \param[in] ISRperiod ISR period in sec
//! \param[in] het_vCNT_SCALE The scaler to the timer
void DRV_setupPwms(DRV_Handle handle, const float32_t ISRperiod, const int32_t het_vCNT_SCALE);
#ifdef __cplusplus
}
#endif // extern "C"
//@} // ingroup
#endif // end of _DRV_H_ definition
Thank you in advance,
Omkar