Sensorless FOC Motor Control Library Overview¶
1. Software Overview¶
Sensorless Field-Oriented Control (FOC) Library is made of three main layers: Application layer, HAL Layer, and MSPM0 DriverLib.
Fig. 1 Sensorless FOC Architecture¶
1.1 Application Layer Overview¶
The user specific applications (such as GUI) are present in this layer. From this layer, various instances of motor driver modules can be configured and used. If the user needs to perform any hardware specific actions, the user is recommended to use the APIs from HAL module.
1.2 HAL Module¶
Overview¶
The Hardware Abstraction Layer (HAL) creates an abstraction layer that provides APIs to configure different pins and peripherals. The goal of using HAL is to abstract all device specific configurations which simplifies porting of the library to various hardware by minimizing the updates needed to other components. The HAL is meant to abstract only the required pins or peripherals required for the application while still having flexibility and scalability for porting to other MSPM0 MCUs or motor drivers.
HAL is designed to have specific number of pins or channels associated with a peripheral. For example, consider the case of GPIOs. HAL has enum HAL_GPIO_OUT_PIN which has all the GPIO output pins as members as shown below.
/*! @enum HAL_GPIO_OUT_PIN */
typedef enum{
/*! Index associated to output GPIO PIN 0 */
HAL_GPIO_OUT_PIN_0 = 0,
/*! Index associated to output GPIO PIN 1 */
HAL_GPIO_OUT_PIN_1,
/*! Total number of output GPIO pins */
HAL_GPIO_OUT_PIN_MAX,
}HAL_GPIO_OUT_PIN;
To map the HAL GPIO pins to the real hardware pins, a structure is used which is indexed by the members of the HAL_GPIO_OUT_PIN enum. This structure stores various members like the port instance, pin name, etc. See below the gpioOUT structure which holds data on the port and pin.
gpioOUT[HAL_GPIO_OUT_PIN_0].iomux = GENERIC_GPIO_OUT_PINO_0_IOMUX;
gpioOUT[HAL_GPIO_OUT_PIN_0].port = GENERIC_GPIO_OUT_PORT;
gpioOUT[HAL_GPIO_OUT_PIN_0].pin = GENERIC_GPIO_OUT_PINO_0_PIN;
Note that GENERIC_GPIO_OUT_PINO_0_PIN is defined in the TI SysConfig generated files the specific line is shown below:
#define GENERIC_GPIO_OUT_PINO_0_PIN (DL_GPIO_PIN_26)
Thus, HAL_GPIO_OUT_PIN_0 indirectly refers to DL_GPIO_PIN_0, but the advantage of this mapping is that since TI SysConfig controls the generation of the GENERIC_GPIO_OUT_PINO_0_PIN, it is very easy to change the pin in the TI SysConfig GUI. The HAL automatically follows this without the user having to change any code in the HAL layer.
As seen above, when accessing the hardware through the HAL, we need to pass a HAL specific enum like HAL_GPIO_OUT_PIN_0. These enums are stored in the instances that access the HAL layer. In the case of the DRV8323RS motor driver, the instances of the important pins are initialized with its pins assigned to the HAL enums as shown in the snippet below.
drv8323rs.enable = HAL_GPIO_OUT_PIN_0;
drv8323rs.nfault = HAL_PWM_FAULT_0;
drv8323rs.spi = HAL_SPI_CHANNEL_0;
drv8323rs.spiCS = HAL_SPI_CS_2;
drv8323rs.vsenvm = HAL_ADC_CHANNEL_1;
drv8323rs.isena = HAL_ADC_CHANNEL_2;
drv8323rs.isenb = HAL_ADC_CHANNEL_0;
If the ENABLE pin needs to be set high, the API DRV8323RS_enable() is used and passes the DRV8323RS instance with it. The code snippet is shown below:
void DRV8323RS_enable(DRV8323RS_Instance *handle)
{
/* Enable the DRV8323RS */
HAL_setGPIOVal(handle->enable, HAL_GPIO_VALUE_HIGH);
/* Startup delay for the DRV8323RS SPI to be ready */
HAL_delayMilliSeconds(DRV8323RS_SPI_READY_DELAY_MS);
}
When DRV8323RS_enable() interacts with the HAL layer, it passes the member of the DRV8323RS instance. This is the same concept for using other HAL APIs such as the timer, SPI, DAC, etc. The user is free to expand the HAL’s API to support other peripherals and features of the MSPM0 but it is strongly recommended not to modify existing API to ensure easy migration to new versions of this library.
1.3 Motor Driver Module¶
Motor Driver Module uses the HAL APIs to motor driver specific operations APIs like SPI read, SPI write, voltage and current measurements. The idea of this module is to be independent of the hardware and use the HAL APIs to perform the hardware tasks specific to the motor driver.
Motor Driver Pin Association¶
The user before using the Motor Driver module is expected to specify the HAL enums mapped to the motor driver instance. See the below code snippet.
/* Assign the pins specific for the DRV */
drv8323rs.enable = HAL_GPIO_OUT_PIN_0;
drv8323rs.nfault = HAL_PWM_FAULT_0;
drv8323rs.spi = HAL_SPI_CHANNEL_0;
drv8323rs.spiCS = HAL_SPI_CS_2;
drv8323rs.vsenvm = HAL_ADC_CHANNEL_1;
drv8323rs.isena = HAL_ADC_CHANNEL_2;
drv8323rs.isenb = HAL_ADC_CHANNEL_0;
Motor Driver APIs¶
The Motor Driver Module provides simple APIs which the user can use along with an instance of the motor drive module. The motor driver module APIs also handles the motor driver specific logic while keeping the APIs generic, thus the user can use different motor drivers and not worry of any difference in the internal logic. For example, below is an API for updating the SPI registers in the drv8323rs.
void DRV8323RS_spiUpdateRegister(DRV8323RS_Instance *handle,
DRV8323RS_REG_ADDR addr, uint32_t mask, uint16_t data)
{
uint16_t dataValue;
dataValue = (uint16_t) DRV8323RS_spiRead(handle, addr);
dataValue &= ~(mask);
dataValue |= data;
DRV8323RS_spiWrite(handle, addr, dataValue);
}
Note from the above code snippet that any bit in the spi register in the DRV8323RS can be updated. The register address can be different for different devices, but here the enumerator DRV8323RS_REG_ADDR is used so the user doesn’t need to know the address of each register.
1.4 Sensorless FOC Library Module¶
Overview¶
The Sensorless FOC library contains generic algorithms for 3-phase sensorless FOC motor control. This module has APIs that the user can use to configure and control the FOC motor control. This module takes care of setting the PWM modulations based on the FOC algorithm. This module uses the HAL APIs for any using any hardware resources. The user is required to map the HAL PWM channels for the FOC module. Below is the code snippet that allocates the HAL PWM channels to the foc module.
/* Assign the pins specific for FOC */
foc.pwmAHal = HAL_PWM_CHANNEL_1;
foc.pwmBHal = HAL_PWM_CHANNEL_2;
foc.pwmCHal = HAL_PWM_CHANNEL_0;
1.5 MSPM0 DriverLib Overview¶
MSPM0 DriverLib is a set of fully functional APIs used to configure, control, and manipulate the hardware peripherals of the MSPM0 platform. Please refer to the DriverLib documentation for more information.
2. Software User Guide¶
The Sensorless FOC software can be used along with the CCS debug window. If the user wishes to use the software with GUI, please do look into the GUI user guide for the specific hardware.
2.1 Setting the Motor Parameters¶
The motor parameter can be found in the motor_parameter.h file. There are four motor parameters required for Sensorless FOC:
Stator resistance, Rs (ohm)
Stator inductance, Ls (H)
Number of motor poles
Base maximum RPM of the motor
Fig. 2 Locate motor parameter c file¶
These parameters are defined using an #elif statement for a motor. To define these parameters for a custom motor, modify the #define statements for MOTOR_PARA_RS, MOTOR_PARA_LS, MOTOR_PARA_POLES, and MOTOR_PARA_BASE_RPM for USER_MOTOR. To add another motor, copy and paste the #elif statement below and rename USER_MOTOR to another name.
#elif (USER_MOTOR)
/* Define the electrical motor parameters (User motor) */
/* @brief Stator resistance (ohm) */
#define MOTOR_PARA_RS 1.7
/* @brief Stator inductance (H) */
#define MOTOR_PARA_LS 0.004
/* @brief Number of poles */
#define MOTOR_PARA_POLES 8
/* @brief Base RPM */
#define MOTOR_PARA_BASE_RPM 5000
To select a motor defined in motor_params.h, click Project -> Properties in the toolbar. In the Properties window, go to Build -> Arm Compiler -> Predefined Symbols. The pre-defined motor name is LVSERVOMTR=1. To change the pre-defined motor name, click “Edit” and change LVSERVOMTR to another defined motor in motor_params.h, such as LVBLDCMTR or USER_MOTOR.
Fig. 3 Showing LVSERVOMTR=1 symbol¶
2.2 Setting the System Parameters¶
The initial parameters are found in the drv8323rs-gui.h file as #define GUI_DEFAULT_XXXX. The user is required to set the parameters as per the requirement. By default the default parameters are set for LVSERVOMTR motor.
Initial Parameters |
Description |
|---|---|
DRV_VDS_LVL |
VDS comparator threshold of DRV8323RS |
DRV_SEN_LVL |
OCP level for DRV8323RS |
DRV_CSA_GAIN |
CSA gain setting for DRV8323RS |
DRV_RSHUNT |
Rshunt resistor value in DRV8323RS |
FOC_RS |
Selected motor phase resistance for FOC |
FOC_LS |
Selected motor phase inductance for FOC |
FOC_POLES |
Selected motor poles for FOC |
FOC_BASE_RPM |
Selected Base rpm for FOC |
FOC_PWMFREQ |
PWM frequency for FOC |
FOC_PWMADCSAMPLE |
PWM counts spend in ADC sampling |
FOC_CNTRLDIV |
Control loop divider for FOC, only set to 1 |
FOC_DEADBAND |
Deadband in ns |
FOC_RSHUNT |
Rshunt resistor value |
FOC_VOLT_RATIO |
Bus voltage conversion ratio |
FOC_AMP_GAIN |
Current amplifier gain |
FOC_KSLIDE |
Kslide coefficient value |
FOC_PISPD_KP |
Proportional coefficient for PI controller for speed |
FOC_PISPD_KI |
Integral coefficient for PI controller for speed |
FOC_PISPD_MAX |
Maximum value output from PI controller for speed |
FOC_PISPD_MIN |
Minimum value output from PI controller for speed |
FOC_PISPD_DIV |
PI controller for speed Execution divider from FOC control loop frequency |
FOC_PIIQ_KP |
Proportional coefficient for PI controller for Iq |
FOC_PIIQ_KI |
Integral coefficient for PI controller for Iq |
FOC_PIIQ_MAX |
Maximum value output from PI controller for Iq |
FOC_PIIQ_MIN |
Minimum value output from PI controller for Iq |
FOC_PIID_KP |
Proportional coefficient for PI controller for Id |
FOC_PIID_KI |
Integral coefficient for PI controller for Id |
FOC_PIID_MAX |
Maximum value output from PI controller for Id |
FOC_PIID_MIN |
Minimum value output from PI controller for Id |
2.3 Selecting the Build levels¶
This software package uses an incremental system build to demonstrate a complete fixed-point sensorless Field Oriented control solution. There are 5 selectable build levels choices to incrementally verify the functioning.
Build Levels |
Description |
|---|---|
LEVEL1 |
Module functionality check out. |
LEVEL2 |
Verify ADC, park/clarke, calibrate the offset. |
LEVEL3 |
Verify closed current(torque) loop and PIDs and speed measurement. |
LEVEL4 |
Verify speed estimation and rotor position estimation. |
LEVEL5 |
Verify closed speed loop, speed PID and eSMO. |
To select a build level in foc.h, click Project -> Properties in the toolbar. In the Properties window, go to Build -> Arm Compiler -> Predefined Symbols. The pre-defined BUILDLEVEL name is LEVEL5. To change the pre-defined build level, click “Edit” and change LEVEL5 to another defined build level in foc.h.
Fig. 4 Build levels¶
Important Note¶
The build levels are only used for verifying the modules. While using a build level lower than LEVEL5, the user should only use the motor in a no-load condition. The user should use LEVEL5 as final build level for the user to test the motor in loaded conditions.
2.4 Variables for controlling motor¶
Below are the list of variables to include in the debug window for controlling the motor. Note, for variables in IQ24 type, set the type by right clicking the variables and changing to IQ type 24.
Variables |
Description |
Type |
|---|---|---|
enableFOC |
Control whether FOC is enabled or disabled. If set 0, PWM is disabled and the drive is in HighZ state. If set 1, The PWM output is set as per the FOC code. |
boolean |
lsw |
Controls the FOC state. If set 0, Aligns the motor to A phase. If set 1, Rotates the motor in open loop with speed from speedRef variable. If set 2, Rotates the motor in closed loop with speed from speedRef variable. lsw=2 is not applicable to Build levels other than LEVEL5 and should not be set. |
int |
idRef |
Set the align current in per unit. |
IQ24 |
iqRef |
Set the q axis current in lsw = 1 in per unit. |
IQ24 |
speedRef |
Sets the reference speed, used in open loop acceleration and in lsw = 2 |
IQ24 |
speedEst.EstimatedSpeed |
Display the estimated motor speed in per unit. |
IQ24 |
speedEst.EstimatedSpeedRpm |
Display the estimated motor speed in RPM. |
int |
piSpd.Kp |
Proportional constant in PI for Speed. |
IQ24 |
piSpd.Ki |
Integral constant in PI for Speed. |
IQ24 |
piId.Kp |
Proportional constant in PI for Id current. |
IQ24 |
piId.Ki |
Integral constant in PI for Id current. |
IQ24 |
piIq.Kp |
Proportional constant in PI for Iq current. |
IQ24 |
piIq.Ki |
Integral constant in PI for Iq current. |
IQ24 |
guiOverCurrentLimit |
Value of phase current in ampere above which software triggers overcurrent |
float |
guiVmOverVoltageLimit |
Value of voltage in volts above which software triggers overvoltage fault. |
float |
guiVmUnderVoltageLimit |
Value of voltage in volts below which software triggers undervoltage fault. |
float |
gui_faults.clearFault |
if set 1, clears all the fault bits. |
bool |
gui_faults.drvFault |
Set when drv fault is detected. |
bool |
gui_faults.uvlo |
Set when undervoltage is detected. |
bool |
gui_faults.ovlo |
Set when overvoltage is detected. |
bool |
gui_faults.ocp |
Set when overcurrent is detected. |
bool |
2.5 Running the motor¶
Below is the steps to run the motor:
Check if enableFOC = 0.
Check if any fault bit in the “gui_faults” structure is set. If any fault is set, clear the fault by setting gui_faults.clearFault = 1.
Set idRef to desired Align current.
Set iqRef to desired open loop current.
Set speedRef to desired open loop speed.
Set lsw = 0 to align the motor to the A phase. Note with enableFOC = 0, the FOC is disabled currently.
Set enableFOC = 1 to enable the FOC code to actuate the PWM. Because lsw = 0, we should see positive current in the A phase and half of the negative current in the B and C phases. If current is not constant, see PI tuning for Id.
Set lsw = 1 to switch to open loop. The motor starts to spin and ramp to the speed set in speedRef. If the motor is vibrating, reset to lsw = 0 and set a higher IdRef value. The current in the A phase should be sinusoidal. If there are spikes in current or distorted waveforms, see PI tuning for Iq.
Set lsw = 2 to switch to closed loop. The estimated motor speed (speedEst.EstimatedSpeed) should match speedRef across load conditions and the motor should continue to run smoothly.
Increase or decrease speedRef to run the desired motor speed. Check if the motor speed is stable after the ramp and no oscillations in speed occur, especially if load is applied. If the motor speed is unstable or there are oscillations in the final speed, use the speed PI controller to modify the speed control response.
To stop the motor, set enableFOC = 0.
If a fault occurs, the corresponding fault will be set in the gui_faults structure.
To clear the fault, remove the fault condition and set gui_faults.clearFault. The corresponding fault bit will be cleared.
2.6 Tuning the motor¶
Tuning PI controllers¶
There are three PI controllers for Speed, Id current and Iq current. For tuning a PI controller, the user should first adjust the Kp first and then adjust the Ki for that PI controller. To tune the PI controllers:
Use lsw = 0 to tune PI Id gains (piId.kp, piId.ki)
Use lsw = 1 to tune PI Iq gains (piIq.kp, piIq.ki)
Use lsw = 2 in PI speed gains (piSpd.kp, piSpd.ki)
2.7 Logging the variables¶
The user can add the __ENABLE_LOG predefined symbol to enable logging. The user can set the log index and variable as shown in the below code:
FOC_addVarToLog(FOC_LOG_IDX_0, phaseVolt.Valpha);
To see the logged data as a graph, the user can add the variable cssLog[X], where X is the index. Right click the variable and select “Graph”.
Fig. 5 Image of graph¶
Select “Continuous Refresh” mode to see continuous data.
Fig. 6 Image of graph¶
Note that the software consumes 24KB extra space in SRAM to store the values when logging is enabled.
2.8 Access SPI Register¶
The software allows to independently change values in the SPI registers of the DRV. There are 3 options of writing to SPI register. Below are the variables and examples to use.
There are 3 options in SPI register:
Write 8-bit data to register
Variables |
Description |
|---|---|
gui_spi.writeRegFlag |
Writes the register when set to 1. |
gui_spi.writeRegAddr |
Set address of register to write. |
gui_spi.writeRegData |
Set data of register to write. |
For example, to write 0x01 to the Gate Drive HS register, select gui_spi.writeRegAddr as DRV8323RS_REG_ADDR_GATE_DRIVE_HS, set gui_spi.writeRegData = 0x01, and then set gui_spi.writeRegFlag = 1.
Update some bits in SPI register
Variables |
Description |
|---|---|
gui_spi.writeBitfieldRegFlag |
Writes the bitfield when set to 1. |
gui_spi.writeBitfieldRegAddr |
Set register address to write Bitfield. |
gui_spi.bitfieldRegPosData |
Set position of Bitfield to write. |
gui_spi.bitfieldRegMaskData |
Set mask of Bitfield to write. |
gui_spi.writeBitfieldRegData |
Set data of Bitfield to write. |
For setting IDRIVEP_HS = 0x03 register, select gui_spi.writeBitfieldRegAddr as DRV8323RS_REG_ADDR_GATE_DRIVE_HS, set gui_spi.bitfieldRegPosData = 0x04, set gui_spi.bitfieldRegMaskData = 0x03, set gui_spi.writeBitfieldRegData = 0x03 and then set gui_spi.writeBitfieldRegFlag = 1.
Read SPI register
Variables |
Description |
|---|---|
gui_spi.readRegFlag |
Reads the register when set to 1. |
gui_spi.readRegAddr |
Set address of register to read. |
gui_spi.readRegData |
Shows data read from register. |
For reading the Gate Driver HS register, select gui_spi.readRegAddr as DRV8323RS_REG_ADDR_GATE_DRIVE_HS, and then set gui_spi.writeRegFlag = 1. The data read can be seen in gui_spi.readRegData.
3. API Guide¶
4. Known Issues¶
Function implicit declaration warning for IQrepeat function while compiling.
Current solution supports power up to 100W. Applying high torque at low speeds can cause motor to spin backwards with high rpm.
5. Supported Devices¶
DRV8323RS¶
Supported MSPM0 Launchpads
Links