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

Merge pull request #17342 from aabadie/pr/sysclk

sys: introduce sysclk function to retrieve core clock frequency
This commit is contained in:
Alexandre Abadie 2021-12-15 15:41:34 +01:00 committed by GitHub
commit 9c71dd7566
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 226 additions and 174 deletions

View File

@ -28,16 +28,6 @@
extern "C" {
#endif
/**
* @name Clock configuration
* @{
*/
#ifndef CLOCK_CORECLOCK
/* Using 32MHz internal oscillator as default clock source */
#define CLOCK_CORECLOCK (32000000ul)
#endif
/** @} */
/**
* @name LED configuration
* @{

View File

@ -21,6 +21,7 @@
#include <stdint.h>
#include "macros/units.h"
#include "cpu.h"
#include "periph_cpu.h"
@ -28,6 +29,16 @@
extern "C" {
#endif
/**
* @name Clock configuration
* @{
*/
#ifndef CLOCK_CORECLOCK
/* Using 32MHz internal oscillator as default clock source */
#define CLOCK_CORECLOCK MHZ(32) /**< System core clock frequency in Hz */
#endif
/** @} */
/**
* @name ADC configuration
*

View File

@ -20,6 +20,7 @@
#define PERIPH_CPU_H
#include <stdint.h>
#include "sdk_conf.h"
#ifdef __cplusplus
extern "C" {

View File

@ -23,6 +23,7 @@
#include <limits.h>
#include "eagle_soc.h"
#include "cpu_conf.h"
#ifdef __cplusplus
extern "C" {

View File

@ -17,13 +17,14 @@
* @}
*/
#include "clk.h"
#include "cpu.h"
#include "periph_conf.h"
#include "vendor/prci_driver.h"
#if IS_ACTIVE(CONFIG_USE_CLOCK_HFROSC) || IS_ACTIVE(CONFIG_USE_CLOCK_HFROSC_PLL)
static uint32_t _cpu_frequency = 0;
uint32_t cpu_coreclk = 0;
#endif
void fe310_clock_init(void)
@ -92,21 +93,10 @@ void fe310_clock_init(void)
/* Don't use PLL clock source */
PRCI_REG(PRCI_PLLCFG) &= ~PLL_SEL(PLL_SEL_PLL);
}
}
uint32_t cpu_freq(void)
{
#if IS_ACTIVE(CONFIG_USE_CLOCK_HFROSC) || IS_ACTIVE(CONFIG_USE_CLOCK_HFROSC_PLL)
/* Clock frequency with HFROSC cannot be determined precisely from
settings */
/* If not done already, estimate the CPU frequency */
if (_cpu_frequency == 0) {
/* Ignore the first run (for icache reasons) */
_cpu_frequency = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
_cpu_frequency = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
}
return _cpu_frequency;
#else
return CLOCK_CORECLOCK;
/* Ignore the first run (for icache reasons) */
cpu_coreclk = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
cpu_coreclk = PRCI_measure_mcycle_freq(3000, RTC_FREQ);
#endif
}

View File

@ -17,6 +17,7 @@
* @}
*/
#include "clk.h"
#include "cpu.h"
#include "periph/init.h"
#include "periph_conf.h"
@ -80,7 +81,7 @@ void flash_init(void)
* by the following formula (Fin is processor/tile-link clock):
* Fsck = Fin/(2(div + 1))
*/
uint32_t freq = cpu_freq();
uint32_t freq = coreclk();
uint32_t sckdiv = (freq - 1) / (MAX_FLASH_FREQ * 2);
if (sckdiv > SCKDIV_SAFE) {

View File

@ -113,7 +113,7 @@ extern "C" {
/*
When using HFROSC input clock, the core clock cannot be computed from settings,
call cpu_freq() to get the configured CPU frequency.
in this case, coreclk() returns the configured CPU frequency.
*/
#ifndef CONFIG_CLOCK_DESIRED_FREQUENCY
#define CONFIG_CLOCK_DESIRED_FREQUENCY MHZ(320)

View File

@ -175,13 +175,6 @@ typedef struct {
*/
void fe310_clock_init(void);
/**
* @brief Get and eventually compute the current CPU core clock frequency
*
* @return the cpu core clock frequency in Hz
*/
uint32_t cpu_freq(void);
/** @} */
#ifdef __cplusplus

View File

@ -23,6 +23,7 @@
#include <assert.h>
#include <errno.h>
#include "clk.h"
#include "cpu.h"
#include "mutex.h"
@ -69,7 +70,7 @@ void i2c_init(i2c_t dev)
/* Compute prescale: presc = (CORE_CLOCK / (5 * I2C_SPEED)) - 1 */
uint16_t presc =
((uint16_t)(cpu_freq() / 1000) /
((uint16_t)(coreclk() / 1000) /
(5 * _fe310_i2c_speed[i2c_config[dev].speed])) - 1;
DEBUG("[i2c] init: computed prescale: %i (0x%02X|0x%02X)\n", presc,

View File

@ -24,6 +24,7 @@
#include <assert.h>
#include "clk.h"
#include "cpu.h"
#include "mutex.h"
#include "periph/spi.h"
@ -62,7 +63,7 @@ void spi_init(spi_t dev)
mutex_init(&lock);
for (uint8_t i = 0; i < SPI_CLK_NUMOF; ++i) {
_spi_clks_config[i] = SPI_DIV_UP(cpu_freq(), 2 * _spi_clks[i]) - 1;
_spi_clks_config[i] = SPI_DIV_UP(coreclk(), 2 * _spi_clks[i]) - 1;
}
/* trigger pin initialization */

View File

@ -22,6 +22,7 @@
#include <assert.h>
#include <inttypes.h>
#include "clk.h"
#include "irq.h"
#include "cpu.h"
#include "periph/uart.h"
@ -87,7 +88,7 @@ int uart_init(uart_t dev, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
uart_poweron(dev);
/* Calculate baudrate divisor given current CPU clk rate */
uartDiv = cpu_freq() / baudrate;
uartDiv = coreclk() / baudrate;
/* Enable UART 8-N-1 at given baudrate */
_REG32(uart_config[dev].addr, UART_REG_DIV) = uartDiv;

View File

@ -16,10 +16,21 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "macros/units.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief System core clock in Hz
*
* 1GHz is an arbitrary value used for compatibility with other platforms.
*/
#ifndef CLOCK_CORECLOCK
#define CLOCK_CORECLOCK GHZ(1)
#endif
/**
* @name hardware timer clock skew avoidance
* @{

View File

@ -23,6 +23,7 @@
#include <stdint.h>
#include <string.h>
#include "clk.h"
#include "atmega_gpio.h"
#include "ws281x.h"
#include "ws281x_params.h"
@ -94,114 +95,122 @@ void ws281x_write_buffer(ws281x_t *dev, const void *buf, size_t size)
mask_off = port_state & ~(1 << atmega_pin_num(dev->params.pin));
}
#if (CLOCK_CORECLOCK >= 7500000U) && (CLOCK_CORECLOCK <= 8500000U)
const uint8_t port_num = atmega_port_num(dev->params.pin);
switch (port_num) {
case PORT_B:
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* Cycles | 1 | 0 */
"out %[port], %[on]" "\n\t" /* 1 | x | x */
"sbrs %[data], 7" "\n\t" /* 1 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | - | x */
"rjmp .+0" "\n\t" /* 2 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | x | x */
/* Total CPU cycles for high period:
* 5 cycles for bit 1, 2 cycles for bit 0 */
: [data] "+r" (data)
: [port] "I" (_SFR_IO_ADDR(PORTB)),
[on] "r" (mask_on),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
if (coreclk() >= 7500000U && coreclk() <= 8500000U) {
const uint8_t port_num = atmega_port_num(dev->params.pin);
switch (port_num) {
case PORT_B:
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* Cycles | 1 | 0 */
"out %[port], %[on]" "\n\t" /* 1 | x | x */
"sbrs %[data], 7" "\n\t" /* 1 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | - | x */
"rjmp .+0" "\n\t" /* 2 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | x | x */
/* Total CPU cycles for high period:
* 5 cycles for bit 1, 2 cycles for bit 0 */
: [data] "+r" (data)
: [port] "I" (_SFR_IO_ADDR(PORTB)),
[on] "r" (mask_on),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
}
pos++;
}
pos++;
}
break;
case PORT_C:
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* Cycles | 1 | 0 */
"out %[port], %[on]" "\n\t" /* 1 | x | x */
"sbrs %[data], 7" "\n\t" /* 1 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | - | x */
"rjmp .+0" "\n\t" /* 2 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | x | x */
/* Total CPU cycles for high period:
* 5 cycles for bit 1, 2 cycles for bit 0 */
: [data] "+r" (data)
: [port] "I" (_SFR_IO_ADDR(PORTC)),
[on] "r" (mask_on),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
break;
#ifdef PORT_C
case PORT_C:
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* Cycles | 1 | 0 */
"out %[port], %[on]" "\n\t" /* 1 | x | x */
"sbrs %[data], 7" "\n\t" /* 1 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | - | x */
"rjmp .+0" "\n\t" /* 2 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | x | x */
/* Total CPU cycles for high period:
* 5 cycles for bit 1, 2 cycles for bit 0 */
: [data] "+r" (data)
: [port] "I" (_SFR_IO_ADDR(PORTC)),
[on] "r" (mask_on),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
}
pos++;
}
pos++;
}
break;
case PORT_D:
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* Cycles | 1 | 0 */
"out %[port], %[on]" "\n\t" /* 1 | x | x */
"sbrs %[data], 7" "\n\t" /* 1 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | - | x */
"rjmp .+0" "\n\t" /* 2 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | x | x */
/* Total CPU cycles for high period:
* 5 cycles for bit 1, 2 cycles for bit 0 */
: [data] "+r" (data)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[on] "r" (mask_on),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
}
pos++;
}
break;
default:
assert(0);
break;
}
#elif (CLOCK_CORECLOCK >= 15500000U) && (CLOCK_CORECLOCK <= 16500000U)
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* CPU Cycles | 1 | 0 */
"st %a[port], %[on]" "\n\t" /* 2 | x | x */
"sbrc %[data], 7" "\n\t" /* 1 | x | x */
"rjmp .+0" "\n\t" /* 2 | x | - */
"sbrc %[data], 7" "\n\t" /* 1 | x | x */
"rjmp .+0" "\n\t" /* 2 | x | - */
"sbrc %[data], 7" "\n\t" /* 1 | x | x */
"nop" "\n\t" /* 1 | x | - */
"st %a[port], %[off]" "\n\t" /* 2 | x | x */
/* Total CPU cycles for high period:
* 10 cycles for bit 1, 5 cycles for bit 0 */
: [data] "+r" (data)
: [on] "r" (mask_on),
[port] "e" (port_addr),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
}
pos++;
}
#else
#error "No low level WS281x implementation for ATmega CPUs for your CPU clock"
break;
#endif
case PORT_D:
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* Cycles | 1 | 0 */
"out %[port], %[on]" "\n\t" /* 1 | x | x */
"sbrs %[data], 7" "\n\t" /* 1 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | - | x */
"rjmp .+0" "\n\t" /* 2 | x | x */
"out %[port], %[off]" "\n\t" /* 1 | x | x */
/* Total CPU cycles for high period:
* 5 cycles for bit 1, 2 cycles for bit 0 */
: [data] "+r" (data)
: [port] "I" (_SFR_IO_ADDR(PORTD)),
[on] "r" (mask_on),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
}
pos++;
}
break;
default:
assert(0);
break;
}
}
else if (coreclk() >= 15500000U && coreclk() <= 16500000U) {
while (pos < end) {
uint8_t cnt = 8;
uint8_t data = *pos;
while (cnt > 0) {
__asm__ volatile( /* CPU Cycles | 1 | 0 */
"st %a[port], %[on]" "\n\t" /* 2 | x | x */
"sbrc %[data], 7" "\n\t" /* 1 | x | x */
"rjmp .+0" "\n\t" /* 2 | x | - */
"sbrc %[data], 7" "\n\t" /* 1 | x | x */
"rjmp .+0" "\n\t" /* 2 | x | - */
"sbrc %[data], 7" "\n\t" /* 1 | x | x */
"nop" "\n\t" /* 1 | x | - */
"st %a[port], %[off]" "\n\t" /* 2 | x | x */
/* Total CPU cycles for high period:
* 10 cycles for bit 1, 5 cycles for bit 0 */
: [data] "+r" (data)
: [on] "r" (mask_on),
[port] "e" (port_addr),
[off] "r" (mask_off)
);
cnt--;
data <<= 1;
}
pos++;
}
}
else {
/* No low level WS281x implementation for ATmega CPUs for the used CPU
* clock. Abusing the linker to give a compile time error instead of
* emitting a broken firmware */
extern void clock_frequency_is_not_supported_by_ws281x_driver(void);
clock_frequency_is_not_supported_by_ws281x_driver();
}
}
int ws281x_init(ws281x_t *dev, const ws281x_params_t *params)

View File

@ -19,9 +19,3 @@ QUIET ?= 1
FEATURES_OPTIONAL += periph_timer
include $(RIOTBASE)/Makefile.include
ifeq (native,$(BOARD))
# For the native board, CLOCK_CORECLOCK is undefined. But we need
# a valid number to get the example compiled
CFLAGS += -DCLOCK_CORECLOCK=1000000000
endif

View File

@ -20,6 +20,7 @@
#include <stdio.h>
#include "clk.h"
#include "board.h"
#include "periph_conf.h"
#include "timex.h"
@ -41,7 +42,8 @@ static void delay(void)
* compilers would detect that the loop is only wasting CPU cycles and
* optimize it out - but here the wasting of CPU cycles is desired.
*/
for (volatile uint32_t i = 0; i < CLOCK_CORECLOCK / 20; i++) { }
uint32_t loops = coreclk() / 20;
for (volatile uint32_t i = 0; i < loops; i++) { }
}
}

View File

@ -23,6 +23,7 @@
#include "leds.h"
#include "openwsn_leds.h"
#include "clk.h"
#include "board.h"
#include "periph/gpio.h"
@ -86,7 +87,8 @@ static void _blink_checked(gpio_t pin)
/* toggle for ~10s if ztimer is used */
for (uint8_t i = 0; i < 100; i++) {
_toggle_checked(pin);
for (uint32_t i = 0; i < (CLOCK_CORECLOCK / 50); i++) {
uint32_t runs = coreclk() / 50;
for (uint32_t i = 0; i < runs; i++) {
/* Make sure for loop is not optimized out */
__asm__ ("");
}

49
sys/include/clk.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2021 Inria
*
* 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 sys_clk System core clock
* @ingroup sys
* @{
*
* @file
* @brief System core clock utility functions
*/
#ifndef CLK_H
#define CLK_H
#include <assert.h>
#include <stdint.h>
#include "periph_conf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Get the current system core clock frequency in Hz.
*
* @returns current system core clock frequency in Hz
*/
static inline uint32_t coreclk(void) {
#if defined(CLOCK_CORECLOCK)
return CLOCK_CORECLOCK;
#else
extern uint32_t cpu_coreclk;
assert(cpu_coreclk != 0);
return cpu_coreclk;
#endif
}
#ifdef __cplusplus
}
#endif
#endif /* CLK_H */
/** @} */

View File

@ -23,6 +23,7 @@
#include <stdio.h>
#include "macros/units.h"
#include "thread.h"
#include "clk.h"
#include "msg.h"
#include "xtimer.h"
@ -80,10 +81,8 @@ int main(void)
}
printf("{ \"result\" : %"PRIu32, n);
#ifdef CLOCK_CORECLOCK
printf(", \"ticks\" : %"PRIu32,
(uint32_t)((TEST_DURATION_US/US_PER_MS) * (CLOCK_CORECLOCK/KHZ(1)))/n);
#endif
(uint32_t)((TEST_DURATION_US/US_PER_MS) * (coreclk()/KHZ(1)))/n);
puts(" }");
return 0;

View File

@ -21,6 +21,7 @@
#include <stdio.h>
#include "macros/units.h"
#include "clk.h"
#include "mutex.h"
#include "thread.h"
#include "xtimer.h"
@ -79,10 +80,8 @@ int main(void)
}
printf("{ \"result\" : %"PRIu32, n);
#ifdef CLOCK_CORECLOCK
printf(", \"ticks\" : %"PRIu32,
(uint32_t)((TEST_DURATION/US_PER_MS) * (CLOCK_CORECLOCK/KHZ(1)))/n);
#endif
(uint32_t)((TEST_DURATION/US_PER_MS) * (coreclk()/KHZ(1)))/n);
puts(" }");
return 0;

View File

@ -20,6 +20,7 @@
#include <stdio.h>
#include "macros/units.h"
#include "clk.h"
#include "thread.h"
#include "xtimer.h"
@ -53,10 +54,8 @@ int main(void)
}
printf("{ \"result\" : %"PRIu32, n);
#ifdef CLOCK_CORECLOCK
printf(", \"ticks\" : %"PRIu32,
(uint32_t)((TEST_DURATION/US_PER_MS) * (CLOCK_CORECLOCK/KHZ(1)))/n);
#endif
(uint32_t)((TEST_DURATION/US_PER_MS) * (coreclk()/KHZ(1)))/n);
puts(" }");
return 0;

View File

@ -20,6 +20,7 @@
#include <stdio.h>
#include "macros/units.h"
#include "clk.h"
#include "thread.h"
#include "thread_flags.h"
@ -76,10 +77,8 @@ int main(void)
}
printf("{ \"result\" : %"PRIu32, n);
#ifdef CLOCK_CORECLOCK
printf(", \"ticks\" : %"PRIu32,
(uint32_t)((TEST_DURATION/US_PER_MS) * (CLOCK_CORECLOCK/KHZ(1)))/n);
#endif
(uint32_t)((TEST_DURATION/US_PER_MS) * (coreclk()/KHZ(1)))/n);
puts(" }");
return 0;

View File

@ -21,6 +21,7 @@
#include <stdio.h>
#include "macros/units.h"
#include "clk.h"
#include "thread.h"
#include "xtimer.h"
@ -73,10 +74,8 @@ int main(void)
}
printf("{ \"result\" : %"PRIu32, n);
#ifdef CLOCK_CORECLOCK
printf(", \"ticks\" : %"PRIu32,
(uint32_t)((TEST_DURATION/US_PER_MS) * (CLOCK_CORECLOCK/KHZ(1)))/n);
#endif
(uint32_t)((TEST_DURATION/US_PER_MS) * (coreclk()/KHZ(1)))/n);
puts(" }");
return 0;

View File

@ -21,14 +21,11 @@
#include <stdio.h>
#include <stdint.h>
#include "clk.h"
#include "board.h"
#include "periph_conf.h"
#ifdef CLOCK_CORECLOCK
#define DELAY_SHORT (CLOCK_CORECLOCK / 50)
#else
#define DELAY_SHORT (500000UL)
#endif
#define DELAY_SHORT (coreclk() / 50)
#define DELAY_LONG (DELAY_SHORT * 4)
void dumb_delay(uint32_t delay)

View File

@ -37,7 +37,7 @@ BOARDS_TIMER_32kHz := \
stk3700 \
#
BOARDS_TIMER_CLOCK_CORECLOCK := \
BOARDS_TIMER_SYSCLK := \
cc2538dk \
openmote-b \
openmote-cc2538 \
@ -52,8 +52,8 @@ else ifneq (,$(filter $(BOARDS_TIMER_250kHz),$(BOARD)))
TIMER_SPEED ?= 250000
else ifneq (,$(filter $(BOARDS_TIMER_32kHz),$(BOARD)))
TIMER_SPEED ?= 32768
else ifneq (,$(filter $(BOARDS_TIMER_CLOCK_CORECLOCK),$(BOARD)))
TIMER_SPEED ?= CLOCK_CORECLOCK
else ifneq (,$(filter $(BOARDS_TIMER_SYSCLK),$(BOARD)))
TIMER_SPEED ?= coreclk\(\)
endif
TIMER_SPEED ?= 1000000

View File

@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "clk.h"
#include "periph/timer.h"
/**

View File

@ -22,6 +22,7 @@
#include <string.h>
#include <stdlib.h>
#include "clk.h"
#include "board.h"
#include "periph/uart.h"
#include "periph_conf.h"
@ -69,7 +70,8 @@ static void _delay(void)
* compilers would detect that the loop is only wasting CPU cycles and
* optimize it out - but here the wasting of CPU cycles is desired.
*/
for (volatile uint32_t i = 0; i < CLOCK_CORECLOCK / 20; i++) { }
uint32_t loops = coreclk() / 20;
for (volatile uint32_t i = 0; i < loops; i++) { }
}
}