Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix-timer-sdk #564

Merged
merged 10 commits into from
Sep 5, 2024
Prev Previous commit
Next Next commit
Revision
Added tests, comments and renamings
FrancescoPoluzzi committed Jul 23, 2024
commit 4d1fc51928413e768cbcd2c3f51bf0163569f92c
59 changes: 43 additions & 16 deletions sw/applications/example_timer_sdk/main.c
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@
// File: example_timer_sdk.c
// Author: Juan Sapriza, Francesco Poluzzi
// Date: 23/07/2024
// Author: Juan Sapriza, Francesco Poluzzi
// Date: 23/07/2024
// Description: Example application to test the Timer SDK. Will count the time to execute a few short tasks.

#include <stdint.h>
@@ -15,7 +17,12 @@

/* By default, printfs are activated for FPGA and disabled for simulation. */
#define PRINTF_IN_FPGA 1
#define PRINTF_IN_SIM 1
#define PRINTF_IN_SIM 0

/* Error tolerances for the tests. */
#define CYCLE_TOLERANCE 2 // cycles tolerance for simple timer reads
#define INTERRUPT_TOLERANCE 50 // cycles tolerance for timer interrupt
#define TIMER_WAIT_TOLERANCE 100 // milliseconds tolerance for timer wait

#if TARGET_SIM && PRINTF_IN_SIM
#define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
@@ -34,50 +41,70 @@ void __attribute__((aligned(4), interrupt)) handler_irq_timer(void) {
int main(){
uint32_t i = 0;
uint32_t timer_cycles;
uint32_t nop_cycles[4];

timer_init(); // Init the timer SDK for clock cycles
timer_cycles_init(); // Init the timer SDK for clock cycles
timer_start(); // Start counting the time
timer_cycles = timer_stop(); // Stop counting the time
PRINTF("0 NOPs:\t%d cc\n\r", timer_cycles );

nop_cycles[0] = timer_stop(); // Stop counting the time
PRINTF("0 NOPs:\t%d cc\n\r", nop_cycles[0] );
timer_start();
asm volatile ("nop");
timer_cycles = timer_stop();
PRINTF("1 NOP:\t%d cc\n\r", timer_cycles );
nop_cycles[1] = timer_stop();
PRINTF("1 NOP:\t%d cc\n\r", nop_cycles[1] );

timer_start();
asm volatile ("nop");
asm volatile ("nop");
timer_cycles = timer_stop();
PRINTF("2 NOPs:\t%d cc\n\r", timer_cycles );
nop_cycles[2] = timer_stop();
PRINTF("2 NOPs:\t%d cc\n\r", nop_cycles[2] );

timer_start();
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
timer_cycles = timer_stop();
PRINTF("3 NOPs:\t%d cc\n\r", timer_cycles );
nop_cycles[3] = timer_stop();
PRINTF("3 NOPs:\t%d cc\n\r", nop_cycles[3] );

if( abs(nop_cycles[1] - nop_cycles[0])>CYCLE_TOLERANCE || abs(nop_cycles[2] - nop_cycles[1])>CYCLE_TOLERANCE || abs(nop_cycles[3] - nop_cycles[2])>CYCLE_TOLERANCE){
PRINTF("Clock count failed\n\r");
return EXIT_FAILURE;
}

enable_timer_interrupt(); // Enable the timer machine-level interrupt

timer_init();
timer_cycles_init();
timer_irq_enable();
timer_arm_start(1000);
timer_start();
asm volatile ("wfi"); // Wait for interrupt
timer_cycles = timer_stop();
PRINTF("wait ARM timer 1000 (%d)\n\r", timer_cycles );

timer_init_us(); // Init the timer SDK for microseconds
if(abs(timer_cycles-1000) < INTERRUPT_TOLERANCE){
PRINTF("Timer thershold interrupt working\n" );
} else {
PRINTF("Timer thershold interrupt failed\n\r");
return EXIT_FAILURE;
}

timer_microseconds_init(); // Init the timer SDK for microseconds
timer_start();
for(i = 0; i < 1000; i++){
asm volatile ("nop");
}
PRINTF("Microseconds for 1000 NOPs:\t%d μs\n\r", timer_stop() );
timer_cycles = timer_stop();
PRINTF("Microseconds for 1000 NOPs:\t%d μs\n\r", timer_cycles );

PRINTF("Wait 5 seconds\n\r");
timer_wait_ms(5000); // Wait for 5 seconds
PRINTF("Done\n\r");
timer_cycles = timer_stop();

FrancescoPoluzzi marked this conversation as resolved.
Show resolved Hide resolved
if(abs(timer_cycles/1000)-5000 > TIMER_WAIT_TOLERANCE){
PRINTF("Timer wait failed\n\r");
return EXIT_FAILURE;
}

PRINTF("All tests passed\n\r");
return EXIT_SUCCESS;
}

6 changes: 6 additions & 0 deletions sw/device/lib/drivers/rv_timer/rv_timer.h
Original file line number Diff line number Diff line change
@@ -105,6 +105,12 @@ typedef enum rv_timer_approximate_tick_params_result {
* @param[out] out Tick parameters that will approximately produce the desired
* counter frequency.
* @return The result of the operation.
*
* The minimum value for `counter_freq` is given by:
* counter_freq_min = (255/4096) * clock_freq
* For example, if the clock frequency is 15MHz, the minimum value for `counter_freq` is about
* 1 MHz.
* The maximum value for `counter_freq` is given by the clock frequency.
*/
rv_timer_approximate_tick_params_result_t
rv_timer_approximate_tick_params(uint64_t clock_freq, uint64_t counter_freq,
12 changes: 7 additions & 5 deletions sw/device/lib/sdk/timer/timer_sdk.c
Original file line number Diff line number Diff line change
@@ -5,6 +5,8 @@
// File: timer_sdk.c
// Author: Michele Caon, Francesco Poluzzi
// Date: 23/07/2024
// Author: Michele Caon, Francesco Poluzzi
// Date: 23/07/2024
// Description: Timer functions

#include <stdint.h>
@@ -81,7 +83,7 @@ uint32_t hw_timer_stop()
}

// Initialize the timer
void timer_init()
void timer_cycles_init()
{
// Get current Frequency
soc_ctrl_t soc_ctrl;
@@ -96,7 +98,7 @@ void timer_init()
}

// Initialize the timer
void timer_init_us()
void timer_microseconds_init()
{
// Get current Frequency
soc_ctrl_t soc_ctrl;
@@ -105,15 +107,15 @@ void timer_init_us()

// Initialize the timer
rv_timer_init(timer_base, timer_cfg, &timer);
rv_timer_approximate_tick_params(freq_hz, FREQ_US, &tick_params);
rv_timer_approximate_tick_params(freq_hz, FREQ_1MHz, &tick_params);
rv_timer_set_tick_params(&timer, 0, tick_params);
rv_timer_counter_set_enabled(&timer, 0, kRvTimerEnabled);
}

// Initialize the timer
void timer_wait_ms(uint32_t ms)
{
timer_init_us();
timer_microseconds_init();
timer_irq_enable();
timer_arm_start(ms*1000);
timer_start();
@@ -129,4 +131,4 @@ void enable_timer_interrupt()
// Set mie.MEIE bit to one to enable machine-level timer interrupts
const uint32_t mask = 1 << 7;
CSR_SET_BITS(CSR_REG_MIE, mask);
}
}
22 changes: 19 additions & 3 deletions sw/device/lib/sdk/timer/timer_sdk.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@

// Copyright 2023 EPFL and Politecnico di Torino.
// Solderpad Hardware License, Version 2.1, see LICENSE.md for details.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// File: timer_sdk.h
// Authors: Michele Caon, Luigi Giuffrida, Francesco Poluzzi
// Date: 23/07/2024
// Authors: Michele Caon, Luigi Giuffrida, Francesco Poluzzi
// Date: 23/07/2024
// Description: Execution time measurements utilities

#ifndef TIMER_SDK_H_
@@ -20,7 +23,7 @@
#include "x-heep.h"

#define TICK_FREQ 1000000
#define FREQ_US 1000000
#define FREQ_1MHz 1000000

/******************************/
/* ---- GLOBAL VARIABLES ---- */
@@ -58,16 +61,17 @@ uint32_t hw_timer_stop();


/**
* @brief Initialize the timer for counting clock cycles
* @brief Initialize the timer for counting clock cycles
*
*/
void timer_init();
void timer_cycles_init();

/**
* @brief Initialize the timer for counting microseconds
*
*/
void timer_init_us();
void timer_microseconds_init();

/**
* @brief Get the current value of the MCYCLE CSR
@@ -129,4 +133,16 @@ void timer_wait_ms(uint32_t ms);
*/
void enable_timer_interrupt();

/**
* @brief Wait for a certain amount of milliseconds. Not precise with small
* numbers of milliseconds.
* You need to enable timer interrupts with enable_timer_interrupt() before using this function
*/
void timer_wait_ms(uint32_t ms);

/**
* @brief Enable the timer machine-level interrupts for X-Heep
*/
void enable_timer_interrupt();

#endif /* TIMER_SDK_H_ */