MM32SPIN160C开发板试用
本次测试的MM32 Motor-DK低压电动机开发板,采用MM32SPIN160C处理器,内部集成了NMOS的预驱动,及丰富的和电机驱动相关外设。
测试目标对象为12V的直流无刷电机,采用FOC+SVPWM的方式完成驱动控制过程。
使用高性能的Arm® Cortex®-M0 为内核的 32 位微控制器,最高工作频率可达72MHz,内置高速存储器,丰富的 I/O 端口和多种外设。
- 32KB Flash,4KB SRAM
- 包含 12 位的 ADC,采样速度高达 1Msps
- 5 个通用定时器、1 个针对电机控制的 PWM 高级定时器
- 1 个 I2C 接口、2 个 SPI 接口和 2 个 UART 接口
- 针对电机应用内置 1 个比较器
- 预驱工作电压高达 75V
- 工作温度范围(环境温度)-40℃ - 85℃
- 提供 QFN32 封装
适合于多种应用场合:
- 空气净化器
- 服务器风机
- 吊扇
- 吊扇灯
- 落地扇
- 电动工具
- 吸尘器
- 无人机电调
- 水泵
1.2. MM32SPIN160C开发板介绍
图 MM32 Motor-DK开发板照片
1)基本介绍
输入电压范围 : 12V~28V
使用60V/40A N-MOS管*6
使用外挂(SPIN0x) GBW 6MHz 高速运放*4
MCU 电源使用 5V
支持有/无霍, 方波/弦波驱动
支持1/2 Shunt R 三相电流采样
BEMF 电压回授使用ADC 采样
DC Bus 电压, 总电流量测
使用MCU 内建比较器做为过电流保护
具VR, LED等功能
2) 硬件资源描述
类型 | 子项 | 硬件IO引脚 | 外设应用 |
LED | LED0 | PDO | GPIO |
模拟量 AD采样 | VR | PB1 | AD1-CH09 |
总线电压VBUS | PA7 | AD1-CH07 | |
反电动势U相 | PA0 | AD1-CH00 | |
反电动势V相 | PA1 | AD1-CH01 | |
反电动势W相 | PA2 | AD1-CH02 | |
电机电流U相 | PA5 | AD1-CH05 | |
电机电流V相 | PA6 | AD1-CH06 | |
电机电流总电流SUM | PA3 | AD1-CH03 | |
比较器 | 电机过流制动 | PA4 | CMP1-CH03 |
驱动控制 | UH | PA10 | TIM1-CH1 |
UL | PA9 | TIM1-CH1N | |
VH | PA8 | TIM1-CH2 | |
VL | PB15 | TIM1-CH2N | |
WH | PB14 | TIM1-CH3 | |
WL | PB13 | TIM1-CH3N | |
输出使能 | PB12 | GPIO |
3)跳线冒配置描述
由于采用无霍尔FOC+2ShuntR驱动输出方式,因此官方说明文件中给了我们基本配置说明,这里直接拿来主义了。
图 跳线帽的选择
采用Keil搭建基本开发环境,首先我们安装Pack库文件,前面已经介绍,MM32SPIN160C采用的是Cortex-M0内核,实际处理器等同于MM32SPIN05PF。因此我们需要安装MindMotion.MM32SPIN0x_DFP.1.0.8.pack文件到Keil系统中。
为了方便调试,我们可以选择支持Cortex-M0的仿真器,我这里采用JTAG-OB V2版本,实际测试发现,代码烧录没有任何问题,速度也挺快,但是仿真过程一直磕磕绊绊,经常出现中途退出的现象,我分析可能有两个原因,一个是我这个仿真器对MM32SPIN160C的支持不太好;另一个可能是仿真器质量不太好,在外部干扰的情况下不太稳定。这个请大家在测试。
2.1. 电机极对数P
示波器途中包含3组波形,每组都是转子转动一周出现的若干个正弦波,可以数出有6个波峰和6个波谷,可以确定为6对极。
图 反电势确定电机极对数
2.2. 相电阻Rs实测电阻:3.1欧/2 = 1.55欧姆
2.3. 相电感Ls
实测电感:1.78mH/2 = 0.89mH
2.4. 反电动势常数Ke
如示波器实测,峰峰值为2.460V,周期为8.723ms,可计算频率为114.64Hz。
反电动势系数Ke = 1000*P*Vpp/(2*1.732*60*f) = 1000 * 6 * 2.460/(2*1.732*60*114.6)=0.62
图 通过反电势峰值确定反电动势系数
3. 程序移植
FOC驱动代码基础来自与MM32官方的一个风机测试程序,程序基于MM32SPIN05,采用外扩MOS驱动回路的方式,因此和我们这款开发板还是又较大区别的。经过摸索,总结如下几个移植注意事项:
主要移植工作量都在这个文件中,其中包括对于不同板卡之间硬件差异的移植过程,所选择电机及系统的匹配移植。
1) 硬件差异移植
前面已经描述了我们测试开发板的硬件资源,这里面需要对应上去。
图 与原版程序的差异对比
- WL_PIN引脚的输出操作函数对应的引脚是不同的
- //----define WL pin I/O ploarity in IPD mode-------------------------------------------------------------------------------
- //#define WL_PIN_IO_MODE_LOW_ACTIVE //if define WL pin will active low in IO mode. if not define, WL pin will active high in IO mode
- #define WL_PIN_IO_MODE_OUTPUT_LOW GPIOB->BRR |= GPIO_Pin_13 //20190626
- #define WL_PIN_IO_MODE_OUTPUT_HIGH GPIOB->BSRR |= GPIO_Pin_13 //20190626
- 直流母线电压采样通道是不同的
- #define VBUS_ADC_DATA_REGISTER (ADC1->ADDR7)//DC Bus voltage input//20181215
- #define ADC_VBUS_CHANNEL_ENABLE CHEN7_ENABLE//DC Bus voltage input//20181215
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image014.jpg
file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image016.jpg
- LED灯的个数和驱动引脚不同
- #define LED0_ON GPIOD->BRR |= GPIO_Pin_0 //Green light ON
- #define LED0_OFF GPIOD->BSRR |= GPIO_Pin_0 //Green light OFF
- #define LED0_TOGGLE() (GPIO_ReadOutputDataBit(GPIOD,GPIO_Pin_0))?(GPIO_ResetBits(GPIOD,GPIO_Pin_0)):(GPIO_SetBits(GPIOD,GPIO_Pin_0))
2)匹配移植
- 极对数和驱动频率的调整
- #define PWM_FREQUENCY 16000 //unit:HZ
- #define POLE_NUMBER 12//8
- 闭环参数不同
- //-----Close loop parameters------------------------------------------------------------------------------------------------
- #define TARGET_SPEED_1 1000 //unit: RPM, define the user's lowest target speed
- #define TARGET_SPEED_2 2000 //unit: RPM, define the user's second target speed
- #define TARGET_SPEED_3 3000 //unit: RPM, define the user's Third target speed
- #define TARGET_SPEED_4 4000 //unit: RPM, define the user's 4th target speed
- #define TARGET_SPEED_5 5000 //unit: RPM, define the user's 5th target speed
- #define TARGET_SPEED_6 6000 //unit: RPM, define the user's 6th target speed
- #define TARGET_SPEED_7 7000 //unit: RPM, define the user's highest target speed
- 直流母线电压水平
- #define USE_MEASURED_DC_BUS_VOLTAGE_TO_GET_POWER //if enable,it will use measured dc bus voltage to calculate power consumption. if not, it will use fixed DC_BUS_VOLTAGE parameter
- #define DC_BUS_VOLTAGE 120 //unit: 0.1V, define the dc bus voltage, 100 means 10V. it will be used if not define "USE_MEASURED_DC_BUS_VOLTAGE_TO_GET_POWER"
由于两块板子的驱动引脚差异较大,因此,对于TIM1的OC输出引脚的配置差别较大。
- 输出引脚差异
- void TIM1_PWM_Init(uint16_t u16Period,uint16_t u16Prescaler,uint8_t u8DeadTime)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA| RCC_AHBPeriph_GPIOB , ENABLE);//GPIOA,GPIOB外设时钟使能
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //TIM1外设时钟使能
- <font color="#ff0000"> //TIM1_CH1,TIM1_CH2,TIM1_CH1N输出
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- //TIM1_CH3N,TIM1_CH3,TIM1_CH2N输出
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure); </font>
- <font color="#ff0000"> GPIO_PinAFConfig(GPIOA, GPIO_PinSource8,GPIO_AF_6);//GPIO端口复用功能使能
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,GPIO_AF_6);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_6);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource13,GPIO_AF_6);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource14,GPIO_AF_6);
- GPIO_PinAFConfig(GPIOB, GPIO_PinSource15,GPIO_AF_6);</font>
- // TIM_Cmd(TIM1, ENABLE); //使能TIM1开始计数
- // TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
- TIM_TimeBaseStructure.TIM_Period = u16Period; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
- TIM_TimeBaseStructure.TIM_Prescaler =u16Prescaler; //设置用来作为TIMx时钟频率除数的预分频值 不分频
- TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_CenterAligned2;//for ADC trigger effective when TIM_CounterMode_Up;
- #ifdef ENABLE_TIM1_CC4_CC5_TO_TRIG_ADC1_FOR_1_SHUNTR
- TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_CenterAligned1;//for ADC trigger, TIM Down count effective, TIM_CounterMode_down
- #endif
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_RepetitionCounter = 1; //重复计数器清0 = Update Event at every overflow
- TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
- TIM_OCStructInit(&TIM_OCInitStructure); //初始化TIM_OCInitStructure
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //CH1比较输出使能
- TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //CH1N比较输出使能
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //CH1输出极性:TIM输出比较极性高
- TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; //CH1N输出极性:TIM输出比较极性高
- TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; //CH1输出空闲状态:1
- TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; //CH1N输出空闲状态:0
- TIM_OCInitStructure.TIM_Pulse = u16Period>>1;//设置待装入捕获比较寄存器的脉冲值
- TIM_OC1Init(TIM1, &TIM_OCInitStructure); //CH1,CH1N根据TIM_OCInitStruct中指定的参数初始化外设TIM1
- TIM_OCInitStructure.TIM_Pulse = u16Period>>1;//设置待装入捕获比较寄存器的脉冲值
- TIM_OC2Init(TIM1, &TIM_OCInitStructure); //CH2,CH2N根据TIM_OCInitStruct中指定的参数初始化外设TIM1
- TIM_OCInitStructure.TIM_Pulse = u16Period>>1;//设置待装入捕获比较寄存器的脉冲值
- TIM_OC3Init(TIM1, &TIM_OCInitStructure); //CH3,CH3N根据TIM_OCInitStruct中指定的参数初始化外设TIM1
- /* Divided clock for TIM1*/
- TIM1->PSC = 0x00; // CLK = HSI/(0+1) = 48MHz/1 = 48MHz
- #ifdef ENABLE_OVER_CURRENT_TIM1BKIN_PROTECTION //enable this to do over current protection (PWM OFF), if comparator output Low signal
- {
- TIM_BDTRInitTypeDef TIM_BDTRInitStruct;
- TIM_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Disable;//TIM_OSSRState_Enable;//运行模式下关闭状态选择
- TIM_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Disable;//TIM_OSSIState_Enable;//空闲模式下关闭状态选择
- TIM_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_OFF;//软件错误锁定配置:锁定关闭无保护
- TIM_BDTRInitStruct.TIM_DeadTime = u8DeadTime;//DTG[7:0]死区发生器配置:(死区时间DT)
- TIM_BDTRInitStruct.TIM_Break = TIM_Break_Enable;//TIM_Break_Disable;//TIM_Break_Enable; //刹车配置:使能刹车
- TIM_BDTRInitStruct.TIM_BreakPolarity = BREAK_POLARITY;//TIM_BreakPolarity_High;//TIM_BreakPolarity_Low;//刹车输入极性选择
- TIM_BDTRInitStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable;//TIM_AutomaticOutput_Enable;//自动输出使能配置:MOE只能软件置1
- TIM_BDTRConfig( TIM1, &TIM_BDTRInitStruct); //配置互补输出死区时间
- }
- #else
- /* Dead Time Setting */
- TIM1->BDTR |= 0x00|u8DeadTime; // Setting Dead Time [7:0] = 0x30 = 1us at 48MHz
- #endif
- //--------------------------------------------------------------------------------------------------------------------------------
- #ifdef ENABLE_1_SHUNT_R_TO_MEASURE_3_PHASE_CURRENT
- TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Disable ); //Disable Preload, CCR will be updated right away when new value be written.
- TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Disable ); //Disable Preload, CCR will be updated right away when new value be written.
- TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Disable ); //Disable Preload, CCR will be updated right away when new value be written.
- TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIM1在ARR上的预装载寄存器
- //TIM_CtrlPWMOutputs(TIM1, ENABLE); //使能TIM1 PWM互补死区输出
- #ifdef ENABLE_OVER_CURRENT_TIM1BKIN_PROTECTION
- TIM_ITConfig(TIM1, TIM_IT_Update | TIM_IT_Break , ENABLE);
- TIM_ClearITPendingBit(TIM1, TIM_IT_Break | TIM_FLAG_Update);
- #else
- TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); // Enable TIM1 Update Event Interrupt
- #endif
- NVIC_Configuration4TTIM1();
- #endif
- //--------------------------------------------------------------------------------------------------------------------------------
- #ifndef ENABLE_1_SHUNT_R_TO_MEASURE_3_PHASE_CURRENT
- TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable ); //使能自动装载
- TIM_OC2PreloadConfig(TIM1,TIM_OCPreload_Enable ); //使能自动装载
- TIM_OC3PreloadConfig(TIM1,TIM_OCPreload_Enable ); //使能自动装载
- TIM_ARRPreloadConfig(TIM1, ENABLE); //使能TIM1在ARR上的预装载寄存器
- //TIM_CtrlPWMOutputs(TIM1, ENABLE); //使能TIM1 PWM互补死区输出
- #ifdef ENABLE_OVER_CURRENT_TIM1BKIN_PROTECTION
- // TIM_ITConfig(TIM1, TIM_IT_Update | TIM_IT_Break , ENABLE);
- // TIM_ClearITPendingBit(TIM1, TIM_IT_Break | TIM_FLAG_Update);
- TIM_ITConfig(TIM1, TIM_IT_Break , ENABLE);
- TIM_ClearITPendingBit(TIM1, TIM_IT_Break | TIM_FLAG_Update);
- // #else
- // TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); // Enable TIM1 Update Event Interrupt
- #endif
- NVIC_Configuration4TTIM1();
- TIM1->BDTR |= 0x8000; // 主输出使能
- #ifdef ENABLE_TIM1_CC4_TO_TRIG_ADC_FOR_2_SHUNTR//for use TIM1_CC4 to trigger ADC in 2 shunt R phase current sensing
- TIM_Cmd(TIM1, ENABLE);//Enable TIM1 only
- #endif
- #endif
- <font color="#ff0000"> Gate_Driver_Init();</font>
- }
其中引脚的复用功能选择位不同。
- PWM驱动输出总使能控制
原系统中没有总使能控制引脚,因此我们必须增加初始化和应用控制。
1)总输出使能引脚初始化
- void Gate_Driver_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- GATE_DRIVER_DISABLE();
- }
2)PWM初始化函数中,增加总输出使能引脚的初始化函数调用
- void TIM1_PWM_Init(uint16_t u16Period,uint16_t u16Prescaler,uint8_t u8DeadTime)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- 。。。。。。。。
- #endif
- Gate_Driver_Init();
- }
3)pwm.h文件中增加总输出使能控制宏
#defineGATE_DRIVER_ENABLE() GPIO_SetBits(GPIOB,GPIO_Pin_12)
#defineGATE_DRIVER_DISABLE() GPIO_ResetBits(GPIOB,GPIO_Pin_12)
4)PWM输出使能控制函数中增加总输出控制
- void Enable_Motor1_PWM_Output(void)//PWM開始為互補
- {
- TIM_CtrlPWMOutputs(TIM1, ENABLE); //使能TIM1 PWM互补死区输出
- GATE_DRIVER_ENABLE();
- // TIM1->CCMR1=0x6868; // Output keep PWM1 mode (CH2/CH1)
- // TIM1->CCMR2=0x0068; // Output keep PWM1 mode (CH4/CH3)
- // TIM1->CCER =0x0555; // D:CCxNP=0/CCxNE=1/CCxP=0/CCxE=1
- // TIM1->EGR =0x0020; // Active immediately : PWM is complementary type and H_side = High active L_side = High active
- }
5)PWM输出禁止控制函数中增加总输出控制
- void Disable_Motor1_PWM_Output(void)//PWM關閉為0輸出
- {
- GATE_DRIVER_DISABLE();
- TIM_CtrlPWMOutputs(TIM1, DISABLE); //Disable TIM1 PWM互补死区输出
- // TIM1->CCMR1=0x5858; // Output keep OCREF=1 (CH2/CH1)
- // TIM1->CCMR2=0x0058; // Output keep OCREF=1 (CH4/CH3)
- // TIM1->CCER =0x0CCC; // D:CCxNP=1/CCxNE=1/CCxP=0/CCxE=0
- // TIM1->EGR =0x0020; // Active immediately : H_side = 0, Low_side = 0
- }
视频网址
https://v.youku.com/v_show/id_XNTgyNjQwOTkwOA==.html
5. 与STSPIN驱动系统的对比
对比的STM32专用电机芯片为STSPIN32F0601。以下的对比是我的个人感受。
MM32SPIN160C与STSPIN32F0601同样采用ARM Cortex-M0内核,主频最高可达72MHz,32KB的代码空间,多通道高速ADC,高级定时器等外设,最关键的它们同样都集成了NMOS的预驱动。
它们相比,硬件配置的差异主要体现在MM32的ADC提供的功能上稍逊色于ST的同类型产品,它的ADC不支持注入式转换方式,导致实际使用出现了一些不便。
辅助开发工具这方面应该是国内芯片的普遍短板了吧,和ST的产品相比,在使用体验上就会有比较大的落差,我想这也就是我们为了的发展空间之一吧。
通过本次MM32产品的试用,发现MM32SPIN系列的电机驱动产品系列比较全面,芯片配置硬件功能也基本够用。但是在软件设计辅助工具方面,以及用户体验上还有提升空间。
移植后可以正确驱动电机的源码:
t2.rar
(2.51 MB, 下载次数: 51)
继续阅读本篇相关更多标签
热门资料
热门活动
全部回复 8
- 1 主题
- 6 帖子
- 356 积分
身份:LV2 初级技术员
E币:326
发消息
不错,感谢楼主的辛勤付出.
>>资料:TOSHIBA东芝TB6612FNG电机驱动IC产品规格书datasheet
举报
内容系网友发布,其中涉及到安全隐患的内容系网友个人行为,不代表面包板社区观点
关闭
站长推荐 /2
- 返回顶部