Bug in EMIOS_PWM_IP_MODE_OPWMCB - setduty - for ZERO duty

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Bug in EMIOS_PWM_IP_MODE_OPWMCB - setduty - for ZERO duty

1,141件の閲覧回数
StabFlo
Contributor II

Hi,

when using a EMIOS channel in EMIOS_PWM_IP_MODE_OPWMCB_TRAIL_EDGE_FLAG mode setting dutycycle with  Emios_Pwm_Ip_SetDutyCycle to 0 sporadically causes 100% on the channel.

Steps to reproduce:

1. set dutycycle to 1 for n periods: Emios_Pwm_Ip_SetDutyCycle(0,1, 1 );

2. set dutycycle to 0: Emios_Pwm_Ip_SetDutyCycle(0,1, 0) ;

--> channel goes to 100%

 

suspected root cause:

dutycylce = 1 causes A register to go to 3001 --> output flipflop is on on the first tick.

dutycylce = 0 causes A register to go to 3002 (never reached)  --> output flipflop stays on forever.

critical line in RTD(Emios_Pwm_Ip_SetDutyCycleOpwmcb

StabFlo_2-1739285366401.jpeg

 

main code:

     dutycycle = (potiValue/1000*6000); // val / max potival * max duty ticks
 
    if(dutycycle == 1) // workaround 100% at 0 duty bug
    {
    dutycycle = 2;
    }
 
Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, dutycycle);

RTD config:

StabFlo_0-1739285260876.png

StabFlo_1-1739285336733.png

* Project : RTD AUTOSAR 4.7
* Platform : CORTEXM
* Peripheral : Emios Flexio FlexPwm eTpu
* Dependencies : none
*
* Autosar Version : 4.7.0
* Autosar Revision : ASR_REL_4_7_REV_0000
* Autosar Conf.Variant :
* SW Version : 5.0.0
* Build Version : S32K3_RTD_5_0_0_D2408_ASR_REL_4_7_REV_0000_20241002

 

 

ラベル(1)
タグ(1)
0 件の賞賛
返信
4 返答(返信)

1,128件の閲覧回数
_Leo_
NXP TechSupport
NXP TechSupport

Hi,

Thank you so much for your interest in our products and for using our community.

It is not a bug.

In OPWMCB mode:

To achieve 100% duty cycle, A1[n] must be set to $1.

To achieve 0% duty cycle, A1[n] must be set to a value greater than the maximum value of the selected time base.

Caution: The internal counter should not reach $0 as consequence of a rollover.

Please refer to 63.5.3.17.10 Duty cycle section of S32K3XXRM Reference Manual Rev. 9, 07/2024.

Hope it helps you.

Have a nice day!

0 件の賞賛
返信

1,107件の閲覧回数
StabFlo
Contributor II

All statements you wrote are true.

But do not catch what i meant.

The issue is that instead of 0% ON get 100% ON by setting Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, dutycycle); for dutycycle = 0. under certain perconditions.

This could cause damage to attached motors or drivers.

The precondition for this undefined behavior is NOT going 100% pwm to 0% (which is actually a caught exception).

But setting the dutycycle to ALMOST 0.  to be precise exactly 1 tick dutycycle with e.g. 6000ticks period.

 

Okay sequence:

1. Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, 3000);

--> okay, Pin is at 50% Dutycycle

 2. Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, 0);

--> okay, Pin is off = 0% Dutycycle

sequence with observed issue:

1. Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, 1);

--> okay, Pin is at 0.0167% Dutycycle

 2. Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, 0);

--> okay, Pin is on at 100% Dutycycle

 

Workaround:

if(dutycycle == 1) // workaround 100% to avoid 0 duty bug
{
dutycycle = 2;
}

 

タグ(1)
0 件の賞賛
返信

1,083件の閲覧回数
_Leo_
NXP TechSupport
NXP TechSupport

Your should never set duty cycle in the following way:

Emios_Pwm_Ip_SetDutyCycle(0, Emios_Pwm_Ip_I0_Ch1.ChannelId, 0);

To achieve 0% duty cycle, A1[n] must be set to a value greater than the maximum value of the selected time base.

For example, of your period [ticks] is 6000, please select duty cycle [ticks] as 6001.

0 件の賞賛
返信

1,062件の閲覧回数
StabFlo
Contributor II

hi,

 

Emios_Pwm_Ip_SetDutyCycle does the abstraction for you. The duty cycle enter there is always 0....channelperiod.

The issue is with the following line when duty cycle = 1 (from Emios_Pwm_Ip_SetDutyCycleOpwmcb which is called by Emios_Pwm_Ip_SetDutyCycle)

Emios_Pwm_Ip_SetUCRegA(Base, Channel, (Emios_Pwm_Ip_PeriodType)(ChPeriod - (NewDutyCycle >> 1U)));

--> shift (NewDutyCycle >> 1U)  = 0 --> Reg A = ChPeriod   which causes the issue.

 

But i do not see any point discussing this further. The work around not setting dutycycle to 1 works. So this is just an FYI.

 

static inline Emios_Pwm_Ip_StatusType Emios_Pwm_Ip_SetDutyCycleOpwmcb(uint8 Instance,
uint8 Channel,
Emios_Pwm_Ip_DutyType NewDutyCycle
)
{
#if (EMIOS_PWM_IP_DEV_ERROR_DETECT == STD_ON)
DevAssert(EMIOS_PWM_IP_INSTANCE_COUNT > Instance);
DevAssert(EMIOS_PWM_IP_CHANNEL_COUNT > Channel);
#endif
Emios_Pwm_Ip_HwAddrType *const Base = Emios_Pwm_Ip_aBasePtr[Instance];
Emios_Pwm_Ip_StatusType Ret = EMIOS_PWM_IP_STATUS_SUCCESS;
Emios_Pwm_Ip_PeriodType ChPeriod = Emios_Pwm_Ip_GetCounterBusPeriod(Instance, Channel, Emios_Pwm_Ip_GetCounterBus(Base, Channel));
/* Get the value of channel Index */
uint8 ChannelIdx = Emios_Pwm_Ip_GetChannelIndex(Instance, Channel);

if (ChannelIdx < EMIOS_PWM_IP_NUM_OF_CHANNELS_USED_U8)
{
/* OPWMCB Mode */
if(NewDutyCycle > ((ChPeriod * 2U) - 2U))
{ /* Duty cycle value should not be greater than the Channel Period. */
Ret = EMIOS_PWM_IP_STATUS_ERROR;
}
else if(0U == NewDutyCycle)
{
/* Disable and clear interrupt flag */
Emios_Pwm_Ip_SetInterruptRequest(Base, Channel, FALSE);
Emios_Pwm_Ip_ClearFlagEvent(Base, Channel);

Emios_Pwm_Ip_SetUCRegA(Base, Channel, ChPeriod + 1U);
Emios_Pwm_Ip_aNotif[ChannelIdx] = (uint8)1U;
/* This statement is required to avoid limitation of 0% duty cycle (if call 100% to 0%) */
if(1U == Emios_Pwm_Ip_GetUCRegA(Base, Channel))
{
if((Emios_Pwm_Ip_aInitialModes[ChannelIdx] == EMIOS_PWM_IP_MODE_OPWMCB_TRAIL_EDGE_FLAG) ||
(Emios_Pwm_Ip_aInitialModes[ChannelIdx] == EMIOS_PWM_IP_MODE_OPWMCB_TRAIL_EDGE_FLAG_BOTH))
{
Emios_Pwm_Ip_SetForceMatchB(Base, Channel, TRUE);
}
else
{
Emios_Pwm_Ip_SetForceMatchA(Base, Channel, TRUE);
}
}
}
else if(NewDutyCycle == ((ChPeriod * 2U) - 2U))
{
/* Disable and clear interrupt flag */
Emios_Pwm_Ip_SetInterruptRequest(Base, Channel, FALSE);
Emios_Pwm_Ip_ClearFlagEvent(Base, Channel);

Emios_Pwm_Ip_SetUCRegA(Base, Channel, 1U);
Emios_Pwm_Ip_aNotif[ChannelIdx] = (uint8)1U;
}
else
{
Emios_Pwm_Ip_SetUCRegA(Base, Channel, (Emios_Pwm_Ip_PeriodType)(ChPeriod - (NewDutyCycle >> 1U)));
Emios_Pwm_Ip_aNotif[ChannelIdx] = (uint8)0U;
Emios_Pwm_Ip_SetInterruptRequest(Base, Channel, (Emios_Pwm_Ip_aCheckEnableNotif[ChannelIdx] == 0U)? FALSE : TRUE);
}

/* Stores the new duty cycle in ticks */
Emios_Pwm_Ip_aDutyCycle[ChannelIdx] = NewDutyCycle;
}
else

0 件の賞賛
返信