aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/boot.s75
-rw-r--r--src/clock.c81
-rw-r--r--src/clock.h10
-rw-r--r--src/main.c7
-rw-r--r--src/register.h12
-rw-r--r--src/types.h17
6 files changed, 202 insertions, 0 deletions
diff --git a/src/boot.s b/src/boot.s
new file mode 100644
index 0000000..a2bb4b2
--- /dev/null
+++ b/src/boot.s
@@ -0,0 +1,75 @@
+.syntax unified
+.thumb
+
+.section .vector_table, "a"
+.word __stack_top /* Initial stack pointer */
+
+/**
+ * Exceptions
+ */
+.word _start /* Reset Handler */
+.word _hang /* Non Maskable Interrupts */
+.word _hang /* Hard Fault */
+.word _hang /* Memory Management Fault */
+.word _hang /* Bus Fault */
+.word _hang /* Usage Fault */
+.skip 16 /* Reserved */
+.word _hang /* SVCall */
+.skip 8 /* Reserved */
+.word _hang /* PendSV */
+.word _hang /* SysTick */
+
+/**
+ * IRQs
+ */
+
+
+.text
+.align
+.thumb_func
+_start:
+/* Zero init BSS */
+_bss_init_start:
+ /* BSS section start and end addresses are 4-bytes aligned thanks to the linker script */
+ ldr r0, =__bss_start
+ ldr r1, =__bss_end
+ mov r2, #0
+_bss_init_loop:
+ cmp r0, r1
+ beq _bss_init_end
+ str r2, [r0], #4
+ b _bss_init_loop
+_bss_init_end:
+
+/* Init data section */
+_data_init_start:
+ /* Data section start and end addresses are also 4-bytes aligned */
+ ldr r0, =__data_lma
+ ldr r1, =__data_start
+ ldr r2, =__data_end
+__data_init_loop:
+ cmp r1, r2
+ beq _data_init_end
+ ldr r4, [r0], #4
+ ldr r4, [r1], #4
+ b __data_init_loop
+_data_init_end:
+
+ /* Reset all general purpose registers */
+ mov r0, #0
+ mov r1, #0
+ mov r2, #0
+ mov r3, #0
+ mov r4, #0
+ mov r5, #0
+ mov r6, #0
+ mov r7, #0
+ mov r8, #0
+ mov r9, #0
+ mov r10, #0
+ mov r11, #0
+ mov r12, #0
+ bl main
+
+_hang:
+ b .
diff --git a/src/clock.c b/src/clock.c
new file mode 100644
index 0000000..743d72f
--- /dev/null
+++ b/src/clock.c
@@ -0,0 +1,81 @@
+#include "clock.h"
+#include "register.h"
+#include "types.h"
+
+#define CLOCK_BASE_ADDR 0x40000000
+
+#define WRITE_CLK_REG(reg, value) (WRITE_REGISTER(CLOCK_BASE_ADDR, reg, value))
+#define READ_CLK_REG(reg) (READ_REGISTER(CLOCK_BASE_ADDR, reg))
+
+enum hfclk_src {
+ HFINT = 0,
+ HFXO = 1,
+};
+
+enum lfclk_src {
+ LFRC = 0,
+ LFXO = 1,
+ LFSYNT = 2,
+};
+
+/**
+ * Memory-mapped registers for the CLOCK peripheral with their offset from its base address,
+ * Check the nrf52832's manual for their description.
+ */
+enum clock_registers {
+ TASKS_HFCLKSTART = 0x000,
+ TASKS_HFCLKSTOP = 0x004,
+ TASKS_LFCLKSTART = 0x008,
+ TASKS_LFCLKSTOP = 0x00c,
+ TASKS_CAL = 0x010,
+ TASKS_CTSTART = 0x014,
+ TASKS_CTSTOP = 0x018,
+ EVENTS_HFCLKSTARTED = 0x100,
+ EVENTS_LFCLKSTARTED = 0x104,
+ EVENTS_DONE = 0x10c,
+ EVENTS_CTTO = 0x110,
+ INTENSET = 0x304,
+ INTENCLR = 0x308,
+ HFCLKRUN = 0x408,
+ HFCLKSTAT = 0x40c,
+ LFCLKRUN = 0x414,
+ LFCLKSTAT = 0x418,
+ LFCLKSRCCOPY = 0x41c,
+ LFCLKSRC = 0x518,
+ CTIV = 0x538,
+ TRACECONFIG = 0x55c,
+};
+
+static int init_hfclk() {
+ /* We just assert that the source clock is running with the CPU internal clock
+ * as source */
+ u32 hfclk_status = READ_CLK_REG(HFCLKSTAT);
+ u32 clk_src = hfclk_status & 0x1;
+ u32 clk_running = (hfclk_status >> 16) & 0x1;
+
+ return (clk_src == HFINT) && clk_running;
+}
+
+static int init_lfclk() {
+ int clk_started = 0;
+ enum lfclk_src src = LFRC;
+
+ /* LFCLK use the LFRC clock by default, so it should be ready
+ * to be started directly */
+ WRITE_CLK_REG(TASKS_LFCLKSTART, 0x1);
+
+ /* Wait for the LFCLK to be started */
+ /* TODO: We should rely on the IRQ for the LFCLKSTARTED event instead */
+ do {
+ u32 lfclk_stat = READ_CLK_REG(LFCLKSTAT);
+
+ clk_started = (lfclk_stat >> 16) & 0x1;
+ src = lfclk_stat & 0x2;
+ } while (!clk_started);
+
+ return src == LFRC;
+}
+
+int init_clock() {
+ return init_hfclk() && init_lfclk();
+}
diff --git a/src/clock.h b/src/clock.h
new file mode 100644
index 0000000..8c5d1f0
--- /dev/null
+++ b/src/clock.h
@@ -0,0 +1,10 @@
+#ifndef CLOCK_H
+#define CLOCK_H
+
+/**
+ * Init the nrf52832 CLOCK device and ensure that clock sources are correctly
+ * selected.
+ */
+int init_clock();
+
+#endif
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..aab0723
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,7 @@
+#include "clock.h"
+
+void main() {
+ init_clock();
+
+ while (1) {}
+}
diff --git a/src/register.h b/src/register.h
new file mode 100644
index 0000000..299cbe9
--- /dev/null
+++ b/src/register.h
@@ -0,0 +1,12 @@
+#ifndef PERIPHERALS_H
+#define PERIPHERALS_H
+
+#include "types.h"
+
+#define WRITE_REGISTER(base_addr, reg_offset, value) \
+ (*(volatile u32 *)(base_addr + reg_offset) = value)
+
+#define READ_REGISTER(base_addr, reg_offset) \
+ (*(volatile u32 *)(base_addr + reg_offset))
+
+#endif
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..2a8b9bb
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,17 @@
+#ifndef TYPES_H
+#define TYPES_H
+
+/*
+ * Integer types
+ */
+typedef signed char i8;
+typedef unsigned char u8;
+typedef signed short i16;
+typedef unsigned short u16;
+typedef signed int i32;
+typedef unsigned int u32;
+typedef signed long long i64;
+typedef unsigned long long u64;
+typedef u32 hwaddr;
+
+#endif