打印
[电机控制专用MCU]

APM32F035-协处理器(M0CP)

[复制链接]
834|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
      概述
     APM32F035是电机专用芯片,而电机控制算法FOC通常需要进行复杂的数**算和控制逻辑计算,因此APM32F035集成了协处理器(M0CP),以确保FOC系统的实时性和稳定性。

一.简介
       协处理器(M0CP)包含硬件除法、硬件开方、三角函数生成、SVPWM 生成五段和七段式功能。


二.主要特征
  • 1 个可配置 RV32ECM 内核。PM 最大为 8 KB
  • 1 32 AHB 从接口用于寄存器配置。仅支持按 32 位数据对齐据访问。
  • 1 32 AHB 主接口用于访问 PM DM。其中对 IBUS 主接口的响应必须为零等待。
  • 1 个紧耦合的接口用于访问与 SVPWM 算法对应的 PWM 模块。
  • 1 TX 中断(计算结束产生中断)。
  • 两组参数/结果寄存器,寄存器组的切换方式可编程,由硬件或软件实现。
  • 支持 Arm® Cortex®-M0+TXEV 接口通信。
  • 可编程数据格式,Q0 Q15
  • 支持并优化了 CORDIC 算法,实现部分三角函数加速。支持旋转模式和矢量模式。
  • 支持并优化 SVPWM 算法,支持五段式和七段式。
  • 支持和优化定点平方根和除法(32/32 位)。
  • 支持 atan2 运算。




三.结构框图
   协处理器(M0CP) 旨在加速一些运行在Arm® Cortex®-M0+上,与FOCField  Oriented Control,磁场定向控制)相关的应用。M0CP MCU 的典型集成如下图所示。

    M0CP 采用两个 32 AHB lite 主接口分别访问 PM DM
    M0CP 可通过一32 AHB 从接口进行配置,通过 TXEV 与处理器通信,通过紧耦合握手协议接口直接更新 PWM 模块所需数据。



四.功能描述
    1.CORDIC 算法描述
    CORDICcoordinate rotation digital computer,坐标旋转数字计算法)是一种硬件高效的迭代方法,通过基本的加法和移位运算,实现矢量的旋转和定向计算不再需要复杂的函数就能得出结果。
它使用旋转计算范围广泛的初等函数,同时支持旋转模式和向量模式,如下表所示。



2.SVPWM 算法描述
     SVPWMSpace Vector Pulse Width Modulation,空间矢量脉宽调制)用于调制电机所需要的三相电压。5 段和 7 段的算法流程如下图所示。


注意:SVPWM COUNT 模式需要将输出的占空比乘以 TMR1 的周期值,所以在不使能 TMR1 的情况下 M0CP 会一直处于 busy 状态。所以在 COUNT 模式下,应使能TMR1
注意:操作数/结果 XYZWSector)的数据存储在 X_REG/Y_REG/Z_REG/W_REG 寄存器中。


3. 除法算法描述
进行 32bit/32bit 除法时,寄存器存放数据的情况如下:
  • 除数应放在 X_REG 寄存器
  • 被除数应放在 Y_REG 寄存器
  • (计算完成后)商(32-bit)存放在 X_REG 寄存器
  • (计算完成后)余数存放在 Y_REG 寄存器

通过配置 CTRL_REG 寄存器的 ALG 位选择有符号或无符号除法。
对于有符号除法运算,取余数规则描述如下:余数的符号与被除数相同,即
余数 = 被除数 – 商×除数
例子 1-20÷6,商为-3,余数为-2,而不是商为-4,余数为+4
例子 220÷(-3),商为-7,余数为 1
配置进来的输入的数据类型和读取出的结果的数据类型应和 ALG 的值选择对应;即计算有符号除法时,输入、输出为 int32 类型。计算无符号除法时,输入、输出为 uint32 类型。
对除法操作启动之前的除数和被除数的配置没有顺序要求。启动除法后,如果硬件运算完成, 会自动将 STAT_REG BUSY 位清 0。此时,可以从相应寄存器中读取运算结果,即商和余数。


五.以下是SDK中使用M0CP外设完成SVPWM占空比输出操作的示例代码。

int main(void)
{
    uint8_t model = 1;
    uint8_t i;
    int16_t seq_X[] = {sqrt2, -sqrt2, sqrt2, - sqrt2}; /*!< sin(45°), sin(135°), sin(-45°), sin(-135°) */
    int16_t seq_Y[] = {sqrt2, sqrt2, -sqrt2, -sqrt2}; /*!< cos(45°), cos(135°), cos(-45°), cos(-135°) */


    SVPWM_DATA_T svpwmInfo;


    APM_MINI_Init();


    APM_MINI_TMR1_PWMOutPut_Init();


    M0CP_Init();


    printf("This is an example of M0CP SVPWM output duty operation \r\n");


    printf("Press KEY1 to start test.\r\n");


    while (1)
    {
        if (APM_MINI_PBGetState(BUTTON_KEY1) == 0)
        {
            for (i = 0; i < 4; i++)
            {
                svpwmInfo.Ualpha = (model * seq_X);
                svpwmInfo.Ubeta = (model * seq_Y);
#if M0CP_USE_FAST_IQ
                /* SVPWM counter segmentation 7 and Q15 algorithm */
                M0CP_Fast_IQCounterQ15SVPWM7(&svpwmInfo);


                printf(">> SVPWM(%d,%d), Seg = 7, Qn = 15\r\n", svpwmInfo.Ualpha, svpwmInfo.Ubeta);
                printf("<< Ca = %d%%, Cb = %d%%, Cc = %d%%, sector = %d\r\n"
                       , (svpwmInfo.Ca * 100 / PWM_Period)
                       , (svpwmInfo.Cb * 100 / PWM_Period)
                       , (svpwmInfo.Cc * 100 / PWM_Period)
                       , svpwmInfo.sector);
#else
                /* SVPWM counter segmentation 7 and Q15 algorithm */
                if (M0CP_IQCounterSVPWM(&svpwmInfo, M0CP_FP_Q15, M0CP_SVPWM_SEG_7) != M0CP_OK)
                {
                    printf("M0CP SVPWM 7 Q15 segmentation timeout\r\n");
                }
                else
                {
                    printf(">> SVPWM(%d,%d), Seg = 7, Qn = 15\r\n", svpwmInfo.Ualpha, svpwmInfo.Ubeta);
                    printf("<< Ca = %d%%, Cb = %d%%, Cc = %d%%, sector = %d\r\n"
                           , (svpwmInfo.Ca * 100 / PWM_Period)
                           , (svpwmInfo.Cb * 100 / PWM_Period)
                           , (svpwmInfo.Cc * 100 / PWM_Period)
                           , svpwmInfo.sector);
                }
#endif
            }
            model++;
        }


        APM_MINI_LEDToggle(LED2);
        APM_MINI_DelayMs(200);
    }
}


void APM_MINI_Init(void)
{
    /* Init delay function */
    APM_MINI_DelayInit();


    APM_MINI_LEDInit(LED2);
    APM_MINI_LEDInit(LED3);
    APM_MINI_PBInit(BUTTON_KEY1, BUTTON_MODE_GPIO);
    APM_MINI_COMInit(COM1);
}


void APM_MINI_TMR1_PWMOutPut_Init(void)
{
    TMR_TimeBase_T  timeBaseConfig;
    TMR_OCConfig_T  occonfig;
    GPIO_Config_T   gpioconfig;

    /* Enable Clock */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_TMR1);

    /* Connect TMR1 to CH1 */
    GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN2);
    gpioconfig.mode  = GPIO_MODE_AF;
    gpioconfig.outtype = GPIO_OUT_TYPE_PP;
    gpioconfig.pin   = GPIO_PIN_8;
    gpioconfig.pupd  = GPIO_PUPD_NO;
    gpioconfig.speed = GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA, &gpioconfig);

    /* Set clockDivision = 1 */
    timeBaseConfig.clockDivision = TMR_CKD_DIV1;
    /* Up-counter */
    timeBaseConfig.counterMode = TMR_COUNTER_MODE_UP;
    /* Set divider = 47 .So TMR1 clock freq ~= 48/(47+1) = 1MHZ */
    timeBaseConfig.div = SystemCoreClock / 1000000 - 1;
    /* Set counter = 1000 */
    timeBaseConfig.period = 1000;
    /* Repetition counter = 0x0 */
    timeBaseConfig.repetitionCounter =  0;
    TMR_ConfigTimeBase(TMR1, &timeBaseConfig);

    /* PWM1 mode */
    occonfig.OC_Mode = TMR_OC_MODE_PWM1;
    /* Idle State is reset */
    occonfig.OC_Idlestate = TMR_OCIDLESTATE_RESET;
    /* NIdle State is reset */
    occonfig.OC_NIdlestate = TMR_OCNIDLESTATE_RESET;
    /* Enable CH1N ouput */
    occonfig.OC_OutputNState = TMR_OUTPUT_NSTATE_DISABLE;
    /* Enable CH1 ouput */
    occonfig.OC_OutputState = TMR_OUTPUT_STATE_ENABLE;
    /* CH1  polarity is high */
    occonfig.OC_Polarity = TMR_OC_POLARITY_HIGH;
    /* CH1N polarity is high */
    occonfig.OC_NPolarity = TMR_OC_NPOLARITY_HIGH;
    /* Set compare value */
    occonfig.Pulse = 500;
    TMR_OC1Config(TMR1, &occonfig);

    /* Enable PWM output */
    TMR_EnablePWMOutputs(TMR1);

    /* Config TMR1 M0CP */
    TMR_M0CP_Init();

    /* Enable TMR1  */
    TMR_Enable(TMR1);
}

void M0CP_Init(void)
{
    M0CP_Config_T m0cpConfigStruct;

    /* Load firmware from Flash to SRAM */
    M0CP_Firmware_Init();

    /* Reset M0CP */
    RCM_EnableAHBPeriphReset(RCM_AHB_PERIPH_M0CP);
    RCM_DisableAHBPeriphReset(RCM_AHB_PERIPH_M0CP);

    /* Enable M0CP clock */
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_M0CP);

    /* Init M0CP hardware */
    M0CP_HardInit();

    M0CP_ClearStatusFlag(M0CP_FLAG_DONE);
    /* Disable M0CP TX interrupt */
    M0CP_DisableInterrupt(M0CP_INT_TX);

    /* Wait for M0CP to be ready */
    while (M0CP_ReadStatusFlag(M0CP_FLAG_BUSY) == SET)
    {

    }

    M0CP_ConfigStructInit(&m0cpConfigStruct);

    /* Configure M0CP */
    m0cpConfigStruct.algebraMode        = M0CP_ALG_SVPWM;
    m0cpConfigStruct.bankAutoConv       = M0CP_BANK_CONV_SOFTWARE;
    m0cpConfigStruct.bankRegGroup       = M0CP_BANK_REG_GROUP_0;
    m0cpConfigStruct.fixedPoint         = M0CP_FP_Q15;
    m0cpConfigStruct.outputSVPWM        = M0CP_SVPWM_OUT_CNT;
    m0cpConfigStruct.segSVPWM           = M0CP_SVPWM_SEG_7;
    M0CP_Config(&m0cpConfigStruct);
}








使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

18

主题

19

帖子

0

粉丝