hardware.c 3.11 KB
Newer Older
q3k's avatar
q3k committed
1 2 3 4 5 6 7 8 9 10 11
/*
 * Hardware routines for l0dables.
 *
 * You shouldn't have to do much here. SystemInit/SystemCoreClockUpdate are
 * called automatically before main(), and provide you with a sensible execution
 * environment.
 *
 * However, if you wish, you can define your own SystemInit and take over the
 * initialization before main() gets called.
 */

12 13 14
#include <stddef.h>
#include "epicardium.h"

q3k's avatar
q3k committed
15 16 17 18 19 20
#include "max32665.h"
#include "mxc_sys.h"
#include "gcr_regs.h"
#include "icc_regs.h"
#include "pwrseq_regs.h"

q3k's avatar
q3k committed
21
uint32_t SystemCoreClock = HIRC_FREQ >> 1;
q3k's avatar
q3k committed
22 23 24

void SystemCoreClockUpdate(void)
{
q3k's avatar
q3k committed
25
	uint32_t base_freq, div, clk_src;
q3k's avatar
q3k committed
26

q3k's avatar
q3k committed
27 28
	// Determine the clock source and frequency
	clk_src = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_CLKSEL);
q3k's avatar
q3k committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
	switch (clk_src) {
	case MXC_S_GCR_CLKCN_CLKSEL_HIRC:
		base_freq = HIRC_FREQ;
		break;
	case MXC_S_GCR_CLKCN_CLKSEL_XTAL32M:
		base_freq = XTAL32M_FREQ;
		break;
	case MXC_S_GCR_CLKCN_CLKSEL_LIRC8:
		base_freq = LIRC8_FREQ;
		break;
	case MXC_S_GCR_CLKCN_CLKSEL_HIRC96:
		base_freq = HIRC96_FREQ;
		break;
	case MXC_S_GCR_CLKCN_CLKSEL_HIRC8:
		base_freq = HIRC8_FREQ;
		break;
	case MXC_S_GCR_CLKCN_CLKSEL_XTAL32K:
		base_freq = XTAL32K_FREQ;
		break;
	default:
q3k's avatar
q3k committed
49 50
		// Values 001 and 111 are reserved, and should never be encountered.
		base_freq = HIRC_FREQ;
q3k's avatar
q3k committed
51
		break;
q3k's avatar
q3k committed
52 53 54
	}
	// Clock divider is retrieved to compute system clock
	div = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_PSC) >> MXC_F_GCR_CLKCN_PSC_POS;
q3k's avatar
q3k committed
55

q3k's avatar
q3k committed
56
	SystemCoreClock = base_freq >> div;
q3k's avatar
q3k committed
57 58
}

q3k's avatar
q3k committed
59 60
__weak void SystemInit()
{
q3k's avatar
q3k committed
61 62 63 64
	// Enable FPU.
	SCB->CPACR |= SCB_CPACR_CP10_Msk | SCB_CPACR_CP11_Msk;
	__DSB();
	__ISB();
q3k's avatar
q3k committed
65

q3k's avatar
q3k committed
66 67
	// Enable ICache1 Clock
	MXC_GCR->perckcn1 &= ~(1 << 22);
q3k's avatar
q3k committed
68

q3k's avatar
q3k committed
69 70
	// Invalidate cache and wait until ready
	MXC_ICC1->invalidate = 1;
q3k's avatar
q3k committed
71 72
	while (!(MXC_ICC1->cache_ctrl & MXC_F_ICC_CACHE_CTRL_CACHE_RDY))
		;
q3k's avatar
q3k committed
73

q3k's avatar
q3k committed
74 75
	// Enable Cache
	MXC_ICC1->cache_ctrl |= MXC_F_ICC_CACHE_CTRL_CACHE_EN;
q3k's avatar
q3k committed
76

q3k's avatar
q3k committed
77
	SystemCoreClockUpdate();
78

q3k's avatar
q3k committed
79
	// Enable API interrupt.
80
	NVIC_EnableIRQ(TMR3_IRQn);
q3k's avatar
q3k committed
81
}
82 83 84 85

// newlib syscall to allow printf to work.
long _write(int fd, const char *buf, size_t cnt)
{
q3k's avatar
q3k committed
86 87
	// Only print one line at a time.  Insert `\r` between lines so
	// they are properly displayed on the serial console.
88 89 90 91 92 93 94 95
	size_t i, last = 0;
	for (i = 0; i < cnt; i++) {
		if (buf[i] == '\n') {
			epic_uart_write_str(&buf[last], i - last);
			epic_uart_write_str("\r", 1);
			last = i;
		}
	}
q3k's avatar
q3k committed
96
	epic_uart_write_str(&buf[last], cnt - last);
97 98 99 100 101 102 103 104 105 106 107 108
	return cnt;
}

// newlib syscall to allow for a heap
extern uint32_t __heap_start;
uint32_t _sbrk(int incr)
{
	static char *brk = NULL;
	if (brk == NULL) {
		brk = (char *)&__heap_start;
	}

q3k's avatar
q3k committed
109 110 111 112 113 114 115 116
	// Ensure we don't overflow the heap by checking agsinst the current stack
	// pointer (the heap grows towards the stack, and vice-versa).
	//
	// This is only a last-ditch attempt at saving ourselves from memory
	// corruption. It doesn't prevent the stack from growing into the heap
	// first.

	void *sp;
q3k's avatar
q3k committed
117
	__asm__ __volatile__("mov %0, sp" : "=r"(sp));
q3k's avatar
q3k committed
118 119 120 121 122 123 124 125 126

	// Require a 'safe margin' of 4k between the heap and stack.
	uint32_t stack_bottom = (uint32_t)sp - 4096;

	if (((uint32_t)brk + incr) > stack_bottom) {
		errno = ENOMEM;
		return (uint32_t)-1;
	}

127 128 129 130
	char *prev_brk = brk;
	brk += incr;
	return (uint32_t)prev_brk;
}