mirror of
https://github.com/mytechnotalent/Embedded-Hacking.git
synced 2026-04-21 10:36:03 +02:00
256 lines
10 KiB
ArmAsm
256 lines
10 KiB
ArmAsm
/**
|
||
* FILE: main.s
|
||
*
|
||
* DESCRIPTION:
|
||
* RP2350 Bare-Metal GPIO16 Blink, Coprocessor Version.
|
||
* Minimal bare‑metal LED blink on the RP2350 using direct coprocessor
|
||
* (MCRR) instructions to manipulate GPIO control registers. This bypasses
|
||
* SDK abstractions and demonstrates register‑level control in assembler.
|
||
*
|
||
* AUTHOR: Kevin Thomas
|
||
* CREATION DATE: October 5, 2025
|
||
* UPDATE DATE: October 5, 2025
|
||
*/
|
||
|
||
.syntax unified // use unified assembly syntax
|
||
.cpu cortex-m33 // target Cortex-M33 core
|
||
.thumb // use Thumb instruction set
|
||
|
||
/**
|
||
* Memory addresses and constants.
|
||
*/
|
||
.equ IO_BANK0_BASE, 0x40028000 // base address of IO_BANK0
|
||
.equ PADS_BANK0_BASE, 0x40038000 // base address of PADS_BANK0
|
||
.equ SIO_BASE, 0xD0000000 // base address of SIO block
|
||
.equ GPIO16_CTRL, 0x84 // io[16].ctrl offset
|
||
.equ GPIO16_PAD, 0x44 // pads io[16] offset
|
||
.equ GPIO16_BIT, (1<<16) // bit mask for GPIO16
|
||
.equ GPIO_OUT_SET, 0x18 // SIO->GPIO_OUT_SET offset
|
||
.equ GPIO_OUT_XOR, 0x28 // SIO->GPIO_OUT_XOR offset
|
||
.equ GPIO_OE_SET, 0x38 // SIO->GPIO_OE_SET offset
|
||
.equ STACK_TOP, 0x20082000 // top of non-secure SRAM
|
||
.equ STACK_LIMIT, 0x2007A000 // stack limit (32 KB below top)
|
||
|
||
/**
|
||
* Initialize the .vectors section. The .vectors section contains vector
|
||
* table.
|
||
*/
|
||
.section .vectors, "ax" // vector table section
|
||
.align 2 // align to 4-byte boundary
|
||
|
||
/**
|
||
* Vector table section.
|
||
*/
|
||
.global _vectors // export symbol
|
||
_vectors:
|
||
.word STACK_TOP // initial stack pointer
|
||
.word Reset_Handler + 1 // reset handler (Thumb bit set)
|
||
|
||
/**
|
||
* @brief Reset handler for RP2350.
|
||
*
|
||
* @details Entry point after reset. Performs:
|
||
* - Stack initialization
|
||
* - Coprocessor enable
|
||
* - GPIO16 pad/function configuration
|
||
* - Branches to main() which contains the blink loop
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.global Reset_Handler // export Reset_Handler
|
||
.type Reset_Handler, %function // mark as function
|
||
Reset_Handler:
|
||
BL Init_Stack // initialize MSP/PSP and limits
|
||
BL Enable_Coprocessor // enable CP0 in CPACR for MCRR
|
||
B main // branch to main loop
|
||
.size Reset_Handler, . - Reset_Handler
|
||
|
||
/**
|
||
* @brief Initialize stack pointers.
|
||
*
|
||
* @details Sets Main and Process Stack Pointers (MSP/PSP) and their limits.
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.type Init_Stack, %function
|
||
Init_Stack:
|
||
LDR R0, =STACK_TOP // load stack top
|
||
MSR PSP, R0 // set PSP
|
||
LDR R0, =STACK_LIMIT // load stack limit
|
||
MSR MSPLIM, R0 // set MSP limit
|
||
MSR PSPLIM, R0 // set PSP limit
|
||
LDR R0, =STACK_TOP // reload stack top
|
||
MSR MSP, R0 // set MSP
|
||
BX LR // return
|
||
|
||
/**
|
||
* @brief Enable coprocessor access.
|
||
*
|
||
* @details Grants full access to coprocessor 0 (CP0) via CPACR.
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.type Enable_Coprocessor , %function
|
||
Enable_Coprocessor:
|
||
LDR R0, =0xE000ED88 // CPACR address
|
||
LDR R1, [R0] // read CPACR
|
||
ORR R1, R1, #0x3 // set CP0 full access
|
||
STR R1, [R0] // write CPACR
|
||
DSB // data sync barrier
|
||
ISB // instruction sync barrier
|
||
BX LR // return
|
||
|
||
/**
|
||
* Initialize the .text section.
|
||
* The .text section contains executable code.
|
||
*/
|
||
.section .text // code section
|
||
.align 2 // align to 4-byte boundary
|
||
|
||
/**
|
||
* @brief Main application entry point.
|
||
*
|
||
* @details Implements the infinite blink loop:
|
||
* - Set GPIO16 high
|
||
* - Delay ~500 ms
|
||
* - Set GPIO16 low
|
||
* - Delay ~500 ms
|
||
* - Repeat forever
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.global main // export main
|
||
.type main, %function // mark as function
|
||
main:
|
||
.Push_Registers:
|
||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||
.GPIO16_Config:
|
||
BL GPIO16_Config // configure pads and FUNCSEL for GPIO16
|
||
.Loop:
|
||
BL GPIO16_Set // set GPIO16 high
|
||
BL Delay_500ms // ~500 ms delay
|
||
BL GPIO16_Clear // set GPIO16 low
|
||
BL Delay_500ms // ~500 ms delay
|
||
B Loop // loop forever
|
||
.Pop_Registers:
|
||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||
BX LR // return to caller
|
||
|
||
/**
|
||
* @brief Configure GPIO16 for SIO control.
|
||
*
|
||
* @details Sets pad control (IE, OD, ISO) and FUNCSEL = 5 (SIO). Enables OE.
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.type GPIO16_Config, %function
|
||
GPIO16_Config:
|
||
.GPIO16_Config_Push_Registers:
|
||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||
.GPIO16_Config_Modify_Pad:
|
||
LDR R3, =PADS_BANK0_BASE + GPIO16_PAD // pad control address
|
||
LDR R2, [R3] // read pad config
|
||
BIC R2, R2, #0x80 // clear OD
|
||
ORR R2, R2, #0x40 // set IE
|
||
BIC R2, R2, #0x100 // clear ISO
|
||
STR R2, [R3] // write pad config
|
||
.GPIO16_Config_Modify_IO:
|
||
LDR R3, =IO_BANK0_BASE + GPIO16_CTRL // IO control address
|
||
LDR R2, [R3] // read IO config
|
||
BIC R2, R2, #0x1F // clear FUNCSEL
|
||
ORR R2, R2, #5 // set FUNCSEL=5
|
||
STR R2, [R3] // write IO config
|
||
.GPIO16_Config_Enable_OE:
|
||
MOVS R4, #16 // GPIO number
|
||
MOVS R5, #1 // enable output
|
||
MCRR p0, #4, R4, R5, c4 // gpioc_bit_oe_put(16, 1)
|
||
.GPIO16_Config_Pop_Registers:
|
||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||
BX LR // return
|
||
|
||
/**
|
||
* @brief Set GPIO16 high.
|
||
*
|
||
* @details Drives GPIO16 output = 1 via coprocessor MCRR.
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.type GPIO16_Set, %function
|
||
GPIO16_Set:
|
||
.GPIO16_Set_Push_Registers:
|
||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||
.GPIO16_Set_Load_Operands:
|
||
MOVS R4, #16 // GPIO number
|
||
MOVS R5, #1 // logic high
|
||
.GPIO16_Set_Execute:
|
||
MCRR p0, #4, R4, R5, c0 // gpioc_bit_out_put(16, 1)
|
||
.GPIO16_Set_Pop_Registers:
|
||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||
BX LR // return to caller
|
||
|
||
/**
|
||
* @brief Clear GPIO16 (set low).
|
||
*
|
||
* @details Drives GPIO16 output = 0 via coprocessor MCRR.
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.type GPIO16_Clear, %function
|
||
GPIO16_Clear:
|
||
.GPIO16_Clear_Push_Registers:
|
||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||
.GPIO16_Clear_Load_Operands:
|
||
MOVS R4, #16 // GPIO number
|
||
MOVS R5, #0 // logic low
|
||
.GPIO16_Clear_Execute:
|
||
MCRR p0, #4, R4, R5, c0 // gpioc_bit_out_put(16, 0)
|
||
.GPIO16_Clear_Pop_Registers:
|
||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||
BX LR // return to caller
|
||
|
||
/**
|
||
* @brief Busy‑wait Delay_500ms loop.
|
||
*
|
||
* @details Consumes ~2,000,000 cycles to approximate ~500 ms at boot clock.
|
||
*
|
||
* @param None
|
||
* @retval None
|
||
*/
|
||
.type Delay_500ms, %function
|
||
Delay_500ms:
|
||
.Delay_500ms_Push_Registers:
|
||
PUSH {R4-R12, LR} // push registers R4-R12, LR to the stack
|
||
.Delay_500ms_Setup:
|
||
LDR R2, =2000000 // loop count (~500 ms)
|
||
.Delay_500ms_Loop:
|
||
SUBS R2, R2, #1 // decrement counter
|
||
BNE .Delay_500ms_Loop // branch until zero
|
||
.Delay_500ms_Pop_Registers:
|
||
POP {R4-R12, LR} // pop registers R4-R12, LR from the stack
|
||
BX LR // return to caller
|
||
|
||
/**
|
||
* Test data and constants.
|
||
* The .rodata section is used for constants and static data.
|
||
*/
|
||
.section .rodata // read-only data section
|
||
|
||
/**
|
||
* Initialized global data.
|
||
* The .data section is used for initialized global or static variables.
|
||
*/
|
||
.section .data // data section
|
||
|
||
/**
|
||
* Uninitialized global data.
|
||
* The .bss section is used for uninitialized global or static variables.
|
||
*/
|
||
.section .bss // BSS section
|