Skip to content

Commit

Permalink
Merge pull request #20147 from maribu/periph_timer_query_freq-sam0
Browse files Browse the repository at this point in the history
cpu/sam0_common: implement periph_timer_query_freqs
  • Loading branch information
maribu authored Dec 7, 2023
2 parents 67df59b + b6a7815 commit eb2e698
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 12 deletions.
1 change: 1 addition & 0 deletions cpu/sam0_common/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ config CPU_COMMON_SAM0
select HAS_PERIPH_SPI_RECONFIGURE
select HAS_PERIPH_SPI_GPIO_MODE
select HAS_PERIPH_TIMER_PERIODIC
select HAS_PERIPH_TIMER_QUERY_FREQS
select HAS_PERIPH_UART_MODECFG
select HAS_PERIPH_UART_NONBLOCKING
select HAS_PERIPH_UART_RECONFIGURE
Expand Down
4 changes: 3 additions & 1 deletion cpu/sam0_common/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ FEATURES_PROVIDED += periph_flashpage_pagewise
FEATURES_PROVIDED += periph_flashpage_rwee
FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_i2c_reconfigure
FEATURES_PROVIDED += periph_rtt_set_counter
FEATURES_PROVIDED += periph_rtt_overflow
FEATURES_PROVIDED += periph_rtt_set_counter
FEATURES_PROVIDED += periph_sdmmc_auto_cmd12
FEATURES_PROVIDED += periph_sdmmc_hs
FEATURES_PROVIDED += periph_sdmmc_mmc
FEATURES_PROVIDED += periph_sdmmc_sdhc
FEATURES_PROVIDED += periph_spi_reconfigure
FEATURES_PROVIDED += periph_spi_gpio_mode
FEATURES_PROVIDED += periph_spi_reconfigure
FEATURES_PROVIDED += periph_timer_periodic # implements timer_set_periodic()
FEATURES_PROVIDED += periph_timer_query_freqs
FEATURES_PROVIDED += periph_uart_modecfg
FEATURES_PROVIDED += periph_uart_nonblocking
FEATURES_PROVIDED += periph_uart_reconfigure
Expand Down
48 changes: 37 additions & 11 deletions cpu/sam0_common/periph/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ static timer_isr_ctx_t config[TIMER_NUMOF];

static uint32_t _oneshot;

/* Number of right-shifts to perform on the input frequency to get the output
* frequency the prescaler will divide it down to */
static const uint8_t _prescaler_shifts[] = {
[TC_CTRLA_PRESCALER_DIV1_Val] = 0,
[TC_CTRLA_PRESCALER_DIV2_Val] = 1,
[TC_CTRLA_PRESCALER_DIV4_Val] = 2,
[TC_CTRLA_PRESCALER_DIV8_Val] = 3,
[TC_CTRLA_PRESCALER_DIV16_Val] = 4,
[TC_CTRLA_PRESCALER_DIV64_Val] = 6,
[TC_CTRLA_PRESCALER_DIV256_Val] = 8,
[TC_CTRLA_PRESCALER_DIV1024_Val] = 10,
};

static_assert(ARRAY_SIZE(_prescaler_shifts) == (TC_CTRLA_PRESCALER_DIV1024_Val + 1),
"_prescaler_shifts needs an update for the selected MCU");

static inline void set_oneshot(tim_t tim, int chan)
{
_oneshot |= (1 << chan) << (TIMER_CHANNEL_NUMOF * tim);
Expand Down Expand Up @@ -94,20 +110,13 @@ static inline void _irq_enable(tim_t tim)

static uint8_t _get_prescaler(uint32_t freq_out, uint32_t freq_in)
{
uint8_t scale = 0;
while (freq_in > freq_out) {
freq_in >>= 1;

/* after DIV16 the prescaler gets more coarse */
if (++scale > TC_CTRLA_PRESCALER_DIV16_Val) {
freq_in >>= 1;
for (uint8_t scale = 0; scale < ARRAY_SIZE(_prescaler_shifts); scale++) {
if ((freq_in >> _prescaler_shifts[scale]) == freq_out) {
return scale;
}
}

/* fail if output frequency can't be derived from input frequency */
assert(freq_in == freq_out);

return scale;
return UINT8_MAX;
}

/* TOP value is CC0 */
Expand All @@ -130,6 +139,23 @@ static inline void _set_nfrq(tim_t tim)
#endif
}

uword_t timer_query_freqs_numof(tim_t dev)
{
assert(dev < TIMER_NUMOF);
(void)dev;
return ARRAY_SIZE(_prescaler_shifts);
}

uint32_t timer_query_freqs(tim_t dev, uword_t index)
{
assert(dev < TIMER_NUMOF);
const tc32_conf_t *cfg = &timer_config[dev];
if (index >= ARRAY_SIZE(_prescaler_shifts)) {
return 0;
}
return sam0_gclk_freq(cfg->gclk_src) >> _prescaler_shifts[index];
}

/**
* @brief Setup the given timer
*/
Expand Down

0 comments on commit eb2e698

Please sign in to comment.