mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
sam0_common: make Timer implementation common across all sam0 MCUs
The currently supported SAM0 MCUs (samd21, saml21, saml1x) share the same Timer peripheral, yet each of them carries it's own copy of the Timer driver. This introduces a new timer driver that is common for all sam0 MCUs and uses structs for configuration instead of defines.
This commit is contained in:
parent
c439346f6d
commit
849dd4cdce
@ -33,7 +33,7 @@ extern "C" {
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#define XTIMER TIMER_DEV(1)
|
||||
#define XTIMER_DEV TIMER_DEV(1)
|
||||
#define XTIMER_CHAN (0)
|
||||
/** @} */
|
||||
|
||||
|
@ -83,22 +83,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -81,21 +81,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -35,14 +35,23 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (1U)
|
||||
#define TIMER_0_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC0,
|
||||
.irq = TC0_IRQn,
|
||||
.mclk = &MCLK->APBCMASK.reg,
|
||||
.mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1,
|
||||
.gclk_id = TC0_GCLK_ID,
|
||||
.gclk_src = GCLK_PCHCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER(4),
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC0->COUNT32
|
||||
#define TIMER_0_CHANNELS 1
|
||||
#define TIMER_0_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_0_ISR isr_tc0
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_ISR isr_tc0
|
||||
#define TIMER_NUMOF (sizeof(timer_config)/sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -78,21 +78,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -113,21 +113,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name xtimer configuration
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#define XTIMER_DEV TIMER_DEV(1)
|
||||
|
@ -89,21 +89,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -38,14 +38,23 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (1U)
|
||||
#define TIMER_0_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC0,
|
||||
.irq = TC0_IRQn,
|
||||
.mclk = &MCLK->APBCMASK.reg,
|
||||
.mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1,
|
||||
.gclk_id = TC0_GCLK_ID,
|
||||
.gclk_src = GCLK_PCHCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER(4),
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC0->COUNT32
|
||||
#define TIMER_0_CHANNELS 1
|
||||
#define TIMER_0_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_0_ISR isr_tc0
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_ISR isr_tc0
|
||||
#define TIMER_NUMOF (sizeof(timer_config)/sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -89,21 +89,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -34,14 +34,23 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (1U)
|
||||
#define TIMER_0_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC0,
|
||||
.irq = TC0_IRQn,
|
||||
.mclk = &MCLK->APBCMASK.reg,
|
||||
.mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1,
|
||||
.gclk_id = TC0_GCLK_ID,
|
||||
.gclk_src = GCLK_PCHCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER(4),
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC0->COUNT32
|
||||
#define TIMER_0_CHANNELS 1
|
||||
#define TIMER_0_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_0_ISR isr_tc0
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_ISR isr_tc0
|
||||
#define TIMER_NUMOF (sizeof(timer_config)/sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -79,21 +79,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -79,21 +79,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -26,13 +26,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name xtimer configuration
|
||||
* @{
|
||||
*/
|
||||
#define XTIMER_WIDTH (16)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name LED pin definitions and handlers
|
||||
* @{
|
||||
|
@ -76,21 +76,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -79,21 +79,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -81,21 +81,44 @@ extern "C" {
|
||||
* @name Timer peripheral configuration
|
||||
* @{
|
||||
*/
|
||||
#define TIMER_NUMOF (2U)
|
||||
#define TIMER_0_EN 1
|
||||
#define TIMER_1_EN 1
|
||||
static const tc32_conf_t timer_config[] = {
|
||||
{ /* Timer 0 - System Clock */
|
||||
.dev = TC3,
|
||||
.irq = TC3_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC3,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TCC2_TC3,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT16,
|
||||
},
|
||||
{ /* Timer 1 */
|
||||
.dev = TC4,
|
||||
.irq = TC4_IRQn,
|
||||
.pm_mask = PM_APBCMASK_TC4 | PM_APBCMASK_TC5,
|
||||
.gclk_ctrl = GCLK_CLKCTRL_ID_TC4_TC5,
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(1),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV1,
|
||||
#else
|
||||
.gclk_src = GCLK_CLKCTRL_GEN(0),
|
||||
.prescaler = TC_CTRLA_PRESCALER_DIV8,
|
||||
#endif
|
||||
.flags = TC_CTRLA_MODE_COUNT32,
|
||||
}
|
||||
};
|
||||
|
||||
/* Timer 0 configuration */
|
||||
#define TIMER_0_DEV TC3->COUNT16
|
||||
#define TIMER_0_CHANNELS 2
|
||||
#define TIMER_0_MAX_VALUE (0xffff)
|
||||
#define TIMER_0_MAX_VALUE 0xffff
|
||||
|
||||
/* interrupt function name mapping */
|
||||
#define TIMER_0_ISR isr_tc3
|
||||
|
||||
/* Timer 1 configuration */
|
||||
#define TIMER_1_DEV TC4->COUNT32
|
||||
#define TIMER_1_CHANNELS 2
|
||||
#define TIMER_1_MAX_VALUE (0xffffffff)
|
||||
#define TIMER_1_ISR isr_tc4
|
||||
|
||||
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
@ -289,6 +289,25 @@ typedef struct {
|
||||
uint8_t flags; /**< allow SERCOM to run in standby mode */
|
||||
} i2c_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Timer device configuration
|
||||
*/
|
||||
typedef struct {
|
||||
Tc *dev; /**< pointer to the used Timer device */
|
||||
IRQn_Type irq; /**< IRQ# of Timer Interrupt */
|
||||
#ifdef MCLK
|
||||
volatile uint32_t *mclk;/**< Pointer to MCLK->APBxMASK.reg */
|
||||
uint32_t mclk_mask; /**< MCLK_APBxMASK bits to enable Timer */
|
||||
uint16_t gclk_id; /**< TCn_GCLK_ID */
|
||||
#else
|
||||
uint32_t pm_mask; /**< PM_APBCMASK bits to enable Timer */
|
||||
uint16_t gclk_ctrl; /**< GCLK_CLKCTRL_ID for the Timer */
|
||||
#endif
|
||||
uint16_t gclk_src; /**< GCLK source which supplys Timer */
|
||||
uint16_t prescaler; /**< prescaler used by the Timer */
|
||||
uint16_t flags; /**< flags for CTRA, e.g. TC_CTRLA_MODE_COUNT32 */
|
||||
} tc32_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Set up alternate function (PMUX setting) for a PORT pin
|
||||
*
|
||||
|
269
cpu/sam0_common/periph/timer.c
Normal file
269
cpu/sam0_common/periph/timer.c
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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
|
||||
* @ingroup drivers_periph_timer
|
||||
* @{
|
||||
*
|
||||
* @file timer.c
|
||||
* @brief Low-level timer driver implementation
|
||||
*
|
||||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "periph/timer.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Timer state memory
|
||||
*/
|
||||
static timer_isr_ctx_t config[TIMER_NUMOF];
|
||||
|
||||
static inline TcCount32 *dev(tim_t tim)
|
||||
{
|
||||
return &timer_config[tim].dev->COUNT32;
|
||||
}
|
||||
|
||||
static inline TcCount16 *dev16(tim_t tim)
|
||||
{
|
||||
return &timer_config[tim].dev->COUNT16;
|
||||
}
|
||||
|
||||
static inline TcCount8 *dev8(tim_t tim)
|
||||
{
|
||||
return &timer_config[tim].dev->COUNT8;
|
||||
}
|
||||
|
||||
static inline void wait_synchronization(tim_t tim)
|
||||
{
|
||||
#if defined(TC_SYNCBUSY_MASK)
|
||||
/* SYNCBUSY is a register */
|
||||
while ((dev(tim)->SYNCBUSY.reg & TC_SYNCBUSY_MASK) != 0) {}
|
||||
#elif defined(TC_STATUS_SYNCBUSY)
|
||||
/* SYNCBUSY is a bit */
|
||||
while ((dev(tim)->STATUS.reg & TC_STATUS_SYNCBUSY) != 0) {}
|
||||
#else
|
||||
#error Unsupported device
|
||||
#endif
|
||||
}
|
||||
|
||||
/* enable timer interrupts */
|
||||
static inline void _irq_enable(tim_t tim)
|
||||
{
|
||||
NVIC_EnableIRQ(timer_config[tim].irq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup the given timer
|
||||
*/
|
||||
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
{
|
||||
const tc32_conf_t *cfg = &timer_config[tim];
|
||||
|
||||
/* make sure given device is valid */
|
||||
if (tim >= TIMER_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* at the moment, the timer can only run at 1MHz */
|
||||
if (freq != 1000000ul) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make sure the timer is not running */
|
||||
timer_stop(tim);
|
||||
|
||||
#ifdef MCLK
|
||||
GCLK->PCHCTRL[cfg->gclk_id].reg = cfg->gclk_src | GCLK_PCHCTRL_CHEN;
|
||||
*cfg->mclk |= cfg->mclk_mask;
|
||||
#else
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | cfg->gclk_src | cfg->gclk_ctrl;
|
||||
PM->APBCMASK.reg |= cfg->pm_mask;
|
||||
#endif
|
||||
|
||||
/* reset the timer */
|
||||
dev(tim)->CTRLA.bit.SWRST = 1;
|
||||
while (dev(tim)->CTRLA.bit.SWRST) {}
|
||||
|
||||
dev(tim)->CTRLA.reg = cfg->flags
|
||||
#ifdef TC_CTRLA_WAVEGEN_NFRQ
|
||||
| TC_CTRLA_WAVEGEN_NFRQ
|
||||
#endif
|
||||
| cfg->prescaler
|
||||
| TC_CTRLA_PRESCSYNC_RESYNC;
|
||||
|
||||
#ifdef TC_WAVE_WAVEGEN_NFRQ
|
||||
dev(tim)->WAVE.reg = TC_WAVE_WAVEGEN_NFRQ;
|
||||
#endif
|
||||
|
||||
wait_synchronization(tim);
|
||||
|
||||
dev(tim)->INTENCLR.reg = TC_INTENCLR_MASK;
|
||||
|
||||
/* save callback */
|
||||
config[tim].cb = cb;
|
||||
config[tim].arg = arg;
|
||||
|
||||
timer_start(tim);
|
||||
|
||||
/* enable interrupts for given timer */
|
||||
_irq_enable(tim);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _set_cc(tim_t tim, int cc, unsigned int value)
|
||||
{
|
||||
const uint16_t flags = timer_config[tim].flags;
|
||||
|
||||
if (flags & TC_CTRLA_MODE_COUNT32) {
|
||||
dev(tim)->CC[cc].reg = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & TC_CTRLA_MODE_COUNT8) {
|
||||
dev8(tim)->CC[cc].reg = value;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 16 bit is the default */
|
||||
dev16(tim)->CC[cc].reg = value;
|
||||
}
|
||||
|
||||
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
{
|
||||
DEBUG("Setting timer %i channel %i to %i\n", tim, channel, value);
|
||||
|
||||
/* set timeout value */
|
||||
switch (channel) {
|
||||
case 0:
|
||||
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
_set_cc(tim, 0, value);
|
||||
dev(tim)->INTENSET.bit.MC0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
_set_cc(tim, 1, value);
|
||||
dev(tim)->INTENSET.bit.MC1 = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t tim, int channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case 0:
|
||||
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
dev(tim)->INTENCLR.bit.MC0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
dev(tim)->INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
dev(tim)->INTENCLR.bit.MC1 = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int timer_read(tim_t tim)
|
||||
{
|
||||
/* WORKAROUND to prevent being stuck there if timer not init */
|
||||
if (!dev(tim)->CTRLA.bit.ENABLE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* request syncronisation */
|
||||
#ifdef TC_CTRLBSET_CMD_READSYNC_Val
|
||||
dev(tim)->CTRLBSET.bit.CMD = TC_CTRLBSET_CMD_READSYNC_Val;
|
||||
#else
|
||||
dev(tim)->READREQ.reg = TC_READREQ_RREQ | TC_READREQ_ADDR(0x10);
|
||||
#endif
|
||||
wait_synchronization(tim);
|
||||
|
||||
return dev(tim)->COUNT.reg;
|
||||
}
|
||||
|
||||
void timer_stop(tim_t tim)
|
||||
{
|
||||
dev(tim)->CTRLA.bit.ENABLE = 0;
|
||||
}
|
||||
|
||||
void timer_start(tim_t tim)
|
||||
{
|
||||
dev(tim)->CTRLA.bit.ENABLE = 1;
|
||||
}
|
||||
|
||||
static inline void timer_isr(tim_t tim)
|
||||
{
|
||||
TcCount32 *tc = dev(tim);
|
||||
uint8_t status = tc->INTFLAG.reg;
|
||||
|
||||
/* Acknowledge all interrupts */
|
||||
tc->INTFLAG.reg = status;
|
||||
|
||||
if ((status & TC_INTFLAG_MC0) && tc->INTENSET.bit.MC0) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
if (config[tim].cb) {
|
||||
config[tim].cb(config[tim].arg, 0);
|
||||
}
|
||||
}
|
||||
if ((status & TC_INTFLAG_MC1) && tc->INTENSET.bit.MC1) {
|
||||
tc->INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
if (config[tim].cb) {
|
||||
config[tim].cb(config[tim].arg, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TIMER_0_ISR
|
||||
void TIMER_0_ISR(void)
|
||||
{
|
||||
timer_isr(0);
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif
|
||||
#ifdef TIMER_1_ISR
|
||||
void TIMER_1_ISR(void)
|
||||
{
|
||||
timer_isr(1);
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif
|
||||
#ifdef TIMER_2_ISR
|
||||
void TIMER_2_ISR(void)
|
||||
{
|
||||
timer_isr(2);
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif
|
||||
#ifdef TIMER_3_ISR
|
||||
void TIMER_3_ISR(void)
|
||||
{
|
||||
timer_isr(3);
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif
|
@ -1,351 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
*
|
||||
* 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_samd21
|
||||
* @ingroup drivers_periph_timer
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level timer driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "periph/timer.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Timer state memory
|
||||
*/
|
||||
static timer_isr_ctx_t config[TIMER_NUMOF];
|
||||
|
||||
/* enable timer interrupts */
|
||||
static inline void _irq_enable(tim_t dev);
|
||||
|
||||
/**
|
||||
* @brief Setup the given timer
|
||||
*/
|
||||
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
{
|
||||
/* at the moment, the timer can only run at 1MHz */
|
||||
if (freq != 1000000ul) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* select the clock generator depending on the main clock source:
|
||||
* GCLK0 (1MHz) if we use the internal 8MHz oscillator
|
||||
* GCLK1 (8MHz) if we use the PLL */
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
/* configure GCLK1 (configured to 1MHz) to feed TC3, TC4 and TC5 */;
|
||||
/* configure GCLK1 to feed TC3, TC4 and TC5 */;
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (TC3_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
/* TC4 and TC5 share the same channel */
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (TC4_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
#else
|
||||
/* configure GCLK0 to feed TC3, TC4 and TC5 */;
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (TC3_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
/* TC4 and TC5 share the same channel */
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (TC4_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
#endif
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
if (TIMER_0_DEV.CTRLA.bit.ENABLE) {
|
||||
return 0;
|
||||
}
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_TC3;
|
||||
/* reset timer */
|
||||
TIMER_0_DEV.CTRLA.bit.SWRST = 1;
|
||||
while (TIMER_0_DEV.CTRLA.bit.SWRST) {}
|
||||
/* choosing 16 bit mode */
|
||||
TIMER_0_DEV.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val;
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
/* PLL/DFLL: sourced by 1MHz and prescaler 1 to reach 1MHz */
|
||||
TIMER_0_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
|
||||
#else
|
||||
/* sourced by 8MHz with Presc 8 results in 1MHz clk */
|
||||
TIMER_0_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV8_Val;
|
||||
#endif
|
||||
/* choose normal frequency operation */
|
||||
TIMER_0_DEV.CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
if (TIMER_1_DEV.CTRLA.bit.ENABLE) {
|
||||
return 0;
|
||||
}
|
||||
PM->APBCMASK.reg |= PM_APBCMASK_TC4;
|
||||
/* reset timer */
|
||||
TIMER_1_DEV.CTRLA.bit.SWRST = 1;
|
||||
|
||||
while (TIMER_1_DEV.CTRLA.bit.SWRST) {}
|
||||
|
||||
|
||||
TIMER_1_DEV.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT32_Val;
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
/* PLL/DFLL: sourced by 1MHz and prescaler 1 to reach 1MHz */
|
||||
TIMER_1_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
|
||||
#else
|
||||
/* sourced by 8MHz with Presc 8 results in 1Mhz clk */
|
||||
TIMER_1_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV8_Val;
|
||||
#endif
|
||||
/* choose normal frequency operation */
|
||||
TIMER_1_DEV.CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save callback */
|
||||
config[dev].cb = cb;
|
||||
config[dev].arg = arg;
|
||||
|
||||
/* enable interrupts for given timer */
|
||||
_irq_enable(dev);
|
||||
|
||||
timer_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
|
||||
{
|
||||
DEBUG("Setting timer %i channel %i to %i\n", dev, channel, value);
|
||||
|
||||
/* get timer base register address */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* set timeout value */
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_0_DEV.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.CC[0].reg = value;
|
||||
TIMER_0_DEV.INTENSET.reg = TC_INTENSET_MC0;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_0_DEV.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.CC[1].reg = value;
|
||||
TIMER_0_DEV.INTENSET.reg = TC_INTENSET_MC1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
/* set timeout value */
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_1_DEV.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
TIMER_1_DEV.CC[0].reg = value;
|
||||
TIMER_1_DEV.INTENSET.reg = TC_INTENSET_MC0;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_1_DEV.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
TIMER_1_DEV.CC[1].reg = value;
|
||||
TIMER_1_DEV.INTENSET.reg = TC_INTENSET_MC1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t dev, int channel)
|
||||
{
|
||||
/* get timer base register address */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_0_DEV.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_0_DEV.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_1_DEV.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
TIMER_1_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_1_DEV.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
TIMER_1_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int timer_read(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* request syncronisation */
|
||||
TIMER_0_DEV.READREQ.reg = TC_READREQ_RREQ | TC_READREQ_ADDR(0x10);
|
||||
while (TIMER_0_DEV.STATUS.bit.SYNCBUSY) {}
|
||||
return TIMER_0_DEV.COUNT.reg;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
/* request syncronisation */
|
||||
TIMER_1_DEV.READREQ.reg = TC_READREQ_RREQ | TC_READREQ_ADDR(0x10);
|
||||
while (TIMER_1_DEV.STATUS.bit.SYNCBUSY) {}
|
||||
return TIMER_1_DEV.COUNT.reg;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void timer_stop(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV.CTRLA.bit.ENABLE = 0;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
TIMER_1_DEV.CTRLA.bit.ENABLE = 0;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV.CTRLA.bit.ENABLE = 1;
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
TIMER_1_DEV.CTRLA.bit.ENABLE = 1;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _irq_enable(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
NVIC_EnableIRQ(TC3_IRQn);
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_1_EN
|
||||
case TIMER_1:
|
||||
NVIC_EnableIRQ(TC4_IRQn);
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TIMER_0_EN
|
||||
void TIMER_0_ISR(void)
|
||||
{
|
||||
if (TIMER_0_DEV.INTFLAG.bit.MC0 && TIMER_0_DEV.INTENSET.bit.MC0) {
|
||||
TIMER_0_DEV.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
if(config[TIMER_0].cb) {
|
||||
config[TIMER_0].cb(config[TIMER_0].arg, 0);
|
||||
}
|
||||
}
|
||||
if (TIMER_0_DEV.INTFLAG.bit.MC1 && TIMER_0_DEV.INTENSET.bit.MC1) {
|
||||
TIMER_0_DEV.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
if(config[TIMER_0].cb) {
|
||||
config[TIMER_0].cb(config[TIMER_0].arg, 1);
|
||||
}
|
||||
}
|
||||
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif /* TIMER_0_EN */
|
||||
|
||||
|
||||
#if TIMER_1_EN
|
||||
void TIMER_1_ISR(void)
|
||||
{
|
||||
if (TIMER_1_DEV.INTFLAG.bit.MC0 && TIMER_1_DEV.INTENSET.bit.MC0) {
|
||||
TIMER_1_DEV.INTFLAG.reg = TC_INTFLAG_MC0;
|
||||
TIMER_1_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
if (config[TIMER_1].cb) {
|
||||
config[TIMER_1].cb(config[TIMER_1].arg, 0);
|
||||
}
|
||||
}
|
||||
if (TIMER_1_DEV.INTFLAG.bit.MC1 && TIMER_1_DEV.INTENSET.bit.MC1) {
|
||||
TIMER_1_DEV.INTFLAG.reg = TC_INTFLAG_MC1;
|
||||
TIMER_1_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
if(config[TIMER_1].cb) {
|
||||
config[TIMER_1].cb(config[TIMER_1].arg, 1);
|
||||
}
|
||||
}
|
||||
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif /* TIMER_1_EN */
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Mesotic SAS
|
||||
*
|
||||
*
|
||||
* 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_saml1x
|
||||
* @ingroup drivers_periph_timer
|
||||
* @{
|
||||
*
|
||||
* @file timer.c
|
||||
* @brief Low-level timer driver implementation
|
||||
*
|
||||
* @author Dylan Laduranty <dylan.laduranty@mesotic.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "periph/timer.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Timer state memory
|
||||
*/
|
||||
static timer_isr_ctx_t config[TIMER_NUMOF];
|
||||
|
||||
/* enable timer interrupts */
|
||||
static inline void _irq_enable(tim_t dev);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Setup the given timer
|
||||
*/
|
||||
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
{
|
||||
/* at the moment, the timer can only run at 1MHz */
|
||||
if (freq != 1000000ul) {
|
||||
return -1;
|
||||
}
|
||||
/* configure GCLK0 to feed TC0 & TC1*/
|
||||
GCLK->PCHCTRL[TC0_GCLK_ID].reg |= GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
|
||||
while (!(GCLK->PCHCTRL[TC0_GCLK_ID].reg & GCLK_PCHCTRL_CHEN)) {}
|
||||
|
||||
/* select the timer and enable the timer specific peripheral clocks */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
if (TIMER_0_DEV.CTRLA.bit.ENABLE) {
|
||||
return 0;
|
||||
}
|
||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC0;
|
||||
/* reset timer */
|
||||
TIMER_0_DEV.CTRLA.bit.SWRST = 1;
|
||||
while (TIMER_0_DEV.SYNCBUSY.bit.SWRST) {}
|
||||
TIMER_0_DEV.CTRLA.reg |= TC_CTRLA_MODE_COUNT32 | /* choosing 32 bit mode */
|
||||
TC_CTRLA_PRESCALER(4) | /* sourced by 4MHz with Presc 4 results in 1MHz*/
|
||||
TC_CTRLA_PRESCSYNC_RESYNC; /* initial prescaler resync */
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save callback */
|
||||
config[dev].cb = cb;
|
||||
config[dev].arg = arg;
|
||||
|
||||
/* enable interrupts for given timer */
|
||||
_irq_enable(dev);
|
||||
|
||||
timer_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
|
||||
{
|
||||
DEBUG("Setting timer %i channel %i to %i\n", dev, channel, value);
|
||||
|
||||
/* get timer base register address */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* set timeout value */
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.CC[0].reg = value;
|
||||
TIMER_0_DEV.INTENSET.bit.MC0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.CC[1].reg = value;
|
||||
TIMER_0_DEV.INTENSET.bit.MC1 = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t dev, int channel)
|
||||
{
|
||||
/* get timer base register address */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.INTENCLR.bit.MC0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.INTENCLR.bit.MC1 = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int timer_read(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* request syncronisation */
|
||||
TIMER_0_DEV.CTRLBSET.bit.CMD = TC_CTRLBSET_CMD_READSYNC_Val;
|
||||
while (TIMER_0_DEV.SYNCBUSY.bit.CTRLB) {
|
||||
/* WORKAROUND to prevent being stuck there if timer not init */
|
||||
if(!TIMER_0_DEV.CTRLA.bit.ENABLE) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return TIMER_0_DEV.COUNT.reg;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void timer_stop(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV.CTRLA.bit.ENABLE = 0;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV.CTRLA.bit.ENABLE = 1;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _irq_enable(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
NVIC_EnableIRQ(TC0_IRQn);
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TIMER_0_EN
|
||||
void TIMER_0_ISR(void)
|
||||
{
|
||||
if (TIMER_0_DEV.INTFLAG.bit.MC0 && TIMER_0_DEV.INTENSET.bit.MC0) {
|
||||
if(config[TIMER_0].cb) {
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
config[TIMER_0].cb(config[TIMER_0].arg, 0);
|
||||
}
|
||||
}
|
||||
else if (TIMER_0_DEV.INTFLAG.bit.MC1 && TIMER_0_DEV.INTENSET.bit.MC1) {
|
||||
if(config[TIMER_0].cb) {
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
config[TIMER_0].cb(config[TIMER_0].arg, 1);
|
||||
}
|
||||
}
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif /* TIMER_0_EN */
|
@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
|
||||
* 2015 FreshTemp, LLC.
|
||||
* 2014 Freie Universität Berlin
|
||||
*
|
||||
*
|
||||
* 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_saml21
|
||||
* @ingroup drivers_periph_timer
|
||||
* @{
|
||||
*
|
||||
* @file timer.c
|
||||
* @brief Low-level timer driver implementation
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "periph/timer.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Timer state memory
|
||||
*/
|
||||
static timer_isr_ctx_t config[TIMER_NUMOF];
|
||||
|
||||
/* enable timer interrupts */
|
||||
static inline void _irq_enable(tim_t dev);
|
||||
|
||||
/**
|
||||
* @brief Setup the given timer
|
||||
*/
|
||||
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
{
|
||||
/* at the moment, the timer can only run at 1MHz */
|
||||
if (freq != 1000000ul) {
|
||||
return -1;
|
||||
}
|
||||
/* configure GCLK0 to feed TC0 & TC1*/;
|
||||
GCLK->PCHCTRL[TC0_GCLK_ID].reg |= GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
|
||||
while (!(GCLK->PCHCTRL[TC0_GCLK_ID].reg & GCLK_PCHCTRL_CHEN)) {}
|
||||
|
||||
/* select the timer and enable the timer specific peripheral clocks */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
if (TIMER_0_DEV.CTRLA.bit.ENABLE) {
|
||||
return 0;
|
||||
}
|
||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC0;
|
||||
/* reset timer */
|
||||
TIMER_0_DEV.CTRLA.bit.SWRST = 1;
|
||||
while (TIMER_0_DEV.SYNCBUSY.bit.SWRST) {}
|
||||
TIMER_0_DEV.CTRLA.reg |= TC_CTRLA_MODE_COUNT32 | /* choosing 32 bit mode */
|
||||
TC_CTRLA_PRESCALER(4) | /* sourced by 4MHz with Presc 4 results in 1MHz*/
|
||||
TC_CTRLA_PRESCSYNC_RESYNC; /* initial prescaler resync */
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save callback */
|
||||
config[dev].cb = cb;
|
||||
config[dev].arg = arg;
|
||||
|
||||
/* enable interrupts for given timer */
|
||||
_irq_enable(dev);
|
||||
|
||||
timer_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
|
||||
{
|
||||
DEBUG("Setting timer %i channel %i to %i\n", dev, channel, value);
|
||||
|
||||
/* get timer base register address */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* set timeout value */
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.CC[0].reg = value;
|
||||
TIMER_0_DEV.INTENSET.bit.MC0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.CC[1].reg = value;
|
||||
TIMER_0_DEV.INTENSET.bit.MC1 = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t dev, int channel)
|
||||
{
|
||||
/* get timer base register address */
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
switch (channel) {
|
||||
case 0:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.INTENCLR.bit.MC0 = 1;
|
||||
break;
|
||||
case 1:
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.INTENCLR.bit.MC1 = 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int timer_read(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
/* request syncronisation */
|
||||
TIMER_0_DEV.CTRLBSET.bit.CMD = TC_CTRLBSET_CMD_READSYNC_Val;
|
||||
while (TIMER_0_DEV.SYNCBUSY.bit.STATUS) {}
|
||||
return TIMER_0_DEV.COUNT.reg;
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void timer_stop(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV.CTRLA.bit.ENABLE = 0;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
TIMER_0_DEV.CTRLA.bit.ENABLE = 1;
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _irq_enable(tim_t dev)
|
||||
{
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
case TIMER_0:
|
||||
NVIC_EnableIRQ(TC0_IRQn);
|
||||
break;
|
||||
#endif
|
||||
case TIMER_UNDEFINED:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TIMER_0_EN
|
||||
void TIMER_0_ISR(void)
|
||||
{
|
||||
if (TIMER_0_DEV.INTFLAG.bit.MC0 && TIMER_0_DEV.INTENSET.bit.MC0) {
|
||||
if(config[TIMER_0].cb) {
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC0;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC0;
|
||||
config[TIMER_0].cb(config[TIMER_0].arg, 0);
|
||||
}
|
||||
}
|
||||
else if (TIMER_0_DEV.INTFLAG.bit.MC1 && TIMER_0_DEV.INTENSET.bit.MC1) {
|
||||
if(config[TIMER_0].cb) {
|
||||
TIMER_0_DEV.INTFLAG.reg |= TC_INTFLAG_MC1;
|
||||
TIMER_0_DEV.INTENCLR.reg = TC_INTENCLR_MC1;
|
||||
config[TIMER_0].cb(config[TIMER_0].arg, 1);
|
||||
}
|
||||
}
|
||||
cortexm_isr_end();
|
||||
}
|
||||
#endif /* TIMER_0_EN */
|
Loading…
Reference in New Issue
Block a user