SPRUJ26A September   2021  – April 2024

 

  1.   1
  2.   Abstract
  3.   Trademarks
  4. 1Introduction
  5. 2Motor Control Theory
    1. 2.1 Mathematical Model and FOC Structure of PMSM
    2. 2.2 Field Oriented Control of PM Synchronous Motor
    3. 2.3 Sensorless Control of PM Synchronous Motor
      1. 2.3.1 Enhanced Sliding Mode Observer with Phase Locked Loop
        1. 2.3.1.1 Design of ESMO for PMSM
        2. 2.3.1.2 Rotor Position and Speed Estimation With PLL
    4. 2.4 Hardware Prerequisites for Motor Drive
      1. 2.4.1 Motor Phase Voltage Feedback
    5. 2.5 Additional Control Features
      1. 2.5.1 Field Weakening (FW) and Maximum Torque Per Ampere (MTPA) Control
      2. 2.5.2 Flying Start
  6. 3Running the Universal Lab on TI Hardware Kits
    1. 3.1 Supported TI Motor Evaluation Kits
    2. 3.2 Hardware Board Setup
      1. 3.2.1  LAUNCHXL-F280025C Setup
      2. 3.2.2  LAUNCHXL-F280039C Setup
      3. 3.2.3  LAUNCHXL-F2800137 Setup
      4. 3.2.4  TMDSCNCD280025C Setup
      5. 3.2.5  TMDSCNCD280039C Setup
      6. 3.2.6  TMDSCNCD2800137 Setup
      7. 3.2.7  TMDSADAP180TO100 Setup
      8. 3.2.8  DRV8329AEVM Setup
      9. 3.2.9  BOOSTXL-DRV8323RH Setup
      10. 3.2.10 BOOSTXL-DRV8323RS Setup
      11. 3.2.11 DRV8353RS-EVM Setup
      12. 3.2.12 BOOSTXL-3PHGANINV Setup
      13. 3.2.13 DRV8316REVM Setup
      14. 3.2.14 TMDSHVMTRINSPIN Setup
      15.      34
      16.      35
    3. 3.3 Lab Software Implementation
      1. 3.3.1 Importing and Configuring Project
      2.      38
      3.      39
      4. 3.3.2 Lab Project Structure
      5. 3.3.3 Lab Software Overview
    4. 3.4 Monitoring Feedback or Control Variables
      1. 3.4.1 Using DATALOG Function
      2. 3.4.2 Using PWMDAC Function
      3. 3.4.3 Using External DAC Board
    5. 3.5 Running the Project Incrementally Using Different Build Levels
      1. 3.5.1 Level 1 Incremental Build
        1. 3.5.1.1 Build and Load Project
        2. 3.5.1.2 Setup Debug Environment Windows
        3. 3.5.1.3 Run the Code
      2. 3.5.2 Level 2 Incremental Build
        1. 3.5.2.1 Build and Load Project
        2. 3.5.2.2 Setup Debug Environment Windows
        3. 3.5.2.3 Run the Code
      3. 3.5.3 Level 3 Incremental Build
        1. 3.5.3.1 Build and Load Project
        2. 3.5.3.2 Setup Debug Environment Windows
        3. 3.5.3.3 Run the Code
      4. 3.5.4 Level 4 Incremental Build
        1. 3.5.4.1 Build and Load Project
        2. 3.5.4.2 Setup Debug Environment Windows
        3. 3.5.4.3 Run the Code
  7. 4Building a Custom Board
    1. 4.1 Building a New Custom Board
      1. 4.1.1 Hardware Setup
      2. 4.1.2 Migrating Reference Code to a Custom Board
        1. 4.1.2.1 Setting Hardware Board Parameters
        2. 4.1.2.2 Modifying Motor Control Parameters
        3. 4.1.2.3 Changing Pin Assignment
        4. 4.1.2.4 Configuring the PWM Module
        5. 4.1.2.5 Configuring the ADC Module
        6. 4.1.2.6 Configuring the CMPSS Module
        7. 4.1.2.7 Configuring Fault Protection Function
      3. 4.1.3 Adding Additional Functionality to Motor Control Project
        1. 4.1.3.1 Adding Push Buttons Functionality
        2. 4.1.3.2 Adding Potentiometer Read Functionality
        3. 4.1.3.3 Adding CAN Functionality
    2. 4.2 Supporting New BLDC Motor Driver Board
    3. 4.3 Porting Reference Code to New C2000 MCU
  8.   A Appendix A. Motor Control Parameters
  9.   References
  10.   Revision History

Adding CAN Functionality

CAN functionality can be added into the lab project to provide the user a communication bus for sending the start/stop command and getting the feedback running states. To utilize this, enable the pre-define symbol CMD_CAN_EN in project build properties as shown in Figure 3-19. The detailed steps are as the followings.

  1. Add the CAN source files to the project. Right-click on the project name in the CCS project explorer window, and select “Add Files.” Next, navigate to the following folder and select “Link to Files”.

    <install_location>\c2000ware\driverlib\f28002x\driverlib\can.c

  2. Edit the HAL_Obj to add canHandle in the hal_obj.h header file.
    typedef struct _HAL_Obj_
    {
      uint32_t       adcHandle[2];      //!< the ADC handles
    ... ...
      uint32_t       canHandle;         //!< the CAN handle
    ... ...
    } HAL_Obj;
  3. Initialize the CAN handles in the HAL_init() function in the hal.c file.
    HAL_Handle HAL_init(void *pMemory,const size_t numBytes)
    {
    ... ...
        // initialize CAN handle
        obj->canHandle = CANA_BASE;             //!< the CAN handle
    ... ... 
        return(handle);
    } // end of HAL_init() function
  4. Prototype the CAN setup function in the communication.h file as the following code.
    //! \brief     Sets up the CANA
    //! \param[in] handle  The hardware abstraction layer (HAL) handle
    extern void HAL_setupCANA(HAL_Handle handle);
  5. Define the CAN setup functions in the communication.c file as the following code.
    void HAL_setupCANA(HAL_Handle halHandle)
    {
        HAL_Obj *obj = (HAL_Obj *)halHandle;
    
        // Initialize the CAN controller
        CAN_initModule(obj->canHandle);
    
        // Set up the CAN bus bit rate to 200kHz
        // Refer to the Driver Library User Guide for information on how to set
        // tighter timing control. Additionally, consult the device data sheet
        // for more information about the CAN module clocking.
        CAN_setBitRate(obj->canHandle, DEVICE_SYSCLK_FREQ, 500000, 16);
    
        // Initialize the transmit message object used for sending CAN messages.
        // Message Object Parameters:
        //      Message Object ID Number: 1
        //      Message Identifier: 0x1
        //      Message Frame: Standard
        //      Message Type: Transmit
        //      Message ID Mask: 0x0
        //      Message Object Flags: Transmit Interrupt
        //      Message Data Length: 8 Bytes
        CAN_setupMessageObject(CANA_BASE, TX_MSG_OBJ_ID, 0x1, CAN_MSG_FRAME_STD,
                               CAN_MSG_OBJ_TYPE_TX, 0, CAN_MSG_OBJ_TX_INT_ENABLE,
                               MSG_DATA_LENGTH);
    
        // Initialize the receive message object used for receiving CAN messages.
        // Message Object Parameters:
        //      Message Object ID Number: 2
        //      Message Identifier: 0x1
        //      Message Frame: Standard
        //      Message Type: Receive
        //      Message ID Mask: 0x0
        //      Message Object Flags: Receive Interrupt
        //      Message Data Length: 8 Bytes
        CAN_setupMessageObject(obj->canHandle, RX_MSG_OBJ_ID, 0x1, CAN_MSG_FRAME_STD,
                               CAN_MSG_OBJ_TYPE_RX, 0, CAN_MSG_OBJ_RX_INT_ENABLE,
                               MSG_DATA_LENGTH);
    
        // Start CAN module operations
        CAN_startModule(obj->canHandle);
    
        return;
    }  // end of HAL_setupCANA() function
    Note: The various CAN module parameters are to be initialized according to the system needs, and the above is just a simple reference.
  6. Enable the appropriate CAN peripheral clocks in the HAL setup clocks function HAL_setupPeripheralClks() of the hal.c file.
       SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_CANA);
  7. Configure the related GPIOs to CAN function in HAL_setupGpios() function of the hal.c file.
        // GPIO33->CAN_TX
        GPIO_setPinConfig(GPIO_32_CANA_TX);
        GPIO_setDirectionMode(32, GPIO_DIR_MODE_OUT);
        GPIO_setPadConfig(32, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(32, GPIO_QUAL_ASYNC);
    
        // GPIO33->CAN_RX
        GPIO_setPinConfig(GPIO_33_CANA_RX);
        GPIO_setDirectionMode(33, GPIO_DIR_MODE_IN);
        GPIO_setPadConfig(33, GPIO_PIN_TYPE_STD);
        GPIO_setQualificationMode(33, GPIO_QUAL_ASYNC);
  8. Prototype the CAN interrupt setup function in the communication.h file.
    extern void HAL_enableCANInts(HAL_Handle handle);
  9. Define the CAN interrupt setup function.
    void HAL_enableCANInts(HAL_Handle handle)
    {
        HAL_Obj *obj = (HAL_Obj *)handle;
    
        // Enable CAN test mode with external loopback
    //     CAN_enableTestMode(CANA_BASE, CAN_TEST_EXL);    // Only for debug
    
        // Enable interrupts on the CAN peripheral.
        CAN_enableInterrupt(obj->canHandle, CAN_INT_IE0 | CAN_INT_ERROR |
                            CAN_INT_STATUS);
    
    
        // enable the PIE interrupts associated with the CAN interrupts
        Interrupt_enable(INT_CANA0);
    
    
        CAN_enableGlobalInterrupt(obj->canHandle, CAN_GLOBAL_INT_CANINT0);
    
        // enable the cpu interrupt for CAN interrupts
        Interrupt_enableInCPU(INTERRUPT_CPU_INT9);
    
        return;
    } // end of HAL_enableCANInts() function
  10. Call the CAN setup function and the CAN interrupt setup function in the sys_main.c file.
        // setup the CAN
        HAL_setupCANA(halHandle);
        // setup the CAN interrupt
        HAL_enableCANInts(halHandle);
  11. Prototype the CAN interrupt service (ISR) routine in the communication.h file.
    extern __interrupt void canaISR(void);
  12. Add the CAN interrupt service (ISR) routine vector to the PIE table in initCANCOM() in the communication.c file.
        Interrupt_register(INT_CANA0, &canaISR);
  13. To place the CAN ISR code in flash and run from RAM for accelerating the execution speed by adding the following code in the communication.c file.
    #pragma CODE_SECTION(canaISR, ".TI.ramfunc");
  14. Define the CAN interrupt routine canaISR() in the communication.c file. Define the canaIS() function that has been prototyped and passed to the PIE vector table. The example code below provides a function to receive/transmit the message data with CAN and clears the interrupt in the PIE, allowing the CAN interrupt to be triggered again.
    __interrupt void canaISR(void)
    {
    ... ...
        // Check if the cause is the transmit message object 1
        // Check if the cause is the transmit message object 1
        else if(status == TX_MSG_OBJ_ID)
        {
            //
            // Getting to this point means that the TX interrupt occurred on
            // message object 1, and the message TX is complete.  Clear the
            // message object interrupt.
            //
            CAN_clearInterruptStatus(CANA_BASE, TX_MSG_OBJ_ID);
    
            // Increment a counter to keep track of how many messages have been
            // sent.  In a real application this could be used to set flags to
            // indicate when a message is sent.
            canComVars.txMsgCount++;
    
            // Since the message was sent, clear any error flags.
            canComVars.errorFlag = 0;
        }
    
        // Check if the cause is the receive message object 2
        else if(status == RX_MSG_OBJ_ID)
        {
            //
            // Get the received message
            //
            CAN_readMessage(halHandle->canHandle, RX_MSG_OBJ_ID,
                            (uint16_t *)(&canComVars.rxMsgData[0]));
    
            // Getting to this point means that the RX interrupt occurred on
            // message object 2, and the message RX is complete.  Clear the
            // message object interrupt.
            CAN_clearInterruptStatus(halHandle->canHandle, RX_MSG_OBJ_ID);
    
            canComVars.rxMsgCount++;
            canComVars.flagRxDone = true;
    
            // Since the message was received, clear any error flags.
            canComVars. errorFlag = 0;
        }
    ... ... 
        // Clear the global interrupt flag for the CAN interrupt line
        CAN_clearGlobalInterruptStatus(halHandle->canHandle, CAN_GLOBAL_INT_CANINT0);
    
        // Acknowledge this interrupt located in group 9
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    
        return;
    }
    
  15. Prototype and define updateCANCmdFreq() in the communication.h file and the communication.c file separately. The CAN bus received and transmitting data is processed and linked to motor control variables in updateCANCmdFreq().
    void updateCANCmdFreq(MOTOR_Handle handle)
    {
    ...
    }
  16. Call updateCANCmdFreq() in endless loop.
    updateCANCmdFreq(motorHandle_M1);
    
    if((motorVars_M1.cmdCAN.flagEnablCmd == true) && (motorVars_M1.faultMtrUse.all == 0))
    {
    	canComVars.flagCmdTxRun = motorVars_M1.cmdCAN.flagCmdRun;
    	canComVars.speedSet_Hz = motorVars_M1.cmdCAN.speedSet_Hz;
    
    	if(motorVars_M1.cmdCAN.flagEnablSyncLead == true)
    	{
    		motorVars_M1.flagEnableRunAndIdentify = motorVars_M1.cmdCAN.flagCmdRun;
    		motorVars_M1.speedRef_Hz = motorVars_M1.cmdCAN.speedSet_Hz;
    	}
    	else
    	{
    		motorVars_M1.flagEnableRunAndIdentify = canComVars.flagCmdRxRun;
    		motorVars_M1.speedRef_Hz = canComVars.speedRef_Hz;
    	}
    }