diff options
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | blink.s | 54 | ||||
-rw-r--r-- | clocks.s | 18 | ||||
-rw-r--r-- | gpio.s | 25 | ||||
-rw-r--r-- | main.s | 13 | ||||
-rw-r--r-- | pll.s | 58 | ||||
-rw-r--r-- | xosc.s | 23 |
7 files changed, 158 insertions, 50 deletions
@@ -2,19 +2,16 @@ all: build build: blink.uf2 -# convert ELF file to UF2 file blink.uf2: blink.elf - elf2uf2 blink.elf blink.uf2 + ./elf2uf2 blink.elf blink.uf2 -# compile -blink.elf: blink.o - arm-none-eabi-ld -T pico_ram_only.ld -o blink.elf blink.o +objects = main.o blink.o clocks.o gpio.o pll.o xosc.o -blink.o: blink.s - arm-none-eabi-as -o blink.o blink.s +blink.elf: $(objects) + arm-none-eabi-ld -T pico_ram_only.ld -o blink.elf $(objects) -# flash: build/blink.uf2 -# cp build/blink.uf2 /Volumes/RPI-RP2 +$(objects): %.o: %.s + arm-none-eabi-as -o $@ $< clean: - rm blink.elf blink.uf2 blink.o + rm blink.elf blink.uf2 *.o @@ -2,10 +2,6 @@ .cpu cortex-m0plus .thumb -.equ RESETS_BASE, 0x4000c000 -.equ RESET_OFST, 0x0 -.equ RESET_DONE_OFST, 0x8 - .equ IO_BANK0_BASE, 0x40014000 .equ GPIO25_STATUS, (IO_BANK0_BASE + 0x0c8) .equ GPIO25_CTRL, (IO_BANK0_BASE + 0x0cc) @@ -16,43 +12,21 @@ .equ ATOMIC_CLEAR, 0x3000 -.type main, %function -.global main -main: - - // Deassert GPIO reset - ldr r1, =(RESETS_BASE + ATOMIC_CLEAR) - movs r0, 0x20 // IO_BANK0 is bit 5 - str r0, [r1, RESET_OFST] - - // Wait for GPIO reset to finish - ldr r1, =RESETS_BASE -1: - ldr r2, [r1, RESET_DONE_OFST] - tst r0, r2 - beq 1b +.type blink, %function +.global blink - // Set GPIO25 function to SIO +blink: ldr r1, =GPIO25_CTRL - movs r0, #5 - str r0, [r1, #0] - + movs r0, 5 // SIO function = 5 + str r0, [r1, 0] ldr r1, =SIO_BASE - - // Set output enable for GPIO 25 - movs r0, #1 - lsls r0, r0, #25 + movs r0, 1 + lsls r0, r0, 25 // GPIO 25 (LED) output enable str r0, [r1, GPIO_OE_SET_OFST] - -loop: - - // Toggle output level for GPIO 25 - str r0, [r1, GPIO_OUT_XOR_OFST] - - // Delay - ldr r2, =400000 -1: - subs r2, r2, #1 - bne 1b - - b loop +toggle_one_second: + str r0, [r1, GPIO_OUT_XOR_OFST] // toggle GPIO 25 output level + ldr r2, =0x1fca055 // 33.3 * 10^6 (one-third of a second at 100MHz) +1: // 3 clock cycle loop + subs r2, r2, 1 // 1 clock cycle + bne 1b // 2 clock cycles when taken + b toggle_one_second diff --git a/clocks.s b/clocks.s new file mode 100644 index 0000000..09a0f6d --- /dev/null +++ b/clocks.s @@ -0,0 +1,18 @@ +.syntax unified +.cpu cortex-m0plus +.thumb + +.equ CLOCKS_BASE, 0x40008000 +.equ CLK_REF_CTRL_OFST, 0x30 +.equ CLK_SYS_CTRL_OFST, 0x3c + +.type setup_clocks, %function +.global setup_clocks + +setup_clocks: + ldr r1, =CLOCKS_BASE + movs r0, 2 // use xosc (=0x2) as clk_ref source + str r0, [r1, CLK_REF_CTRL_OFST] + movs r0, 1 // use auxsrc (default pll_sys, =0x1) as clk_sys source + str r0, [r1, CLK_SYS_CTRL_OFST] + mov pc, lr @@ -0,0 +1,25 @@ +.syntax unified +.cpu cortex-m0plus +.thumb + +.equ RESETS_BASE, 0x4000c000 +.equ RESET_OFST, 0x0 +.equ RESET_DONE_OFST, 0x8 + +.equ ATOMIC_CLEAR, 0x3000 + +.type setup_gpio, %function +.global setup_gpio + +setup_gpio: + // clear reset + ldr r1, =(RESETS_BASE + ATOMIC_CLEAR) + movs r0, 0x20 // IO_BANK0 is bit 5 + str r0, [r1, RESET_OFST] + ldr r1, =RESETS_BASE +1: + ldr r2, [r1, RESET_DONE_OFST] + tst r0, r2 // IO_BANK0 is still bit 5 + // wait for reset done + beq 1b + mov pc, lr @@ -0,0 +1,13 @@ +.syntax unified +.cpu cortex-m0plus +.thumb + +.type main, %function +.global main + +main: + bl start_xosc + bl start_pll + bl setup_clocks + bl setup_gpio + b blink @@ -0,0 +1,58 @@ +.syntax unified +.cpu cortex-m0plus +.thumb + +.equ RESETS_BASE, 0x4000c000 +.equ RESET_OFST, 0x0 +.equ RESET_DONE_OFST, 0x8 + +.equ PLL_SYS_BASE, 0x40028000 +.equ CS_OFST, 0x0 +.equ PWR_OFST, 0x4 +.equ FBDIV_INT_OFST, 0x8 +.equ PRIM_OFST, 0xc + +.equ ATOMIC_CLEAR, 0x3000 + +.type start_pll, %function +.global start_pll + +// configure pll_sys for 100MHz +start_pll: + // clear reset + ldr r1, =(RESETS_BASE + ATOMIC_CLEAR) + movs r0, 1 + lsls r0, 12 // pll_sys is bit 12 + str r0, [r1, RESET_OFST] + ldr r1, =RESETS_BASE +1: + ldr r2, [r1, RESET_DONE_OFST] + tst r0, r2 // pll_sys is still bit 12 + // wait for reset done + beq 1b + // set pls_sys feedback divider to 100 + ldr r1, =PLL_SYS_BASE + movs r0, 100 // FBDIV = 100 + str r0, [r1, FBDIV_INT_OFST] + // set pl_sys post dividers to 12 (6 * 2) + ldr r1, =PLL_SYS_BASE + movs r0, 6 // POSTDIV1 = 6 + lsls r0, r0, 4 + adds r0, r0, 2 // POSTDIV2 = 2 + lsls r0, r0, 12 + str r0, [r1, PRIM_OFST] + // turn on main power and VCO + ldr r1, =(PLL_SYS_BASE + ATOMIC_CLEAR) + movs r0, 0x21 // power and VCO (bits 0 and 5) + str r0, [r1, PWR_OFST] + // wait for VCO to lock + ldr r1, =PLL_SYS_BASE +vco_lock: + ldr r2, [r1, CS_OFST] + lsrs r2, r2, 31 + beq vco_lock + // turn on post divider power + ldr r1, =(PLL_SYS_BASE + ATOMIC_CLEAR) + movs r0, 0x8 // postdiv (bit 3) + str r0, [r1, PWR_OFST] + mov pc, lr @@ -0,0 +1,23 @@ +.syntax unified +.cpu cortex-m0plus +.thumb + +.equ XOSC_BASE, 0x40024000 +.equ CTRL_OFST, 0x0 +.equ STATUS_OFST, 0x4 +.equ STARTUP_OFST, 0xc + +.type start_xosc, %function +.global start_xosc + +start_xosc: + ldr r1, =XOSC_BASE + movs r0, 47 // startup delay = 47 for 12Mhz crystal + str r0, [r1, STARTUP_OFST] + ldr r0, =0x00fabaa0 // enable + str r0, [r1, CTRL_OFST] +1: + ldr r0, [r1, STATUS_OFST] + lsrs r0, r0, 31 // poll status bit + beq 1b + mov pc, lr |