rp2040

RP2040 Programming without SDK
Log | Files | Refs

start.s (7234B)


      1 .cpu cortex-m0plus
      2 .thumb
      3 
      4 	.align 8
      5 	.section .vectors
      6 	.global vectors
      7 vectors:
      8 	.word 0x20040000 // 0 initial SP
      9 	// "+1" is to indicate that the handlers are thumb functions.
     10 	.word reset+1  // 1 entry point
     11 	.word reset+1  // 2 NMI
     12 	.word isr_hard_fault+1  // 3 hard fault
     13 	.word reset+1  // 4
     14 	.word reset+1  // 5
     15 	.word reset+1  // 6
     16 	.word reset+1  // 7
     17 	.word reset+1  // 8
     18 	.word reset+1  // 9
     19 	.word reset+1  // 10
     20 	.word isr_svcall+1  // 11 svcall
     21 	.word reset+1  // 12
     22 	.word reset+1  // 13
     23 	.word reset+1  // 14
     24 	.word reset+1  // 15 systick
     25 	.word isr_alarm+1  // 16 alarm_0
     26 
     27 	.section .text
     28 reset:
     29 	bl main
     30 loop:
     31 	wfi
     32 	b loop
     33 
     34 // functions
     35 
     36 	// void init(void);
     37 	// Init initializes the chip.
     38 	.global init
     39 init:
     40 	push {lr}
     41 	// unreset gpio, pll_sys, timer
     42 	ldr r0, =(1 << 21 | 1 << 12 | 1 << 5) // | timer | pll_sys | io_bank0
     43 	bl unreset
     44 
     45 	// set gpio functions
     46 	ldr r3, io_bank0_base
     47 	mov r0, #2 // uart0
     48 	mov r1, #0x4
     49 	str r0, [r3, r1] // IO_BANK0: GPIO0_CTRL
     50 	mov r1, #0xc
     51 	str r0, [r3, r1] // IO_BANK0: GPIO1_CTRL
     52 
     53 	// setup xosc
     54 	ldr r3, xosc_base
     55 	mov r0, #47 // start up delay for 12MHz rosc (xosc?)
     56 	str r0, [r3, #0xc] // XOSC: STARTUP
     57 	ldr r0, =(0xfab << 12 | 0xaa0)
     58 	str r0, [r3, #0] // XOSC: CTRL
     59 wait_xosc:
     60 	ldr r0, [r3, #0x4] // XOSC: STATUS
     61 	lsr r0, r0, #31 // STABLE bit
     62 	beq wait_xosc
     63 
     64 	// setup pll_sys 133MHz
     65 	ldr r3, pll_sys_base
     66 	// set feedback divider
     67 	mov r0, #133
     68 	str r0, [r3, #0x8] // PLL: FBDIV_INT
     69 	// power on pll and vco
     70 	ldr r0, =(1 << 5 | 1) // VCOPD | PD
     71 	ldr r1, atomic_clr
     72 	add r1, r1, #0x4
     73 	str r0, [r3, r1] // PLL: PWR
     74 	// wait vco to lock
     75 wait_vco:
     76 	ldr r0, [r3, #0] // PLL: CS
     77 	lsl r0, r0, #31
     78 	beq wait_vco
     79 	// setup post dividers
     80 	ldr r0, =(4 << 16 | 3 << 12)
     81 	str r0, [r3, #0xc] // PLL: PRIM
     82 	// power on post divider
     83 	mov r0, #8 // POSTDIVPD
     84 	str r0, [r3, r1] // PLL: PWR
     85 
     86 	// setup clock
     87 	ldr r3, clocks_base
     88 	// set system clock clksrc_pll_sys
     89 	ldr r0, =(0x0 << 5 | 0x1)
     90 	str r0, [r3, #0x3c] // CLOCKS: CLK_SYS_CTRL
     91 	// enable clk_peri
     92 	mov r0, #1
     93 	lsl r0, r0, #11
     94 	str r0, [r3, #0x48] // CLOCKS: CLK_PERI_CTRL
     95 	// setup clk_ref
     96 	mov r0, #0x2
     97 	str r0, [r3, #0x30] // CLOCKS: CLK_REF_CTRL
     98 
     99 	// unreset uart0
    100 	ldr r0, =(1 << 22)
    101 	bl unreset
    102 
    103 	// disable rosc
    104 	ldr r3, rosc_base
    105 	ldr r0, =0xd1e000
    106 	str r0, [r3, #0] // ROSC: CTRL
    107 
    108 	// setup uart0
    109 	bl enable_uart
    110 
    111 	// enable interrupt
    112 	// enable timer_irq_0
    113 	mov r0, #1 // timer_irq_0
    114 	bl enable_irq
    115 
    116 	// set timer
    117 	bl init_timer
    118 	ldr r0, =0x20000
    119 	bl set_alarm
    120 
    121 	pop {pc} // end of init.
    122 
    123 	// void unreset(unsigned int sub_systems);
    124 	// unreset deasserts reset bit of subsystems specified by sub_systems.
    125 	// and wait for them complete unreset.
    126 	.global unreset
    127 unreset:
    128 	ldr r3, resets_base
    129 	ldr r1, atomic_clr
    130 	str r0, [r3, r1] // RESETS: RESET
    131 unreset_chk:
    132 	ldr r1, [r3, #0x8] // RESETS: RESET_DONE
    133 	bic r0, r1
    134 	bne unreset_chk
    135 	bx lr
    136 
    137 	// void enable_uart(void);
    138 	// Enable_uart enables uart.
    139 enable_uart:
    140 	ldr r3, uart0_base
    141 	// set baudrate 115200
    142 	// BDRI = 72, BDRF = 0.157 (10 / 64)
    143 	mov r0, #72
    144 	str r0, [r3, #0x24] // UART: UARTIBRD
    145 	mov r0, #10
    146 	str r0, [r3, #0x28] // UART: UARTFBRD
    147 	// enable uart0
    148 	mov r0, #1 // UARTEN
    149 	ldr r1, atomic_set
    150 	add r1, r1, #0x30
    151 	str r0, [r3, r1] // UART: UARTCR
    152 	// enable FIFO and set format
    153 	ldr r0, =(3 << 5 | 1 << 4) // WLEN = 8, FEN = 1
    154 	str r0, [r3, #0x2c] // UART: UARTLCR_H
    155 	bx lr
    156 
    157 	// void enable_irq(unsigned int);
    158 	// Enable_irq enables irq specified by the argument.
    159 enable_irq:
    160 	ldr r3, ppb_base
    161 	ldr r1, =0xe100
    162 	str r0, [r3, r1] // M0PLUS: NVIC_ISER
    163 	bx lr
    164 
    165 	// void init_timer(void);
    166 	// Init_timer enables alarm_0 and its interrupt.
    167 	// It assumes that the timer is out of reset.
    168 	.global init_timer
    169 init_timer:
    170 	ldr r3, timer_base
    171 	// enable alarm_0 interrupt
    172 	mov r0, #1 // ALARM_0
    173 	str r0, [r3, #0x38] // TIMER: INTE
    174 	bx lr
    175 
    176 	// void set_alarm(unsigned int us);
    177 	// Set_alarm clears timer interrupt and then sets alarm_0 to fire,
    178 	// after us micro seconds.
    179 	.global set_alarm
    180 set_alarm:
    181 	ldr r3, timer_base
    182 	// clear interrupt
    183 	ldr r2, atomic_clr
    184 	mov r1, #0x34
    185 	add r1, r1, r2
    186 	mov r2, #1
    187 	str r2, [r3, r1] // TIMER: INTR
    188 	// set alarm0
    189 	ldr r1, [r3, #0x28] // TIMER: TIMERAWL
    190 	add r0, r1
    191 	str r0, [r3, #0x10] // TIMER: ALARM0
    192 	bx lr
    193 
    194 	// print r0 in hex for debugging.
    195 	.global printh
    196 printh:
    197 	push {r4, r5, r6, r7, lr}
    198 	mov r4, r0
    199 	mov r5, #28
    200 	mov r6, #0xf
    201 	mov r7, #10
    202 printh_loop:
    203 	mov r0, r4
    204 	lsr r0, r0, r5
    205 	and r0, r0, r6
    206 	sub r1, r0, r7
    207 	blt digi
    208 	add r0, r0, #('a' - 10)
    209 	b alpha
    210 digi:
    211 	add r0, r0, #'0'
    212 alpha:
    213 	bl putbyte
    214 	sub r5, r5, #4
    215 	bge printh_loop
    216 	pop {r4, r5, r6, r7, pc}
    217 
    218 	// Puts prints null terminated string starting at r0 and a trailing new line
    219 	// to uart0.
    220 	// It returns a nonnegative number on success.
    221 	.global puts
    222 puts:
    223 	push {r4, lr}
    224 	mov r4, r0
    225 puts_loop:
    226 	ldrb r0, [r4, #0]
    227 	cmp r0, #0
    228 	beq puts_end
    229 	bl putbyte
    230 	add r4, #1
    231 	b puts_loop
    232 puts_end:
    233 	mov r0, #'\n'
    234 	bl putbyte
    235 	mov r0, #0 // return value
    236 	pop {r4, pc}
    237 
    238 	// void *memcpy(void *s1, void *s2, long n);
    239 	// Memcpy copies n bytes from memory area s2 to s1. It returns s1.
    240 	// TODO: Use ldr instead of ldrb.
    241 	.global memcpy
    242 memcpy:
    243 	push {r4, lr}
    244 	mov r4, #0
    245 memcpy_loop:
    246 	ldrb r3, [r1, r4]
    247 	strb r3, [r0, r4]
    248 	add r4, #1
    249 	cmp r4, r2
    250 	blt memcpy_loop
    251 	pop {r4, pc}
    252 
    253 	// void putbyte(char b);
    254 	// Putbyte writes b to uart0.
    255 	.global putbyte
    256 putbyte:
    257 	ldr r3, uart0_base
    258 	mov r1, #1
    259 	lsl r1, r1, #5 // TXFF
    260 txff:
    261 	ldr r2, [r3, #0x18] // UART: UARTFR
    262 	tst r1, r2
    263 	bne txff
    264 	mov r1, #0xff
    265 	and r0, r0, r1
    266 	str r0, [r3, #0] // UART: UARTDR
    267 	bx lr
    268 
    269 	// char getbyte(void);
    270 	// Getbyte reads a byte from uart0.
    271 getbyte:
    272 	ldr r3, uart0_base
    273 	mov r1, #1
    274 	lsl r1, r1, #4 // RXFE
    275 rxfe:
    276 	ldr r2, [r3, #0x18] // UART: UARTFR
    277 	tst r1, r2
    278 	bne rxfe
    279 	ldr r0, [r3, #0] // UART: UARTDR
    280 	mov r1, #0xff
    281 	and r0, r0, r1
    282 	bx lr
    283 
    284 	.global halt
    285 halt:
    286 	wfe
    287 	b halt
    288 
    289 	.global wfi
    290 wfi:
    291 	wfi
    292 	bx lr
    293 
    294 // The following functions make no side effects and
    295 // can be used anywhare without pushing and popping
    296 // registers.
    297 
    298 	// Print register content with 2 leds, lsb first.
    299 pled:
    300 	push {r0, r1, r2, r3, r4, r5, r6, lr}
    301 	mov r4, r0
    302 	mov r5, #32
    303 	mov r6, #1
    304 pled_loop:
    305 	tst r4, r6
    306 	beq pled0
    307 	bl bled1
    308 	b pled1
    309 pled0:
    310 	bl bled0
    311 pled1:
    312 	lsr r4, r4, #1
    313 	sub r5, r5, #1
    314 	bne pled_loop
    315 	pop {r0, r1, r2, r3, r4, r5, r6, pc}
    316 
    317 bled0:
    318 	push {r0, r1, r2, r3, lr}
    319 	mov r0, #1
    320 	lsl r0, r0, #24
    321 	bl bled
    322 	pop {r0, r1, r2, r3, pc}
    323 
    324 bled1:
    325 	push {r0, r1, r2, r3, lr}
    326 	mov r0, #1
    327 	lsl r0, r0, #25
    328 	bl bled
    329 	pop {r0, r1, r2, r3, pc}
    330 
    331 bled:
    332 	push {r0, r1, r2, r3, r4, r5, lr}
    333 	ldr r4, sio_base
    334 	mov r5, r0
    335 	str r5, [r4, #0x10] // SIO: GPIO_OUT_XOR
    336 	bl delay
    337 	str r5, [r4, #0x18] // SIO: GPIO_OUT_XOR
    338 	bl delay
    339 	pop {r0, r1, r2, r3, r4, r5, pc}
    340 
    341 	// void delay(void);
    342 	.global delay
    343 delay:
    344 	push {r0}
    345 	mov r0, #1
    346 	lsl r0, r0, #20
    347 delay_loop:
    348 	sub r0, r0, #1
    349 	bne delay_loop
    350 	pop {r0}
    351 	bx lr
    352 
    353 	.align 2
    354 literals:
    355 	.ltorg
    356 atomic_set:
    357 	.word 0x00002000
    358 atomic_clr:
    359 	.word 0x00003000
    360 syscfg_base:
    361 	.word 0x40004000
    362 clocks_base:
    363 	.word 0x40008000
    364 resets_base:
    365 	.word 0x4000c000
    366 io_bank0_base:
    367 	.word 0x40014000
    368 xosc_base:
    369 	.word 0x40024000
    370 pll_sys_base:
    371 	.word 0x40028000
    372 uart0_base:
    373 	.word 0x40034000
    374 timer_base:
    375 	.word 0x40054000
    376 rosc_base:
    377 	.word 0x40060000
    378 sio_base:
    379 	.word 0xd0000000
    380 ppb_base:
    381 	.word 0xe0000000