Files
Embedded-Hacking/RA-0x0001-GPIO-Output/main.s
T
2025-10-05 12:00:31 -07:00

256 lines
10 KiB
ArmAsm
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* FILE: main.s
*
* DESCRIPTION:
* RP2350 Bare-Metal GPIO16 Blink, Coprocessor Version.
* Minimal baremetal LED blink on the RP2350 using direct coprocessor
* (MCRR) instructions to manipulate GPIO control registers. This bypasses
* SDK abstractions and demonstrates registerlevel 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 Busywait 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