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

176 lines
3.5 KiB
C

/*
* Copyright 2017 Ken Rabold
*
* 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_fe310
* @{
*
* @file timer.c
* @brief Low-level timer implementation
*
* @author Ken Rabold
* @}
*/
#include <stdlib.h>
#include <unistd.h>
#include "cpu.h"
#include "periph_cpu.h"
#include "periph_conf.h"
#include "periph/timer.h"
#include "vendor/encoding.h"
#include "vendor/platform.h"
/**
* @brief Save reference to the timer callback
*/
static timer_cb_t isr_cb;
/**
* @brief Save argument for the callback
*/
static void *isr_arg;
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
{
/* Using RISC-V built in timer (64bit value) */
if (dev != 0) {
return -1;
}
/* Built in timer for FE310 is 32KHz */
if (freq != RTC_FREQ) {
return -1;
}
/* Save timer callback and arg */
isr_cb = cb;
isr_arg = arg;
/* reset timer counter */
volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
*mtime = 0;
return 0;
}
int timer_set(tim_t dev, int channel, unsigned int timeout)
{
volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
volatile uint64_t *mtimecmp =
(uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
/* Compute delta for timer */
uint64_t now = *mtime;
uint64_t then = now + (uint64_t) timeout;
if (dev != 0 || channel != 0) {
return -1;
}
/* Avoid spurious timer intr */
clear_csr(mie, MIP_MTIP);
/* New intr time */
*mtimecmp = then;
/* Re-enalble timer intr */
set_csr(mie, MIP_MTIP);
return 0;
}
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
{
volatile uint64_t *mtime = (uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
volatile uint64_t *mtimecmp =
(uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
/* Compute absolute for timer */
uint64_t now = *mtime;
uint64_t then = (now & 0xFFFFFFFF00000000) + (uint64_t) value;
if (dev != 0 || channel != 0) {
return -1;
}
/* Avoid spurious timer intr */
clear_csr(mie, MIP_MTIP);
/* New intr time (handle 32bit rollover) */
*mtimecmp = (then > now) ? then : then + 0x100000000;
/* Re-enable timer intr */
set_csr(mie, MIP_MTIP);
return 0;
}
int timer_clear(tim_t dev, int channel)
{
if (dev != 0 || channel != 0) {
return -1;
}
return 0;
}
unsigned int timer_read(tim_t dev)
{
uint32_t lo = *(volatile uint32_t *) (CLINT_CTRL_ADDR + CLINT_MTIME);
if (dev != 0) {
return 0;
}
/* Read current timer value */
return (unsigned int) lo;
}
void timer_start(tim_t dev)
{
if (dev != 0) {
return;
}
/* Timer is continuous running
* Enable the timer interrupt */
set_csr(mie, MIP_MTIP);
}
void timer_stop(tim_t dev)
{
if (dev != 0) {
return;
}
/* Disable the timer interrupt */
clear_csr(mie, MIP_MTIP);
}
void timer_isr(void)
{
volatile uint64_t *mtimecmp =
(uint64_t *) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
/* Clear intr */
clear_csr(mie, MIP_MTIP);
/* Set mtimecmp to largest value to clear the interrupt */
*mtimecmp = 0xFFFFFFFFFFFFFFFF;
/* Call timer callback function */
if (isr_cb) {
isr_cb(isr_arg, 0);
}
/* Reset interrupt */
set_csr(mie, MIP_MTIP);
}