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();
}