1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #20147 from maribu/periph_timer_query_freq-sam0

cpu/sam0_common: implement periph_timer_query_freqs
This commit is contained in:
Marian Buschsieweke 2023-12-07 16:24:32 +00:00 committed by GitHub
commit eb2e6983d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 12 deletions

View File

@ -25,6 +25,7 @@ config CPU_COMMON_SAM0
select HAS_PERIPH_SPI_RECONFIGURE select HAS_PERIPH_SPI_RECONFIGURE
select HAS_PERIPH_SPI_GPIO_MODE select HAS_PERIPH_SPI_GPIO_MODE
select HAS_PERIPH_TIMER_PERIODIC select HAS_PERIPH_TIMER_PERIODIC
select HAS_PERIPH_TIMER_QUERY_FREQS
select HAS_PERIPH_UART_MODECFG select HAS_PERIPH_UART_MODECFG
select HAS_PERIPH_UART_NONBLOCKING select HAS_PERIPH_UART_NONBLOCKING
select HAS_PERIPH_UART_RECONFIGURE select HAS_PERIPH_UART_RECONFIGURE

View File

@ -14,15 +14,17 @@ FEATURES_PROVIDED += periph_flashpage_pagewise
FEATURES_PROVIDED += periph_flashpage_rwee FEATURES_PROVIDED += periph_flashpage_rwee
FEATURES_PROVIDED += periph_gpio periph_gpio_irq FEATURES_PROVIDED += periph_gpio periph_gpio_irq
FEATURES_PROVIDED += periph_i2c_reconfigure FEATURES_PROVIDED += periph_i2c_reconfigure
FEATURES_PROVIDED += periph_rtt_set_counter
FEATURES_PROVIDED += periph_rtt_overflow FEATURES_PROVIDED += periph_rtt_overflow
FEATURES_PROVIDED += periph_rtt_set_counter
FEATURES_PROVIDED += periph_sdmmc_auto_cmd12 FEATURES_PROVIDED += periph_sdmmc_auto_cmd12
FEATURES_PROVIDED += periph_sdmmc_hs FEATURES_PROVIDED += periph_sdmmc_hs
FEATURES_PROVIDED += periph_sdmmc_mmc FEATURES_PROVIDED += periph_sdmmc_mmc
FEATURES_PROVIDED += periph_sdmmc_sdhc FEATURES_PROVIDED += periph_sdmmc_sdhc
FEATURES_PROVIDED += periph_spi_reconfigure FEATURES_PROVIDED += periph_spi_reconfigure
FEATURES_PROVIDED += periph_spi_gpio_mode FEATURES_PROVIDED += periph_spi_gpio_mode
FEATURES_PROVIDED += periph_spi_reconfigure
FEATURES_PROVIDED += periph_timer_periodic # implements timer_set_periodic() FEATURES_PROVIDED += periph_timer_periodic # implements timer_set_periodic()
FEATURES_PROVIDED += periph_timer_query_freqs
FEATURES_PROVIDED += periph_uart_modecfg FEATURES_PROVIDED += periph_uart_modecfg
FEATURES_PROVIDED += periph_uart_nonblocking FEATURES_PROVIDED += periph_uart_nonblocking
FEATURES_PROVIDED += periph_uart_reconfigure FEATURES_PROVIDED += periph_uart_reconfigure

View File

@ -43,6 +43,22 @@ static timer_isr_ctx_t config[TIMER_NUMOF];
static uint32_t _oneshot; 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) static inline void set_oneshot(tim_t tim, int chan)
{ {
_oneshot |= (1 << chan) << (TIMER_CHANNEL_NUMOF * tim); _oneshot |= (1 << chan) << (TIMER_CHANNEL_NUMOF * tim);
@ -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) static uint8_t _get_prescaler(uint32_t freq_out, uint32_t freq_in)
{ {
uint8_t scale = 0; for (uint8_t scale = 0; scale < ARRAY_SIZE(_prescaler_shifts); scale++) {
while (freq_in > freq_out) { if ((freq_in >> _prescaler_shifts[scale]) == freq_out) {
freq_in >>= 1; return scale;
/* after DIV16 the prescaler gets more coarse */
if (++scale > TC_CTRLA_PRESCALER_DIV16_Val) {
freq_in >>= 1;
} }
} }
/* fail if output frequency can't be derived from input frequency */ return UINT8_MAX;
assert(freq_in == freq_out);
return scale;
} }
/* TOP value is CC0 */ /* TOP value is CC0 */
@ -130,6 +139,23 @@ static inline void _set_nfrq(tim_t tim)
#endif #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 * @brief Setup the given timer
*/ */