mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #14007 from benpicco/cpu/sam0_common-pwm
cpu/sam0_common: move PWM to common code, add support for saml21, samd5x
This commit is contained in:
commit
30ebabb84e
@ -137,7 +137,7 @@ static const pwm_conf_chan_t pwm_chan0_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC0, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -189,10 +189,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC0, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TCC1, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)},
|
||||
{TCC_CONFIG(TCC1), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -166,10 +166,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC0, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TCC2, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)},
|
||||
{TCC_CONFIG(TCC2), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -186,10 +186,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC1, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC1), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TCC0, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)},
|
||||
{TCC_CONFIG(TCC0), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -226,13 +226,13 @@ static const pwm_conf_chan_t pwm_chan2_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC2, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC2), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TC4, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)},
|
||||
{TCC_CONFIG(TC4), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_2_EN
|
||||
{TC6, pwm_chan2_config, ARRAY_SIZE(pwm_chan2_config)},
|
||||
{TCC_CONFIG(TC6), pwm_chan2_config, ARRAY_SIZE(pwm_chan2_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@ FEATURES_PROVIDED += periph_dac
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_pwm
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
FEATURES_PROVIDED += periph_uart
|
||||
|
@ -185,6 +185,35 @@ static const uart_conf_t uart_config[] = {
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name PWM configuration
|
||||
* @{
|
||||
*/
|
||||
#define PWM_0_EN 1
|
||||
|
||||
#if PWM_0_EN
|
||||
/* PWM0 channels */
|
||||
static const pwm_conf_chan_t pwm_chan0_config[] = {
|
||||
/* GPIO pin, MUX value, TCC channel */
|
||||
{ GPIO_PIN(PC, 18), GPIO_MUX_F, 2 },
|
||||
};
|
||||
#endif
|
||||
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{ .tim = TCC_CONFIG(TCC0),
|
||||
.chan = pwm_chan0_config,
|
||||
.chan_numof = ARRAY_SIZE(pwm_chan0_config),
|
||||
.gclk_src = SAM0_GCLK_48MHZ,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* number of devices that are actually defined */
|
||||
#define PWM_NUMOF ARRAY_SIZE(pwm_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
|
@ -5,6 +5,7 @@ CPU_MODEL = saml21j18a
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_dac
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_pwm
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
|
@ -104,6 +104,35 @@ static const uart_conf_t uart_config[] = {
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name PWM configuration
|
||||
* @{
|
||||
*/
|
||||
#define PWM_0_EN 1
|
||||
|
||||
#if PWM_0_EN
|
||||
/* PWM0 channels */
|
||||
static const pwm_conf_chan_t pwm_chan0_config[] = {
|
||||
/* GPIO pin, MUX value, TCC channel */
|
||||
{ GPIO_PIN(PB, 10), GPIO_MUX_F, 4 },
|
||||
};
|
||||
#endif
|
||||
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{ .tim = TCC_CONFIG(TCC0),
|
||||
.chan = pwm_chan0_config,
|
||||
.chan_numof = ARRAY_SIZE(pwm_chan0_config),
|
||||
.gclk_src = SAM0_GCLK_8MHZ,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* number of devices that are actually defined */
|
||||
#define PWM_NUMOF ARRAY_SIZE(pwm_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
|
@ -211,10 +211,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC1, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC1), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TCC0, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)},
|
||||
{TCC_CONFIG(TCC0), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,7 @@ CPU_MODEL = samd21e18a
|
||||
FEATURES_PROVIDED += bootloader_arduino
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_pwm
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
|
@ -148,6 +148,47 @@ static const uart_conf_t uart_config[] = {
|
||||
#define UART_NUMOF ARRAY_SIZE(uart_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name PWM configuration
|
||||
* @{
|
||||
*/
|
||||
#define PWM_0_EN 1
|
||||
#define PWM_1_EN 1
|
||||
|
||||
#if PWM_0_EN
|
||||
/* PWM0 channels */
|
||||
static const pwm_conf_chan_t pwm_chan0_config[] = {
|
||||
/* GPIO pin, MUX value, TCC channel */
|
||||
{ GPIO_PIN(PA, 4), GPIO_MUX_E, 0 },
|
||||
{ GPIO_PIN(PA, 5), GPIO_MUX_E, 1 },
|
||||
{ GPIO_PIN(PA, 19), GPIO_MUX_F, 3 },
|
||||
{ GPIO_PIN(PA, 22), GPIO_MUX_F, 4 },
|
||||
{ GPIO_PIN(PA, 23), GPIO_MUX_F, 5 },
|
||||
};
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
/* PWM1 channels */
|
||||
static const pwm_conf_chan_t pwm_chan1_config[] = {
|
||||
/* GPIO pin, MUX value, TCC channel */
|
||||
{ GPIO_PIN(PA, 6), GPIO_MUX_E, 0 },
|
||||
{ GPIO_PIN(PA, 7), GPIO_MUX_E, 1 },
|
||||
};
|
||||
#endif
|
||||
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC_CONFIG(TCC0), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TCC_CONFIG(TCC1), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
/* number of devices that are actually defined */
|
||||
#define PWM_NUMOF ARRAY_SIZE(pwm_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name SPI configuration
|
||||
* @{
|
||||
|
@ -171,10 +171,10 @@ static const pwm_conf_chan_t pwm_chan1_config[] = {
|
||||
/* PWM device configuration */
|
||||
static const pwm_conf_t pwm_config[] = {
|
||||
#if PWM_0_EN
|
||||
{TCC1, pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config)},
|
||||
{TCC_CONFIG(TCC1), pwm_chan0_config, ARRAY_SIZE(pwm_chan0_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
#if PWM_1_EN
|
||||
{TCC0, pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config)},
|
||||
{TCC_CONFIG(TCC0), pwm_chan1_config, ARRAY_SIZE(pwm_chan1_config), SAM0_GCLK_MAIN},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exti_config.h"
|
||||
#include "timer_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -216,6 +217,57 @@ 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 */
|
||||
} pwm_conf_chan_t;
|
||||
|
||||
/**
|
||||
* @brief PWM device configuration data structure
|
||||
*/
|
||||
typedef struct {
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief Available values for SERCOM SPI MISO pad selection
|
||||
*/
|
||||
|
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);
|
||||
}
|
@ -70,24 +70,6 @@ enum {
|
||||
*/
|
||||
#define SPI_HWCS(x) (UINT_MAX - 1)
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
} 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 */
|
||||
} pwm_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Return the numeric id of a SERCOM device derived from its address
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user