mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 10:32:44 +01:00
cpu/sam0_common: add PWM support for saml2x, samd5x
This commit is contained in:
parent
824f7aa82b
commit
bce7d25f10
@ -23,6 +23,7 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exti_config.h"
|
||||
#include "timer_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -212,22 +213,55 @@ typedef struct {
|
||||
uint8_t gclk_src; /**< GCLK source which supplys SERCOM */
|
||||
} uart_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Common configuration for timer devices
|
||||
*/
|
||||
typedef struct {
|
||||
#ifdef REV_TCC
|
||||
Tcc *dev; /**< TCC device to use */
|
||||
#endif
|
||||
#ifdef MCLK
|
||||
volatile uint32_t *mclk; /**< Pointer to MCLK->APBxMASK.reg */
|
||||
uint32_t mclk_mask; /**< MCLK_APBxMASK bits to enable Timer */
|
||||
#else
|
||||
uint32_t pm_mask; /**< PM_APBCMASK bits to enable Timer */
|
||||
#endif
|
||||
uint16_t gclk_id; /**< TCn_GCLK_ID */
|
||||
} tcc_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Static initializer for timer configuration
|
||||
*/
|
||||
#ifdef MCLK
|
||||
#define TCC_CONFIG(tim) { \
|
||||
.dev = tim, \
|
||||
.mclk = MCLK_ ## tim, \
|
||||
.mclk_mask = MCLK_ ## tim ## _MASK, \
|
||||
.gclk_id = tim ## _GCLK_ID, }
|
||||
#else
|
||||
#define TCC_CONFIG(tim) { \
|
||||
.dev = tim, \
|
||||
.pm_mask = PM_APBCMASK_ ## tim, \
|
||||
.gclk_id = tim ## _GCLK_ID, }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief PWM channel configuration data structure
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_t pin; /**< GPIO pin */
|
||||
gpio_mux_t mux; /**< pin function multiplex value */
|
||||
uint8_t chan; /**< TCC channel to use */
|
||||
gpio_t pin; /**< GPIO pin */
|
||||
gpio_mux_t mux; /**< pin function multiplex value */
|
||||
uint8_t chan; /**< TCC channel to use */
|
||||
} pwm_conf_chan_t;
|
||||
|
||||
/**
|
||||
* @brief PWM device configuration data structure
|
||||
*/
|
||||
typedef struct {
|
||||
Tcc *dev; /**< TCC device to use */
|
||||
const pwm_conf_chan_t *chan;/**< channel configuration */
|
||||
const uint8_t chan_numof; /**< number of channels */
|
||||
tcc_cfg_t tim; /**< timer configuration */
|
||||
const pwm_conf_chan_t *chan; /**< channel configuration */
|
||||
uint8_t chan_numof; /**< number of channels */
|
||||
uint8_t gclk_src; /**< GCLK source which clocks TIMER */
|
||||
} pwm_conf_t;
|
||||
|
||||
/**
|
||||
|
255
cpu/sam0_common/include/timer_config.h
Normal file
255
cpu/sam0_common/include/timer_config.h
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2020 ML!PA Consulting 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_sam0_common
|
||||
* @brief Generic Timer MCLK masks.
|
||||
* @{
|
||||
*
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
*/
|
||||
|
||||
#ifndef TIMER_CONFIG_H
|
||||
#define TIMER_CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Automatically generated helper defines
|
||||
* @{
|
||||
*/
|
||||
#ifdef MCLK_APBAMASK_TC0
|
||||
#define MCLK_TC0 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC0_MASK (MCLK_APBAMASK_TC0)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC0
|
||||
#define MCLK_TC0 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC0_MASK (MCLK_APBBMASK_TC0)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC0
|
||||
#define MCLK_TC0 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC0_MASK (MCLK_APBCMASK_TC0)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC0
|
||||
#define MCLK_TC0 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC0_MASK (MCLK_APBDMASK_TC0)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC1
|
||||
#define MCLK_TC1 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC1_MASK (MCLK_APBAMASK_TC1)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC1
|
||||
#define MCLK_TC1 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC1_MASK (MCLK_APBBMASK_TC1)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC1
|
||||
#define MCLK_TC1 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC1_MASK (MCLK_APBCMASK_TC1)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC1
|
||||
#define MCLK_TC1 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC1_MASK (MCLK_APBDMASK_TC1)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC2
|
||||
#define MCLK_TC2 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC2_MASK (MCLK_APBAMASK_TC2)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC2
|
||||
#define MCLK_TC2 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC2_MASK (MCLK_APBBMASK_TC2)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC2
|
||||
#define MCLK_TC2 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC2_MASK (MCLK_APBCMASK_TC2)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC2
|
||||
#define MCLK_TC2 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC2_MASK (MCLK_APBDMASK_TC2)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC3
|
||||
#define MCLK_TC3 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC3_MASK (MCLK_APBAMASK_TC3)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC3
|
||||
#define MCLK_TC3 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC3_MASK (MCLK_APBBMASK_TC3)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC3
|
||||
#define MCLK_TC3 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC3_MASK (MCLK_APBCMASK_TC3)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC3
|
||||
#define MCLK_TC3 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC3_MASK (MCLK_APBDMASK_TC3)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC4
|
||||
#define MCLK_TC4 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC4_MASK (MCLK_APBAMASK_TC4)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC4
|
||||
#define MCLK_TC4 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC4_MASK (MCLK_APBBMASK_TC4)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC4
|
||||
#define MCLK_TC4 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC4_MASK (MCLK_APBCMASK_TC4)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC4
|
||||
#define MCLK_TC4 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC4_MASK (MCLK_APBDMASK_TC4)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC5
|
||||
#define MCLK_TC5 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC5_MASK (MCLK_APBAMASK_TC5)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC5
|
||||
#define MCLK_TC5 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC5_MASK (MCLK_APBBMASK_TC5)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC5
|
||||
#define MCLK_TC5 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC5_MASK (MCLK_APBCMASK_TC5)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC5
|
||||
#define MCLK_TC5 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC5_MASK (MCLK_APBDMASK_TC5)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC6
|
||||
#define MCLK_TC6 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC6_MASK (MCLK_APBAMASK_TC6)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC6
|
||||
#define MCLK_TC6 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC6_MASK (MCLK_APBBMASK_TC6)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC6
|
||||
#define MCLK_TC6 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC6_MASK (MCLK_APBCMASK_TC6)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC6
|
||||
#define MCLK_TC6 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC6_MASK (MCLK_APBDMASK_TC6)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TC7
|
||||
#define MCLK_TC7 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TC7_MASK (MCLK_APBAMASK_TC7)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TC7
|
||||
#define MCLK_TC7 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TC7_MASK (MCLK_APBBMASK_TC7)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TC7
|
||||
#define MCLK_TC7 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TC7_MASK (MCLK_APBCMASK_TC7)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TC7
|
||||
#define MCLK_TC7 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TC7_MASK (MCLK_APBDMASK_TC7)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TCC0
|
||||
#define MCLK_TCC0 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TCC0_MASK (MCLK_APBAMASK_TCC0)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TCC0
|
||||
#define MCLK_TCC0 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TCC0_MASK (MCLK_APBBMASK_TCC0)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TCC0
|
||||
#define MCLK_TCC0 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TCC0_MASK (MCLK_APBCMASK_TCC0)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TCC0
|
||||
#define MCLK_TCC0 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TCC0_MASK (MCLK_APBDMASK_TCC0)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TCC1
|
||||
#define MCLK_TCC1 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TCC1_MASK (MCLK_APBAMASK_TCC1)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TCC1
|
||||
#define MCLK_TCC1 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TCC1_MASK (MCLK_APBBMASK_TCC1)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TCC1
|
||||
#define MCLK_TCC1 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TCC1_MASK (MCLK_APBCMASK_TCC1)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TCC1
|
||||
#define MCLK_TCC1 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TCC1_MASK (MCLK_APBDMASK_TCC1)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TCC2
|
||||
#define MCLK_TCC2 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TCC2_MASK (MCLK_APBAMASK_TCC2)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TCC2
|
||||
#define MCLK_TCC2 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TCC2_MASK (MCLK_APBBMASK_TCC2)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TCC2
|
||||
#define MCLK_TCC2 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TCC2_MASK (MCLK_APBCMASK_TCC2)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TCC2
|
||||
#define MCLK_TCC2 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TCC2_MASK (MCLK_APBDMASK_TCC2)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TCC3
|
||||
#define MCLK_TCC3 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TCC3_MASK (MCLK_APBAMASK_TCC3)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TCC3
|
||||
#define MCLK_TCC3 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TCC3_MASK (MCLK_APBBMASK_TCC3)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TCC3
|
||||
#define MCLK_TCC3 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TCC3_MASK (MCLK_APBCMASK_TCC3)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TCC3
|
||||
#define MCLK_TCC3 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TCC3_MASK (MCLK_APBDMASK_TCC3)
|
||||
#endif
|
||||
|
||||
#ifdef MCLK_APBAMASK_TCC4
|
||||
#define MCLK_TCC4 (&MCLK->APBAMASK.reg)
|
||||
#define MCLK_TCC4_MASK (MCLK_APBAMASK_TCC4)
|
||||
#endif
|
||||
#ifdef MCLK_APBBMASK_TCC4
|
||||
#define MCLK_TCC4 (&MCLK->APBBMASK.reg)
|
||||
#define MCLK_TCC4_MASK (MCLK_APBBMASK_TCC4)
|
||||
#endif
|
||||
#ifdef MCLK_APBCMASK_TCC4
|
||||
#define MCLK_TCC4 (&MCLK->APBCMASK.reg)
|
||||
#define MCLK_TCC4_MASK (MCLK_APBCMASK_TCC4)
|
||||
#endif
|
||||
#ifdef MCLK_APBDMASK_TCC4
|
||||
#define MCLK_TCC4 (&MCLK->APBDMASK.reg)
|
||||
#define MCLK_TCC4_MASK (MCLK_APBDMASK_TCC4)
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TIMER_CONFIG_H */
|
||||
/** @} */
|
@ -17,14 +17,11 @@
|
||||
*
|
||||
* @author Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "cpu.h"
|
||||
#include "board.h"
|
||||
#include "periph/gpio.h"
|
||||
@ -32,7 +29,7 @@
|
||||
|
||||
static inline Tcc *_tcc(pwm_t dev)
|
||||
{
|
||||
return pwm_config[dev].dev;
|
||||
return pwm_config[dev].tim.dev;
|
||||
}
|
||||
|
||||
static inline uint8_t _chan(pwm_t dev, int chan)
|
||||
@ -40,57 +37,7 @@ static inline uint8_t _chan(pwm_t dev, int chan)
|
||||
return pwm_config[dev].chan[chan].chan;
|
||||
}
|
||||
|
||||
static int _clk_id(pwm_t dev)
|
||||
{
|
||||
Tcc *tcc = _tcc(dev);
|
||||
|
||||
if (tcc == TCC0) {
|
||||
return TCC0_GCLK_ID;
|
||||
}
|
||||
|
||||
if (tcc == TCC1) {
|
||||
return TCC1_GCLK_ID;
|
||||
}
|
||||
|
||||
if (tcc == TCC2) {
|
||||
return TCC2_GCLK_ID;
|
||||
}
|
||||
#ifdef TCC3
|
||||
if (tcc == TCC3) {
|
||||
return TCC3_GCLK_ID;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t _apbcmask_tcc(pwm_t dev)
|
||||
{
|
||||
Tcc *tcc = _tcc(dev);
|
||||
|
||||
if (tcc == TCC0) {
|
||||
return PM_APBCMASK_TCC0;
|
||||
}
|
||||
|
||||
if (tcc == TCC1) {
|
||||
return PM_APBCMASK_TCC1;
|
||||
}
|
||||
|
||||
if (tcc == TCC2) {
|
||||
return PM_APBCMASK_TCC2;
|
||||
}
|
||||
#ifdef TCC3
|
||||
if (tcc == TCC3) {
|
||||
return PM_APBCMASK_TCC3;
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t get_prescaler(unsigned int target, int *scale)
|
||||
static uint8_t _get_prescaler(unsigned int target, int *scale)
|
||||
{
|
||||
if (target == 0) {
|
||||
return 0xff;
|
||||
@ -124,13 +71,68 @@ static uint8_t get_prescaler(unsigned int target, int *scale)
|
||||
return target - 1;
|
||||
}
|
||||
|
||||
static uint8_t _get_cc_numof(Tcc *tcc)
|
||||
{
|
||||
switch ((uintptr_t) tcc) {
|
||||
#ifdef TCC0_CC_NUM
|
||||
case (uintptr_t)TCC0:
|
||||
return TCC0_CC_NUM;
|
||||
#endif
|
||||
#ifdef TCC1_CC_NUM
|
||||
case (uintptr_t)TCC1:
|
||||
return TCC1_CC_NUM;
|
||||
#endif
|
||||
#ifdef TCC2_CC_NUM
|
||||
case (uintptr_t)TCC2:
|
||||
return TCC2_CC_NUM;
|
||||
#endif
|
||||
#ifdef TCC3_CC_NUM
|
||||
case (uintptr_t)TCC3:
|
||||
return TCC3_CC_NUM;
|
||||
#endif
|
||||
#ifdef TCC4_CC_NUM
|
||||
case (uintptr_t)TCC4:
|
||||
return TCC4_CC_NUM;
|
||||
#endif
|
||||
#ifdef TCC5_CC_NUM
|
||||
case (uintptr_t)TCC5:
|
||||
return TCC5_CC_NUM;
|
||||
#endif
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void poweron(pwm_t dev)
|
||||
{
|
||||
PM->APBCMASK.reg |= _apbcmask_tcc(dev);
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
|
||||
GCLK_CLKCTRL_GEN_GCLK0 |
|
||||
GCLK_CLKCTRL_ID(_clk_id(dev)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
const pwm_conf_t *cfg = &pwm_config[dev];
|
||||
|
||||
sam0_gclk_enable(cfg->gclk_src);
|
||||
#ifdef MCLK
|
||||
GCLK->PCHCTRL[cfg->tim.gclk_id].reg = GCLK_PCHCTRL_GEN(cfg->gclk_src)
|
||||
| GCLK_PCHCTRL_CHEN;
|
||||
*cfg->tim.mclk |= cfg->tim.mclk_mask;
|
||||
#else
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN
|
||||
| GCLK_CLKCTRL_GEN(cfg->gclk_src)
|
||||
| GCLK_CLKCTRL_ID(cfg->tim.gclk_id);
|
||||
PM->APBCMASK.reg |= cfg->tim.pm_mask;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void poweroff(pwm_t dev)
|
||||
{
|
||||
const pwm_conf_t *cfg = &pwm_config[dev];
|
||||
|
||||
#ifdef MCLK
|
||||
GCLK->PCHCTRL[cfg->tim.gclk_id].reg = 0;
|
||||
*cfg->tim.mclk &= ~cfg->tim.mclk_mask;
|
||||
#else
|
||||
PM->APBCMASK.reg &= ~cfg->tim.pm_mask;
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK7
|
||||
| GCLK_CLKCTRL_ID(cfg->tim.gclk_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
@ -143,12 +145,14 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint32_t f_src = sam0_gclk_freq(pwm_config[dev].gclk_src);
|
||||
|
||||
/* calculate the closest possible clock presacler */
|
||||
prescaler = get_prescaler(CLOCK_CORECLOCK / (freq * res), &scale);
|
||||
prescaler = _get_prescaler(f_src / (freq * res), &scale);
|
||||
if (prescaler == 0xff) {
|
||||
return 0;
|
||||
}
|
||||
f_real = (CLOCK_CORECLOCK / (scale * res));
|
||||
f_real = f_src / (scale * res);
|
||||
|
||||
/* configure the used pins */
|
||||
for (unsigned i = 0; i < pwm_config[dev].chan_numof; i++) {
|
||||
@ -164,6 +168,7 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
/* reset TCC module */
|
||||
_tcc(dev)->CTRLA.reg = TCC_CTRLA_SWRST;
|
||||
while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {}
|
||||
|
||||
/* set PWM mode */
|
||||
switch (mode) {
|
||||
case PWM_LEFT:
|
||||
@ -179,16 +184,20 @@ uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res)
|
||||
while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {}
|
||||
|
||||
/* configure the TCC device */
|
||||
_tcc(dev)->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val
|
||||
| TCC_CTRLA_PRESCALER(prescaler));
|
||||
_tcc(dev)->CTRLA.reg = TCC_CTRLA_PRESCSYNC_GCLK_Val
|
||||
| TCC_CTRLA_PRESCALER(prescaler);
|
||||
|
||||
/* select the waveform generation mode -> normal PWM */
|
||||
_tcc(dev)->WAVE.reg = (TCC_WAVE_WAVEGEN_NPWM);
|
||||
while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE) {}
|
||||
|
||||
/* set the selected period */
|
||||
_tcc(dev)->PER.reg = (res - 1);
|
||||
while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {}
|
||||
|
||||
/* start PWM operation */
|
||||
_tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE);
|
||||
_tcc(dev)->CTRLA.reg |= TCC_CTRLA_ENABLE;
|
||||
|
||||
/* return the actual frequency the PWM is running at */
|
||||
return f_real;
|
||||
}
|
||||
@ -206,14 +215,12 @@ void pwm_set(pwm_t dev, uint8_t channel, uint16_t value)
|
||||
}
|
||||
|
||||
uint8_t chan = _chan(dev, channel);
|
||||
if (chan < 4) {
|
||||
_tcc(dev)->CC[chan].reg = value;
|
||||
while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << chan)) {}
|
||||
} else {
|
||||
chan -= 4;
|
||||
_tcc(dev)->CCB[chan].reg = value;
|
||||
while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CCB0 << chan)) {}
|
||||
}
|
||||
|
||||
/* TODO: use OTMX for pin remapping */
|
||||
chan %= _get_cc_numof(_tcc(dev));
|
||||
|
||||
_tcc(dev)->CC[chan].reg = value;
|
||||
while (_tcc(dev)->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << chan)) {}
|
||||
}
|
||||
|
||||
void pwm_poweron(pwm_t dev)
|
||||
@ -225,9 +232,5 @@ void pwm_poweron(pwm_t dev)
|
||||
void pwm_poweroff(pwm_t dev)
|
||||
{
|
||||
_tcc(dev)->CTRLA.reg &= ~(TCC_CTRLA_ENABLE);
|
||||
|
||||
PM->APBCMASK.reg &= ~_apbcmask_tcc(dev);
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK7 |
|
||||
GCLK_CLKCTRL_ID(_clk_id(dev)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
poweroff(dev);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user