/** @file stk.c
 * Module handling the system timer (systick or STK for short)
 *
 * The module provides functions to configure and use the system timer embedded
 * in the cortex m core
 */

//--includes--------------------------------------------------------------------

#include "stk.h"
#include "stk_regs.h"

#include "rcc.h"


//--local definitions-----------------------------------------------------------

static volatile struct STK* regs = (struct STK*)STK_BASE_ADDRESS;


//--local variables-------------------------------------------------------------

static StkCallback callback;
static uint32_t prescaler;


//--public functions------------------------------------------------------------

uint32_t stk_configure(uint32_t period_us, StkCallback cb)
{
	stk_reset();

	struct RccClocks clocks;
	rcc_get_clocks(&clocks);

	uint32_t prescaler = (clocks.ahb_freq / 1000000 / 8);
	uint32_t reload = period_us * prescaler;
	if (reload < 1) {
		//period is too small, try using the non-prescaled clock
		prescaler *= 8;
		reload = period_us * prescaler;
		if (reload < 1) {
			//period is still too small
			return 1;
		}
		regs->CTRL.CLKSOURCE = 1;
	}
	regs->LOAD.RELOAD = reload;
	regs->CTRL.TICKINT = 1;

	callback = cb;

	return 0;
}

void stk_reset(void)
{
	regs->CTRL.ENABLE = 0;
	regs->CTRL.TICKINT = 0;
	regs->CTRL.CLKSOURCE = 0;
	regs->CTRL.COUNTFLAG = 0;

	regs->LOAD.RELOAD = 0;
	regs->VAL.CURRENT = 0;
}

void stk_start(void)
{
	regs->CTRL.ENABLE = 1;
}

void stk_stop(void)
{
	regs->CTRL.ENABLE = 0;
}

uint32_t stk_read_us(void)
{
	return (regs->VAL.word & 0x00FFFFFF) / prescaler;
}


//--local functions-------------------------------------------------------------

void hdr_sys_tick(void)
{
	//clearing the pending bit in SCB_ICSR isn't needed, though I don't know why
	callback();
}

