From fb859c9c85688d1a144b732cf688746f2651be40 Mon Sep 17 00:00:00 2001 From: Victor Mignot Date: Mon, 2 Feb 2026 20:17:04 +0100 Subject: nrf52832: bootstrap and init the CLOCK device --- src/boot.s | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/clock.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/clock.h | 10 ++++++++ src/main.c | 7 +++++ src/register.h | 12 +++++++++ src/types.h | 17 ++++++++++++ 6 files changed, 202 insertions(+) create mode 100644 src/boot.s create mode 100644 src/clock.c create mode 100644 src/clock.h create mode 100644 src/main.c create mode 100644 src/register.h create mode 100644 src/types.h (limited to 'src') 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 -- cgit v1.2.3