/*FUNCTION********************************************************************** * * Function Name : FTM_DRV_GetClock * Description : Retrieves the frequency of the clock source feeding the FTM counter. * Function will return a 0 if no clock source is selected and the FTM counter is disabled * *END**************************************************************************/ uint32_t FTM_DRV_GetClock(uint8_t instance) { assert(instance < FTM_INSTANCE_COUNT); FTM_Type *ftmBase = g_ftmBase[instance]; uint8_t clkPs; uint32_t freq = 0; clkPs = (1 << FTM_HAL_GetClockPs(ftmBase)); switch(s_ftmClockSource) { case kClock_source_FTM_ExternalClk: freq = CLOCK_SYS_GetFtmExternalFreq(instance) / clkPs; break; case kClock_source_FTM_FixedClk: freq = CLOCK_SYS_GetFtmFixedFreq(instance) / clkPs; break; case kClock_source_FTM_SystemClk: freq = CLOCK_SYS_GetFtmSystemClockFreq(instance) / clkPs; break; default: break; } return freq; }
/*See fsl_ftm_driver.h for documentation of this function.*/ void FTM_DRV_PwmStart(uint8_t instance, ftm_pwm_param_t *param, uint8_t channel) { uint32_t uFTMhz; uint16_t uMod, uCnv, uCnvFirstEdge = 0; assert(instance < HW_FTM_INSTANCE_COUNT); assert(param->uDutyCyclePercent <= 100); assert(channel < FSL_FEATURE_FTM_CHANNEL_COUNTn(instance)); uint32_t ftmBaseAddr = g_ftmBaseAddr[instance]; /* Clear the overflow flag */ FTM_HAL_ClearTimerOverflow(g_ftmBaseAddr[instance]); FTM_HAL_EnablePwmMode(ftmBaseAddr, param, channel); #if FSL_FEATURE_FTM_BUS_CLOCK CLOCK_SYS_GetFreq(kBusClock, &uFTMhz); #else CLOCK_SYS_GetFreq(kSystemClock, &uFTMhz); #endif /* Based on Ref manual, in PWM mode CNTIN is to be set 0*/ FTM_HAL_SetCounterInitVal(ftmBaseAddr, 0); uFTMhz = uFTMhz / (1 << FTM_HAL_GetClockPs(ftmBaseAddr)); switch(param->mode) { case kFtmEdgeAlignedPWM: uMod = uFTMhz / (param->uFrequencyHZ) - 1; uCnv = uMod * param->uDutyCyclePercent / 100; /* For 100% duty cycle */ if(uCnv >= uMod) { uCnv = uMod + 1; } FTM_HAL_SetMod(ftmBaseAddr, uMod); FTM_HAL_SetChnCountVal(ftmBaseAddr, channel, uCnv); break; case kFtmCenterAlignedPWM: uMod = uFTMhz / (param->uFrequencyHZ * 2); uCnv = uMod * param->uDutyCyclePercent / 100; /* For 100% duty cycle */ if(uCnv >= uMod) { uCnv = uMod + 1; } FTM_HAL_SetMod(ftmBaseAddr, uMod); FTM_HAL_SetChnCountVal(ftmBaseAddr, channel, uCnv); break; case kFtmCombinedPWM: uMod = uFTMhz / (param->uFrequencyHZ) - 1; uCnv = uMod * param->uDutyCyclePercent / 100; uCnvFirstEdge = uMod * param->uFirstEdgeDelayPercent / 100; /* For 100% duty cycle */ if(uCnv >= uMod) { uCnv = uMod + 1; } FTM_HAL_SetMod(ftmBaseAddr, uMod); FTM_HAL_SetChnCountVal(ftmBaseAddr, FTM_HAL_GetChnPairIndex(channel) * 2, uCnvFirstEdge); FTM_HAL_SetChnCountVal(ftmBaseAddr, FTM_HAL_GetChnPairIndex(channel) * 2 + 1, uCnv + uCnvFirstEdge); break; default: assert(0); break; } /* Set clock source to start counter */ FTM_HAL_SetClockSource(ftmBaseAddr, kClock_source_FTM_SystemClk); }
/*! * @brief Main demo function. */ int main (void) { ftm_pwm_param_t xAxisParams, yAxisParams; accel_dev_t accDev; accel_dev_interface_t accDevice; accel_sensor_data_t accelData; accel_i2c_interface_t i2cInterface; int16_t xData, yData; int16_t xAngle, yAngle; uint32_t ftmModulo; // Register callback func for I2C i2cInterface.i2c_init = I2C_DRV_MasterInit; i2cInterface.i2c_read = I2C_DRV_MasterReceiveDataBlocking; i2cInterface.i2c_write = I2C_DRV_MasterSendDataBlocking; accDev.i2c = &i2cInterface; accDev.accel = &accDevice; accDev.slave.baudRate_kbps = BOARD_ACCEL_BAUDRATE; accDev.slave.address = BOARD_ACCEL_ADDR; accDev.bus = BOARD_ACCEL_I2C_INSTANCE; // Initialize standard SDK demo application pins. hardware_init(); // Accel device driver utilizes the OSA, so initialize it. OSA_Init(); // Initialize the LEDs used by this application. LED2_EN; LED3_EN; // Print the initial banner. PRINTF("Bubble Level Demo!\r\n\r\n"); // Initialize the Accel. accel_init(&accDev); // Turn on the clock to the FTM. CLOCK_SYS_EnableFtmClock(BOARD_FTM_INSTANCE); // Initialize the FTM module. FTM_HAL_Init(BOARD_FTM_BASE); // Configure the sync mode to software. FTM_HAL_SetSyncMode(BOARD_FTM_BASE, kFtmUseSoftwareTrig); // Enable the overflow interrupt. FTM_HAL_EnableTimerOverflowInt(BOARD_FTM_BASE); // Set the FTM clock divider to /16. FTM_HAL_SetClockPs(BOARD_FTM_BASE, kFtmDividedBy16); // Configure the FTM channel used for the X-axis. Initial duty cycle is 0%. xAxisParams.mode = kFtmEdgeAlignedPWM; xAxisParams.edgeMode = kFtmHighTrue; FTM_HAL_EnablePwmMode(BOARD_FTM_BASE, &xAxisParams, BOARD_FTM_X_CHANNEL); FTM_HAL_SetChnCountVal(BOARD_FTM_BASE, BOARD_FTM_X_CHANNEL, 0); // Configure the FTM channel used for the Y-axis. Initial duty cycle is 0%. yAxisParams.mode = kFtmEdgeAlignedPWM; yAxisParams.edgeMode = kFtmHighTrue; FTM_HAL_EnablePwmMode(BOARD_FTM_BASE, &yAxisParams, BOARD_FTM_Y_CHANNEL); FTM_HAL_SetChnCountVal(BOARD_FTM_BASE, BOARD_FTM_Y_CHANNEL, 0); // Get the FTM reference clock and calculate the modulo value. ftmModulo = (CLOCK_SYS_GetFtmSystemClockFreq(BOARD_FTM_INSTANCE) / (1 << FTM_HAL_GetClockPs(BOARD_FTM_BASE))) / (BOARD_FTM_PERIOD_HZ - 1); // Initialize the FTM counter. FTM_HAL_SetCounterInitVal(BOARD_FTM_BASE, 0); FTM_HAL_SetMod(BOARD_FTM_BASE, ftmModulo); // Set the clock source to start the FTM. FTM_HAL_SetClockSource(BOARD_FTM_BASE, kClock_source_FTM_SystemClk); // Enable the FTM interrupt at the NVIC level. INT_SYS_EnableIRQ(BOARD_FTM_IRQ_VECTOR); // Main loop. Get sensor data and update globals for the FTM timer update. while(1) { // Wait 5 ms in between samples (accelerometer updates at 200Hz). OSA_TimeDelay(5); // Get new accelerometer data. accDev.accel->accel_read_sensor_data(&accDev,&accelData); // Turn off interrupts (FTM) while updating new duty cycle values. INT_SYS_DisableIRQGlobal(); // Get the X and Y data from the sensor data structure. xData = (int16_t)((accelData.data.accelXMSB << 8) | accelData.data.accelXLSB); yData = (int16_t)((accelData.data.accelYMSB << 8) | accelData.data.accelYLSB); // Convert raw data to angle (normalize to 0-90 degrees). No negative // angles. xAngle = abs((int16_t)(xData * 0.011)); yAngle = abs((int16_t)(yData * 0.011)); // Set values for next FTM ISR udpate. Use 5 degrees as the threshold // for whether to turn the LED on or not. g_xValue = (xAngle > 5) ? (uint16_t)((xAngle / 90.0) * ftmModulo) : 0; g_yValue = (yAngle > 5) ? (uint16_t)((yAngle / 90.0) * ftmModulo) : 0; // Re-enable interrupts. INT_SYS_EnableIRQGlobal(); // Print out the raw accelerometer data. PRINTF("x= %d y = %d\r\n", xData, yData); } }