1
0
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:
benpicco 2020-07-09 10:01:08 +02:00 committed by GitHub
commit 30ebabb84e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 505 additions and 111 deletions

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

View File

@ -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

View File

@ -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
* @{

View File

@ -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

View File

@ -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
* @{

View File

@ -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
};

View File

@ -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

View File

@ -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
* @{

View File

@ -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
};

View File

@ -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
*/

View 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 */
/** @} */

View File

@ -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);
}

View File

@ -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
*