【GD32F310开发板试用】GD电机驱动底层配置——永磁同步电机控制

首发极术社区。如对兆易创新GD32F310 MCU感兴趣,欢迎添加微信 aijishu2020 加入GD32技术讨论群。

1.摘要

GD32F310是一款基于 Arm® Cortex®-M4 RISC 内核的32 位通用微控制器,最高主频可达72MHz并支持DSP指令运算。配备了16KB到64KB的内置Flash及4KB到8KB的SRAM,整合了丰富的外设,包括1个支持三相PWM互补输出和死区管理功能的16位高级定时器可用于矢量控制,多达5个16位通用定时器, 1个12位ADC,可使GD32F310系列广泛应用于永磁同步电机控制领域。本文将介绍应用于电机控制时,高级定时器和ADC的配置过程。

2.底层驱动配置

GD32F310中的高级定时器TIMER0是一个四通道16位定时器,同时支持向上计数、向下计数和中央计数,可编程的计数器重复功能,并包含了一个死区时间插入模块,可以生成两路互补的PWM波,非常适应电机控制,因而使用TIMER0生成三组六路PWM波来驱动三相逆变桥,如图1所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VCIwVQe3-1649928273952)(/img/bVbur0 " title=")]

在驱动三相逆变器的同时需要配合采样永磁同步电机A、B、C三相电流,通常为节省成本,将采样电阻设置在逆变器的下桥臂,因此配置触发ADC采样的时机就显的非常关键,须在下桥臂打开时采样三相电流。在电机控制中,通常将高级定时器TIMER0配置为中央计数模式,ADC采样的时刻和其中一相的上下桥臂PWM如图2所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MtXnlh0q-1649928273953)(/img/bVbur1 " title=")]

配置要点是:

  1. 高级定时器TIMER0配置为中央计数模式,并在计数值接近到零处触发ADC采样三相电流;
  2. 在高级定时器TIMER0输出的两路PWM中插入死区时间,通常在20kHZ的PWM中设置100ns的死区;
  3. 电机的两相电流的ADC采样模块配置为注入通道组,在触发ADC采样后,同时采样电机的两相电流值;
  4. 在ADC采样完成后,进行FOC运算;

具体配置代码如下:

    uint32_t dummy = 0;
    timer_parameter_struct timer_initpara;
    timer_oc_parameter_struct timer_ocintpara;
    timer_break_parameter_struct timer_bkdtpara;
    
/************************************* step0: 开启时钟 *******************************************/
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_TIMER0);
    rcu_periph_clock_enable(RCU_ADC);
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV2);
    
/************************************* step1: GPIO配置 *******************************************/
    /* 配置6路PWM的IO */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_8);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
    gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_8);

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
    gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_9);

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
    gpio_af_set(GPIOA, GPIO_AF_2, GPIO_PIN_10);

    /* 驱动使能 */
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_5);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
    gpio_bit_reset(GPIOA, GPIO_PIN_5);
    
    /* 配置电流采样的IO */
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);


/************************************* step2: timer配置 ******************************************/
    timer_deinit(TIMER0);
    timer_initpara.prescaler = PWM_PRSC;
    timer_initpara.alignedmode = TIMER_COUNTER_CENTER_DOWN;
    timer_initpara.period = HALF_PWM_PERIOD;          /* 配置三相桥开关频率 */
    timer_initpara.clockdivision = TIMER_CKDIV_DIV2;  /* 死区时间计算用到的分频 */
    timer_initpara.repetitioncounter = 1;                /* 重复计数器, 影响更新事件的频率 */
    timer_init(TIMER0, &timer_initpara);
    
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
    timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;     
    timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
    timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
    
    timer_channel_output_config(TIMER0, TIMER_CH_0,&timer_ocintpara);
    timer_channel_output_config(TIMER0, TIMER_CH_1,&timer_ocintpara);
    timer_channel_output_config(TIMER0, TIMER_CH_2,&timer_ocintpara);
    
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
    timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
    timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
    timer_channel_output_config(TIMER0, TIMER_CH_3,&timer_ocintpara);
    
    /* channel1~3 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, HALF_PWM_PERIOD/2);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM1);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);   /* 预装载使能 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_1, HALF_PWM_PERIOD/2);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);   /* 预装载使能 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_2, HALF_PWM_PERIOD/2);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_2, TIMER_OC_MODE_PWM1);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);   /* 预装载使能 */
    
    /* channel4 设置, 触发ADC用 */
    timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_3, 5);
    timer_channel_output_mode_config(TIMER0, TIMER_CH_3, TIMER_OC_MODE_PWM0);
    timer_channel_output_shadow_config(TIMER0, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);   /* 预装载使能 */
    timer_master_output_trigger_source_select(TIMER0, TIMER_TRI_OUT_SRC_O3CPRE);      /* 上升沿触发ADC */
    
    /* 配置死区 */
    timer_bkdtpara.runoffstate = TIMER_ROS_STATE_ENABLE;
    timer_bkdtpara.ideloffstate = TIMER_IOS_STATE_ENABLE;
    timer_bkdtpara.protectmode = TIMER_CCHP_PROT_0;
    timer_bkdtpara.deadtime = DEADTIME;
    timer_bkdtpara.breakstate = TIMER_BREAK_DISABLE;
    timer_bkdtpara.breakpolarity = TIMER_BREAK_POLARITY_LOW;
    timer_bkdtpara.outputautostate = TIMER_OUTAUTO_DISABLE;
    timer_break_config(TIMER0, &timer_bkdtpara);

    /* 多电机控制同步用的 */
    timer_input_trigger_source_select(TIMER0, TIMER_SMCFG_TRGSEL_ITI1);
    timer_slave_mode_select(TIMER0, TIMER_SLAVE_MODE_EVENT);
    timer_event_software_generate(TIMER0, TIMER_EVENT_SRC_UPG);
    timer_counter_value_config(TIMER0, 0);

    /* 只需要CC4使能 */
    timer_channel_output_state_config(TIMER0, TIMER_CH_0, TIMER_CCX_DISABLE);
    timer_channel_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCX_DISABLE);
    timer_channel_output_state_config(TIMER0, TIMER_CH_2, TIMER_CCX_DISABLE);
    timer_channel_output_state_config(TIMER0, TIMER_CH_3, TIMER_CCX_ENABLE);
    timer_channel_complementary_output_state_config(TIMER0, TIMER_CH_0, TIMER_CCXN_DISABLE);
    timer_channel_complementary_output_state_config(TIMER0, TIMER_CH_1, TIMER_CCXN_DISABLE);
    timer_channel_complementary_output_state_config(TIMER0, TIMER_CH_2, TIMER_CCXN_DISABLE);

    timer_update_source_config(TIMER0, TIMER_UPDATE_SRC_REGULAR);
    timer_single_pulse_mode_config(TIMER0, TIMER_SP_MODE_REPETITIVE);
    timer_primary_output_config(TIMER0,ENABLE);
    timer_auto_reload_shadow_enable(TIMER0);
    timer_enable(TIMER0);

    dbg_periph_enable(DBG_TIMER0_HOLD);

/************************************** step3: adc配置 *******************************************/
    adc_deinit();
    adc_special_function_config(ADC_SCAN_MODE, ENABLE);
    adc_special_function_config(ADC_CONTINUOUS_MODE, DISABLE);
    adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE); 
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);

    /* 注入组配置 */
    adc_channel_length_config(ADC_INSERTED_CHANNEL, 2);
    adc_inserted_channel_config(0, ADC_CHANNEL_1, ADC_SAMPLETIME_7POINT5);         /* A相电流 */
    adc_inserted_channel_config(1, ADC_CHANNEL_2, ADC_SAMPLETIME_7POINT5);         /* B相电流 */

    adc_external_trigger_source_config(ADC_INSERTED_CHANNEL, ADC_EXTTRIG_INSERTED_T0_CH3); 
    adc_external_trigger_config(ADC_INSERTED_CHANNEL, ENABLE);

    adc_enable();
    for(dummy = 0; dummy < 60000; dummy++);
    adc_calibration_enable();
    
    adc_interrupt_enable(ADC_INT_EOIC);
    nvic_irq_enable(ADC_CMP_IRQn, ADC_PRE_PRIORITY, ADC_SUB_PRIORITY);
3.让电机转动

参考《2.有感FOC——永磁同步电机控制》,获取转子位置后可实现永磁同步电机电角度以10Hz频率运动,如图3所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lqYJHPbk-1649928273953)(/img/bVbusc)]

4.让电机演奏

参考英飞凌公众号文章《如何打造一台会演奏音乐的电机》和《4.无感FOC之高频注入法——永磁同步电机控制》,向电机注入不同频率的电压信号,按乐谱进行组合,就可以控制电机演奏不同的歌曲,音频如图4所示。
《送别》

  • 9
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值