目录
六步换相控制
单极性PWM
反电动势过零点检测技术
反电动势的测量
总线电流的测量
电机状态切换
Alignment
Start-up
Run
算法用到的各模块
各模块间的连接
ADC触发顺序
芯片的初始化
时钟配置与电源管理
FTM
Trigger MUX Control (TRGMUX)
PDB
ADC
LPSPI
LPUART
LPIT
引脚分配
软件架构
电机三状态
状态机
定时器与中断
过零点检测算法
转速估计、电流PI限制
针对三相无位置传感器BLDC控制
可实现:
- 六步换相
- 反电动势过零点检测或者霍尔传感器获取转子位置
- 总线电压、电流、BEMF传感器
- 通过霍尔或者BEMF获取转子速度
- 直流母线过压、欠压、过流、过载、启动故障保护
无感电机控制获取转子位置常用方法有哪些:
- 反电动势过零点检测技术
- Flux level detection method我理解着时磁链的意思
- 各种类型的观测器技术(滑膜、卡尔曼、龙博格……)
- 信号注入
从控制角度来看:
- 换向控制,即根据转子位置给各相通电,并采用 准方形的电流波形
- 速度/转矩控制,即控制应用于各相的准方形电流波形的振幅,以实现所需的速度/转矩性能。
六步换相控制
又称为方波控制,某一时刻任意两相打开,另一相产生反电动势。
单极性PWM
该技术包括了换相控制与扭矩控制。
MOS管的开关状态决定换相;占空比决定扭矩。
具体模式:一相互补PWM输出,一相接地,一相断电
反电动势过零点检测技术
从图里面可以看出来,在反电动势过零点之后,延迟30°电角度,进行换相。
断电那一相的相电压为:
我们要找出的就是uc为0的时候,因此比较ec与一半总线电压值,既可得到过零点时刻。
在速度不变的情况下,两个过零点之间的时间就是换相周期(60°)。
反电动势的测量
BEMF的测量应在(使用PWM互补输出)某相上桥臂 高电平时刻:如下图绿色部分
需要注意的是,根据电机和功率级参数的不同,电压振铃的振幅、周期和阻尼都会发生变化。因此,建议在靠近窗口的末端测量BEMF电压。这个样本点的时间也需要存储,因为它被用来增强过零检测。
如果出现了下面这个情况怎么办?
过零点出现在了 ADC相邻两个采样点之间,此时将无法准确获取过零点时刻,怎么办?
使用方法:近似插值法
总线电流的测量
为了直接获得直流母线电流的平均值,则必须在PWM中间来测量。
电机状态切换
Alignment
预定位,把转子拉到指定位置上。
方式:C上桥臂打开,A、B下桥臂打开。
Start-up
强制换相,换向周期由一个开环启动曲线控制
转速达到额定转速5%时,产生可识别的BEMF电压时,进行切换。
Run
算法用到的各模块
电控算法会用到的芯片外设:
- 定时器FlexTimer Module (FTM)
- 复用触发器Trigger MUX Control (TRGMUX)
- 可编程延迟模块Programmable delay block (PDB)
- 采样Analogue-to-Digital Converter (ADC)
各模块间的连接
从上往下看上图:蓝色部分属于无感
- FTM1用于换相,被配置成计时器,对BEMF进行过零点检测
- 使用FTM0 PWM初始化触发器init_trig或者外部触发器ext_trig
- FTM0触发信号通过TRGMUX触发PDB0模块,PDB0模块又与ADC0模块配合工作
S32K116与预驱芯片MC34GD3000之间的配合部分有四个:
- 两者之间通过低功耗的SPI LPSPI0通信
- PWM信号
- PTA11对GD3000故障检测信号
- 总线电流的采样
ADC触发顺序
还是从上往下,从左往右看这个图:
- FTM1 init_trig信号触发换相事件;同时通过TRGMUX触发FTM0,使其计数器清零;同时FTM0 PWM初始化触发PDB0计数器,PDB0达到自己第一个预触发延迟值时,启动第一个ADC0采样,这里第一个采样的是总线电流
- 总线电压与反电动势的采样在PWM高电平快结束时进行连续采样
- ADC0转换完成中断通知CPU后,进行过零点检测
芯片的初始化
打开示例代码,找到main.c文件main()函数,首先看到就是芯片的初始化函数:
/* MCU peripherals initialization */
McuClockConfig();
McuPowerConfig();
McuIntConfig();
McuTrigmuxConfig();
McuPinsConfig();
McuLpuartConfig();
McuLpitConfig();
McuAdcConfig();
McuPdbConfig();
McuFtmConfig();
时钟配置与电源管理
RUN模式下的时钟频率:Fast Internal Reference Clock (FIRC)
配置如下:
/*******************************************************************************
*
* Function: void McuClockConfig(void)
*
* Description: This function installs the pre-defined clock configuration table
* to the clock manager. For details see clockMan1 configuration
* in Processor Expert.
*
*******************************************************************************/
void McuClockConfig(void)
{
/* Clock configuration for MCU and MCU's peripherals */
CLOCK_SYS_Init(g_clockManConfigsArr,
CLOCK_MANAGER_CONFIG_CNT,
g_clockManCallbacksArr,
CLOCK_MANAGER_CALLBACK_CNT);
/* Clock configuration update */
CLOCK_SYS_UpdateConfiguration(0, CLOCK_MANAGER_POLICY_FORCIBLE);
}
电源配置:
代码:
/*******************************************************************************
*
* Function: void McuPowerConfig(void)
*
* Description: This function configures the Power manager for operation.
* For details see pwrMan1 configuration in Processor Expert.
*
*******************************************************************************/
void McuPowerConfig(void)
{
/* Power mode configuration for RUN mode */
POWER_SYS_Init(&powerConfigsArr, 0, &powerStaticCallbacksConfigsArr, 0);
/* Power mode configuration update */
POWER_SYS_SetMode(0, POWER_MANAGER_POLICY_AGREEMENT);
}
/* *************************************************************************
* Configuration structure for Power Manager Configuration 0
* ************************************************************************* */
/*! @brief User Configuration structure power_managerCfg_0 */
power_manager_user_config_t pwrMan1_InitConfig0 = {
.powerMode = POWER_MANAGER_RUN, /*!< Power manager mode */
.sleepOnExitValue = false, /*!< Sleep on exit value */
};
/*! @brief Array of pointers to User configuration structures */
power_manager_user_config_t * powerConfigsArr[] = {
&pwrMan1_InitConfig0
};
/*! @brief Array of pointers to User defined Callbacks configuration structures */
power_manager_callback_user_config_t * powerStaticCallbacksConfigsArr[] = {(void *)0};
FTM
FlexTimer module (FTM) 16为计数器,功能强大:向上计数模式、死区插入、故障注入……
中心对齐模式,6个互补的通道生成中心对齐PWM
换相用的FTM1配置如下:
代码:
void McuFtmConfig(void)
{
/* FTM1 initialized as a simple up-counting timer */
FTM_DRV_Init(INST_FLEXTIMER_MC0, &flexTimer_mc0_InitConfig, &stateMc0);
/* init FTM1 counter */
FTM_DRV_InitCounter(INST_FLEXTIMER_MC0, &flexTimer_mc0_TimerConfig);
/* FTM0 module initialized as PWM signals generator */
FTM_DRV_Init(INST_FLEXTIMER_PWM0, &flexTimer_pwm0_InitConfig, &statePwm0);
/* FTM0 module PWM initialization */
FTM_DRV_InitPwm(INST_FLEXTIMER_PWM0, &flexTimer_pwm0_PwmConfig);
/* Mask all FTM0 channels to disable PWM output */
FTM_DRV_MaskOutputChannels(INST_FLEXTIMER_PWM0, PWM_CHANNEL_GROUP, false);
/* Set FTM0SYNCBIT to trigger and update FTM0 registers */
SIM->FTMOPT1 |= SIM_FTMOPT1_FTM0SYNCBIT_MASK;
}
Trigger MUX Control (TRGMUX)
FTM0初始化触发信号init_trig触发PDB0模块,必须指定TRGMUX_PDB0寄存器的选择位字段SEL0来定义触发源。
在后面找到了:
PDB
无感六步换相中需要配置的PDB:
表中,第二行 总线电流采样,在PWM高电平正中间(50%)
第三行,第四行总线电压与反电动势,都尽量在PWM高电平后期(80%处进行采样),可使用背对背模式,在采集完总线电压后,直接采集反电动势。
PDB预触发器也可以配置为背靠背模式工作,当ADC转换完成时触发下一个PDB通道预触发器和触发输出。
pdb_delay0是一个静态值,在初始化的时候就可定义。
pdb_delay1则需要计算:
[100,1200]的限制,100主要防止在占空比比较小的时候,与 pdb0_ch0_pretrig1发成碰撞;同样考虑到ADC的转换时间1.1us左右。
配置如下:
代码:
pre-trigger0直接设置为0,在PWM高电平开始时,就直接采样总线电流.
pre-trigger1设置应该是实时的,根据占空比的变化而变化,80%,但在初始化的时候应该设置一个最小值100。
pre-trigger2设置成背靠背模式,只要pre-trigger1转换完成,就直接进行反电动势的采样。
void McuPdbConfig(void)
{
/* PDB0 module initialization */
PDB_DRV_Init(INST_PDB0, &pdb0_InitConfig0);
/* PDB0 CH0 pre-trigger0 initialization */
PDB_DRV_ConfigAdcPreTrigger(INST_PDB0, 0, &pdb0_AdcTrigInitConfig0);
/* PDB0 CH0 pre-trigger1 initialization */
PDB_DRV_ConfigAdcPreTrigger(INST_PDB0, 0, &pdb0_AdcTrigInitConfig1);
/* PDB0 CH0 pre-trigger1 initialization */
PDB_DRV_ConfigAdcPreTrigger(INST_PDB0, 0, &pdb0_AdcTrigInitConfig2);
/* Set PDB0 modulus value set to half of the PWM cycle */
PDB_DRV_SetTimerModulusValue(INST_PDB0, HALF_PWM_MODULO);
/* PDB0 CH0 pre-trigger0 delay set to sense DC bus current in the middle of the PWM cycle */
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB0, 0, 0, 0);
/* PDB0 CH0 pre-trigger1 delay set to sense DC bus voltage towards the end of the active PWM pulse */
/* BEMF voltage will be automatically triggered after DC bus voltage conversion is completed */
PDB_DRV_SetAdcPreTriggerDelayValue(INST_PDB0, 0, 1, PDB_DELAY_MIN);
/* Enable PDB0 prior to PDB0 load */
PDB_DRV_Enable(INST_PDB0);
/* Load PDB0 configuration */
PDB_DRV_LoadValuesCmd(INST_PDB0);
}
ADC
在不同的扇区对不同的相进行反电动势采样。
配置
代码:
基本参数配置
/*! adConv0 configuration structure */
const adc_converter_config_t adConv0_ConvConfig0 = {
.clockDivide = ADC_CLK_DIVIDE_1,
.sampleTime = 12U,
.resolution = ADC_RESOLUTION_12BIT,
.inputClock = ADC_CLK_ALT_1,
.trigger = ADC_TRIGGER_HARDWARE,
.pretriggerSel = ADC_PRETRIGGER_SEL_PDB,
.triggerSel = ADC_TRIGGER_SEL_PDB,
.dmaEnable = false,
.voltageRef = ADC_VOLTAGEREF_VREF,
.continuousConvEnable = false,
.supplyMonitoringEnable = false,
};
const adc_chan_config_t adConv0_ChnConfig0 = {
.interruptEnable = false,
.channel = ADC_INPUTCHAN_EXT3,
};
const adc_chan_config_t adConv0_ChnConfig1 = {
.interruptEnable = false,
.channel = ADC_INPUTCHAN_EXT12,
};
const adc_chan_config_t adConv0_ChnConfig2 = {
.interruptEnable = true,
.channel = ADC_INPUTCHAN_EXT13,
};
sector 0,3 -> ADC0_SE13 -> Phase C voltage measurement
sector 1,4 -> ADC0_SE14 -> Phase B voltage measurement
sector 2,5 -> ADC0_SE9 -> Phase A voltage measurement
ADC0_SE3 -> DC bus current measurement
ADC0_SE12 -> DC bus voltage measurement
void McuAdcConfig(void)
{
/* ADC0 module initialization */
ADC_DRV_ConfigConverter(INST_ADCONV0, &adConv0_ConvConfig0);
ADC_DRV_AutoCalibration(INST_ADCONV0);
/* ADC0_SE3 input channel is used for DC bus current sensing */
ADC_DRV_ConfigChan(INST_ADCONV0, 0, &adConv0_ChnConfig0);
/* ADC0_SE12 input channel is used for DC bus voltage sensing */
ADC_DRV_ConfigChan(INST_ADCONV0, 1, &adConv0_ChnConfig1);
/* ADC0_SE9, ADC0_14, ADC0_13 input channel is used for BEMF voltage sensing */
ADC_DRV_ConfigChan(INST_ADCONV0, 2, &adConv0_ChnConfig2);
}
LPSPI
TPP配置并控制GPIO引脚,以启用/禁用或重置应用程序中的MC34GD3000。
void GD3000_Init(void)
{
/* GD3000 pin configuration - EN1:PTA3 EN2:PTA3 & RST:PTA2 */
tppDrvConfig.en1PinIndex = 3U;
tppDrvConfig.en1PinInstance = instanceA;
tppDrvConfig.en2PinIndex = 3U;
tppDrvConfig.en2PinInstance = instanceA;
tppDrvConfig.rstPinIndex = 2U;
tppDrvConfig.rstPinInstance = instanceA;
/* GD3000 device configuration */
tppDrvConfig.deviceConfig.deadtime = INIT_DEADTIME;
tppDrvConfig.deviceConfig.intMask0 = INIT_INTERRUPTS0;
tppDrvConfig.deviceConfig.intMask1 = INIT_INTERRUPTS1;
tppDrvConfig.deviceConfig.modeMask = INIT_MODE;
tppDrvConfig.deviceConfig.statusRegister[0U] = 0U;
tppDrvConfig.deviceConfig.statusRegister[1U] = 0U;
tppDrvConfig.deviceConfig.statusRegister[2U] = 0U;
tppDrvConfig.deviceConfig.statusRegister[3U] = 0U;
tppDrvConfig.csPinIndex = 5U;
tppDrvConfig.csPinInstance = instanceB;
tppDrvConfig.spiInstance = 0;
tppDrvConfig.spiTppConfig.baudRateHz = LPSPI_FREQ;
tppDrvConfig.spiTppConfig.sourceClockHz = 48000000U;
TPP_ConfigureGpio(&tppDrvConfig);
TPP_ConfigureSpi(&tppDrvConfig, NULL);
TPP_Init(&tppDrvConfig, tppModeEnable);
//TPP_Deinit(&tppDrvConfig);
}
LPUART
UART作为FreeMASTER运行时调试和可视化工具之间的通信接口,也需要配置一下
配置的时候注意这几个参数就可以:
代码 波特率38400,8位,1个停止位
void McuLpuartConfig(void)
{
/* LPUART module initialization */
LPUART_DRV_Init(INST_LPUART0, &lpuart0_State, &lpuart0_InitConfig0);
}
const lpuart_user_config_t lpuart0_InitConfig0 = {
.transferType = LPUART_USING_INTERRUPTS,
.baudRate = 38400U,
.parityMode = LPUART_PARITY_DISABLED,
.stopBitCount = LPUART_ONE_STOP_BIT,
.bitCountPerChar = LPUART_8_BITS_PER_CHAR,
.rxDMAChannel = 0U,
.txDMAChannel = 0U,
};
LPIT
中断主要用来控制电机速度,电流。
每1ms产生一个中断
配置
我理解这里的1ms中断进行速度控制,意思是说,速度的更新速度
/*******************************************************************************
*
* Function: void McuLpitConfig(void)
*
* Description: This function configures LPIT module.
* For more details see configuration in Processor Expert.
*
* Note: Speed control of the BLDC motor is executed in LPIT interrupt
* routine every 1ms.
*
*******************************************************************************/
void McuLpitConfig(void)
{
/* LPIT module initialization */
LPIT_DRV_Init(INST_LPIT1, &lpit1_InitConfig);
/* LPIT channel0 initialization */
LPIT_DRV_InitChannel(INST_LPIT1, 0, &lpit1_ChnConfig0);
}
/*! Global configuration of lpit1 */
const lpit_user_config_t lpit1_InitConfig =
{
.enableRunInDebug = false, /*!< true: LPIT run in debug mode; false: LPIT stop in debug mode */
.enableRunInDoze = false /*!< true: LPIT run in doze mode; false: LPIT stop in doze mode */
};
/*! User channel configuration 0 */
lpit_user_channel_config_t lpit1_ChnConfig0 =
{
.timerMode = LPIT_PERIODIC_COUNTER,
.periodUnits = LPIT_PERIOD_UNITS_MICROSECONDS,
.period = 1000U,
.triggerSource = LPIT_TRIGGER_SOURCE_INTERNAL,
.triggerSelect = 0U,
.enableReloadOnTrigger = false,
.enableStopOnInterrupt = false,
.enableStartOnTrigger = false,
.chainChannel = false,
.isInterruptEnabled = true
};
引脚分配
配置
FTM0
ADC0
SPI
UART
TRGMUX
还有一些GPIO口的配置:复位、片选、按键……
软件架构
框图
两部分逻辑:
- 换相控制,通过反电动势过零点检测确定换相事件,并为下一次换相做准备
- 速度/扭矩控制,速度PI通过控制占空比控制速度
电机三状态
还是三个状态来启动:alignment state、 open-loop start state、 the run state。
- 外设初始化完成,进入alignment state
- alignment state状态下,转子会被稳定在一个已知的位置上(预定位),以便在两个旋转方向上产生相同的启动扭矩(实现方式:C相PWM信号,AB相占空比为0,也就是接到负极)
- 当alignment时间到达后,进入open-loop start,这时候转速比较低,是没办法进行反电动势过零点检测的。
- 当开环转速达到额定转速的5%时,进入闭环run state
状态机
INIT,PWM占空比和直流总线电流偏移校准的初始配置,之后状态机将转换到STOP状态。
STOP, appSwitchState variable = 1切换到CALIB
CALIB,提供直流总线电流校准,之后进入ALIGNMENT
ALIGNMENT,在BLDC appconfig.h可以查看具体的预定位占空比,和预定位持续时间
START,该状态下,属于强制换相,换相周期由STARTUP_CMT_PER控制;电机加速度由START_CMT_ACCELER控制;该状态下的换相次数由STARTUP_CMT_CNT控制
完成换相次数后,进入RUN
RUN,反电动势过零点检测,闭环
FAULT,故障检测,过压、欠压、过流、GD3000故障
定时器与中断
这部分有些不理解?
过零点检测算法
转速估计、电流PI限制
极对数:
电机每相可以有多个极对,每相的极对数定义了电旋转和机械旋转之间的比率
原文档下载地址
https://www.nxp.com.cn/docs/en/application-note/AN13000.pdf