mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
fffadba309
commit
840cd1ccb5
libraries
mbed/targets/hal/TARGET_Freescale/TARGET_KSDK2_MCUS
TARGET_K22F
TARGET_K64F
TARGET_KL27Z
tests/mbed/pwm_led
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
|
@ -20,6 +20,7 @@
|
|||
#define TEST_LED D3
|
||||
|
||||
#elif defined (TARGET_K22F) || \
|
||||
defined(TARGET_KL27Z) || \
|
||||
defined (TARGET_LPC824)
|
||||
#define TEST_LED LED_GREEN
|
||||
|
||||
|
|
Loading…
Reference in New Issue