PWM SetDutyMs/US goes to hard fault

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

PWM SetDutyMs/US goes to hard fault

Jump to solution
1,324 Views
rolandchok
Contributor I

every time i call SetDutMS or US it just crash and goes to a hard fault. but using SetRatio8/16 does not have any problems. but im just curios how do you use SetDutyMS or US?

thank you

0 Kudos
1 Solution
902 Views
BlackNight
NXP Employee
NXP Employee

Hi Roland,

yes, if you add FreeRTOS with that option set, it will enable the FPU during startup of the scheduler.That code snippet is actually from the FreeRTOS port.

Erich

View solution in original post

0 Kudos
8 Replies
902 Views
BlackNight
NXP Employee
NXP Employee

Just a thought:

could it be that you do not have the floating point unit enabled in your project, and that you get a hard fault because of that?

Below is snippet you can call to enable the floating point unit (assembly code for GNU assembler):

void vPortEnableVFP(void) {

  /* The FPU enable bits are in the CPACR. */

  __asm volatile (

    "  ldr.w r0, =0xE000ED88  \n" /* CAPCR, 0xE000ED88 */

    "  ldr r1, [r0]           \n" /* read CAPR */

    "  orr r1, r1, #(0xf<<20) \n" /* enable CP10 and CP11 coprocessors */

    "  str r1, [r0]           \n" /* store to new value back */

    : /* no output */

    : /* no input */

    : "r0","r1" /* clobber */

  );

}

Erich

902 Views
rolandchok
Contributor I

thank you for the reply guys.

i tried the snippet to enable the floating point. it actually fix the problem. i thought that floating point unit are automatically enabled once you called a variable Float data type and the variable is handled by the hardware using the Floating point unit.

thanks

regards,

Roland

0 Kudos
902 Views
BlackNight
NXP Employee
NXP Employee

Hi Roland,

out of reset, the FPU is disabled. It needs to be enabled if you want to use the hardware floating point instructions (which are probably enabled in your compiler settings). So what happened was that the CPU was running into an illegal instruction exception. Enabling the FPU fixed that problem.

Erich

902 Views
rolandchok
Contributor I

thanks Erich,

     i added FreeRTOS from processor expert i has an option to enable the floating point unit. now i don't have to add the snippet to enable the FPU. let me try this one if it will work. once i finish adding the task

thanks

regards,

Roland

0 Kudos
903 Views
BlackNight
NXP Employee
NXP Employee

Hi Roland,

yes, if you add FreeRTOS with that option set, it will enable the FPU during startup of the scheduler.That code snippet is actually from the FreeRTOS port.

Erich

0 Kudos
902 Views
chris_brown
NXP Employee
NXP Employee

Hi Roland,

Can you give us some more details regarding your specific situation?  What device are you using?  What tools are you using?  Do you have some code snippets? 

Most of the time when I hear of things like this happening it turns out to be a clock gate that isn't set correctly.  Can you check this?

Thanks,

Chris

0 Kudos
902 Views
rolandchok
Contributor I

i'm using KDS IDE with FRDM-K22F board. i have attach a simple change on the duty cycle bellow. after initialization i set my starting pulse with at 1.5ms it runs fine i can see on the scope it generated a PWM after 3sec i want to change the duty cycle using SetDutyUS

after that it just go to hard fault. but if i use SetRatio16 it just run fine. i can change the duty without any problems. i just want to use SetDutyUS its more convenient and less code line for my application. the PWM headers are from Processor expert so after adding all the components from processor expert i add those two lines of code.

thank you

roland

------------------------------------------------------------------------------------------------------------------------------------------------------------------

int main(void)

/*lint -restore Enable MISRA rule (6.3) checking. */

{

  /* Write your local variable definition here */

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/

  PE_low_level_init();

  /*** End of Processor Expert internal initialization.                    ***/

  /* Write your code here */

  /* For example: for(;;) { } */

WAIT1_Waitms(3000);

PWM1_SetDutyUS(2000);

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/

  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/

  #ifdef PEX_RTOS_START

    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */

  #endif

  /*** End of RTOS startup code.  ***/

--------------------------------------------------------------------------------------------------------------------------------------------------------------------

0 Kudos
902 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Roland,

It seems that the PE code has bug.

Pls refer to the following code. Firstly, you call the PWM1_SetDutyUS(2000); the LDD_TError PwmLdd1_SetDutyUS(LDD_TDeviceData *DeviceDataPtr, uint16_t Time) is called actually due to a macro. In the function, the float variable   rtval = Time * 20.97152F; the rtval value is the tick number rather than a ratio to FTM_MOD register, because the system clock is 20.97125. In the case, the rtval value should be written the FTM_CnV register directly to change the duty cycle. But the PwmLdd1_SetDutyUS(LDD_TDeviceData *DeviceDataPtr, uint16_t Time) function treats the rtval as a ratio, the rtval is multiplied with the period, then write the FTM_CnV register, I think it is wrong. You can debug the code.

currently, it is okay to call the Setratio16() api function as you have done.

BR

XiangJun Rong

static void SetRatio(LDD_TDeviceData *DeviceDataPtr)

{

  PwmLdd1_TDeviceData *DeviceDataPrv = (PwmLdd1_TDeviceData*)DeviceDataPtr;

  uint16_t Period;

  uint16_t Duty;

  (void)TU1_GetPeriodTicks(DeviceDataPrv->LinkedDeviceDataPtr, &Period);

  if (Period == 0U) {

    Duty = DeviceDataPrv->RatioStore;

  }

  else {

    Duty = (uint16_t)((((uint32_t)(Period) * DeviceDataPrv->RatioStore) + 0x8000) >> 0x10);

  }

  (void)TU1_SetOffsetTicks(DeviceDataPrv->LinkedDeviceDataPtr, CHANNEL, Duty);

}

LDD_TError PwmLdd1_SetDutyUS(LDD_TDeviceData *DeviceDataPtr, uint16_t Time)

{

  PwmLdd1_TDeviceData *DeviceDataPrv = (PwmLdd1_TDeviceData *)DeviceDataPtr;

  LDD_TimerUnit_Tfloat rtval;          /* Result of multiplication */

  /* Time test - this test can be disabled by setting the "Ignore range checking"

     property to the "yes" value in the "Configuration inspector" */

  if (Time > 0x0C35U) {                /* Is the given value out of range? */

    return ERR_PARAM_RANGE;            /* If yes then error */

  }

  rtval = Time * 20.97152F;            /* Multiply given value and actual clock configuration coefficient */

  if (rtval > 0xFFFFUL) {              /* Is the result greater than 65535 ? */

    DeviceDataPrv->RatioStore = 0xFFFFU; /* If yes then use maximal possible value */

  }

  else {

    DeviceDataPrv->RatioStore = (uint16_t)rtval;

  }

  SetRatio(DeviceDataPtr);             /* Calculate and set up new appropriate values of the duty register */

  return ERR_OK;                       /* OK */

}

0 Kudos