How to use E-Capture for MC56F83783

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

How to use E-Capture for MC56F83783

Jump to solution
1,734 Views
cody1
Contributor III

I want to measure the rpm of the fan. Is there anyone who can give me some example or suggestion?

My DSC is MC56F83783.

Q1: I saw E-Capture and Quad Timer in the reference manual. Fan's speed range is from 50Hz to 500Hz. Which one is more suitable to measure that? 

Q2: Where can find out the example code about E-Capture and Quad Timer? or documents?

I want to capture the counts between two pulses of FAN's RPM without using any interrupt.

Post my code as below, but it's not working. I can not get any of the capture values from SM2CVAL4/SM2CVAL5.

 

/*
 * fan.c
 *
 *  Created on: Apr 9, 2021
 *      Author: Cody_Chen
 */

#include "peripheral.h"
#include "Cpu.h"

void initFanGpio(void)
{
	/* Configure GPIO E0 */
	SIM->PCE0 |= SIM_PCE0_GPIOE_MASK;
	GPIOE->PER |= MASK_BIT0;    // Set to GPIO mode. 0: GPIO, 1: Peripheral	

	// /* Configure FAN_RPM */	  
	// //GPIOE->PER |= MASK_BIT6;    // Set to GPIO mode. 0: GPIO, 1: Peripheral
	// GPIOE->PER &= ~MASK_BIT6;    // Set to GPIO mode. 0: GPIO, 1: Peripheral
	// GPIOE->DDR &= ~MASK_BIT6;   // Set to output mode. 0: input, 1: output
}


void initFanXbarOut4(void)
{
	/***************** FAN PWM output *******************/
	// 00 Function = PWMA_0B; Peripheral = PWMA; Direction = IO
	// 11 Function = XB_OUT4; Peripheral = XBAR; Direction = OUT
	SIM->GPSEL = (SIM->GPSEL & ~SIM_GPSEL_E0_MASK)|SIM_GPSEL_E0(3);  // 11 Function = XB_OUT4; Peripheral = XBAR; Direction = OUT
	
	// Naming rule as below: PWMyn_MUX_TRIGm - y is A or B, representing eFlexPWMA/B, 
	//                                         n is sub module number(0~3), 
	//                                         m is 0 or 1; 
	//                       PWMyn_OUT_TRIGm - y is A or B, representing eFlexPWMA/B, 
	//                                         n is sub module number(0~3), 
	//                                         m is 0 or 1 .
	
	// PWM[n]_OUT_TRIG0 and PWM[n]_OUT_TRIG1 - Output Triggers
	// OUT_TRIG_EN bits in the Output Trigger Control Register for
	// information about how to enable these outputs and how the compare registers match up to
	// the output triggers.
	
	// PWM[n]_MUX_TRIG0 and PWM[n]_MUX_TRIG1 - Output Triggers
	// PWAOT0 and PWBOT1 bits in the Output Trigger Control
	// Register for information about how to enable these outputs.
	
	// XBAR_IN30
	// 0 PWMB1_MUX_TRIG0
	// 1 PWMA1_OUT_TRIG0
	SIM->PWM_SEL = (SIM->PWM_SEL & ~SIM_PWM_SEL_XBAR_IN30_MASK)|SIM_PWM_SEL_XBAR_IN30(0);
	
	
	// XBARA_SEL2 field descriptions
	// Input (XBARA_INn) to be muxed to XBARA_OUT4
	XBARA->SEL2 = (XBARA->SEL2 & ~XBARA_SEL2_SEL4_MASK) | XBARA_SEL2_SEL4(30);
}

void initFanPwm(void)
{
	initFanGpio();
	initFanXbarOut4();

	// /* Enable PWMB SM0 PWMB0_OUT_TRIG0  */
	SIM->PCE3 |= (SIM_PCE3_PWMBCH1_MASK);

	PWMB->MCTRL &= ~PWM_MCTRL_RUN(2);              // Stops the PWM counter for SM1
	//PWMB->MCTRL &= ~PWM_MCTRL_RUN_MASK;          // Stops the PWM counter for all submodules.
	PWMB->MCTRL |= PWM_MCTRL_IPOL(0x0);            // 0000b - PWM23 is used to generate complementary PWM pair in the corresponding submodule.

	/* Initial SM1 */
	PWMB->SM1CTRL = 0;                             // Reset All SM1CTRL;
	PWMB->SM1CTRL |= PWM_SM1CTRL_FULL_MASK;        // Define by when the submodule counter matches the VAL1 register.

	PWMB->SM1CTRL2 = 0;                            // Reset All SM1CTRL2;
	PWMB->SM1CTRL2 = (PWMB->SM1CTRL2 & ~PWM_SM1CTRL2_CLK_SEL_MASK)|PWM_SM1CTRL2_CLK_SEL(0);  // 00b - The IPBus clock is used as the clock.
	PWMB->SM1CTRL2 = (PWMB->SM1CTRL2 & ~PWM_SM1CTRL2_INIT_SEL_MASK)|PWM_SM1CTRL2_INIT_SEL(0); // Local sync (PWM_X) causes initialization

	/* Fault Disable Mapping Register
	 * This register determines which PWM pins are disabled by the fault protection inputs. */
	PWMB->SM1DISMAP0 = 0;
	PWMB->SM1DISMAP1 = 0;

    PWMB->SM1VAL0 = 0;    // defines the mid-cycle reload point for the PWM in PWM clock periods.
	PWMB->SM1VAL1  = 3999; // defines the modulo count value (maximum count) for the submodule counter.
	PWMB->SM1VAL2 = 0;    // defines the count value to set PWM23 high.
	PWMB->SM1VAL3 = 1999;  // defines the count value to set PWM23 low.
	PWMB->SM1DTCNT0 = 50; // used to control the deadtime  during 0 to 1 transitions.
	PWMB->SM1DTCNT1 = 50; // used to control the deadtime during 0 to 1 transitions.	
	
	
	//Refer to Figure 27-26. Output Logic
	//PWAOT0
	//0b - Route the PWM_OUT_TRIG0 signal to PWM_MUX_TRIG0 port.
	//1b - Route the PWM_A output to the PWM_MUX_TRIG0 port.
	
	//PWBOT1
	//0b - Route the PWM_OUT_TRIG1 signal to PWM_MUX_TRIG1 port.
	//1b - Route the PWM_B output to the PWM_MUX_TRIG1 port.	

	PWMB->SM1TCTRL |= (PWM_SM1TCTRL_PWAOT0_MASK ); // Route the PWM_A output to the PWM_OUT_TRIG0 & 1 port.
	PWMB->OUTEN |= (PWM_OUTEN_PWMA_EN(2));  // PWM_A Output Enables
	PWMB->SM1CTRL2 |= PWM_SM1CTRL2_FORCE_MASK;     // Force Initialization
	
	PWMB->MCTRL |= PWM_MCTRL_CLDOK(2);             // Each write-only bit is used to clear the corresponding bit of MCTRL[LDOK].
	PWMB->MCTRL |= PWM_MCTRL_LDOK(2);              // Load prescaler, modulus, and PWM values of the corresponding submodule.	
	PWMB->MCTRL |= PWM_MCTRL_RUN(2);               // Enable the clocks to the PWM generator of submodules 3-0,
}


void initPwmEcap(void)
{

	/* Configure GPIO E6 */
	SIM->PCE0 |= SIM_PCE0_GPIOE_MASK;

	/* Configure FAN_RPM - GPIOE6 */	  
	GPIOE->PER |= MASK_BIT6;    // Set to GPIO mode. 0: GPIO, 1: Peripheral

	// /* Enable PWMB SM2 PWMB_2B  GPIOE6*/
	SIM->PCE3 |= (SIM_PCE3_PWMBCH2_MASK);

	/***************** FAN RPM intput *******************/
	// 00 Function = PWMA_3B; Peripheral = PWMA; Direction = IO
	// 01 Function = XB_IN4; Peripheral = XBAR; Direction = IN
	//>10 Function = PWMB_2B; Peripheral = PWMB; Direction = IO
	// 11 Function = XB_OUT10; Peripheral = XBAR; Direction = OUT
	SIM->GPSEL = (SIM->GPSEL & ~SIM_GPSEL_E6_MASK)|SIM_GPSEL_E6(2);

 	PWMB->OUTEN &= ~(PWM_OUTEN_PWMB_EN(4));  //  These bits should be set to 0 (output disabled) when a PWM_B pin is being used for input capture.
	PWMB->MCTRL &= ~PWM_MCTRL_RUN(4);        //  Disable the clocks to the PWM generator of submodules 3-0,

	/**< Capture Control B Register, offset: 0xF8 */
	// SM2CAPTCTRLB[1] := ONESHOTB
	// This bit selects between free running and one shot mode for the input capture circuitry. 
	//>0b - Free running mode is selected.
	// 1b - One shot mode is selected.                 
	PWMB->SM2CAPTCTRLB = (PWMB->SM2CAPTCTRLB & ~PWM_SM2CAPTCTRLB_ONESHOTB_MASK)|PWM_SM2CAPTCTRLB_ONESHOTB(0);
	// SM2CAPTCTRLB[2..3] := EDGB0
	// These bits control the input capture 0 circuitry by determining which input edges cause a capture event.
	// 00b - Disabled
	// 01b - Capture falling edges
	//>10b - Capture rising edges
	// 11b - Capture any edge
	PWMB->SM2CAPTCTRLB = (PWMB->SM2CAPTCTRLB & ~PWM_SM2CAPTCTRLB_EDGB0_MASK)|PWM_SM2CAPTCTRLB_EDGB0(2);
	// SM2CAPTCTRLB[4..5] := EDGB1
	// These bits control the input capture 1 circuitry by determining which input edges cause a capture event.
	// 00b - Disabled
	//>01b - Capture falling edges
	// 10b - Capture rising edges
	// 11b - Capture any edge
	PWMB->SM2CAPTCTRLB = (PWMB->SM2CAPTCTRLB & ~PWM_SM2CAPTCTRLB_EDGB1_MASK)|PWM_SM2CAPTCTRLB_EDGB1(1);
	// SM2CAPTCTRLB[6] := INP_SELB
	// This bit selects between the raw PWM_B input signal and the output of the edge counter/compare
    // circuitry as the source for the input capture circuit.
	//>0b - Raw PWM_B input signal selected as source.
	// 1b - Output of edge counter/compare selected as source. 
	PWMB->SM2CAPTCTRLB = (PWMB->SM2CAPTCTRLB & ~PWM_SM2CAPTCTRLB_INP_SELB_MASK)|PWM_SM2CAPTCTRLB_INP_SELB(0);
	// SM2CAPTCTRLB[7] := EDGCNTB_EN
	// This bit enables the edge counter which counts rising and falling edges on the PWM_B input signal.
	// 0b - Edge counter disabled and held in reset
	//>1b - Edge counter enabled
	PWMB->SM2CAPTCTRLB = (PWMB->SM2CAPTCTRLB & ~PWM_SM2CAPTCTRLB_EDGCNTB_EN_MASK)|PWM_SM2CAPTCTRLB_EDGCNTB_EN(1);
	// // SM2CAPTCTRLB[8..9] := CFBWM
	// // This field represents the water mark level for capture B FIFOs.
	// // SM2CAPTCTRLB[10..12] := CB0CNT
	// // This field represents the water mark level for capture B FIFOs.
	// // SM2CAPTCTRLB[13..15] := CB1CNT
	// // This field represents the water mark level for capture B FIFOs.

	// SM2CAPTCTRLB[0] := Arm B
	// Setting this bit high starts the input capture process. 
	// 0b - Input capture operation is disabled.
	//>1b - Input capture operation as specified by CAPTCTRLB[EDGBx] is enabled.
	PWMB->SM2CAPTCTRLB = (PWMB->SM2CAPTCTRLB & ~PWM_SM2CAPTCTRLB_ARMB_MASK)|PWM_SM2CAPTCTRLB_ARMB(1); 

	
	PWMB->MCTRL |= PWM_MCTRL_RUN(4);               // Enable the clocks to the PWM generator of submodules 3-0,
	
	PWMB->SM2INTEN|=0x0300; //edge1(falling edge) trigger interrupt

}

uint16_t sm2cval0 = 0;
uint16_t sm2cval1 = 0;
uint16_t sm2cval2 = 0;
uint16_t sm2cval3 = 0;
uint16_t sm2cval4 = 0;
uint16_t sm2cval5 = 0;
uint16_t sm2cnt = 0;

void scanSpeed(void)
{
//	if(0xFFFF > sm2cnt) sm2cnt = sm2cnt + (GPIOE->DR & MASK_BIT6? 0: 1);
//	else                sm2cnt = 0;
	
	sm2cnt = GPIOE->DR & MASK_BIT6;

//	if(PWMB->SM2STS & 0x0300) {

	if(PWMB->SM2CAPTCTRLB & 0x1C00) {
		sm2cval1++;
		sm2cval4 = PWMB->SM2CVAL4;
	}

	if(PWMB->SM2CAPTCTRLB & 0xE000) {
		sm2cval5 = PWMB->SM2CVAL5;
		sm2cval0++;		
	}

		//PWMB->SM2STS |= 0x0300; //clear the CFB0 and CFB1 bits 
//	}	
}




#define INV_FAN_PWM  1

void setFanDuty(uint16_t u16duty)
{
#if INV_FAN_PWM
	uint32_t u32TempDuty = (((uint32_t)PWMB->SM1VAL1*(uint32_t)(0xFFFF - u16duty)>>16)&0x0000FFFF);
#else	
	uint32_t u32TempDuty = (((uint32_t)PWMB->SM1VAL1*(uint32_t)(u16duty)>>16)&0x0000FFFF);
#endif	
	PWMB->SM1VAL3 = (uint16_t) u32TempDuty;
	
	PWMB->MCTRL |= PWM_MCTRL_LDOK(2); /* LDOK,load enable */ 
}

void initFanConfig(void)
{
	initFanPwm();		
	setFanDuty(0x1FFF);	
	initPwmEcap();
}

 

 

0 Kudos
1 Solution
1,713 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Cody,

I do not suggest you use E-capture feature of eFlexPWM module to compute the clock number between two rising edge of external signal, because E-capture feature is limited by the eFlexPWM counter.

I suggest you use quadTimer module to implement the capture function, you can have one of quadTimer count either external or internal clock. When external captured signal is coming, it's edge will trigger the capture.

 

xiangjun_rong_0-1618192522219.png

 

From above fig, the PCS bits defines the driving clock source, the SCS defines the external captured signal source, when capture event happens, an interrupt can be triggered. You can compute the different of two consecutive edge to get the period.

BTW, each of the quadTimer is independent.

Hope it can help you

View solution in original post

0 Kudos
6 Replies
1,714 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Cody,

I do not suggest you use E-capture feature of eFlexPWM module to compute the clock number between two rising edge of external signal, because E-capture feature is limited by the eFlexPWM counter.

I suggest you use quadTimer module to implement the capture function, you can have one of quadTimer count either external or internal clock. When external captured signal is coming, it's edge will trigger the capture.

 

xiangjun_rong_0-1618192522219.png

 

From above fig, the PCS bits defines the driving clock source, the SCS defines the external captured signal source, when capture event happens, an interrupt can be triggered. You can compute the different of two consecutive edge to get the period.

BTW, each of the quadTimer is independent.

Hope it can help you

0 Kudos
1,692 Views
cody1
Contributor III
#define ENABLE_TMR(x)  TMRA->ENBL = (TMRA->ENBL & ~TMR_ENBL_ENBL_MASK) | TMR_ENBL_ENBL(x); //Disable TMR

void initTMRx(void)
{
	/*! TA0 - TMRA0 IPBus Clock Enable */
	SIM->PCE0 |= (SIM_PCE0_TA0_MASK);
	
	/**< Timer Channel Compare Register 1, offset: 0x0 */
	/* This read/write register stores the value used for comparison with the counter value in count up mode. */
	TMRA->COMP10 = 0xFFFF;                            
    /**< Timer Channel Compare Register 2, offset: 0x1 */
	/* This read/write register stores the value used for comparison with the counter value in count down mode
       or alternating compare mode.*/
  	TMRA->COMP20 = 0;                            
  	TMRA->CAPT0 = 0;                             /**< Timer Channel Capture Register, offset: 0x2 */
  	TMRA->LOAD0 = 0;                             /**< Timer Channel Load Register, offset: 0x3 */
  	TMRA->HOLD0 = 0;                             /**< Timer Channel Hold Register, offset: 0x4 */
	/**< Timer Channel Counter Register, offset: 0x5 
	  *  This read/write register is the counter for the corresponding channel in a timer module. */
  	TMRA->CNTR0 = 0;   
	/**< Timer Channel Control Register, offset: 0x6 */   
	// [0..2]: OUTMODE Output Mode
	//> 000 Asserted while counter is active
	//  001 Clear OFLAG output on successful compare
	//  010 Set OFLAG output on successful compare
	//  011 Toggle OFLAG output on successful compare
	//  100 Toggle OFLAG output using alternating compare registers
	//  101 Set on compare, cleared on secondary source input edge
	//  110 Set on compare, cleared on counter rollover
	//  111 Enable gated clock output while counter is active
  	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_OUTMODE_MASK) | TMR_CTRL0_OUTMODE(0);
	// [3]: COINIT Co-Channel Initialization
	//  0 Co-channel counter/timers cannot force a re-initialization of this counter/timer
	//> 1 Co-channel counter/timers may force a re-initialization of this counter/timer
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_COINIT_MASK) | TMR_CTRL0_COINIT(1);
	// [4]: DIR Count Direction
	//> 0 Count up.
	//  1 Count down.
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_DIR_MASK) | TMR_CTRL0_DIR(0);
	// [5]: LENGTH Count Length
	//> 0 Count until roll over at $FFFF and then continue by re-initializing the counter from the LOAD register.
	//  1 Count until compare, then re-initialize using the LOAD regsiter. 
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_LENGTH_MASK) | TMR_CTRL0_LENGTH(0);
	// [6]: ONCE Count Once
	// This bit selects continuous or one shot counting mode.
	//  0 Count repeatedly.
	//> 1 Count until compare and then stop. 
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_ONCE_MASK) | TMR_CTRL0_ONCE(1);
	// [7..8]: SCS Secondary Count Source
	// These bits identify the external input pin to be used as a count command or timer command.
	//  00 Counter 0 input pin
	//  01 Counter 1 input pin
	//  10 Counter 2 input pin
	//  11 Counter 3 input pin
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_SCS_MASK) | TMR_CTRL0_SCS(0);	
	// [9..12]: PCS Primary Count Source
	// These bits select the primary count source.
	//  0000 Counter 0 input pin
	//  0001 Counter 1 input pin
	//  0010 Counter 2 input pin
	//  0011 Counter 3 input pin
	//  0100 Counter 0 output
	//  0101 Counter 1 output
	//  0110 Counter 2 output
	//  0111 Counter 3 output
	//  1000 IP bus clock divide by 1 prescaler
	//  1001 IP bus clock divide by 2 prescaler
	//  1010 IP bus clock divide by 4 prescaler
	//  1011 IP bus clock divide by 8 prescaler
	//  1100 IP bus clock divide by 16 prescaler
	//  1101 IP bus clock divide by 32 prescaler
	//  1110 IP bus clock divide by 64 prescaler
	//> 1111 IP bus clock divide by 128 prescaler
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_PCS_MASK) | TMR_CTRL0_PCS(0xF);
	// [13..15]: CM Count Mode
	// These bits control the basic counting and behavior of the counter.
	//  000 No operation
	//> 001 Count rising edges of primary source1
	//  010 Count rising and falling edges of primary source2
	//  011 Count rising edges of primary source while secondary input high active
	//  100 Quadrature count mode, uses primary and secondary sources
	//  101 Count rising edges of primary source; secondary source specifies direction3
	//  110 Edge of secondary source triggers primary count until compare
	//  111 Cascaded counter mode (up/down)4
	TMRA->CTRL0 = (TMRA->CTRL0 & ~TMR_CTRL0_CM_MASK) | TMR_CTRL0_CM(1);


  	//TMRA->SCTRL0;                            /**< Timer Channel Status and Control Register, offset: 0x7 */
  	TMRA->CMPLD10 = 0;                         /**< Timer Channel Comparator Load Register 1, offset: 0x8 */
  	TMRA->CMPLD20 = 0xFFFF;                    /**< Timer Channel Comparator Load Register 2, offset: 0x9 */
  	//TMRA->CSCTRL0;                           /**< Timer Channel Comparator Status and Control Register, offset: 0xA */
  	//TMRA->FILT0;                             /**< Timer Channel Input Filter Register, offset: 0xB */
  	//TMRA->DMA0;                              /**< Timer Channel DMA Enable Register, offset: 0xC */


	ENABLE_TMR(0);
}

typedef enum {
	_FG_NO_ACTION = 0,
	_FG_GET_TMRx_COUNT, 
	_FG_WAIT_FOR_NEXT_TRIGGER,
	_FG_ENABLE_TMRx_TO_COUNT,
	_FG_WAIT_FOR_RESTART,
	_FG_END_OF_EVENT
} EV_FGSTAT;

uint32_t u32FanRpmCnt = 0;
uint32_t u32FanRpmResult = 0;
uint32_t u32FanRpmUsec = 0;

uint32_t getFanRpm(void)
{
	// u32FanRpmResult * gain 1000000 / (Bus Clock 100M / TMR_CTRL0_PCS(0xF) 128)
	// u32FanRpmUsec = u32FanRpmResult * 1000000 / 781250 ;
	u32FanRpmUsec = u32FanRpmResult * 100000 / 78125 ;
	return u32FanRpmUsec; 
}

void scanFanRpm(void)  //Place this function in While(1)
{
	static EV_FGSTAT ev = _FG_WAIT_FOR_NEXT_TRIGGER;

	if(GPIOE->DR & MASK_BIT6) {
		if(_FG_WAIT_FOR_NEXT_TRIGGER == ev) {
			u32FanRpmResult = u32FanRpmCnt;
			ENABLE_TMR(1);
			u32FanRpmCnt = TMRA->CNTR0 = 0;
			ev = _FG_GET_TMRx_COUNT;
		}
		else{
			if(0x000FFFFF>u32FanRpmCnt) {
				u32FanRpmCnt += TMRA->CNTR0;
				TMRA->CNTR0 = 0;
			}
			else {
				u32FanRpmResult = u32FanRpmCnt = TMRA->CNTR0 = 0;
				ev = _FG_WAIT_FOR_RESTART;
			}
		}
	}
	else {
		if(_FG_WAIT_FOR_RESTART == ev) {
			u32FanRpmCnt = TMRA->CNTR0 = 0;
			ev = _FG_WAIT_FOR_NEXT_TRIGGER;
		}
		else {
			u32FanRpmCnt += TMRA->CNTR0;
			TMRA->CNTR0 = 0;
			ev = _FG_WAIT_FOR_NEXT_TRIGGER;
		}
	}
	getFanRpm();
}
0 Kudos
1,675 Views
cody1
Contributor III

Thanks a lot.

Cody

0 Kudos
1,698 Views
cody1
Contributor III

Do you have any example code or document about how to using TMRx? 

Thanks

Cody

0 Kudos
1,702 Views
cody1
Contributor III

Thank you, I will try that.

Cody

0 Kudos
1,657 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

This is a capture function example based on quadTimer for MC56F81xxx, you can refer to it, the quadTimer itself is the same.

Hope it can help you

BR

XiangJun Rong

0 Kudos