1,芯片介绍

GD32H759I是高性能的微控制器,采用ARM Cortex-M7处理器,是GD32微控制器系列的一部分。它专为各种应用设计,注重于提高处理能力、降低功耗,并配备全面的外设集合。以下是对其特性、架构以及潜在应用场景的详细介绍:

**性能和核心:**
- ARM Cortex-M7处理器,具有6级超标量流水线和分支预测功能。
- 最高操作频率可达600 MHz。
- 可选的浮点单元(FPU)用于单精度和双精度运算。
- 内存保护单元(MPU)增强了应用的安全性。

**内存:**
- 内置高达3840 KB的闪存和1024 KB的SRAM。
- SRAM被分为AXI SRAM(512KB)、共享的ITCM/DTCM/AXI SRAM(512KB)以及备份SRAM(4KB)。

**电源管理:**
- 供电电压范围为1.71V到3.6V。
- 多种省电模式以优化功耗。

**外设:**
- 高级控制外设,包括多达十二个16位定时器,两个16位PWM高级定时器,和四个32位通用定时器。
- 通信接口丰富,包括六个SPIs、两个OSPIs、四个I2Cs、四个USARTs和四个UARTs。
- 两个14位4 MSPS的ADC和一个12位5.3 MSPS的ADC,用于模拟接口。
- 特殊外设如数字摄像机接口(DCI)、外部存储器控制器(EXMC)接口、TFT-LCD界面(TLI)等。




**总线架构:**
- 64位和32位的AXI和AHB总线接口,提供对内存和外设的访问。
- 使用哈佛架构组织内存,允许指令和数据的同时访问。

**SRAM区块:**
- **AXI SRAM**:这是一块通用的存储区,支持各种数据宽度的访问,适用于存储程序数据和缓存内容。
- **ITCM (Instruction Tightly-Coupled Memory)**:ITCM专门用于存储执行代码,它能提供高速的指令访问,适合存放关键代码和需要快速执行的指令。
- **DTCM (Data Tightly-Coupled Memory)**:DTCM用于存储快速访问的数据,它适用于频繁访问的数据处理任务。
- **备份SRAM (BKPSRAM)**:这是一块在主电源关闭后也能保持数据的RAM,适合存储关键配置和状态信息。

GD32H759I中的SRAM区域有不同的用途和特点:

    片上SRAM(AXI SRAM):它有512KB的容量,支持字节、半字、字、双字访问。这是通用的SRAM,可用于存储程序数据和缓存内容。

    备份SRAM(BKPSRAM):有4KB的容量,主要用于存储在电源关闭后也需要保留的重要数据。它位于备份域中。

    共享RAM:由ITCM、DTCM、AXI SRAM共享的512KB RAM。可以配置为指令紧凑型存储器(ITCM)和数据紧凑型存储器(DTCM),用于存放高速访问的数据和指令。

    SRAM0和SRAM1:各16KB的独立SRAM区域,通常用于特定的存储需求。

使用这些不同的区域时,需要考虑它们的特点和访问速度。例如,对于需要快速访问的数据或指令,可以使用ITCM和DTCM区域。对于不常改变的数据,可以使用备份SRAM,因为它即使在电源关闭后也能保留数据。片上SRAM(AXI SRAM)可以用于通用的程序数据存储,因为它提供了较大的容量和灵活的访问类型。

配置这些区域时,需要根据应用的需求来分配内存,同时考虑到效率和功耗的平衡。例如,常驻内存中的关键性能代码可以放在ITCM中,而DMA传输的数据可以放在AXI SRAM中,以此获得最优的性能。备份SRAM通常用于存储关键配置数据或小规模的重要数据,如加密密钥或配置参数。

0x20000000: 这通常是内部RAM(SRAM)的起始地址。在ARM Cortex-M系列微控制器中,这个地址是标准的内部RAM起始地址。

外部SDRAM 由 EXMC 管理 ,外部SDRAM 起始的地址(0xC0000000)


**应用场景:**
- 工业控制系统,因为它的快速处理能力和强大的定时器外设。
- 消费电子和便携式设备,由于其功率效率。
- 人机界面、安全系统和汽车导航,需要快速数据处理。
- 物联网(IoT)应用,鉴于其丰富的通信接口集合。

2,无感FOC原理

从软件算法的角度来讲,无传感器FOC是比较难的,因为没有传感器去获取电角度,也就是位置信息。看下面的FOC控制框图:




从上图中便可看出FOC的几个关键部分:SVPWM,几个三相交流变两相直流的公式,以及速度/位置反馈,在有传感器的电机控制中,无论是霍尔还是编码器,编码器就更简单一些了,可以直接反馈出电角度,只需要自己对应好电角度与机械角度即可,霍尔传感器虽然没有编码器那么方便,但也是可以轻松霍尔电角度的,只是有霍尔FOC的控制策略需要稍加改变。

有霍尔FOC需要方波启动,然后切换到正弦波(SVPWM),我最开始也是先做了这种控制模式,先使用了简单一些的带霍尔的BLDC,使用方波启动,然后切换到FOC,切换过程需要调试一下霍尔传感器对应的电角度,这个调试并不是很难,0-359的电角度,就算是一个一个试,一天也能试出来了,大约有30个电角度的范围,都是可以正常切换的,也就是说,假如硬件上霍尔U相对应的电角度为60度,那么切换角度大约45-75度之内都是可以切换成功的,只是偏离得大了,电流会大,这个注意一下电源的电流即可,而且偏离得大,电流就不是那么正弦,用电流计观测示波器波形也可以测试出来。关于有霍尔FOC的方波切换正弦波,以后有机会再详细说明。

项目中要求使用无传感器BLDC电机,也就没有传感器去直接获取电角度,需要通过算法来重构出电角度与转速,只要获取到电角度,转速是比较容易的。相比之下,虽然驱动无传感器电机算法要难一些,但是对于有传感器电机,无传感器电机的优势也是比较明显的:
1.成本低,传感器的成本也是高的,尤其是伺服电机的编码器
2.在一些恶劣环境,比如高温环境,传感器是有可能会有失灵或不准确的情况的,此时使用无传感器电机要好很多。

同样,无传感器的BLDC电机的劣势也是显而易见的:
1.算法复杂,开发周期长
2.启动困难,在对启动不能抖动的应用场合,应用不方便
3.精度不高,在对控制精度有要求的应用场合,也基本不会选用无传感器电机

分析各大做电机控制的半导体公司的方案,以及对现有资料的丰富度分析,TI是使用的FAST观测器+反正切,ST是使用的龙伯格观测器+PLL,Microchip使用的是滑模观测器+PLL,新塘使用的滑模观测器+反正切+PLL,传统的方案是滑模观测器+反正切,或滑模观测器+PLL,因为滑模观测器比较简单,编程容易。

综上,根据项目需求以及软件算法综合比较,采用SVPWM强拖+滑模观测器+反正切+PLL的方式实现全正弦无感FOC。

滑模观测器主要包含三部分:
1.电机方程
2.滑模面选取
3.符号函数选取
第一步建立电机方程,有两种方式,第一种:利用静止的α-β坐标系建立电机方程,第二种:利用运动的d-q坐标系建立电机方程,我选用的是第一种,第一种比较简单一些。

第二步选取滑模面,选取估计电流与实际电流的差值作为滑模面。

第三步符号函数,符号函数我尝试了两种,饱和函数与连续函数,都可以调出来效果。

基本就是使用的传统SMO的方法,框图如下:





我加入了注释,应该对滑模+反正切算法的流程一目了然,之后便是各个具体步骤,
α-β坐标系下的电机模型:




结合之前的SMO控制框图,再看这个会比较容易一些

而符号函数的选取,有很多种,可以根据自己的实际芯片能力,以及实际效果来选取,鉴于我的芯片计算能力,我试了两种---饱和函数与连续函数。

观测器之后便是反正切,可以直接使用atan函数,因此需要编写反正切的快速计算算法,实际效果也还行,因为我只需要计算出整数电角度与即可,也就是0-359度,最后测试快速计算算法时间也符合要求,差不多迭代3-4次即可计算出任意整数电角度:




在这些算法程序都编写好之后,便是观测器的调试,主要是符号函数与电机模型参数的调试,这个要看自己的实际情况而定,每个电机的参数都有所不同。

调试观测器的时候,因为此观测器是使用电流重构的,因此要保证电流采样的正确性,以及转速不能太低,转速过低的话是无法从强拖切换到观测器的,因此先调试强拖,转速先到一定水平,一般是电机额定转速的10%左右,之后就是调试电机模型,基本上电机模型调试正确,符号函数就很好调试,模型也就是电机的阻感参数,根据自己的电机类型,凸极式电机就调试Lq,Ld,Rs,表贴式电机就调试Ls,Rs,在知道电机类型,以及使用仪器实际测试电机参数之后,进行微调,切忌盲目调试。

可以参照我的调试方法:先使用有霍尔电机,用霍尔传感器实际测试出来的电角度对观测器的电角度进行验证,先对比一下调试结果是否可用,情况会好很多,我最开始调试的初步效果如下:




当然,这是是使用的有霍尔电机,目标电机是无霍尔电机,也就是说,阻感参数不一样,全部都要重新调试一遍,不过,掌握调试方法即可。

调试出的电流结果奉上:












有关无感FOC的内容,还需要几年的时间去磨练总结,亲身体会,并不是说照着书上的公式把程序写出来就万事大吉,要成为电机大牛还需要见多识广,电机中很多黑匣子是需要个人花时间去钻研的。与君共勉。


代码展示:

sv_mod_t sv = SVGEN_DEFAULTS;

void svpwm_calc_macro(sv_mod_t* p){
SVGENDQ_MACRO((*p));
}

void svpwm_overflow_check(sv_mod_t* p){
  
_iq max_time = 32767;
_iq min_time = -32768;
  
if(p->Ta > max_time){
  p->Ta = max_time;
}
if(p->Ta < min_time){
  p->Ta = min_time;
}  
if(p->Tb > max_time){
  p->Tb = max_time;
}
if(p->Tb < min_time){
  p->Tb = min_time;
}
if(p->Tc > max_time){
  p->Tc = max_time;
}
if(p->Tc < min_time){
  p->Tc = min_time;
}
}

void svpwm_calc(sv_mod_t* v){
  
sv_mod_t *p = v;
if(p == NULL){
  //todo error detect
}
p->tmp1= p->Ubeta;               
p->tmp2= _IQdiv2(p->Ubeta) + (_IQmpy(_IQ(0.866),p->Ualpha));      
    p->tmp3= p->tmp2 - p->tmp1;              
                     
p->VecSector=3;                 
p->VecSector=(p->tmp2> 0)?( p->VecSector-1):p->VecSector;      
p->VecSector=(p->tmp3> 0)?( p->VecSector-1):p->VecSector;      
p->VecSector=(p->tmp1< 0)?(7-p->VecSector) :p->VecSector;      
                     
if(p->VecSector==1 || p->VecSector==4){
  p->Ta= p->tmp2;            
     p->Tb= p->tmp1-p->tmp3;
       p->Tc=-p->tmp2;
}
else if(p->VecSector==2 || p->VecSector==5){
  p->Ta= p->tmp3+p->tmp2;
     p->Tb= p->tmp1;
       p->Tc=-p->tmp1;
}else{
  p->Ta= p->tmp3;
  p->Tb=-p->tmp3;            
       p->Tc=-(p->tmp1+p->tmp2);
}
  
svpwm_overflow_check(p);
}


sv_regs_mod_t svpwm_get_regs_mod(_iq vdc,_iq pwm_t, sv_mod_t* v){
  
/**   
// Convert the unsigned GLOBAL_Q format (ranged (0,1)) -> signed GLOBAL_Q format (ranged (-1,1))
v->Ta = _IQmpy(_IQ(2.0),(v->Ta-_IQ(0.5)));
v->Tb = _IQmpy(_IQ(2.0),(v->Tb-_IQ(0.5)));
v->Tc = _IQmpy(_IQ(2.0),(v->Tc-_IQ(0.5)));
这三条语句实现了占空比由(0,1)到(-1,1)的转换
*/  
  
/**
(-1,1)到(0,1)的转换
*/
sv_regs_mod_t sv_regs;
_iq tmp = 0;
tmp = v->Ta * pwm_t / vdc;
sv_regs.ccr1 = (_iq)((tmp >> 1) + (pwm_t>> 1));
  
tmp = v->Tb * pwm_t / vdc;
sv_regs.ccr2 = (_iq)((tmp >> 1) + (pwm_t>> 1));
  
tmp = v->Tc * pwm_t / vdc;
sv_regs.ccr3 = (_iq)((tmp >> 1) + (pwm_t>> 1));
  
return sv_regs;
}

void HALL_Init_Electrical_Angle(void)
{
  
BLDC_Type_Motor.Hall_Current_State  = Read_HallState();
BLDC_Type_Motor.Hall_Prev_State = BLDC_Type_Motor.Hall_Current_State;

switch(BLDC_Type_Motor.Hall_Current_State)
{
  case STATE_5:
    BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT+S16_60_PHASE_SHIFT/2);
   
    break;
  case STATE_1:
     BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT+S16_60_PHASE_SHIFT+S16_60_PHASE_SHIFT/2);
  
    break;
  case STATE_3:
    BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT+S16_120_PHASE_SHIFT+S16_60_PHASE_SHIFT/2);
   
    break;
  case STATE_2:
    BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT-S16_120_PHASE_SHIFT-S16_60_PHASE_SHIFT/2);      
  
break;
  case STATE_6:
    BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT-S16_60_PHASE_SHIFT-S16_60_PHASE_SHIFT/2);  
   
    break;
  case STATE_4:
    BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT-S16_60_PHASE_SHIFT/2);      
   
    break;     
  default:     
    break;
  
  }

  
  
BLDC_Type_Motor.Hall_EAngle_Prv = BLDC_Type_Motor.Hall_EAngle_Cur;
  
}





//motor1霍尔接口中断处理
void Hall_Capture_EAngle(void)
{
  
uint8_t i;   
  
  //霍尔信号跳变,捕获事件发生
  BLDC_Type_Motor.Hall_Current_State = Read_HallState();
  
  if(BLDC_Type_Motor.Hall_Current_State != BLDC_Type_Motor.Hall_Prev_State)
  
  {
   
  
    BLDC_Type_Motor.Hall_Capture_Flag = 1;
   
   
   
   

  switch(BLDC_Type_Motor.Hall_Current_State)
    {
      
   case STATE_5: //以状态5为准 Hall_EAngle_Cur_onecircle{0}存储一个电周期需要的时间,剩下1到6存储6相间隔的值
         
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0] = 0;
     for(i=1 ;i<7;i++)
     {
        
       BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0] += BLDC_Type_Motor.Hall_EAngle_Cur_onecircle;
     }
      
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[1] = BLDC_Type_Motor.Hall_EAngle_Count ;
      
      
     if(BLDC_Type_Motor.Hall_Prev_State == STATE_4)
     {
      BLDC_Type_Motor.Hall_Direction = POSITIVE;      
      
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)S16_PHASE_SHIFT;
      //BLDC_Type_Motor.Hall_EAngle_Cur += BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[1]*0x7fff/BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0];
      
     // BLDC_Type_Motor.Hall_EAngle_Cur += S16_60_PHASE_SHIFT/2;
     }
     else if (BLDC_Type_Motor.Hall_Prev_State == STATE_1)
     {
      BLDC_Type_Motor.Hall_Direction = NEGATIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT+S16_60_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }
   
        break;
              
    case STATE_1:
   
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[2] = BLDC_Type_Motor.Hall_EAngle_Count ;
         
     if (BLDC_Type_Motor.Hall_Prev_State == STATE_5)
     {
      BLDC_Type_Motor.Hall_Direction = POSITIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT+S16_60_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur += BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[2]*0x7fff/BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0];
      //BLDC_Type_Motor.Hall_EAngle_Cur += S16_60_PHASE_SHIFT/3;
     }
     else if (BLDC_Type_Motor.Hall_Prev_State == STATE_3)
     {
      BLDC_Type_Motor.Hall_Direction = NEGATIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT+S16_120_PHASE_SHIFT);
      
     }
      
      
   
        break;   
      
      case STATE_3:  
         
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[3] = BLDC_Type_Motor.Hall_EAngle_Count ;
   
     if (BLDC_Type_Motor.Hall_Prev_State == STATE_1)
     {
      BLDC_Type_Motor.Hall_Direction = POSITIVE;  
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT+S16_120_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur  +=(s16)BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[3]*0x7fff/BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0];;
      BLDC_Type_Motor.Hall_EAngle_Cur += S16_60_PHASE_SHIFT/3;
     }
     else if (BLDC_Type_Motor.Hall_Prev_State == STATE_2)
     {
      BLDC_Type_Motor.Hall_Direction = NEGATIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT+S16_120_PHASE_SHIFT+S16_60_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }   
      
     break;
      case STATE_2:  
         
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[4] = BLDC_Type_Motor.Hall_EAngle_Count ;
   
     if (BLDC_Type_Motor.Hall_Prev_State == STATE_3)
     {
      BLDC_Type_Motor.Hall_Direction = POSITIVE;  
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT+S16_120_PHASE_SHIFT+S16_60_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur +=(s16)BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[4]*0x7fff/BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0];;
      //BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }
     else if (BLDC_Type_Motor.Hall_Prev_State == STATE_6)
     {
      BLDC_Type_Motor.Hall_Direction = NEGATIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT-S16_120_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }   
      
        break;
   case STATE_6:  
      
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[5] = BLDC_Type_Motor.Hall_EAngle_Count ;
   
     if (BLDC_Type_Motor.Hall_Prev_State == STATE_2)
     {
      BLDC_Type_Motor.Hall_Direction = POSITIVE;  
      BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT-S16_120_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur +=(s16)BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[5]*0x7fff/BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0];;
      
     // BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }
     else if (BLDC_Type_Motor.Hall_Prev_State == STATE_4)
     {
      BLDC_Type_Motor.Hall_Direction = NEGATIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur = (s16)(S16_PHASE_SHIFT-S16_60_PHASE_SHIFT);
      //BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }  

      
         
        break;
   case STATE_4:  
     
     BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[6] = BLDC_Type_Motor.Hall_EAngle_Count ;
         
     if (BLDC_Type_Motor.Hall_Prev_State == STATE_6)
     {
      BLDC_Type_Motor.Hall_Direction = POSITIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur =(s16)(S16_PHASE_SHIFT -S16_60_PHASE_SHIFT);      
      //BLDC_Type_Motor.Hall_EAngle_Cur +=(s16)BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[6]*0x7fff/BLDC_Type_Motor.Hall_EAngle_Cur_onecircle[0]; ;
      BLDC_Type_Motor.Hall_EAngle_Cur += (S16_60_PHASE_SHIFT/3);
     }
     else if (BLDC_Type_Motor.Hall_Prev_State == STATE_5)
     {
      BLDC_Type_Motor.Hall_Direction = NEGATIVE;
      BLDC_Type_Motor.Hall_EAngle_Cur =(s16)S16_PHASE_SHIFT;
      //BLDC_Type_Motor.Hall_EAngle_Cur -= S16_60_PHASE_SHIFT/2;
     }   
         
        break;
      
   
      
      default:
     
     
       // BLDC_Type_Motor.Hall_Direction = ERROR;
        break;
    }
   
  BLDC_Type_Motor.Hall_EAngle_Prv = BLDC_Type_Motor.Hall_EAngle_Cur;
   BLDC_Type_Motor.Hall_Prev_State = BLDC_Type_Motor.Hall_Current_State;
   
   
  /*****************霍尔间隔的平滑滤波*****************************/
  
   BLDC_Type_Motor.Hall_Period[SPEED_BUF_SIZE] = BLDC_Type_Motor.Hall_EAngle_Count;
   BLDC_Type_Motor.Hall_EAngle_Count = 0;
   // 数据左移一个数组位置,最开始的一个会丢掉
   for( i=0;i<SPEED_BUF_SIZE;i++)
   {
     BLDC_Type_Motor.Hall_Period = BLDC_Type_Motor.Hall_Period[i + 1]+BLDC_Type_Motor.Hall_OVF_Timer*0x7fff;
     //求和
     BLDC_Type_Motor.Hall_Period_Sum += BLDC_Type_Motor.Hall_Period;
   }
   //对于数组刚开始还未填充满时的均值获取
   if(BLDC_Type_Motor.buf_count_flag == 0){
    BLDC_Type_Motor.buf_count++;
    BLDC_Type_Motor.Hall_Period_Avg = BLDC_Type_Motor.Hall_Period_Sum/BLDC_Type_Motor.buf_count;
    BLDC_Type_Motor.Hall_Period_Sum = 0;
   }
   //对于数组已经填充满时的均值获取
   else if(BLDC_Type_Motor.buf_count_flag == 1){
    BLDC_Type_Motor.Hall_Period_Avg = BLDC_Type_Motor.Hall_Period_Sum/SPEED_BUF_SIZE;
    BLDC_Type_Motor.Hall_Period_Sum = 0;
    BLDC_Type_Motor.Hall_First_Cycle = 1;//第一个电周期完成
   }
   //数组已经到达SPEED_BUF_SIZE的尺度
   if(BLDC_Type_Motor.buf_count >= SPEED_BUF_SIZE ){
    BLDC_Type_Motor.buf_count_flag = 1;
     
   }
   
   BLDC_Type_Motor.Hall_Direction =1;
   BLDC_Type_Motor.Speed_Omega = (s32)(PWM_FREQUENCY*S16_60_PHASE_SHIFT/BLDC_Type_Motor.Hall_Period_Avg*BLDC_Type_Motor.Hall_Direction);
  // BLDC_Type_Motor.Speed_fb = (s32)(60.0*1000000.0/((BLDC_Type_Motor.Hall_Period_Avg)*M1_PULSES_PER_MECHANICAL)*BLDC_Type_Motor.Hall_Direction);//rpm
   
  
  BLDC_Type_Motor.Hall_Capture_Flag = 0;
   
}
   
else   
   
{
   // hall区间相同的时候
   
   
  BLDC_Type_Motor.Hall_EAngle_Count++;  
   
   
  if(BLDC_Type_Motor.Hall_EAngle_Count >PWM_FREQUENCY)
  {
   BLDC_Type_Motor.Hall_EAngle_Count = PWM_FREQUENCY - 1;
   
  //捕获发生后的溢出次数计数
  if(BLDC_Type_Motor.Hall_Capture_Flag != 1){
   BLDC_Type_Motor.Hall_OVF_Timer++;
   
   //超时归零
   if(BLDC_Type_Motor.Hall_OVF_Timer >= HALL_MAX_OVERFLOWS){
    BLDC_Type_Motor.Hall_OVF_Timer = 0;
    BLDC_Type_Motor.Hall_Capture_Flag = 0;
    for(i=0;i<SPEED_BUF_SIZE;i++){
     BLDC_Type_Motor.Hall_Period=0;
     //BLDC_Type_Motor.Speed_fb_buf=0;
    }
    BLDC_Type_Motor.buf_count = 0;
    BLDC_Type_Motor.buf_count_flag = 0;
    BLDC_Type_Motor.Hall_Period_Sum=0;
    BLDC_Type_Motor.Hall_PulNum=0;
    BLDC_Type_Motor.Speed_fb=0;
    BLDC_Type_Motor.Speed_fb_prv=0;
    BLDC_Type_Motor.Hall_First_Cycle=0;
   }
  }
   
   
}
   
   
   
}
  
}