Hello, i hope someone can help me.
I am programming on a SAM7S256.
I use GCC4.4.2.
When i compile, i do not get any errors.
First some notes to explain :
When the interrupts are disabled my program works fine.
The IRQ handler code is disabled and is not used . I use only the FIQ handler for testing purposes.
When i use the example startup.s with the bulky quantum leaps 2 vector table code in it from olimex , the FIQ interrupt code works as well and perfect. My PIT timer fires every 1 millisecond giving me a led pulsating at 500Hz (2milliseconds). I measure the pulsating led with a frequency counter.
The FIQ interrupt code saves the context of the registers. Branches to the C function System_Int_Handler clears the PIT and toggles a led and returns. After that the registers and the cpsr are restored and the handler gives control back to the program that was running.
I had the idea to create an optimized startup.s. because i do not have a need for 32bit addressing space and wanted as much speed as possible. As such i have written the startup code below.
When i disable the FIQ interrupt, the code works fine.
When i enable the FIQ interrupt, i estimate that it hangs right after the first time the PIT fires. ( I am going to test this by setting a large PIT time and will post the result later.)
I do not branch to the FIQ handler now, instead i execute it directly from address 0x1C.
Knowing all this, i think that there is not an error in my interrupt code.
I think i have an error in the code copying the ram vectors and the interrupt handlers code from ROM to RAM.
Can anybody point my error out for me ?
I am sure i am overlooking something. But i do not see it.
Code:
// ************************************************************************************************
// Startup code assembler file for programs created with the W-ARM IDE for the ARM SAM7S256.
// But can be used as well for all other SAM7S series. All start addresses of ROM and RAM are the same.
// The size of the ROM and the RAM is different between different versions.
// version 1.2 beta.
//
// Supports interrupts.
// Has been optimized for raw execution speed of IRQ interrupt handler and FIQ interrupt handler.
// All interrupt handlers can be written in the C language and can be found in the source file isr.c .
// All hardware initialization can be written in the C language and can be found in the low_level_init.c
// source file.
//
//
// SOMETHING TO NOTE : LDR REGISTER,=value is a pseudo instruction the assembler understands
// but is not an ARM instruction.
// The LDR Rd,= pseudo-instruction can load any 32-bit numeric constant into a register
// The assembler converts the LDR REGISTER,=value into an LDR Rdestination,[pc, #offset to literal pool]
// The literal pool is a set of constants stored in the code.
// ************************************************************************************************
//
// declarations and defines of memory addresses.
.equ _ASM_RAM_START,0x00200000 // Start address of RAM.
.equ _ASM_MC_REMAP_REG,0xFFFFFF00 // Memory address of the remap register of the memory controller.
.equ _ASM_AIC_IVR,0xFFFFF100 // Memory address of interrupt vector register of the
// Advanced Interrupt Controller.
.equ REMAP_CHECK_VALUE,0x5A5A5A5A // Check value to do test if ram is remapped.
// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
.equ I_BIT, 0x80 // when I bit is set, IRQ is disabled
.equ F_BIT, 0x40 // when F bit is set, FIQ is disabled
.equ USR_MODE, 0x10
.equ FIQ_MODE, 0x11
.equ IRQ_MODE, 0x12
.equ SVC_MODE, 0x13
.equ ABT_MODE, 0x17
.equ UND_MODE, 0x1B
.equ SYS_MODE, 0x1F
.equ STACK_FILL, 0xAAAAAAAA // constant to pre-fill the stack
.text
.code 32
.global _start
.func _start
_start:
// ************************************************************************************************
// The symbol _start denotes the beginning of the code, starting with the vector table.
// When the processor starts up from cold reset, The rom is mapped to address 0x0000 0000.
// The ARM7TDMI core expects a Vector table in ROM starting at address 0x0000 0000.
// This table forces the ARM into an infinite loop if any one of these exceptions occur
// with exception of the reset vector. The controller will jump to the label _reset if working properly.
// Since the ARM has nothing setup, and if a crash occurs this early, there must a hardware failure.
// For example external addressing may be wrong or the MCU is damaged when using internal flash.
//
// Each instruction is 32 bits wide and as such takes 4 bytes to store.
//
// THE SAM7S STARTS EXECUTING HERE !
//
// ************************************************************************************************
//
B _reset // address 0x0000 0000 = Reset.
B ROM_UndefHandler // address 0x0000 0004 = Undefined instruction.
B ROM_SWIHandler // address 0x0000 0008 = Software interrupt.
B ROM_PAbortHandler // address 0x0000 000C = Prefetch abort.
B ROM_DAbortHandler // address 0x0000 0010 = Data abort.
.word 0 // address 0x0000 0014 = Reserved. Write 0 to use as test for REMAP CHECK.
B ROM_IRQHandler // address 0x0000 0018 = IRQ interrupt.
B ROM_FIQHandler // address 0x0000 001C = FIQ interrupt.
// ************************************************************************************************
// This is the ram vector table used for the sam7s series.
// This table will be copied to ram before the remapping of the ram.
// The code for the FIQ handler and the IRQ handler is also copied to ram.
// This way we have the maximum speed for executing the FIQ and the IRQ interrupt.
// The FIQ handler executes directly from address 0x00 001C.
// The IRQ handler is programmed in C and by the use of the AIC.
// The Advanced Interrupt controller must be set up first before IRQs can be used.
//
// ************************************************************************************************
//
_asm_ram_vectortable:
B _reset // address 0x0000 0000 = Reset.
B ROM_UndefHandler // address 0x0000 0004 = Undefined instruction.
B ROM_SWIHandler // address 0x0000 0008 = Software interrupt.
B ROM_PAbortHandler // address 0x0000 000C = Prefetch abort.
B ROM_DAbortHandler // address 0x0000 0010 = Data abort.
.word REMAP_CHECK_VALUE // address 0x0000 0014 = Reserved. Write REMAP CHECK value for remap testing.
B RAM_IRQHandler // address 0x0000 0018 = IRQ interrupt.
// address 0x0000 001C = FIQ interrupt. On this address the SUB instruction
// is located. When the FIQ interrupt is called, this is executed.
SUB r14,r14,#4 // Adjust lr to proper address.
STMFD r13!,{r0-r7,r12,r14} // Save registers to stack.
LDR r12,=System_Int_Handler // Load address of System interrupt handler.
MOV r14,pc // Store the return address (=pc+4) in r14 (=lr).
BX r12 // Branch to address pointed to by r12.
LDMFD r13!,{r0-r7,r12,pc}^ // Restore registers and return to code that was interrupted.
RAM_IRQHandler:
SUB r14,r14,#4 // Adjust lr to proper address.
STMFD r13!,{r0-r12,r14} // Save registers to stack.
LDR r12,=_ASM_AIC_IVR // Load address from interrupt vector register.
MOV r14,pc // Store the return address (=pc+4) in r14 (=lr).
BX r12 // Branch to memory address pointed to by r12.
// After executing the specific handler, return to the memory address of the next instruction.
LDMFD r13!,{r0-r12,r14,pc}^ // Restore registers and return.
.word 0
.word
// ************************************************************************************************
// The reset handler starts here.
// The ROM is NOT at its linked address before the remap,as such the branch to
// low_level_init() must be relative (position independent code). The low_level_init() function
// must continue to execute in ARM state. Also, the function low_level_init() cannot rely
// on uninitialized data being cleared and cannot use any initialized data, because the
// .bss and .data sections have not been initialized yet. The Branch instruction stores the
// address to jump to as an relative offset to the current value stored in the program counter PC.
// The code is linked at address 0x0010 0000 but executed at address 0x0000 0000 before the remap command.
// We do all hardware initialization in low level init, because this way it can be done in C language.
//
// ************************************************************************************************
//
_reset:
LDR r0,=_reset // pass the reset address as the 1st argument
LDR r1,=_asm_setup_ram // pass the return address as the 2nd argument
MOV lr,r1 // set the return address after the remap.
LDR sp,=__stack_end // set the temporary stack pointer
B low_level_init // relative branch to low_level_init.
// ************************************************************************************************
// This part is the assembler code that copies the vectors and the interrupt handlers to the RAM
// at address 0x0020 0000.
// This part needs to be checked first.
// ************************************************************************************************
//
_asm_setup_ram:
MOV r0,#0x20 // Load ROM start address of vector table in R0.
MOV r2,#0x6C // Load ROM end address of vector table.
LDR r1,=_ASM_RAM_START
_asm_loop_cpy_vectable:
CMP r0,r2 // Do R0 - R2 . If R0 < R2 = LT.
LDMLTIA r0!,{r3} // LT = only execute if R0 < R2.
STMLTIA r1!,{r3} // LT = only execute if R0 < R2.
BLT _asm_loop_cpy_vectable // LT = only execute if R0 < R2.
// ************************************************************************************************
// Now we do the remapping of the ROM and RAM by programming the memory controller.
//
// Before remapping, the ROM can be found at address 0x0000 0000 to 0x0003 FFFF (size = 256kB).
// Before remapping, the ROM can be found at address 0x0010 0000 to 0x0013 FFFF (size = 256kB).
// Before remapping, the RAM can be found at address 0x0020 0000 to 0x0020 FFFF (size = 64kB).
//
// After remapping, the RAM can be found at address 0x0000 0000 to 0x0000 FFFF (size = 64kB).
// After remapping, the RAM can be found at address 0x0020 0000 to 0x0020 FFFF (size = 256kB).
// After remapping, the ROM can be found at address 0x0010 0000 to 0x0013 FFFF (size = 256kB).
//
// After remapping, we are finally able to setup the controller for c language and after that we can start to
// run code written in the C language.
// ************************************************************************************************
//
LDR r1,=REMAP_CHECK_VALUE // Load R1 with remap check value.
MOV r0,#0x14 // Load r0 with the value 0x14.
STR r1,[r0] // Store at address 0x14(r0) the remap check value (r1).
LDR r2,[r0] // Read the value ar address 0x14(r0)
CMP r0,r2 // If (r2) = (r0) = REMAP_CHECK_VALUE execute the following 3 instr.
LDRNE r0,=_ASM_MC_REMAP_REG // Load R0 with the memory address of remap control register.
MOVNE r1,#1 // Load r1 with the value 1.
STRNE R1, [R0] // Store the content of r1 at the memory address pointed to by the r0.
// This will remap the memory.
// ************************************************************************************************
// This part is the intialization assembler code to set up the controller to run software written in C.
// From this point on, the code does not run from address 0x0000 0000 but from addres 0x0010 0000.
//
// ************************************************************************************************
//
// Relocate .fastcode section (copy from ROM to RAM)
_cstartup:
LDR r0,=__fastcode_load
LDR r1,=__fastcode_start
LDR r2,=__fastcode_end
_asm_loop_cpy_fastcode:
CMP r1,r2 // Do R1 - R2 . If R1 < R2 = LT.
LDMLTIA r0!,{r3} // LT = only execute if R1 < R2.
STMLTIA r1!,{r3} // LT = only execute if R1 < R2.
BLT _asm_loop_cpy_fastcode // LT = only execute if R1 < R2.
// Relocate the .data section (copy from ROM to RAM)
LDR r0,=__data_load
LDR r1,=__data_start
LDR r2,=__data_end
_asm_loop_cpy_data:
CMP r1,r2
LDMLTIA r0!,{r3}
STMLTIA r1!,{r3}
BLT _asm_loop_cpy_data
// Clear the .bss section (zero init)
LDR r1,=__bss_start
LDR r2,=__bss_end
MOV r3,#0
_asm_loop_clr_bss:
CMP r1,r2
STMLTIA r1!,{r3}
BLT _asm_loop_clr_bss
// Fill the .stack section
LDR r1,=__stack_start
LDR r2,=__stack_end
LDR r3,=STACK_FILL
_asm_fill_stack:
CMP r1,r2
STMLTIA r1!,{r3}
BLT _asm_fill_stack
// ************************************************************************************************
// Initialize stack pointers for all ARM modes.
// Enable the used interrupts as well.
//
// when I bit is set, IRQ is disabled
// when F bit is set, FIQ is disabled
//
// ************************************************************************************************
MSR CPSR_c,#(IRQ_MODE | I_BIT | F_BIT) // Set the IRQ stack pointer.
LDR sp,=__irq_stack_top
MSR CPSR_c,#(FIQ_MODE ) // Set the FIQ stack pointer.
LDR sp,=__fiq_stack_top // And enable interrupts.
MSR CPSR_c,#(SVC_MODE ) // Set the SVC stack pointer.
LDR sp,=__svc_stack_top // And enable interrupts.
MSR CPSR_c,#(ABT_MODE | I_BIT | F_BIT)
LDR sp,=__abt_stack_top // Set the ABT stack pointer.
MSR CPSR_c,#(UND_MODE | I_BIT | F_BIT) // Set the UND stack pointer.
LDR sp,=__und_stack_top
MSR CPSR_c,#(SYS_MODE ) // set the C stack pointer.
LDR sp,=__c_stack_top // And enable interrupts.
// Because the system mode is the last one set, the ARM is running in system mode.
// ************************************************************************************************
// Enter the C code.
//
// ************************************************************************************************
mov r0,#0 // Make sure no arguments are passed, argc=0 .
mov r1,r0
mov r2,r0
mov r3,r0
LDR r12,=main
MOV lr,pc // set the return address.
BX r12 // the target code can be ARM or THUMB.
// ************************************************************************************************
// When for some reason the main function returns, then this code section is executed.
// It is no more then an infinite loop.
// ************************************************************************************************
ExitFunction:
NOP
NOP
NOP
B ExitFunction
.size _start, . - _start
.endfunc
// ************************************************************************************************
// Here the assembler section of the interrupt handlers in ROM can be found.
// Because nothing is initialized, we cannot do much more then an infinite loop.
// ************************************************************************************************
ROM_UndefHandler:
B ROM_UndefHandler
ROM_SWIHandler:
B ROM_SWIHandler
ROM_PAbortHandler:
B ROM_PAbortHandler
ROM_DAbortHandler:
B ROM_DAbortHandler
ROM_IRQHandler:
B ROM_IRQHandler
ROM_FIQHandler:
B ROM_FIQHandler
.weak ExitFunction
.weak UndefHandler, PAbortHandler, DAbortHandler
.end
// EOF