mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #20020 from gompper/periph/freqm
drivers/include/periph: add FREQM peripheral driver
This commit is contained in:
commit
c93a5b84a3
@ -18,6 +18,7 @@ config BOARD_SAME54_XPRO
|
|||||||
select HAS_PERIPH_RTC
|
select HAS_PERIPH_RTC
|
||||||
select HAS_PERIPH_RTT
|
select HAS_PERIPH_RTT
|
||||||
select HAS_PERIPH_PWM
|
select HAS_PERIPH_PWM
|
||||||
|
select HAS_PERIPH_FREQM
|
||||||
select HAS_PERIPH_SDMMC
|
select HAS_PERIPH_SDMMC
|
||||||
select HAS_PERIPH_SPI
|
select HAS_PERIPH_SPI
|
||||||
select HAS_PERIPH_TIMER
|
select HAS_PERIPH_TIMER
|
||||||
|
@ -14,6 +14,7 @@ FEATURES_PROVIDED += periph_timer
|
|||||||
FEATURES_PROVIDED += periph_uart
|
FEATURES_PROVIDED += periph_uart
|
||||||
FEATURES_PROVIDED += periph_adc
|
FEATURES_PROVIDED += periph_adc
|
||||||
FEATURES_PROVIDED += periph_usbdev
|
FEATURES_PROVIDED += periph_usbdev
|
||||||
|
FEATURES_PROVIDED += periph_freqm
|
||||||
|
|
||||||
# Put other features for this board (in alphabetical order)
|
# Put other features for this board (in alphabetical order)
|
||||||
FEATURES_PROVIDED += riotboot
|
FEATURES_PROVIDED += riotboot
|
||||||
|
@ -3,4 +3,11 @@
|
|||||||
# debugger.
|
# debugger.
|
||||||
TTY_BOARD_FILTER := --model 'EDBG CMSIS-DAP'
|
TTY_BOARD_FILTER := --model 'EDBG CMSIS-DAP'
|
||||||
|
|
||||||
|
# Overwrite GCLK definitions, so that GCLK_IO[2..7] can be connected to GPIOs.
|
||||||
|
# This way the frequency of signals, connected to these pins, can be measured
|
||||||
|
# with the FREQM peripheral.
|
||||||
|
CFLAGS += -DSAM0_GCLK_TIMER=8
|
||||||
|
CFLAGS += -DSAM0_GCLK_PERIPH=9
|
||||||
|
CFLAGS += -DSAM0_GCLK_100MHZ=10
|
||||||
|
|
||||||
include $(RIOTMAKE)/boards/sam0.inc.mk
|
include $(RIOTMAKE)/boards/sam0.inc.mk
|
||||||
|
@ -406,6 +406,18 @@ static const sam0_common_gmac_config_t sam_gmac_config[] = {
|
|||||||
};
|
};
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name FREQM peripheral configuration
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
static const freqm_config_t freqm_config[] = {
|
||||||
|
{
|
||||||
|
.pin = GPIO_PIN(PB, 17),
|
||||||
|
.gclk_src = SAM0_GCLK_32KHZ
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** @} */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -945,6 +945,14 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
#define WDT_HAS_INIT (1)
|
#define WDT_HAS_INIT (1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frequency meter configuration
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
gpio_t pin; /**< GPIO at which the frequency is to be measured */
|
||||||
|
uint8_t gclk_src; /**< GCLK source select for reference */
|
||||||
|
} freqm_config_t;
|
||||||
|
|
||||||
#if defined(REV_DMAC) || DOXYGEN
|
#if defined(REV_DMAC) || DOXYGEN
|
||||||
/**
|
/**
|
||||||
* @name sam0 DMA peripheral
|
* @name sam0 DMA peripheral
|
||||||
|
259
cpu/sam0_common/periph/freqm.c
Normal file
259
cpu/sam0_common/periph/freqm.c
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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_freqm
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file freqm.c
|
||||||
|
* @brief Frequency meter driver implementation
|
||||||
|
*
|
||||||
|
* @author Urs Gompper <urs.gompper@ml-pa.com>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "periph/freqm.h"
|
||||||
|
|
||||||
|
/* TODO: Remove defines when Microchip vendor files (which include these
|
||||||
|
* defines) get updated.
|
||||||
|
*/
|
||||||
|
/* FREQM_GCLK_ID_REF is defined in newer versions of vendor header files */
|
||||||
|
#ifndef FREQM_GCLK_ID_REF
|
||||||
|
#define FREQM_GCLK_ID_REF (FREQM_GCLK_ID_MSR + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Channel Enable Mask */
|
||||||
|
#define GCLK_PCHCTRL_CHEN_Msk (_U_(0x1) << GCLK_PCHCTRL_CHEN_Pos)
|
||||||
|
/* Enable Mask */
|
||||||
|
#define FREQM_CTRLA_ENABLE_Msk (_U_(0x1) << FREQM_CTRLA_ENABLE_Pos)
|
||||||
|
/* Start Measurement Mask */
|
||||||
|
#define FREQM_CTRLB_START_Msk (_U_(0x1) << FREQM_CTRLB_START_Pos)
|
||||||
|
/* Measurement Done Interrupt Enable Mask */
|
||||||
|
#define FREQM_INTENSET_DONE_Msk (_U_(0x1) << FREQM_INTENSET_DONE_Pos)
|
||||||
|
/* Measurement Done Mask */
|
||||||
|
#define FREQM_INTFLAG_DONE_Msk (_U_(0x1) << FREQM_INTFLAG_DONE_Pos)
|
||||||
|
/* FREQM Status Mask */
|
||||||
|
#define FREQM_STATUS_BUSY_Msk (_U_(0x1) << FREQM_STATUS_BUSY_Pos)
|
||||||
|
/* Sticky Count Value Overflow Mask */
|
||||||
|
#define FREQM_STATUS_OVF_Msk (_U_(0x1) << FREQM_STATUS_OVF_Pos)
|
||||||
|
|
||||||
|
/* check if pin has peripheral function GCLK */
|
||||||
|
static int _freqm_pin(gpio_t pin)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < ARRAY_SIZE(gclk_io_pins); ++i) {
|
||||||
|
if (gclk_io_pins[i] == pin) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _gclk_connect(uint8_t id, uint8_t src, uint32_t flags)
|
||||||
|
{
|
||||||
|
GCLK->GENCTRL[id].reg = GCLK_GENCTRL_SRC(src) | GCLK_GENCTRL_GENEN | flags | GCLK_GENCTRL_IDC;
|
||||||
|
while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(id)) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _freqm_gpio_init(gpio_t msr_gpio_src, uint8_t *gclk_io_id)
|
||||||
|
{
|
||||||
|
/* Check if selected pin has peripheral function GCLK */
|
||||||
|
int index = _freqm_pin(msr_gpio_src);
|
||||||
|
|
||||||
|
/* Fail assertion if pin has no peripheral function GCLK */
|
||||||
|
assert(index > 0);
|
||||||
|
|
||||||
|
/* Lookup which GCLK_IO[x] must be used */
|
||||||
|
*gclk_io_id = gclk_io_ids[index];
|
||||||
|
/* GCLK_IO[0] and GCLK_IO[1] can't be used here. They are associated with
|
||||||
|
GCLKGEN[0] and GCLKGEN[1] respectively. These in turn are used by
|
||||||
|
SAM0_GCLK_MAIN and SAM0_GCLK_32KHZ respectively */
|
||||||
|
assert(*gclk_io_id > 1);
|
||||||
|
|
||||||
|
/* Initialize GPIO as input */
|
||||||
|
gpio_init(msr_gpio_src, GPIO_IN);
|
||||||
|
/* Enable peripheral function GCLK/IO on GPIO */
|
||||||
|
gpio_init_mux(msr_gpio_src, GPIO_MUX_M);
|
||||||
|
/* Connect GCLK_IO[*gclk_io_id] with input pin */
|
||||||
|
_gclk_connect(*gclk_io_id, GCLK_SOURCE_GCLKIN, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _freqm_clock_init(uint8_t pin, uint8_t gclk_src)
|
||||||
|
{
|
||||||
|
/* Selection of the Generator and write Lock for FREQM_MSR */
|
||||||
|
GCLK->PCHCTRL[FREQM_GCLK_ID_MSR].reg = GCLK_PCHCTRL_GEN(pin) | GCLK_PCHCTRL_CHEN_Msk;
|
||||||
|
/* Wait for synchronization */
|
||||||
|
while ((GCLK->PCHCTRL[FREQM_GCLK_ID_MSR].reg & GCLK_PCHCTRL_CHEN_Msk) !=
|
||||||
|
GCLK_PCHCTRL_CHEN_Msk) {}
|
||||||
|
|
||||||
|
/* Selection of the Generator and write Lock for FREQM_REF */
|
||||||
|
GCLK->PCHCTRL[FREQM_GCLK_ID_REF].reg = GCLK_PCHCTRL_GEN(gclk_src) | GCLK_PCHCTRL_CHEN_Msk;
|
||||||
|
/* Wait for synchronization */
|
||||||
|
while ((GCLK->PCHCTRL[FREQM_GCLK_ID_REF].reg & GCLK_PCHCTRL_CHEN_Msk) !=
|
||||||
|
GCLK_PCHCTRL_CHEN_Msk) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
freqm_cb_t callback;
|
||||||
|
void *context;
|
||||||
|
freqm_t idx;
|
||||||
|
uint8_t period_cnt;
|
||||||
|
} freqm_obj;
|
||||||
|
|
||||||
|
struct _sync_ctx {
|
||||||
|
mutex_t lock; /**< Mutex for blocking till measurement is done */
|
||||||
|
uint32_t hz; /**< Measured frequency in Hz */
|
||||||
|
bool overflow; /**< Overflow in FREQM counter */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mutex for locking the FREQM device
|
||||||
|
*/
|
||||||
|
static mutex_t msr_lock = MUTEX_INIT;
|
||||||
|
|
||||||
|
static void _freqm_enable(uint8_t refnum)
|
||||||
|
{
|
||||||
|
mutex_lock(&msr_lock);
|
||||||
|
|
||||||
|
/* Save refnum for frequency calculation */
|
||||||
|
freqm_obj.period_cnt = refnum;
|
||||||
|
|
||||||
|
FREQM->CFGA.reg = (uint16_t)(FREQM_CFGA_REFNUM(refnum));
|
||||||
|
|
||||||
|
/* Enable DONE Interrupt */
|
||||||
|
FREQM->INTENSET.reg = FREQM_INTENSET_DONE_Msk;
|
||||||
|
|
||||||
|
/* Enable FREQM */
|
||||||
|
FREQM->CTRLA.reg = FREQM_CTRLA_ENABLE_Msk;
|
||||||
|
|
||||||
|
/* Wait for Sync */
|
||||||
|
while ((FREQM->SYNCBUSY.reg) != 0U) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _freqm_disable(void)
|
||||||
|
{
|
||||||
|
/* Disable DONE Interrupt */
|
||||||
|
FREQM->INTENCLR.reg = FREQM_INTENCLR_MASK;
|
||||||
|
/* Disable FREQM */
|
||||||
|
FREQM->CTRLA.reg &= ~FREQM_CTRLA_ENABLE_Msk;
|
||||||
|
/* Wait for Sync */
|
||||||
|
while ((FREQM->SYNCBUSY.reg) != 0U) {}
|
||||||
|
|
||||||
|
mutex_unlock(&msr_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _freqm_get_measurement(uint32_t *result)
|
||||||
|
{
|
||||||
|
const freqm_config_t *config = &freqm_config[freqm_obj.idx];
|
||||||
|
|
||||||
|
/* Calculate measured frequency */
|
||||||
|
uint64_t result_tmp = FREQM->VALUE.reg * (uint64_t)(sam0_gclk_freq(config->gclk_src));
|
||||||
|
|
||||||
|
result_tmp = result_tmp / freqm_obj.period_cnt;
|
||||||
|
*result = (uint32_t)result_tmp;
|
||||||
|
|
||||||
|
/* Read overflow status */
|
||||||
|
bool overflow_condition = ((int)FREQM->STATUS.reg & FREQM_STATUS_OVF_Msk);
|
||||||
|
|
||||||
|
/* Clear overflow status */
|
||||||
|
FREQM->STATUS.reg = FREQM_STATUS_OVF_Msk;
|
||||||
|
|
||||||
|
return overflow_condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t _us_to_ref_clock_counts(uint32_t period_us, uint8_t clock_id)
|
||||||
|
{
|
||||||
|
uint64_t clk_cnt = (uint64_t)period_us * sam0_gclk_freq(clock_id) / US_PER_SEC;
|
||||||
|
|
||||||
|
if (clk_cnt > UINT8_MAX) {
|
||||||
|
return UINT8_MAX;
|
||||||
|
}
|
||||||
|
else if (clk_cnt == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return clk_cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _sync_cb(uint32_t res, bool overflow, void *_ctx)
|
||||||
|
{
|
||||||
|
struct _sync_ctx *ctx = _ctx;
|
||||||
|
|
||||||
|
ctx->hz = res;
|
||||||
|
ctx->overflow = overflow;
|
||||||
|
mutex_unlock(&ctx->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int freqm_frequency_get(freqm_t idx, uint32_t *result, uint32_t period_us)
|
||||||
|
{
|
||||||
|
struct _sync_ctx ctx = { .lock = MUTEX_INIT_LOCKED };
|
||||||
|
|
||||||
|
/* Invoke non-blocking FREQM measure function */
|
||||||
|
freqm_frequency_get_async(idx, _sync_cb, &ctx, period_us);
|
||||||
|
|
||||||
|
/* Block until measurement is done */
|
||||||
|
mutex_lock(&ctx.lock);
|
||||||
|
|
||||||
|
*result = ctx.hz;
|
||||||
|
return ctx.overflow ? -EOVERFLOW : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void freqm_frequency_get_async(freqm_t idx, freqm_cb_t freqm_cb, void *context, uint32_t period_us)
|
||||||
|
{
|
||||||
|
const freqm_config_t *config = &freqm_config[idx];
|
||||||
|
|
||||||
|
uint8_t refnum = _us_to_ref_clock_counts(period_us, config->gclk_src);
|
||||||
|
|
||||||
|
_freqm_enable(refnum);
|
||||||
|
|
||||||
|
/* Register callback function */
|
||||||
|
freqm_obj.callback = freqm_cb;
|
||||||
|
freqm_obj.context = context;
|
||||||
|
freqm_obj.idx = idx;
|
||||||
|
|
||||||
|
/* Clear the Done Interrupt flag */
|
||||||
|
FREQM->INTFLAG.reg = FREQM_INTFLAG_DONE_Msk;
|
||||||
|
|
||||||
|
/* Start measurement */
|
||||||
|
FREQM->CTRLB.reg = FREQM_CTRLB_START_Msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void irq_freqm(void)
|
||||||
|
{
|
||||||
|
/* Clear the Done Interrupt flag */
|
||||||
|
FREQM->INTFLAG.reg = FREQM_INTFLAG_DONE_Msk;
|
||||||
|
|
||||||
|
uint32_t result = 0;
|
||||||
|
|
||||||
|
bool overflow_condition = _freqm_get_measurement(&result);
|
||||||
|
|
||||||
|
/* Invoke the callback function */
|
||||||
|
freqm_obj.callback(result, overflow_condition, freqm_obj.context);
|
||||||
|
|
||||||
|
_freqm_disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
void freqm_init(freqm_t idx)
|
||||||
|
{
|
||||||
|
uint8_t gclk_io_id = 0;
|
||||||
|
const freqm_config_t *config = &freqm_config[idx];
|
||||||
|
|
||||||
|
/* Sanity check configuration */
|
||||||
|
assert(config->gclk_src <= GCLK_GEN_NUM_MSB);
|
||||||
|
|
||||||
|
_freqm_gpio_init(config->pin, &gclk_io_id);
|
||||||
|
_freqm_clock_init(gclk_io_id, config->gclk_src);
|
||||||
|
|
||||||
|
/* Enable interrupt */
|
||||||
|
NVIC_EnableIRQ(FREQM_IRQn);
|
||||||
|
}
|
@ -325,6 +325,9 @@ void cpu_init(void)
|
|||||||
#ifdef MODULE_PERIPH_PM
|
#ifdef MODULE_PERIPH_PM
|
||||||
| MCLK_APBAMASK_PM
|
| MCLK_APBAMASK_PM
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef MODULE_PERIPH_FREQM
|
||||||
|
| MCLK_APBAMASK_FREQM
|
||||||
|
#endif
|
||||||
#ifdef MODULE_PERIPH_GPIO_IRQ
|
#ifdef MODULE_PERIPH_GPIO_IRQ
|
||||||
| MCLK_APBAMASK_EIC
|
| MCLK_APBAMASK_EIC
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,13 +70,19 @@ enum {
|
|||||||
* @name SAMD5x GCLK definitions
|
* @name SAMD5x GCLK definitions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
enum {
|
#define SAM0_GCLK_MAIN 0 /**< 120 MHz main clock */
|
||||||
SAM0_GCLK_MAIN = 0, /**< 120 MHz main clock */
|
#ifndef SAM0_GCLK_32KHZ
|
||||||
SAM0_GCLK_32KHZ, /**< 32 kHz clock */
|
#define SAM0_GCLK_32KHZ 1 /**< 32 kHz clock */
|
||||||
SAM0_GCLK_TIMER, /**< 4-8 MHz clock for xTimer */
|
#endif
|
||||||
SAM0_GCLK_PERIPH, /**< 12-48 MHz (DFLL) clock */
|
#ifndef SAM0_GCLK_TIMER
|
||||||
SAM0_GCLK_100MHZ, /**< 100MHz FDPLL clock */
|
#define SAM0_GCLK_TIMER 2 /**< 4-8 MHz clock for xTimer */
|
||||||
};
|
#endif
|
||||||
|
#ifndef SAM0_GCLK_PERIPH
|
||||||
|
#define SAM0_GCLK_PERIPH 3 /**< 12-48 MHz (DFLL) clock */
|
||||||
|
#endif
|
||||||
|
#ifndef SAM0_GCLK_100MHZ
|
||||||
|
#define SAM0_GCLK_100MHZ 4 /**< 100MHz FDPLL clock */
|
||||||
|
#endif
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -198,6 +204,28 @@ static const gpio_t rtc_tamper_pins[RTC_NUM_OF_TAMPERS] = {
|
|||||||
GPIO_PIN(PC, 0), GPIO_PIN(PC, 1)
|
GPIO_PIN(PC, 0), GPIO_PIN(PC, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pins that have peripheral function GCLK
|
||||||
|
*/
|
||||||
|
static const gpio_t gclk_io_pins[] = {
|
||||||
|
GPIO_PIN(PA, 10), GPIO_PIN(PA, 11), GPIO_PIN(PA, 14),
|
||||||
|
GPIO_PIN(PA, 15), GPIO_PIN(PA, 16), GPIO_PIN(PA, 17),
|
||||||
|
GPIO_PIN(PA, 27), GPIO_PIN(PA, 30), GPIO_PIN(PB, 10),
|
||||||
|
GPIO_PIN(PB, 11), GPIO_PIN(PB, 12), GPIO_PIN(PB, 13),
|
||||||
|
GPIO_PIN(PB, 14), GPIO_PIN(PB, 15), GPIO_PIN(PB, 16),
|
||||||
|
GPIO_PIN(PB, 17), GPIO_PIN(PB, 18), GPIO_PIN(PB, 19),
|
||||||
|
GPIO_PIN(PB, 20), GPIO_PIN(PB, 21), GPIO_PIN(PB, 22),
|
||||||
|
GPIO_PIN(PB, 23)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GCLK IDs of pins that have peripheral function GCLK - This maps
|
||||||
|
* directly to gclk_io_pins.
|
||||||
|
*/
|
||||||
|
static const uint8_t gclk_io_ids[] = {
|
||||||
|
4, 5, 0, 1, 2, 3, 1, 0, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NVM User Page Mapping - Dedicated Entries
|
* @brief NVM User Page Mapping - Dedicated Entries
|
||||||
* Config values will be applied at power-on.
|
* Config values will be applied at power-on.
|
||||||
|
1
dist/tools/doccheck/generic_exclude_patterns
vendored
1
dist/tools/doccheck/generic_exclude_patterns
vendored
@ -20,6 +20,7 @@ warning: Member EPD_BW_SPI_DISPLAY_UPDATE_OPTION_[A-Z0-9_]* \(macro definition\)
|
|||||||
warning: Member EPD_BW_SPI_WAIT_[A-Z0-9_]* \(macro definition\) of
|
warning: Member EPD_BW_SPI_WAIT_[A-Z0-9_]* \(macro definition\) of
|
||||||
warning: Member F_CPU \(macro definition\) of
|
warning: Member F_CPU \(macro definition\) of
|
||||||
warning: Member F_RC_OSCILLATOR \(macro definition\) of
|
warning: Member F_RC_OSCILLATOR \(macro definition\) of
|
||||||
|
warning: Member freqm_config\[\] \(variable\) of
|
||||||
warning: Member FXOS8700_PARAM_ADDR \(macro definition\) of
|
warning: Member FXOS8700_PARAM_ADDR \(macro definition\) of
|
||||||
warning: Member FXOS8700_PARAM_I2C \(macro definition\) of
|
warning: Member FXOS8700_PARAM_I2C \(macro definition\) of
|
||||||
warning: Member FXOS8700_PARAM_RENEW_INTERVAL \(macro definition\) of
|
warning: Member FXOS8700_PARAM_RENEW_INTERVAL \(macro definition\) of
|
||||||
|
100
drivers/include/periph/freqm.h
Normal file
100
drivers/include/periph/freqm.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup drivers_periph_freqm FREQM
|
||||||
|
* @ingroup drivers_periph
|
||||||
|
* @brief FREQM peripheral driver interface
|
||||||
|
*
|
||||||
|
* This interface allows to configure and use the Frequency Meter (FREQM)
|
||||||
|
* peripheral.
|
||||||
|
*
|
||||||
|
* The Frequency Meter uses the frequency of a known reference clock to
|
||||||
|
* determine the frequency of a signal connected via GPIO.
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief FREQM peripheral driver interface definitions
|
||||||
|
*
|
||||||
|
* @author Urs Gompper <urs.gompper@ml-pa.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PERIPH_FREQM_H
|
||||||
|
#define PERIPH_FREQM_H
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <mutex.h>
|
||||||
|
|
||||||
|
#include "periph_cpu.h"
|
||||||
|
#include "periph/gpio.h"
|
||||||
|
#include "time_units.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frequency meter callback function.
|
||||||
|
* When a measurement is done the callbackfunction is called.
|
||||||
|
*
|
||||||
|
* @param result measured frequency in hz
|
||||||
|
* @param overflow overflow in sticky counter
|
||||||
|
* @param context pointer to user defined context data
|
||||||
|
*/
|
||||||
|
typedef void (*freqm_cb_t)(uint32_t result, bool overflow, void *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define default Frequency meter type identifier
|
||||||
|
*/
|
||||||
|
#ifndef HAVE_FREQM_T
|
||||||
|
typedef uint_fast8_t freqm_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the frequency meter
|
||||||
|
*
|
||||||
|
* @param[in] idx index of the configuration
|
||||||
|
*/
|
||||||
|
void freqm_init(freqm_t idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read number of periods of measured clock and calculate its frequency
|
||||||
|
*
|
||||||
|
* This function returns after triggering the measurement and calls
|
||||||
|
* @p freqm_callback , with the calculated result and @p context , when the
|
||||||
|
* measurement is done.
|
||||||
|
*
|
||||||
|
* @param[in] idx index of the configuration
|
||||||
|
* @param[in] freqm_cb callback function when measurement is ready
|
||||||
|
* @param[in] context context for the callback function
|
||||||
|
* @param[in] period_us measurement duration in microseconds
|
||||||
|
*/
|
||||||
|
void freqm_frequency_get_async(freqm_t idx, freqm_cb_t freqm_cb, void *context,
|
||||||
|
uint32_t period_us);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read number of periods of measured clock and calculate its frequency
|
||||||
|
*
|
||||||
|
* This function uses a blocking mutex to wait for the measurement to finish.
|
||||||
|
*
|
||||||
|
* @param[in] idx index of the configuration
|
||||||
|
* @param[out] result calculated frequency
|
||||||
|
* @param[in] period_us measurement duration in microseconds
|
||||||
|
*
|
||||||
|
* @return -EOVERFLOW if FREQM sticky counter has an overflow
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int freqm_frequency_get(freqm_t idx, uint32_t *result, uint32_t period_us);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
#endif /* PERIPH_FREQM_H */
|
@ -139,6 +139,10 @@ config MODULE_PERIPH_RTT
|
|||||||
depends on HAS_PERIPH_RTT
|
depends on HAS_PERIPH_RTT
|
||||||
select MODULE_PERIPH_COMMON
|
select MODULE_PERIPH_COMMON
|
||||||
|
|
||||||
|
config MODULE_PERIPH_FREQM
|
||||||
|
bool "Frequency Meter driver"
|
||||||
|
depends on HAS_PERIPH_FREQM
|
||||||
|
|
||||||
config MODULE_PERIPH_RTT_SET_COUNTER
|
config MODULE_PERIPH_RTT_SET_COUNTER
|
||||||
bool "rtc_set_counter() implementation in the RTT peripheral driver"
|
bool "rtc_set_counter() implementation in the RTT peripheral driver"
|
||||||
depends on HAS_PERIPH_RTT_SET_COUNTER && MODULE_PERIPH_RTT
|
depends on HAS_PERIPH_RTT_SET_COUNTER && MODULE_PERIPH_RTT
|
||||||
|
@ -263,6 +263,11 @@ config HAS_PERIPH_FLASHPAGE_RWEE
|
|||||||
help
|
help
|
||||||
Indicates that the Flashpage peripheral is of the Read While Write.
|
Indicates that the Flashpage peripheral is of the Read While Write.
|
||||||
|
|
||||||
|
config HAS_PERIPH_FREQM
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Indicates that a Frequency Meter peripheral is present.
|
||||||
|
|
||||||
config HAS_PERIPH_GPIO
|
config HAS_PERIPH_GPIO
|
||||||
bool
|
bool
|
||||||
help
|
help
|
||||||
|
7
tests/periph/freqm/Makefile
Normal file
7
tests/periph/freqm/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
BOARD ?= same54-xpro
|
||||||
|
|
||||||
|
include ../Makefile.periph_common
|
||||||
|
|
||||||
|
USEMODULE += periph_freqm
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
14
tests/periph/freqm/README.md
Normal file
14
tests/periph/freqm/README.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Peripheral FREQM Test Application
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
This application tests the frequency meter (FREQM) functionality. This is done
|
||||||
|
by measuring the frequency of a clock, connected to a GPIO, with an internal
|
||||||
|
clock as reference.
|
||||||
|
|
||||||
|
Expected Output on Success
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
main(): This is RIOT! (Version: <INSERT VERSION HERE>)
|
||||||
|
FREQM peripheral driver test
|
||||||
|
Measured clock frequency: <MEASURED CLOCK FREQUENCY> Hz
|
||||||
|
Test run finished.
|
52
tests/periph/freqm/main.c
Normal file
52
tests/periph/freqm/main.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 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 tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief Application to test functionality of the frequency meter
|
||||||
|
* peripheral
|
||||||
|
*
|
||||||
|
* @author Urs Gompper <urs.gompper@ml-pa.com>
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "periph/freqm.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
puts("FREQM peripheral driver test");
|
||||||
|
|
||||||
|
/* Initialize frequency meter peripheral */
|
||||||
|
freqm_init(0);
|
||||||
|
|
||||||
|
uint32_t period_us = UINT32_MAX;
|
||||||
|
uint32_t freq_hz = 0;
|
||||||
|
|
||||||
|
/* Measure in blocking mode */
|
||||||
|
if (!freqm_frequency_get(0, &freq_hz, period_us)) {
|
||||||
|
printf("Measured Clock Frequency: %ld Hz\n", freq_hz);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
puts("Overflow occurred to the FREQM value counter!");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("Test run finished.");
|
||||||
|
|
||||||
|
/* main thread exits */
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user