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
61 changes: 44 additions & 17 deletions sw/applications/example_timer_sdk/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// File: example_timer_sdk.c
// Author: Juan Sapriza
// Date: 15/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>
Expand All @@ -15,7 +15,7 @@

/* By default, printfs are activated for FPGA and disabled for simulation. */
#define PRINTF_IN_FPGA 1
#define PRINTF_IN_SIM 0
#define PRINTF_IN_SIM 1
FrancescoPoluzzi marked this conversation as resolved.
Show resolved Hide resolved

#if TARGET_SIM && PRINTF_IN_SIM
#define PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
Expand All @@ -25,32 +25,59 @@
#define PRINTF(...)
#endif

void __attribute__((aligned(4), interrupt)) handler_irq_timer(void) {
timer_arm_stop();
timer_irq_clear();
return;
}

int main(){
uint8_t i = 0;
uint32_t cpu_cycles;
uint32_t i = 0;
uint32_t timer_cycles;

timer_init(); // Init the timer SDK
timer_init(); // Init the timer SDK for clock cycles
FrancescoPoluzzi marked this conversation as resolved.
Show resolved Hide resolved
timer_start(); // Start counting the time
cpu_cycles = timer_stop(); // Stop counting the time
PRINTF("0 NOPs:\t%d cc\n\r", cpu_cycles );
timer_cycles = timer_stop(); // Stop counting the time
PRINTF("0 NOPs:\t%d cc\n\r", timer_cycles );

timer_start();
timer_start();
asm volatile ("nop");
cpu_cycles = timer_stop();
PRINTF("1 NOP:\t%d cc\n\r", cpu_cycles );
timer_cycles = timer_stop();
PRINTF("1 NOP:\t%d cc\n\r", timer_cycles );

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

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

timer_cycles = timer_stop();
PRINTF("3 NOPs:\t%d cc\n\r", timer_cycles );

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

timer_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
timer_start();
for(i = 0; i < 1000; i++){
asm volatile ("nop");
}
PRINTF("Microseconds for 1000 NOPs:\t%d μs\n\r", timer_stop() );

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

FrancescoPoluzzi marked this conversation as resolved.
Show resolved Hide resolved
return EXIT_SUCCESS;
}
}
87 changes: 73 additions & 14 deletions sw/device/lib/sdk/timer/timer_sdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// File: timer_sdk.c
// Author: Michele Caon
// Date: 31/07/2023
// Author: Michele Caon, Francesco Poluzzi
// Date: 23/07/2024
// Description: Timer functions

#include <stdint.h>

#include "timer_sdk.h"
#include "csr.h"
#include "soc_ctrl.h"


/******************************/
/* ---- GLOBAL VARIABLES ---- */
Expand All @@ -33,27 +35,40 @@ mmio_region_t timer_base = {

rv_timer_tick_params_t tick_params;


/*************************************/
/* ---- FUNCTION IMPLEMENTATION ---- */
/*************************************/

// Initialize the hardware timer
void hw_timer_init()
{
// Initialize the timer
rv_timer_init(timer_base, timer_cfg, &timer);
rv_timer_approximate_tick_params(REFERENCE_CLOCK_Hz, REFERENCE_CLOCK_Hz, &tick_params);
rv_timer_set_tick_params(&timer, 0, tick_params);
rv_timer_counter_set_enabled(&timer, 0, kRvTimerEnabled);
}

uint32_t hw_timer_get_cycles()
{
uint64_t cycle_count;
rv_timer_counter_read(&timer, 0, &cycle_count);
return (uint32_t)cycle_count;
}

void timer_irq_enable()
{
rv_timer_irq_enable(&timer, 0, 0, kRvTimerEnabled);
}

void timer_irq_clear()
{
rv_timer_irq_clear(&timer, 0, 0);
}


void timer_arm_start(uint32_t threshold)
{
rv_timer_arm(&timer, 0, 0, threshold);
rv_timer_counter_set_enabled(&timer, 0, kRvTimerEnabled);
}

void timer_arm_stop()
{
rv_timer_counter_set_enabled(&timer, 0, kRvTimerDisabled);
}

void hw_timer_start()
{
hw_timer_value = -hw_timer_get_cycles();
Expand All @@ -68,6 +83,50 @@ uint32_t hw_timer_stop()
// Initialize the timer
void timer_init()
{
// Enable MCYCLE counter
CSR_CLEAR_BITS(CSR_REG_MCOUNTINHIBIT, 0x1);
// Get current Frequency
soc_ctrl_t soc_ctrl;
soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS);
uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl);

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

// Initialize the timer
void timer_init_us()
{
// Get current Frequency
soc_ctrl_t soc_ctrl;
soc_ctrl.base_addr = mmio_region_from_addr((uintptr_t)SOC_CTRL_START_ADDRESS);
uint32_t freq_hz = soc_ctrl_get_frequency(&soc_ctrl);

// Initialize the timer
rv_timer_init(timer_base, timer_cfg, &timer);
rv_timer_approximate_tick_params(freq_hz, FREQ_US, &tick_params);
FrancescoPoluzzi marked this conversation as resolved.
Show resolved Hide resolved
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_irq_enable();
timer_arm_start(ms*1000);
timer_start();
asm volatile ("wfi");
timer_irq_clear();
return;
}

void enable_timer_interrupt()
{
//enable timer interrupt
CSR_SET_BITS(CSR_REG_MSTATUS, 0x8);
// 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);
}
56 changes: 44 additions & 12 deletions sw/device/lib/sdk/timer/timer_sdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// File: timer_sdk.h
// Authors: Michele Caon, Luigi Giuffrida
// Date: 31/07/2023
// Authors: Michele Caon, Luigi Giuffrida, Francesco Poluzzi
// Date: 23/07/2024
// Description: Execution time measurements utilities

#ifndef TIMER_SDK_H_
Expand All @@ -20,6 +20,7 @@
#include "x-heep.h"

#define TICK_FREQ 1000000
#define FREQ_US 1000000

/******************************/
/* ---- GLOBAL VARIABLES ---- */
Expand All @@ -35,12 +36,6 @@ extern rv_timer_t timer;
/* ---- EXPORTED FUNCTIONS ---- */
/********************************/

/**
* @brief Initialize the hardware timer
*
*/
void hw_timer_init();

/**
* @brief Get the current value of the HW timer
*
Expand All @@ -63,11 +58,17 @@ uint32_t hw_timer_stop();


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

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

/**
* @brief Get the current value of the MCYCLE CSR
*
Expand All @@ -84,7 +85,7 @@ inline uint32_t timer_get_cycles() {
*
*/
inline void timer_start() {
timer_value = -timer_get_cycles();
hw_timer_start();
}

/**
Expand All @@ -93,8 +94,39 @@ inline void timer_start() {
* @return int64_t Elapsed time in clock cycles
*/
inline uint32_t timer_stop() {
timer_value += timer_get_cycles();
return timer_value;
return hw_timer_stop();
}

/**
* @brief Enable the timer IRQ
*/
void timer_irq_enable();

/**
* @brief Clear the timer IRQ
*/
void timer_irq_clear();

/**
* @brief Arms the timer to go off once the counter value is greater than or equal to threshold
*/
void timer_arm_start(uint32_t threshold);

/**
* @brief Stop to output when timer is greater than or equal to threshold previously set
*/
void timer_arm_stop();

/**
* @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_ */
Loading