1. 硬件概述
MM32SPIN060G 是灵动 MindSPIN 旗下高性能的单电机控制 SOC 产品,基于 Cortex-M0 内核,集成了丰富的模拟外设和专用资源,适用于无刷直流电机(BLDC)和永磁同步电机(PMSM)的控制。
内核:Cortex-M0,主频高达 48MHz。
模拟外设:
12 位高精度 ADC。
2 路模拟比较器(COMP)。
2 路运算放大器(OPAMP)。
三相 N 沟道栅极驱动器。
专用资源:
MC-TIM(电机控制定时器)。
硬件除法器(HW-Div)。
DMA 控制器。
存储资源:
32KB Flash。
4KB SRAM。
GPIO:11 个 GPIO。
电源管理:
内置 5.0V LDO(50mA)。
输入电压范围:5.5V~18V。
驱动能力:三相全桥 NMOS,60V/40A。
2. 开发板原理图介绍
2.1 最小系统电路
MCU:MM32SPIN060G 内置 MM32SPIN0230 系列芯片。
电源:
输入电压范围:5.5V~18V。
内置 5.0V LDO,为 MCU 和外设供电。
电机驱动:
三相全桥 NMOS,参数为 60V/40A。
支持无霍尔传感器驱动。
支持方波/弦波驱动。
电流采样:
支持 1/2/3 Shunt R 三相电流采样。
电压检测:
支持 BEMF(反电动势)电压回授。
支持 DC Bus 电压和总电流测量。
过流保护:
使用 MCU 内置模拟比较器实现过电流保护。
3. 开发环境
开发工具:Keil MDK
调试工具:J-Link 或 ST-Link。
示例代码:灵动官方提供的电机控制库和示例代码。
4. 电机控制实现
4.1 PWM 配置
配置 MC-TIM 生成三相 PWM 信号,驱动电机。
原理图:

电流采样:

void Drv_Pwm_Init(TIM_TypeDef * pTim, uint16_t u16Period,uint16_t u16DeadTime)
{
/** Define the struct of the PWM configuration */
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_BDTRInitTypeDef TIM_BDTRInitStruct;
TIM_OCInitTypeDef TIM_OCInitStructure;
/** Enable the TIM1 clock */
RCC_APB1PeriphClockCmd(RCC_APB1ENR_TIM1_Msk, ENABLE);
/**
* Sets the value of the automatic reload register Period for the next update event load activity
* Set the Prescaler value used as the divisor of the TIMx clock frequency
* Set clock split :TDTS = TIM_CKD_DIV1
* TIM center aligned mode1
*/
TIM_TimeBaseStructure.TIM_Period = u16Period;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned2;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(pTim, &TIM_TimeBaseStructure);
/**
* Enable state selection in running mode
* Enable state selection in idle mode
* Software error lock configuration: lock closed without protection
* DTG[7:0] dead zone generator configuration (dead zone time DT)
*/
/**
* TDTS = 125nS(8MHz)
* DTG[7: 5] = 0xx => DT = DTG[7: 0] * Tdtg, Tdtg = TDTS;
* DTG[7: 5] = 10x => DT =(64+DTG[5: 0]) * Tdtg, Tdtg = 2 * TDTS;
* DTG[7: 5] = 110 => DT =(32+DTG[4: 0]) * Tdtg, Tdtg = 8 * TDTS;
* DTG[7: 5] = 111=> DT =(32 + DTG[4: 0]) * Tdtg, Tdtg = 16 * TDTS;
*/
TIM_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Enable;
TIM_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Enable;
TIM_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
TIM_BDTRInitStruct.TIM_DeadTime = u16DeadTime;
/**
* Brake configuration: enable brake
* Brake input polarity: active in low level
* Auto output enable configuration: Disable MOE bit hardware control
*/
TIM_BDTRInitStruct.TIM_Break = TIM_Break_Enable;
TIM_BDTRInitStruct.TIM_BreakPolarity = TIM_BreakPolarity_High;
TIM_BDTRInitStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;
TIM_BDTRConfig(pTim, &TIM_BDTRInitStruct);
TIM_BreakInputFilterConfig(pTim,TIM_COMPBKIN_COMP2,TIM_BKINF_2);
TIM_BreakInputFilterCmd(pTim, ENABLE);
/**
* Mode configuration: PWM mode 1
* Output status setting: enabl0Ce output
* Complementary channel output status setting: enable output
* Sets the pulse value to be loaded into the capture comparison register
* Output polarity is high
* N Output polarity is high
*/
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
TIM_OC1Init(pTim, &TIM_OCInitStructure);
TIM_OC2Init(pTim, &TIM_OCInitStructure);
TIM_OC3Init(pTim, &TIM_OCInitStructure);
/** Initialize the CCR4 trigger point */
TIM_OCInitStructure.TIM_Pulse = 10;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
TIM_OC4Init(pTim, &TIM_OCInitStructure);
/** Enable CH1, 2, and 3 to be preloaded */
TIM_OC1PreloadConfig(pTim, TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(pTim, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(pTim, TIM_OCPreload_Enable);
/** Enable TIMx's preloaded register on ARR */
TIM_ARRPreloadConfig(pTim, ENABLE);
/** Enable the TIM1 */
TIM_Cmd(pTim, ENABLE);
/** Main Output Enable:Disable the MOE bit */
TIM_CtrlPWMOutputs(pTim, DISABLE);
}
adc初始化:配置adc转换顺序(U相、V相采样电阻电压,直流母线电压、调速电位器电压),设置ADC1为外部触发源(T1_CC4)。
void Board_ADC_Init(void)
{
/*ADC RANK Array*/
ADC_Channel_TypeDef sUserAdc1Channel[4];
/* Configure the ADC RANK Sequence*/
sUserAdc1Channel[0].u8Rank = IR_U_RANK;
sUserAdc1Channel[0].sAdcChannel = IR_U_CHANNEL;
sUserAdc1Channel[0].pNext = &sUserAdc1Channel[1];
sUserAdc1Channel[1].u8Rank = IR_V_RANK;
sUserAdc1Channel[1].sAdcChannel = IR_V_CHANNEL;
sUserAdc1Channel[1].pNext = &sUserAdc1Channel[2];
sUserAdc1Channel[2].u8Rank = VBUS_RANK;
sUserAdc1Channel[2].sAdcChannel = VBUS_CHANNEL;
sUserAdc1Channel[2].pNext = &sUserAdc1Channel[3];
sUserAdc1Channel[3].u8Rank = VR_RANK;
sUserAdc1Channel[3].sAdcChannel = VR_CHANNEL;
sUserAdc1Channel[3].pNext = NULL;
/* Select the ADC external trigger source of the ADC is T1_CC4*/
Drv_Adc_Basic_Init(ADC1, ADC_ExtTrig_T1_CC4);
/* Select the ADC sample time*/
Drv_Adc_Channel_Init(ADC1, sUserAdc1Channel, ADC_SampleTime_2_5);
}
void ADC_IRQHandler(void)
{
static uint8_t u8ADCTimeCnt = 0;
static uint32_t u32IaSum = 0;
static uint32_t u32IbSum = 0;
static uint16_t u16Cnt = 0;
if( ADC_GetITStatus(ADC1, ADC_IT_EOS))
{
/* Calculae the offset value of current*/
if(u16Cnt <= 127)
{
u16Cnt++;
u32IaSum += (int16_t)GET_ADC_VALUE(IR_U_CHANNEL);
u32IbSum += (int16_t)GET_ADC_VALUE(IR_V_CHANNEL);
}
else if(u16Cnt == 128)
{
u16Cnt++;
u32IaSum = u32IaSum>>7;
u32IbSum = u32IbSum>>7;
Motor_1st.FOC.sIabc_offset.s16A = u32IaSum << 3;
Motor_1st.FOC.sIabc_offset.s16B = u32IbSum << 3;
u32IaSum = 0;
u32IbSum = 0;
}
else
{
Get_ADC_Result(&Motor_1st);
/* Fast Loop Statemachine */
s_STATE_FAST[eM1_MainState]();
if(++u8ADCTimeCnt >= Motor_1st.USER.u16SlowLoopDiv) //For slow loop state machine
{
u8ADCTimeCnt = 0;
Motor_1st.USER.bSlowLoopFlag = 1;
}
}
ADC_ClearITPendingBit(ADC1, ADC_IT_EOS);
}
}
