电机开发板MM32SPIN060G测评

分享作者:xcc1667354064275
作者昵称:meiyao
评测品牌:灵动微电子
评测型号:MM32MDK-SPIN060G
发布时间:2025-03-26 13:18:59
0
概要
MM32SPIN060G 开发板评测单电机控制
开源口碑分享内容

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);
    }

}










全部评论
暂无评论
0/144