Move PWM API to the target specific folder

Some use the FTM module and some use the TPM module.

Signed-off-by: Mahadevan Mahesh <Mahesh.Mahadevan@nxp.com>
pull/1700/head
Mahadevan Mahesh 2016-04-05 12:08:25 -05:00
parent fffadba309
commit 840cd1ccb5
6 changed files with 335 additions and 1 deletions
libraries
mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS
tests/mbed/pwm_led

View File

@ -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

View File

@ -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

View File

@ -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}
};

View File

@ -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

View File

@ -20,6 +20,7 @@
#define TEST_LED D3
#elif defined (TARGET_K22F) || \
defined(TARGET_KL27Z) || \
defined (TARGET_LPC824)
#define TEST_LED LED_GREEN