SRPWM的比较模式设置对波形生成影响的应用指南

功能说明

在ET600X系列中的SRPWM中,可以对比较模式进行设置。

模式一:

时基计数器等于比较值时产生比较事件

模式二:

时基计数器大于等于比较值时(向上计数)或者 时基计数器小于等于比较值时(向下计数)产生比较事件

但在实际应用中,该模式常被忽略,从而导致不符合期望的PWM波形产生。 本文将结合示例,对该比较模式进行详细讲解

模式一

时基计数器等于比较值时产生比较事件,即当时基计数器的计数值等于设置的比较值时,产生相应的比较事件,该事件可以用于动作矩阵的生成,也可以用于信号同步,具体可以参考对应芯片型号的用户手册。 该模式在对应寄存器的值为0,即寄存器级的默认模式。(注意:SDK可能已修改该默认模式) 需要注意的是,由于该模式为默认值,用户在开发时,常常将其忽略,从而导致产生的波形不符合期望。 具体的原因,将在后文作出分析。

模式二

计数方向向上时:时基计数器大于等于比较值时产生比较事件

计数方向向下时:时基计数器小于等于比较值时产生比较事件

可以看到,模式二与模式一的区别在于,不再局限为等于时(时基计数器和比较值的关系),才产生事件。

场景应用

上述章节简述比较模式的两种设置。为了更好地展现两者的区别,接下来,将以具体示例进行说明。

示例代码

以SRPWM8和SRPWM9作为示例。为了方便,本文将SRPWM8的A路简述为8A,SRPWM9的A路简述为9A,SRPWM9的B路简述为9B。

关键项如下:

  1. 均采用上下计数模式。周期初始值为4000,比较值A为2000,比较值B为2000,死区为78。除死区外,均配置影子加载时刻为周期时刻。

  2. 动作矩阵

    • 8A:比较值A向上时拉低;比较值A向下时拉高

    • 8B:比较值B向上时拉低;比较值A向下时拉高

    • 9A:比较值A向上时拉低;比较值A向下时拉高

    • 9B:过零时刻拉低;周期时刻拉高

  3. 死区配置:

    • 8A/9A/8B/9B:均采用自身的动作源做上升沿延时

    • 8A采用上升沿延时后的输出;9A采用上升沿延迟后的取反输出

    • 8B采用下降沿延时后的取反输出;9B采用下降沿延迟后的输出

  4. 使能SRPWM8和SRPWM9的多通道、多参数、一次加载功能。多参数为:周期、相位、比较值。

异常构造

异常产生的时候:周期参数修改,且加载时,9A产生了异常高脉宽,8A未产生该脉宽。根据需求,切换之后,期望波形应该为:在参数加载真实生效之后,8A/9A均为低电平。 对应具体的代码过程:

  1. 8A\9A软件强制封波。

  2. 设置多参数

    • SRPWM8\9周期值由4000设置为6500

    • SRPWM8比较值A设置为1

    • SRPWM8比较值B设置为6499

    • SRPWM9比较值A设置为6499

    • SRPWM9比较值B设置为1

    • SRPWM8\9相位值设置为0

  3. SRPWM8和SRPWM9下发一次加载确认脉冲

  4. 8A\9A取消软件强制封波

代码分成3个部分进行:GPIO配置、PWM配置、测试代码,需包含各自的驱动文件

备注

本文档测试代码以ET6001为例。

  • GPIO配置:将GPIO0_0配置为输出

static void GPIO_Config(void)
{
   IOC_Init_TypeDef init;
   IOC_ConfigStructInit(&init);
   init.mode = IOC_AF_MODE_0;
   init.dir = GPIO_DIR_OUT;
   init.pull = IOC_PULL_NONE;
   IOC_Config(IOC_PIN_GPIO_PLL_REF, &init);
   GPIO_PortOutputEnable(GPIO0, GPIO_PIN_00);
   GPIO_WritePin(GPIO0, GPIO_PIN_00, RESET);
}
  • PWM的配置

static void SRPWM_Config(void)
{
   SRPWM_TBInitTypeDef stTBInit;
   SRPWM_CMPInitTypeDef stCMPInit;
   SRPWM_DBInitTypeDef stDBInit;
   IOC_Init_TypeDef Init;

   /* 复位SRPWM0,并开启SRPWM0的时钟 */
   CRG_PeriphReset(CRG_SRST_SRPWM9);
   /* IO mux配置 */
   IOC_ConfigStructInit(&Init);
   Init.mode = IOC_AF_MODE_1;
   IOC_Config(IOC_PIN_GPIO1_8, &Init); //pwm8a
   IOC_Config(IOC_PIN_GPIO1_10, &Init); //pwm9a
   IOC_Config(IOC_PIN_GPIO1_11, &Init); //pwm9b
   /* 1、TB初始化 */
   SRPWM_TBStructInit(&stTBInit);
   stTBInit.period    = 4000;
   stTBInit.periodLoadSyncEn = ENABLE;
   stTBInit.prdLoadSyncSel = SRPWM_SYNCEVTLOAD1_PERIOD_EVT;
   stTBInit.phsLoadSyncSel = SRPWM_SYNCEVTLOAD1_PERIOD_EVT;
   stTBInit.phaseLoadSyncEn = ENABLE;
   stTBInit.countMode = SRPWM_COUNTMODE_UPDOWN;
   SRPWM_TBInit(SRPWM9, &stTBInit);
   SRPWM_TBInit(SRPWM8, &stTBInit);
   /* 2、CMP初始化 */
   SRPWM_CMPStructInit(&stCMPInit);

   stCMPInit.cmpA = stTBInit.period / 2;
   stCMPInit.cmpB = stTBInit.period / 2;
   stCMPInit.cmpLoadSyncEn = ENABLE;
   stCMPInit.cmpLoadSyncSel = SRPWM_SYNCEVTLOAD1_PERIOD_EVT;
   SRPWM_CMPInit(SRPWM9, &stCMPInit);
   SRPWM_CMPInit(SRPWM8, &stCMPInit);
   /* 修改比较模式 */
   //        SET_BIT(SRPWM8->CMP_CTL, (uint32_t)1 << 0);
   //        SET_BIT(SRPWM9->CMP_CTL, (uint32_t)1 << 0);
   /* 3、PG初始化 */
   SRPWM_SetPG(SRPWM8, SRPWM_PWMA, SRPWM_PG_EVT_CMPA_UP, SRPWM_PG_CLEAR);
   SRPWM_SetPG(SRPWM8, SRPWM_PWMA, SRPWM_PG_EVT_CMPA_DOWN, SRPWM_PG_SET);
   SRPWM_SetPG(SRPWM8, SRPWM_PWMB, SRPWM_PG_EVT_CMPB_UP, SRPWM_PG_CLEAR);
   SRPWM_SetPG(SRPWM8, SRPWM_PWMB, SRPWM_PG_EVT_CMPB_DOWN, SRPWM_PG_SET);

   SRPWM_SetPG(SRPWM9, SRPWM_PWMA, SRPWM_PG_EVT_CMPA_UP, SRPWM_PG_CLEAR);
   SRPWM_SetPG(SRPWM9, SRPWM_PWMA, SRPWM_PG_EVT_CMPA_DOWN, SRPWM_PG_SET);

   SRPWM_SetPG(SRPWM9, SRPWM_PWMB, SRPWM_PG_EVT_ZERO, SRPWM_PG_CLEAR);
   SRPWM_SetPG(SRPWM9, SRPWM_PWMB, SRPWM_PG_EVT_PERIOD, SRPWM_PG_SET);

   /* DB初始化*/
   SRPWM_DBStructInit(&stDBInit);
   stDBInit.a.risingDelay = 78;
   stDBInit.b.fallingDelay = 78;
   stDBInit.a.selComplementChannel = DISABLE;
   stDBInit.a.selRisingDelay = ENABLE;
   stDBInit.a.selFallingDelay = DISABLE;
   stDBInit.a.selOutputState = SRPWM_DB_OUTPUT_STATE_POS_OR_NEG_AFTER;
   stDBInit.b.selRisingDelay = DISABLE;
   stDBInit.b.selFallingDelay = ENABLE;
   stDBInit.b.selComplementChannel = DISABLE;
   stDBInit.b.selOutputState = SRPWM_DB_OUTPUT_STATE_POS_OR_NEG_INVERT;
   SRPWM_DBInit(SRPWM8, &stDBInit);

   SRPWM_DBStructInit(&stDBInit);
   stDBInit.a.fallingDelay = 78;
   stDBInit.a.selComplementChannel = DISABLE;
   stDBInit.a.selFallingDelay = ENABLE;
   stDBInit.a.selRisingDelay = DISABLE;
   stDBInit.a.selOutputState = SRPWM_DB_OUTPUT_STATE_POS_OR_NEG_INVERT;
   SRPWM_DBInit(SRPWM9, &stDBInit);
   SRPWM_ShadowMultiCfgSyncEnable(SRPWM8, SRPWM_SHD_MULTI_SYNC_PRD | SRPWM_SHD_MULTI_SYNC_PHASE | SRPWM_SHD_MULTI_SYNC_CMP);
   SRPWM_ShadowMultiCfgSyncEnable(SRPWM9, SRPWM_SHD_MULTI_SYNC_PRD | SRPWM_SHD_MULTI_SYNC_PHASE | SRPWM_SHD_MULTI_SYNC_CMP);

   /* 4、使能高精度旁路 */
   SRPWM_HRPWMBypassEnable(SRPWM8);
   SRPWM_HRPWMBypassEnable(SRPWM9);
   /* 5、使能指定模块 */
   SRPWMCOM_Enable(SRPWM_CHANNEL_8 | SRPWM_CHANNEL_9);
}
  • 测试代码:

float float32_sat(float in, uint16_t hi, uint16_t lo)
{
   float temp;
   temp = in > hi ? hi : in;
   temp = temp < lo ? lo : temp;
   return temp;
}

#define DRIVER_SET_PWM_PARAM(prd, duty_lv, duty_hv, phase_lv, phase_hv) do{\
   float cmpa;\
   SRPWM_SetPeriod(SRPWM8, (uint16_t)(prd), 0x0);\
   SRPWM_SetPeriod(SRPWM9, (uint16_t)(prd), 0x0);\
   cmpa = float32_sat((float)prd * duty_lv, prd, 1);\
   SRPWM_SetCmpA(SRPWM8, (uint16_t)(cmpa), 0x0);\
   SRPWM_SetCmpB(SRPWM8, (uint16_t)(prd - cmpa), 0x0);\
   cmpa = float32_sat((float)prd * duty_hv, prd, 1);\
   SRPWM_SetCmpA(SRPWM9, (uint16_t)(prd - cmpa), 0x0);\
   SRPWM_SetCmpB(SRPWM9, (uint16_t)(cmpa), 0x0);\
   SRPWM_SetPhase0(SRPWM8, (uint16_t)(phase_lv));\
   SRPWM_SetPhase0(SRPWM9, (uint16_t)(phase_hv));\
}while(0)

int main(void)
{
   GPIO_Config();
   /* 配置SRPWM */
   SRPWM_Config();

   while (1)
   {
      if(testFlag == 1)
      {
         GPIO_WritePin(GPIO0, GPIO_PIN_00, SET);
         testFlag = 0;
         SRPWMCOM_PSTPSwForceOutState(SRPWM_CHANNEL_8, SRPWM_PWMA, SRPWM_PSTP_MUTEX_OUTSTATE_CLEAR);
         SRPWMCOM_PSTPSwForceOutState(SRPWM_CHANNEL_9, SRPWM_PWMA, SRPWM_PSTP_MUTEX_OUTSTATE_CLEAR);


         DRIVER_SET_PWM_PARAM(6500, 0, 0, 0, 0); // 设置周期、比较值、相位

         SRPWMCOM_ShadowMultiCoreSyncEnable(SRPWM_CHANNEL_8);
         SRPWMCOM_ShadowMultiCoreSyncEnable(SRPWM_CHANNEL_9);
         SRPWMCOM_PSTPSwForceOutState(SRPWM_CHANNEL_8, SRPWM_PWMA, SRPWM_PSTP_MUTEX_OUTSTATE_NONE);
         SRPWMCOM_PSTPSwForceOutState(SRPWM_CHANNEL_9, SRPWM_PWMA, SRPWM_PSTP_MUTEX_OUTSTATE_NONE);
         GPIO_WritePin(GPIO0, GPIO_PIN_00, RESET);
      }
   }
}

波形

比较模式:时基计数器等于比较值时,产生比较事件

AN0014008

下图为放大的波形

AN0014009

从上图可以看到,示波器通道2最后出现了一个异常的跨周期高脉宽。 示波器通道描述(后文示波器通道,均采用该对应关系): 通道1:来源于SRPWM_9B。过零拉低,周期拉高。 通道2:来源于SRPWM_9A。 通道3:来源于SRPWM_8A。 通道4:来源于GPIO。为了便于分析,充放电切换时刻,GPIO拉高;参数设置加载完成,GPIO拉低。

比较模式:时基计数器大于等于或者小于等于比较值时,产生比较事件

AN0014010

下图为放大的波形

AN0014011

从上图可以看到,示波器通道2最后未出现异常的跨周期高脉宽。

时序复现

根据上述的场景,我们将配置项以波形时序图的方式呈现。 需要注意,实际异常波形为9A同时引入了GPIO作为软件强制封波和恢复软件强制封波的辅助观测。具体动作为:软件封波时,拉高GPIO;恢复封波时,拉低GPIO

AN0014012

从上图可以看到,不同的比较模式配置,将影响波形的产生

比较模式:时基计数器等于比较值时,产生比较事件

  1. 周期值、比较值都采用周期时刻作为影子加载时刻。一次加载指令下发后,参数在周期时刻(计数值等于4000时)开始加载。在周期时刻+1clk时刻生效(计数值等于4000- 1=3999时刻生效)。此后,计数器持续向下计数至0。在当前PWM周期内,始终无法出现时基计数器向下计数值等于比较值A(6499)的事件,一直到下个PWM周期,计数过了周期时刻,并向下计数到6499时,才会出现向下计数值等于比较值A的比较事件。

  2. 根据上述描述,在活跃周期值从小数值变为大数值,且相应的活跃比较值从小到大变化的过程中,向上计数比较事件和向下计数比较事件的事件间隔将较大增加,从而产生跨周期的宽脉宽现象。

  3. 由于9A是经过死区取反后输出,所以最终的动作为:向上计数比较值事件出现时,9A拉高;向下计数比较值事件出现时,9A拉低。因此当向上计数比较事件和向下计数比较事件的时间间隔基于上述原因被拉长后,9A高脉冲相应的拉长,所以出现了该异常高脉宽。

比较模式:时基计数器大于等于或者小于等于比较值时,产生比较事件 1. 由于比较模式的配置,且向下时的比较值A产生动作矩阵为拉低,所以在当前周期,时基计数器值小于等于比较值A,产生了比较事件,所以,拉低的动作矩阵正常产生。

备注

上述时序,计数方向换向的时刻是计数值等于周期值时。当计数到4000时,条件满足,计数方向由向上变为向下,所以计数值等于4000时,计数方向为向下。

解决方案

从时序复现中,我们得知了异常高脉宽产生的原因。那如何应对呢?

  • 方案一:

我们可以将比较模式配置为:时基计数器大于等于或者小于等于比较值时,产生比较事件。即可解决异常高脉宽的问题。 如果芯片不支持该模式的设置呢?我们可以考虑方案二。

  • 方案二:

我们可以修改影子加载时刻,将周期时刻影子加载修改为过零时刻影子加载。在本文的场景中,即可使默认的比较模式一,产生等于事件,从而生成期望的波形。(需要注意进行参数限幅) 需要注意,该方式仅针对于本文的场景。但是其本质思路是一样的,即保证等于事件的产生。

总结

本文针对SRPWM的比较模式设置对波形生成的影响进行了详细说明,对当中的细节时序进行了展开描述,避免开发者在实际应用中产生的相应问题。 从该案例可以看出,比较模式的配置将影响到波形的产生。在开发中,我们需要根据实际的应用场景,考虑该配置的影响。