1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/kinetis_common/pwm.c

275 lines
6.0 KiB
C
Raw Normal View History

/*
* Copyright (C) 2014 Freie Universität Berlin
* Copyright (C) 2014 PHYTEC Messtechnik GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
* details.
*/
/**
* @ingroup cpu_kinetis_common_pwm
*
* @{
*
* @file
* @brief Low-level PWM driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Johann Fischer <j.fischer@phytec.de>
* @author Jonas Remmert <j.remmert@phytec.de>
*
* @}
*/
#include <stdint.h>
#include <string.h>
#include "cpu.h"
#include "periph/pwm.h"
#include "periph_conf.h"
#include "hwtimer.h"
/* ignore file in case no PWM devices are defined */
#if PWM_NUMOF
int pwm_init(pwm_t dev, pwm_mode_t mode, unsigned int frequency, unsigned int resolution)
{
FTM_Type *tim = NULL;
PORT_Type *port[PWM_MAX_CHANNELS];
/* cppcheck-suppress unassignedVariable */
uint8_t pins[PWM_MAX_CHANNELS];
uint8_t af[PWM_MAX_CHANNELS];
/* cppcheck-suppress unassignedVariable */
uint8_t ftmchan[PWM_MAX_CHANNELS];
int channels = 0;
uint32_t pwm_clk = 0;
pwm_poweron(dev);
switch (dev) {
#if PWM_0_EN
case PWM_0:
tim = PWM_0_DEV;
port[0] = PWM_0_PORT_CH0;
port[1] = PWM_0_PORT_CH1;
port[2] = PWM_0_PORT_CH2;
port[3] = PWM_0_PORT_CH3;
pins[0] = PWM_0_PIN_CH0;
pins[1] = PWM_0_PIN_CH1;
pins[2] = PWM_0_PIN_CH2;
pins[3] = PWM_0_PIN_CH3;
ftmchan[0] = PWM_0_FTMCHAN_CH0;
ftmchan[1] = PWM_0_FTMCHAN_CH1;
ftmchan[2] = PWM_0_FTMCHAN_CH2;
ftmchan[3] = PWM_0_FTMCHAN_CH3;
af[0] = PWM_0_PIN_AF_CH0;
af[1] = PWM_0_PIN_AF_CH1;
af[2] = PWM_0_PIN_AF_CH2;
af[3] = PWM_0_PIN_AF_CH3;
channels = PWM_0_CHANNELS;
pwm_clk = PWM_0_CLK;
PWM_0_PORT_CLKEN();
break;
#endif
default:
return -1;
}
if (channels > PWM_MAX_CHANNELS) {
return -1;
}
/* cppcheck-suppress nullPointer */
tim->MODE = (1 << FTM_MODE_WPDIS_SHIFT);
/* setup pins, reset timer match value */
for (int i = 0; i < channels; i++) {
port[i]->PCR[pins[i]] = PORT_PCR_MUX(af[i]);
/* cppcheck-suppress nullPointer */
tim->CONTROLS[i].CnV = 0;
}
/* reset timer configuration registers */
/* cppcheck-suppress nullPointer */
tim->COMBINE = 0;
/* set prescale and mod registers to matching values for resolution and frequency */
if (resolution > 0xffff || (resolution * frequency) > pwm_clk) {
return -2;
}
/* cppcheck-suppress nullPointer */
tim->SC = FTM_SC_PS((pwm_clk / (resolution * frequency)) - 1);
/* cppcheck-suppress nullPointer */
tim->MOD = resolution;
/* set PWM mode */
switch (mode) {
case PWM_LEFT:
for (int i = 0; i < channels; i++) {
/* cppcheck-suppress nullPointer */
tim->CONTROLS[ftmchan[i]].CnSC = (1 << FTM_CnSC_MSB_SHIFT |
1 << FTM_CnSC_ELSB_SHIFT);
}
break;
case PWM_RIGHT:
for (int i = 0; i < channels; i++) {
/* cppcheck-suppress nullPointer */
tim->CONTROLS[ftmchan[i]].CnSC = (1 << FTM_CnSC_MSB_SHIFT |
1 << FTM_CnSC_ELSA_SHIFT);
}
break;
case PWM_CENTER:
for (int i = 0; i < channels; i++) {
/* cppcheck-suppress nullPointer */
tim->CONTROLS[ftmchan[i]].CnSC = (1 << FTM_CnSC_MSB_SHIFT);
}
/* cppcheck-suppress nullPointer */
tim->SC |= (1 << FTM_SC_CPWMS_SHIFT);
break;
}
/* enable timer ergo the PWM generation */
pwm_start(dev);
return 0;
}
int pwm_set(pwm_t dev, int channel, unsigned int value)
{
FTM_Type *tim = NULL;
switch (dev) {
#if PWM_0_EN
case PWM_0:
tim = PWM_0_DEV;
break;
#endif
#if PWM_1_EN
case PWM_1:
tim = PWM_1_DEV;
break;
#endif
default:
return -1;
}
/* norm value to maximum possible value */
if (value > 0xffff) {
value = 0xffff;
}
switch (channel) {
case 0:
/* cppcheck-suppress nullPointer */
tim->CONTROLS[PWM_0_FTMCHAN_CH0].CnV = value;
break;
case 1:
/* cppcheck-suppress nullPointer */
tim->CONTROLS[PWM_0_FTMCHAN_CH1].CnV = value;
break;
case 2:
/* cppcheck-suppress nullPointer */
tim->CONTROLS[PWM_0_FTMCHAN_CH2].CnV = value;
break;
case 3:
/* cppcheck-suppress nullPointer */
tim->CONTROLS[PWM_0_FTMCHAN_CH3].CnV = value;
break;
default:
return -1;
}
return 0;
}
void pwm_start(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_DEV->SC |= FTM_SC_CLKS(1);
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_DEV->SC |= FTM_SC_CLKS(1);
break;
#endif
}
}
void pwm_stop(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_DEV->SC &= ~FTM_SC_CLKS_MASK;
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_DEV->SC &= ~FTM_SC_CLKS_MASK;
break;
#endif
}
}
void pwm_poweron(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_CLKEN();
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_CLKEN();
break;
#endif
}
}
void pwm_poweroff(pwm_t dev)
{
switch (dev) {
#if PWM_0_EN
case PWM_0:
PWM_0_CLKDIS();
break;
#endif
#if PWM_1_EN
case PWM_1:
PWM_1_CLKDIS();
break;
#endif
}
}
#endif /* PWM_NUMOF */