mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
130 lines
3.2 KiB
C
130 lines
3.2 KiB
C
/*
|
|
* Copyright (C) 2016-2017 Bas Stottelaar <basstottelaar@gmail.com>
|
|
*
|
|
* 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_efm32
|
|
* @ingroup drivers_periph_pwm
|
|
* @{
|
|
*
|
|
* @file
|
|
* @brief Low-level PWM peripheral driver implementation
|
|
*
|
|
* @author Bas Stottelaar <basstottelaar@gmail.com>
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "periph_conf.h"
|
|
#include "periph/gpio.h"
|
|
#include "periph/pwm.h"
|
|
|
|
#include "em_cmu.h"
|
|
#include "em_timer.h"
|
|
#include "em_timer_utils.h"
|
|
|
|
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
|
{
|
|
/* check if device is valid */
|
|
if (dev >= PWM_NUMOF) {
|
|
return 0;
|
|
}
|
|
|
|
/* enable clocks */
|
|
CMU_ClockEnable(cmuClock_HFPER, true);
|
|
CMU_ClockEnable(pwm_config[dev].cmu, true);
|
|
|
|
/* calculate the prescaler by determining the best prescaler */
|
|
uint32_t freq_timer = CMU_ClockFreqGet(pwm_config[dev].cmu);
|
|
TIMER_Prescale_TypeDef prescaler = TIMER_PrescalerCalc(freq * res,
|
|
freq_timer);
|
|
|
|
if (prescaler > timerPrescale1024) {
|
|
return 0;
|
|
}
|
|
|
|
/* reset and initialize peripheral */
|
|
TIMER_Init_TypeDef init = TIMER_INIT_DEFAULT;
|
|
|
|
init.enable = false;
|
|
init.prescale = prescaler;
|
|
init.mode = (TIMER_Mode_TypeDef) mode;
|
|
|
|
TIMER_Reset(pwm_config[dev].dev);
|
|
TIMER_Init(pwm_config[dev].dev, &init);
|
|
TIMER_TopSet(pwm_config[dev].dev, res);
|
|
|
|
/* initialize channels */
|
|
TIMER_InitCC_TypeDef init_channel = TIMER_INITCC_DEFAULT;
|
|
|
|
init_channel.mode = timerCCModePWM;
|
|
|
|
for (int i = 0; i < pwm_config[dev].channels; i++) {
|
|
pwm_chan_conf_t channel = pwm_config[dev].channel[i];
|
|
|
|
/* configure the pin */
|
|
gpio_init(channel.pin, GPIO_OUT);
|
|
|
|
/* configure pin function */
|
|
#if defined(_SILICON_LABS_32B_SERIES_0)
|
|
pwm_config[dev].dev->ROUTE |= (channel.loc |
|
|
TIMER_Channel2Route(channel.index));
|
|
#elif defined(_SILICON_LABS_32B_SERIES_1)
|
|
pwm_config[dev].dev->ROUTELOC0 |= channel.loc;
|
|
pwm_config[dev].dev->ROUTEPEN |= TIMER_Channel2Route(channel.index);
|
|
#endif
|
|
|
|
/* setup channel */
|
|
TIMER_InitCC(pwm_config[dev].dev, channel.index, &init_channel);
|
|
}
|
|
|
|
/* enable peripheral */
|
|
TIMER_Enable(pwm_config[dev].dev, true);
|
|
|
|
return freq_timer / TIMER_Prescaler2Div(prescaler) / res;
|
|
}
|
|
|
|
uint8_t pwm_channels(pwm_t dev)
|
|
{
|
|
assert(dev < PWM_NUMOF);
|
|
return pwm_config[dev].channels;
|
|
}
|
|
|
|
void pwm_set(pwm_t dev, uint8_t channel, uint16_t value)
|
|
{
|
|
assert(dev < PWM_NUMOF);
|
|
TIMER_CompareBufSet(pwm_config[dev].dev,
|
|
pwm_config[dev].channel[channel].index,
|
|
value);
|
|
}
|
|
|
|
void pwm_start(pwm_t dev)
|
|
{
|
|
assert(dev < PWM_NUMOF);
|
|
TIMER_Enable(pwm_config[dev].dev, true);
|
|
}
|
|
|
|
void pwm_stop(pwm_t dev)
|
|
{
|
|
assert(dev < PWM_NUMOF);
|
|
TIMER_Enable(pwm_config[dev].dev, false);
|
|
}
|
|
|
|
void pwm_poweron(pwm_t dev)
|
|
{
|
|
assert(dev < PWM_NUMOF);
|
|
CMU_ClockEnable(pwm_config[dev].cmu, true);
|
|
}
|
|
|
|
void pwm_poweroff(pwm_t dev)
|
|
{
|
|
assert(dev < PWM_NUMOF);
|
|
CMU_ClockEnable(pwm_config[dev].cmu, false);
|
|
}
|