182 lines
4.9 KiB
ArmAsm
182 lines
4.9 KiB
ArmAsm
.section .text
|
||
|
||
.equ rst_base, 0x40020000 // Subsystems reset reg base 7.5.3
|
||
.equ rst_clr, 0x40023000 // Adding 0x3000 according 2.1.3
|
||
.equ io_bank, 0x40028000
|
||
.equ io_bank_gp25, 0x400280cc
|
||
.equ sio_base, 0xd0000000
|
||
.equ big_num, 0x00f00000 // For the delay.
|
||
.equ pads_base, 0x40038000 // Pad control registers base.
|
||
.equ pads_set, 0x4003a000
|
||
.equ pads_clr, 0x4003b000
|
||
.equ resets_wrd, 0b100001001000000 // Bits 14 (PLL_SYS), 9 (PADS_BANK0) and 6 (IO_BANK0)
|
||
// Clocks.
|
||
.equ xosc_base, 0x40048000
|
||
.equ xosc_set, 0x4004a000
|
||
.equ xosc_en_mask, 0xfab000
|
||
.equ clk_base, 0x40010000
|
||
.equ clk_set, 0x40012000
|
||
.equ clk_clr, 0x40013000
|
||
.equ pll_base, 0x40050000
|
||
.equ pll_clr, 0x40053000
|
||
|
||
.thumb_func // This makes sure that the address of start has its LSB set to signal thumb mode.
|
||
.global hello_start
|
||
hello_start:
|
||
// Bring PLL, PADS and IO out of reset
|
||
ldr r0, =rst_clr
|
||
ldr r2, =resets_wrd
|
||
str r2, [r0, #0]
|
||
check_rst:
|
||
ldr r0, =rst_base
|
||
ldr r1, [r0, #0x8] // Offset to RESET_DONE from rst_base
|
||
and r1, r1, r2 // Check bit 14, 9 and 6 to ensure the subsystems we care about are out of reset.
|
||
cmp r1, r2
|
||
bne check_rst
|
||
clocks_setup:
|
||
// Configure and enable the crystal oscilator
|
||
// Set the freq range.
|
||
ldr r0, =xosc_base
|
||
mov r1, #0xaa // 1-15MHz range
|
||
lsl r1, r1, #4
|
||
str r1, [r0]
|
||
// Set the startup delay.
|
||
mov r1, #0xc4 // This is the defualt value and it's around 4ms at 12MHz
|
||
str r1, [r0, #0x0c]
|
||
// Enable the clock.
|
||
ldr r0, =xosc_set
|
||
ldr r1, =xosc_en_mask
|
||
str r1, [r0]
|
||
// Wait for it to be ready.
|
||
ldr r0, =xosc_base
|
||
xosc_rdy:
|
||
ldr r1, [r0, #0x04]
|
||
lsr r1, #31 // The stable flag is bit 31
|
||
beq xosc_rdy // If the flag is zero then keep checking.
|
||
// Set the crystal osc as the reference clock.
|
||
ldr r0, =clk_base
|
||
mov r1, #0x02
|
||
str r1, [r0, #0x30] // Set XOSC_CLKSRC on the CLK_REF_CTRL reg.
|
||
// Wait for it to be selected.
|
||
mov r2, #0b100
|
||
xosc_ref_selected:
|
||
ldr r1, [r0, #0x38]
|
||
and r1, r1, r2
|
||
cmp r1, r2
|
||
bne xosc_ref_selected
|
||
// Configure the PLL and wait for it to lock.
|
||
// Requested: 150.0 MHz
|
||
// FREF: 12MHz (This comes from the XOSC on the board)
|
||
// REFDIV: 1
|
||
// FBDIV: 125 (VCO = 1500.0 MHz)
|
||
// PD1: 5
|
||
// PD2: 2
|
||
// (FREF / REFDIV) × FBDIV / (POSTDIV1 × POSTDIV2)
|
||
// Typically you'd reset the PLL subsystem here, but already did so maybe it'll work.
|
||
ldr r0, =pll_base
|
||
// Set the refdiv
|
||
mov r1, #1 // This is the reset value, just setting it for completeness
|
||
str r1, [r0, #0]
|
||
// Set the fbdiv
|
||
mov r1, #125
|
||
str r1, [r0, #0x08]
|
||
// Turn on PLL
|
||
ldr r0, =pll_clr
|
||
mov r1, #0b100001 // Clearing bits 5 (VCOPD) and 0 (PD)
|
||
str r1, [r0, #0x04]
|
||
// Wait for it to lock (stabilize)
|
||
pll_locked:
|
||
ldr r0, =pll_base
|
||
ldr r1, [r0, #0]
|
||
lsr r1, #31 // Bit 31 of the CS reg is LOCK
|
||
beq pll_locked // Wait until it's not 0
|
||
// Set Post dividers.
|
||
mov r1, #5
|
||
lsl r1, r1, #4 // PD1 goes on bits 18:16
|
||
mov r2, #2
|
||
orr r1, r1, r2
|
||
lsl r1, r1, #12 // PD2 goes on bits 14:12
|
||
str r1, [r0, #0x0c]
|
||
// Turn on Post dividers.
|
||
ldr r0, =pll_clr
|
||
mov r1, #0b1000
|
||
str r1, [r0, #0x04]
|
||
// Change the sys clock source to the PLL
|
||
// Glitchlessly change the sys source to clk ref
|
||
ldr r0, =clk_clr
|
||
mov r1, #1
|
||
str r1, [r0, #0x3c]
|
||
// Wait for it to be selected
|
||
ldr r0, =clk_base
|
||
mov r2, #1
|
||
sys_clk_ref_selected:
|
||
ldr r1, [r0, #0x44]
|
||
and r1, r1, r2
|
||
cmp r1, r2
|
||
bne sys_clk_ref_selected
|
||
// Change the aux clock to pll, will glitch but it's fine because we're on the ref clock as source now.
|
||
ldr r0, =clk_clr
|
||
mov r1, #0b111
|
||
lsl r1, r1, #5 // Clear all bits on AUXSRC, which will make it CLKSRC_PLL_SYS
|
||
str r1, [r0, #0x3c]
|
||
// Glitchlessly change the sys source to AUX
|
||
ldr r0, =clk_set
|
||
mov r1, #1
|
||
str r1, [r0, #0x3c]
|
||
// Wait for it to be selected
|
||
ldr r0, =clk_base
|
||
mov r2, #0b10
|
||
sys_clk_aux_selected:
|
||
ldr r1, [r0, #0x44]
|
||
and r1, r1, r2
|
||
cmp r1, r2
|
||
bne sys_clk_aux_selected
|
||
configure_peripheral:
|
||
// See: https://github.com/raspberrypi/pico-sdk/blob/ee68c78d0afae2b69c03ae1a72bf5cc267a2d94c/src/rp2_common/hardware_gpio/gpio.c#L38
|
||
// Set pad input and output enabled.
|
||
ldr r0, =pads_set
|
||
mov r2, #0b1000000 // Set bit 6 to enable input.
|
||
str r2, [r0, #0x68]
|
||
ldr r0, =pads_clr
|
||
mov r2, #0b10000000 // Clear bit 7 to enable output.
|
||
str r2, [r0, #0x68]
|
||
// Set function 5 (SIO) to GPIO25
|
||
ldr r0, =io_bank_gp25
|
||
mov r1, #5 // FSEL 5 (SIO)
|
||
str r1, [r0]
|
||
// Remove isolation control on the pad control now that it's connected to its peripheral (SIO).
|
||
ldr r0, =pads_clr
|
||
mov r2, #1 // Clear bit 8 to remove isolation control.
|
||
lsl r2, r2, #8
|
||
str r2, [r0, #0x68]
|
||
// Enable the output
|
||
ldr r0, =sio_base
|
||
mov r1, #1
|
||
lsl r1, r1, #25 // Only enable gpio25
|
||
str r1, [r0, #0x38] // GPIO_OE_SET offset
|
||
blink:
|
||
ldr r0, =sio_base
|
||
mov r1, #1
|
||
lsl r1, r1, #25
|
||
led_loop:
|
||
str r1, [r0, #0x18] // GPIO_OUT_SET
|
||
ldr r3, =big_num
|
||
bl delay
|
||
|
||
str r1, [r0, #0x20] // GPIO_OUT_CLR
|
||
ldr r3, =big_num
|
||
bl delay
|
||
|
||
b led_loop
|
||
|
||
delay:
|
||
sub r3, #1
|
||
bne delay
|
||
bx lr
|
||
|
||
// An interrupt handler that just spins.
|
||
.thumb_func
|
||
.global isr_default
|
||
isr_default:
|
||
b isr_default
|
||
|