From 840cd1ccb57659928722e5727b945247dc1f5414 Mon Sep 17 00:00:00 2001 From: Mahadevan Mahesh Date: Tue, 5 Apr 2016 12:08:25 -0500 Subject: [PATCH] Move PWM API to the target specific folder Some use the FTM module and some use the TPM module. Signed-off-by: Mahadevan Mahesh --- .../{api => TARGET_K22F}/pwmout_api.c | 0 .../TARGET_K64F/pwmout_api.c | 143 ++++++++++++++++++ .../TARGET_FRDM/PeripheralNames.h | 12 +- .../TARGET_KL27Z/TARGET_FRDM/PeripheralPins.c | 44 ++++++ .../TARGET_KL27Z/pwmout_api.c | 136 +++++++++++++++++ libraries/tests/mbed/pwm_led/pwm.cpp | 1 + 6 files changed, 335 insertions(+), 1 deletion(-) rename libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/{api => TARGET_K22F}/pwmout_api.c (100%) create mode 100644 libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_K64F/pwmout_api.c create mode 100644 libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/pwmout_api.c diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/api/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_K22F/pwmout_api.c similarity index 100% rename from libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/api/pwmout_api.c rename to libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_K22F/pwmout_api.c diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_K64F/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_K64F/pwmout_api.c new file mode 100644 index 0000000000..216d583191 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_K64F/pwmout_api.c @@ -0,0 +1,143 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_assert.h" +#include "pwmout_api.h" + +#if DEVICE_PWMOUT + +#include "cmsis.h" +#include "pinmap.h" +#include "fsl_ftm.h" +#include "PeripheralPins.h" + +static float pwm_clock_mhz; +/* Array of FTM peripheral base address. */ +static FTM_Type *const ftm_addrs[] = FTM_BASE_PTRS; + +void pwmout_init(pwmout_t* obj, PinName pin) { + PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); + MBED_ASSERT(pwm != (PWMName)NC); + + obj->pwm_name = pwm; + + uint32_t pwm_base_clock; + pwm_base_clock = CLOCK_GetFreq(kCLOCK_BusClk); + float clkval = (float)pwm_base_clock / 1000000.0f; + uint32_t clkdiv = 0; + while (clkval > 1) { + clkdiv++; + clkval /= 2.0f; + if (clkdiv == 7) { + break; + } + } + + pwm_clock_mhz = clkval; + uint32_t channel = pwm & 0xF; + uint32_t instance = pwm >> TPM_SHIFT; + ftm_config_t ftmInfo; + + FTM_GetDefaultConfig(&ftmInfo); + ftmInfo.prescale = (ftm_clock_prescale_t)clkdiv; + /* Initialize FTM module */ + FTM_Init(ftm_addrs[instance], &ftmInfo); + + ftm_addrs[instance]->CONF |= FTM_CONF_NUMTOF(3); + + ftm_chnl_pwm_signal_param_t config = { + .chnlNumber = (ftm_chnl_t)channel, + .level = kFTM_HighTrue, + .dutyCyclePercent = 0, + .firstEdgeDelayPercent = 0 + }; + // default to 20ms: standard for servos, and fine for e.g. brightness control + FTM_SetupPwm(ftm_addrs[instance], &config, 1, kFTM_EdgeAlignedPwm, 50, pwm_base_clock); + + FTM_StartTimer(ftm_addrs[instance], kFTM_SystemClock); + + // Wire pinout + pinmap_pinout(pin, PinMap_PWM); +} + +void pwmout_free(pwmout_t* obj) { + FTM_Deinit(ftm_addrs[obj->pwm_name >> TPM_SHIFT]); +} + +void pwmout_write(pwmout_t* obj, float value) { + if (value < 0.0f) { + value = 0.0f; + } else if (value > 1.0f) { + value = 1.0f; + } + + FTM_Type *base = ftm_addrs[obj->pwm_name >> TPM_SHIFT]; + uint16_t mod = base->MOD & FTM_MOD_MOD_MASK; + uint32_t new_count = (uint32_t)((float)(mod) * value); + // Update of CnV register + base->CONTROLS[obj->pwm_name & 0xF].CnV = new_count; + base->CNT = 0; + /* Software trigger to update registers */ + FTM_SetSoftwareTrigger(base, true); +} + +float pwmout_read(pwmout_t* obj) { + FTM_Type *base = ftm_addrs[obj->pwm_name >> TPM_SHIFT]; + uint16_t count = (base->CONTROLS[obj->pwm_name & 0xF].CnV) & FTM_CnV_VAL_MASK; + uint16_t mod = base->MOD & FTM_MOD_MOD_MASK; + + if (mod == 0) + return 0.0; + float v = (float)(count) / (float)(mod); + return (v > 1.0f) ? (1.0f) : (v); +} + +void pwmout_period(pwmout_t* obj, float seconds) { + pwmout_period_us(obj, seconds * 1000000.0f); +} + +void pwmout_period_ms(pwmout_t* obj, int ms) { + pwmout_period_us(obj, ms * 1000); +} + +// Set the PWM period, keeping the duty cycle the same. +void pwmout_period_us(pwmout_t* obj, int us) { + FTM_Type *base = ftm_addrs[obj->pwm_name >> TPM_SHIFT]; + float dc = pwmout_read(obj); + + // Stop FTM clock to ensure instant update of MOD register + base->MOD = FTM_MOD_MOD((pwm_clock_mhz * (float)us) - 1); + pwmout_write(obj, dc); +} + +void pwmout_pulsewidth(pwmout_t* obj, float seconds) { + pwmout_pulsewidth_us(obj, seconds * 1000000.0f); +} + +void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) { + pwmout_pulsewidth_us(obj, ms * 1000); +} + +void pwmout_pulsewidth_us(pwmout_t* obj, int us) { + FTM_Type *base = ftm_addrs[obj->pwm_name >> TPM_SHIFT]; + uint32_t value = (uint32_t)(pwm_clock_mhz * (float)us); + + // Update of CnV register + base->CONTROLS[obj->pwm_name & 0xF].CnV = value; + /* Software trigger to update registers */ + FTM_SetSoftwareTrigger(base, true); +} + +#endif diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralNames.h b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralNames.h index fff903f849..5e9ed77bcf 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralNames.h +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralNames.h @@ -41,8 +41,18 @@ typedef enum { I2C_1 = 1, } I2CName; +#define TPM_SHIFT 8 typedef enum { - PWM = 0, + PWM_1 = (0 << TPM_SHIFT) | (0), // TPM0 CH0 + PWM_2 = (0 << TPM_SHIFT) | (1), // TPM0 CH1 + PWM_3 = (0 << TPM_SHIFT) | (2), // TPM0 CH2 + PWM_4 = (0 << TPM_SHIFT) | (3), // TPM0 CH3 + PWM_5 = (0 << TPM_SHIFT) | (4), // TPM0 CH4 + PWM_6 = (0 << TPM_SHIFT) | (5), // TPM0 CH5 + PWM_7 = (1 << TPM_SHIFT) | (0), // TPM1 CH0 + PWM_8 = (1 << TPM_SHIFT) | (1), // TPM1 CH1 + PWM_9 = (2 << TPM_SHIFT) | (0), // TPM2 CH0 + PWM_10 = (2 << TPM_SHIFT) | (1), // TPM2 CH1 } PWMName; #define ADC_INSTANCE_SHIFT 8 diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralPins.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralPins.c index fb0ea4a2ff..ff132832b6 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralPins.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/TARGET_FRDM/PeripheralPins.c @@ -148,3 +148,47 @@ const PinMap PinMap_SPI_SSEL[] = { {PTD4 , SPI_1, 2}, {NC , NC , 0} }; + +/************PWM***************/ +const PinMap PinMap_PWM[] = { + {PTE29, PWM_3 , 3}, + {PTE30, PWM_4 , 3}, + {PTE31, PWM_5 , 3}, + {PTE24, PWM_1 , 3}, + {PTE25, PWM_2 , 3}, + {PTA0 , PWM_6 , 3}, + {PTA3 , PWM_1 , 3}, + {PTA4 , PWM_2 , 3}, + {PTA5 , PWM_3 , 3}, + {PTC1 , PWM_1 , 4}, + {PTC2 , PWM_2 , 4}, + {PTC3 , PWM_3 , 4}, + {PTC4 , PWM_4 , 4}, + {PTC8 , PWM_5 , 3}, + {PTC9 , PWM_6 , 3}, + {PTD0 , PWM_1 , 4}, + {PTD1 , PWM_2 , 4}, + {PTD2 , PWM_3 , 4}, + {PTD3 , PWM_4 , 4}, + {PTD4 , PWM_5 , 4}, + {PTD5 , PWM_6 , 4}, + + {PTE20, PWM_7 , 3}, + {PTE21, PWM_8 , 3}, + {PTA12, PWM_7 , 3}, + {PTA13, PWM_8 , 3}, + {PTB0, PWM_7 , 3}, + {PTB1, PWM_8 , 3}, + + {PTE22, PWM_9 , 3}, + {PTE23, PWM_10, 3}, + {PTA1 , PWM_9 , 3}, + {PTA2 , PWM_10, 3}, + {PTB2 , PWM_9 , 3}, + {PTB3 , PWM_10, 3}, + {PTB18, PWM_9 , 3}, + {PTB19, PWM_10, 3}, + + {NC , NC , 0} +}; + diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/pwmout_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/pwmout_api.c new file mode 100644 index 0000000000..dd5e5fd1b3 --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS/TARGET_KL27Z/pwmout_api.c @@ -0,0 +1,136 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_assert.h" +#include "pwmout_api.h" + +#if DEVICE_PWMOUT + +#include "cmsis.h" +#include "pinmap.h" +#include "fsl_tpm.h" +#include "PeripheralPins.h" + +static float pwm_clock_mhz; +/* Array of TPM peripheral base address. */ +static TPM_Type *const tpm_addrs[] = TPM_BASE_PTRS; + +void pwmout_init(pwmout_t* obj, PinName pin) { + PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM); + MBED_ASSERT(pwm != (PWMName)NC); + + obj->pwm_name = pwm; + + uint32_t pwm_base_clock; + pwm_base_clock = CLOCK_GetFreq(kCLOCK_McgIrc48MClk); + float clkval = (float)pwm_base_clock / 1000000.0f; + uint32_t clkdiv = 0; + while (clkval > 1) { + clkdiv++; + clkval /= 2.0f; + if (clkdiv == 7) { + break; + } + } + + pwm_clock_mhz = clkval; + uint32_t channel = pwm & 0xF; + uint32_t instance = pwm >> TPM_SHIFT; + tpm_config_t tpmInfo; + + TPM_GetDefaultConfig(&tpmInfo); + tpmInfo.prescale = (tpm_clock_prescale_t)clkdiv; + /* Initialize TPM module */ + TPM_Init(tpm_addrs[instance], &tpmInfo); + + tpm_chnl_pwm_signal_param_t config = { + .chnlNumber = (tpm_chnl_t)channel, + .level = kTPM_HighTrue, + .dutyCyclePercent = 0, + }; + // default to 20ms: standard for servos, and fine for e.g. brightness control + TPM_SetupPwm(tpm_addrs[instance], &config, 1, kTPM_EdgeAlignedPwm, 50, pwm_base_clock); + + TPM_StartTimer(tpm_addrs[instance], kTPM_SystemClock); + + // Wire pinout + pinmap_pinout(pin, PinMap_PWM); +} + +void pwmout_free(pwmout_t* obj) { + TPM_Deinit(tpm_addrs[obj->pwm_name >> TPM_SHIFT]); +} + +void pwmout_write(pwmout_t* obj, float value) { + if (value < 0.0f) { + value = 0.0f; + } else if (value > 1.0f) { + value = 1.0f; + } + + TPM_Type *base = tpm_addrs[obj->pwm_name >> TPM_SHIFT]; + uint16_t mod = base->MOD & TPM_MOD_MOD_MASK; + uint32_t new_count = (uint32_t)((float)(mod) * value); + // Update of CnV register + base->CONTROLS[obj->pwm_name & 0xF].CnV = new_count; + base->CNT = 0; +} + +float pwmout_read(pwmout_t* obj) { + TPM_Type *base = tpm_addrs[obj->pwm_name >> TPM_SHIFT]; + uint16_t count = (base->CONTROLS[obj->pwm_name & 0xF].CnV) & TPM_CnV_VAL_MASK; + uint16_t mod = base->MOD & TPM_MOD_MOD_MASK; + + if (mod == 0) + return 0.0; + float v = (float)(count) / (float)(mod); + return (v > 1.0f) ? (1.0f) : (v); +} + +void pwmout_period(pwmout_t* obj, float seconds) { + pwmout_period_us(obj, seconds * 1000000.0f); +} + +void pwmout_period_ms(pwmout_t* obj, int ms) { + pwmout_period_us(obj, ms * 1000); +} + +// Set the PWM period, keeping the duty cycle the same. +void pwmout_period_us(pwmout_t* obj, int us) { + TPM_Type *base = tpm_addrs[obj->pwm_name >> TPM_SHIFT]; + float dc = pwmout_read(obj); + + // Stop TPM clock to ensure instant update of MOD register + base->MOD = TPM_MOD_MOD((pwm_clock_mhz * (float)us) - 1); + pwmout_write(obj, dc); +} + +void pwmout_pulsewidth(pwmout_t* obj, float seconds) { + pwmout_pulsewidth_us(obj, seconds * 1000000.0f); +} + +void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) { + pwmout_pulsewidth_us(obj, ms * 1000); +} + +void pwmout_pulsewidth_us(pwmout_t* obj, int us) { + TPM_Type *base = tpm_addrs[obj->pwm_name >> TPM_SHIFT]; + uint32_t value = (uint32_t)(pwm_clock_mhz * (float)us); + + // Update of CnV register + base->CONTROLS[obj->pwm_name & 0xF].CnV = value; +} + +#endif diff --git a/libraries/tests/mbed/pwm_led/pwm.cpp b/libraries/tests/mbed/pwm_led/pwm.cpp index 61656d9a0a..429a3d8dc4 100644 --- a/libraries/tests/mbed/pwm_led/pwm.cpp +++ b/libraries/tests/mbed/pwm_led/pwm.cpp @@ -20,6 +20,7 @@ #define TEST_LED D3 #elif defined (TARGET_K22F) || \ + defined(TARGET_KL27Z) || \ defined (TARGET_LPC824) #define TEST_LED LED_GREEN