Atmel website | ARM Community | AVR freaks | Technical Support
Banner
 FAQ •  Search •  Register •  Login 

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 8:16 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
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


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 8:21 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
I have afcourse also editted the low_level_init.c to remove the code section that i have placed in startup.s

Code:
// ************************************************************************************************
//    W-ARM low level init code.
//  Version 2.0
//   
//  Perform the low level intialization in c language here.
//   The input to the MCK masterclock is 96Mhz.
//   The masterclock prescaler is 2, thus the MCK clock = 48MHz.      
//   
// *************************************************************************************************

#include "AT91SAM7S256.h"

// ************************************************************************************************
// DEFINE: All Structures and Common Constants                           
// ************************************************************************************************


// Register Base Address
#define RSTC_KEY        0xA5000000
#define RSTC_URSTEN     0x00000001

#define MC_FMR_OFF      0x00000060
#define MC_FWS_1FWS     0x00480100

// Startup time of main oscillator (in number of slow clock ticks).
#define BOARD_OSCOUNT   (AT91C_CKGR_OSCOUNT & (0x40 << 8))

// USB PLL divisor value to obtain a 48MHz clock, value = 1 meaning divide input by 2.
#define BOARD_USBDIV    AT91C_CKGR_USBDIV_1   

// PLL frequency range.
#define BOARD_CKGR_PLL  AT91C_CKGR_OUT_0

// PLL startup time (in number of slow clock ticks).
#define BOARD_PLLCOUNT  (16 << 8)

// PLL MUL value.
#define BOARD_MUL       (AT91C_CKGR_MUL & (72 << 16))

// PLL DIV value.
#define BOARD_DIV       (AT91C_CKGR_DIV & 14)

// Master clock prescaler value.
#define BOARD_PRESCALER AT91C_PMC_PRES_CLK_2


// ************************************************************************************************
// This function performs the low level initialization of the hardware.
//                                             
// low_level_init() is invoked in the ARM state. The function gives the   
// application a chance to perform early initializations of the hardware.
// This function cannot rely on initialization of any static variables,   
// because these have not yet been initialized in RAM.                   
// ************************************************************************************************
//
void low_level_init (void *reset_addr, void *return_addr)
{

      // The watchdog is enabled after processor reset. Disable it.
      AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
      
      // Enable user reset: assertion length programmed to 1ms
      AT91C_BASE_RSTC->RSTC_RMR = (RSTC_KEY | RSTC_URSTEN | (4 << 8));
   
      // Flash memory runs at 1 cycle when MCK is lower or equal to 30MHz.
    // We use 2 cycles for flash access because MCK = 48MHz.
      AT91C_BASE_MC->MC_FMR = MC_FWS_1FWS;

      // We disable all interrupts for now. Useful for debugging w/o target reset.
      AT91C_BASE_AIC->AIC_EOICR = 0xFFFFFFFF;   
      AT91C_BASE_AIC->AIC_IDCR  = 0xFFFFFFFF;
   
      
// Now we Setup the CPU core.
      
      // Initialize main oscillator.
      AT91C_BASE_PMC->PMC_MOR = BOARD_OSCOUNT | AT91C_CKGR_MOSCEN;

      while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MOSCS));

      //   Initialize PLL at 96MHz (96.109) and USB clock to 48MHz.
      // USB clock = 96MHz / 2 = 48Mhz.
      AT91C_BASE_PMC->PMC_PLLR =    BOARD_USBDIV |
                                                BOARD_CKGR_PLL |
                                                BOARD_PLLCOUNT |
                                                BOARD_MUL | BOARD_DIV;
                                                
      while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCK));

      // Wait for the master clock to become stable.
      while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

      // Write board prescaler = 2. 
      // At the same time select the slow clock.
      AT91C_BASE_PMC->PMC_MCKR = BOARD_PRESCALER;
      while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

      // Switch to fast clock + prescaler
      AT91C_BASE_PMC->PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK;
      while (!(AT91C_BASE_PMC->PMC_SR & AT91C_PMC_MCKRDY));

}


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 8:27 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
I have increased the PIT value to 2^18 bits. This gives me 80 milliseconds before the ARM hangs. Now i am positive that i made an error. The SAM7S branches to the address 0x1C but hangs from there. The led does not light up. But my main loop is putting out text at 9600 baud at the debug port. Before i got only 1 letter. Now i get an entire sentence before the PIT fires and the my code crashes.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 8:43 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
When i copy the FIQ interrupt code for the FIQ handler to the ROM_FIQHandler and disable the remapping, the FIQ interrupts works normally. I must be doing something wrong while copying the interrupt vectors and the FIQ handler and the IRQ hander from ROM to RAM.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 9:30 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
I am still searching to find out where i went wrong with copying rom code to ram.
Here are the modifications i made to startup.s with some errors removed, the remapping disabled and the ROM_FIQhandler executing the same code :

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.3 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     ROM_soft_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.               
    ADD   pc,pc,#0x16            // address 0x0000 0018 = IRQ interrupt. Relative JUMP to RAM_IRQHandler is executed.       
                                             // 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
   
                                                                        
// ************************************************************************************************
// 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:
      LDR     r0,=_asm_ram_vectortable      // Load ROM start address of vector table in R0.
      LDR     r2,=_reset                          // Load ROM end address of vector table.
      LDR         r1,=_ASM_RAM_START               // Load memory address of 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_soft_reset:
      B   ROM_soft_reset

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:

      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.
      
 
   .weak ExitFunction
   .weak UndefHandler, PAbortHandler, DAbortHandler
   
   .end

//   EOF


Last edited by William_Gaatjes on Sat Sep 11, 2010 10:11 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 10:10 pm 
Offline

Joined: Thu Jul 08, 2010 9:36 pm
Posts: 28
William_Gaatjes wrote:

STMFD r13!,{r0-r7,r12,r14} // Save registers to stack.
LDMFD r13!,{r0-r7,r12,pc}^ // Restore registers and return to code that was interrupted.

It would probably help to restore r14 here as well ;)

Reinhard


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sat Sep 11, 2010 11:20 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
You are right. :). Thank you.

Funny it did not crash my software (yet). Because although i indeed did not restore r14, my FIQ handler did work as long as there is no r14 corruption.
I have made the modifications and enabled the remapping again.
Alas, unfortunately that did not solve the issue.

When i disable remapping and the FIQ handler in ROM is used, it works without crashing on the first FIQ interrupt that is fired by the PIT.
I think that tomorrow i must have a fresh look at it :| ...
I am still sure that there is something going wrong with copying the vector table to RAM together with the FIQ handler.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sun Sep 12, 2010 3:27 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
Well, it turns out you are not right. I overlooked the code now that i am still fresh. As it turns out, i save the registers on the stack as a push mechanism. r14 as well. Then i do my FIQ interrupt handling.
When i pop the stack afterwards, i load the memory address from the stack (which was r14) directly in the pc. The ^ at the end restores the cpsr. This causes the codeline to restore the program execution before the FIQ interrupt occurred. As such it is not necessary to restore fiq_r14. Because the ARM jumps back to system/user and uses the normal r14.
That is if i understand it correctly. I am still a new rookie to ARM assembly. I have not solved the issue yet.
I made some changes again. I noticed a signed less then(LT) is used to check memory addresses which are unsigned by nature. I have rewritten the code to use the carry (CS and CC).
Normally this will not cause a problem because all ROM and RAM is in a region where the MSB bit31 is not used. But i just prefer to use unsigned calculations and comparisons on memory addresses.

I have for now disabled the remapping of the memory.


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.45 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 .
// Core 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.
//
// When the lSB bit0 of Register RM in a BX instruction is 1, The core will switch to Thumb state.
// With ARM and thumb memory addresses, bit0 is always 0 because of the alignment on a 4 byte boundary
// or on a 2 byte boundary(THUMB).
// SEARCH FOR DEBUG to find any debug code enabled !
// ************************************************************************************************
//

// 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     ROM_soft_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.
      
      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,pc}^      // Restore registers and return.

                                                                        
// ************************************************************************************************
// 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.
// ************************************************************************************************
//
_asm_setup_ram:
      LDR     r0,=_asm_ram_vectortable      // Load ROM start address of vector table in R0.
      LDR     r1,=_reset                           // Load ROM end address of vector table.
      LDR         r2,=_ASM_RAM_START               // Load memory address of ram start.

_asm_loop_cpy_vectable:
      CMP     r0,r1                                    // Do r0 - r1 . If r0 < r1, Carry = 0 = CC.                        
      LDMCCIA r0!,{r3}                              // If C = 1 = CS then do not execute.
      STMCCIA r2!,{r3}                              // IF START < END execute instr.
      BCC     _asm_loop_cpy_vectable         



// ************************************************************************************************
// 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.
            LDR      r2,[r0]                           // Read the value at address 0x14(r0)
            CMP      r1,r2                                 // If (r2) != (r1) = REMAP_CHECK_VALUE, execute the following 3 instr.
   
// DEBUG code.   
//         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.
//
// ************************************************************************************************
_cstartup:                                       
      LDR         r0,=__fastcode_load         // Relocate .fastcode section (copy from ROM to RAM)
      LDR         r1,=__fastcode_start
      LDR         r2,=__fastcode_end
_asm_loop_cpy_fastcode:
      CMP         r2,r1                              // Do r2 - r1 . If r2 > r1 or r2 = r1, Carry = 1 = CS.   
      LDMCSIA   r0!,{r3}                        // If C = 0 = CC then do not execute.
      STMCSIA   r1!,{r3}                        // IF END >= START execute instr.
      BCS         _asm_loop_cpy_fastcode   

   
      LDR     r0,=__data_load               // Relocate the .data section (copy from ROM to RAM)
      LDR     r1,=__data_start
      LDR     r2,=__data_end
_asm_loop_cpy_data:
      CMP         r2,r1                                 
      LDMCSIA   r0!,{r3}                        
      STMCSIA   r1!,{r3}                        
      BCS         _asm_loop_cpy_data   


      LDR         r1,=__bss_start               // Clear the .bss section (zero init)
      LDR         r2,=__bss_end
      MOV         r3,#0
_asm_loop_clr_bss:
      CMP         r2,r1
      STMCSIA   r1!,{r3}
      BCS         _asm_loop_clr_bss


      LDR         r1,=__stack_start            // Fill the .stack section
      LDR         r2,=__stack_end
      LDR         r3,=STACK_FILL
_asm_loop_fill_stack:
      CMP         r2,r1
      STMCSIA   r1!,{r3}
      BCS         _asm_loop_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.
      LDR       r12,=System_Int_Handler                     // fiq_r12 stores the memory address where to jump to.
                                                                        // for the system interrupt.

    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_soft_reset:
      B   ROM_soft_reset

ROM_UndefHandler:
      B ROM_UndefHandler
   
ROM_SWIHandler:
      B ROM_SWIHandler

ROM_PAbortHandler:
      B ROM_PAbortHandler

ROM_DAbortHandler:
      B ROM_DAbortHandler
   
ROM_IRQHandler: // DEBUG code.
      B ROM_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,pc}^      // Restore registers and return.
 
ROM_FIQHandler: // DEBUG code.

      SUB       r14,r14,#4                        // Adjust lr to proper address.                
      STMFD      r13!,{r0-r7,r12,r14}      // Save registers to stack.
            
      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.
      
 
   .weak ExitFunction
   .weak UndefHandler, PAbortHandler, DAbortHandler
   .end

//   EOF


Last edited by William_Gaatjes on Sun Sep 12, 2010 5:18 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sun Sep 12, 2010 4:23 pm 
Offline

Joined: Thu Feb 25, 2010 5:02 pm
Posts: 88
Hello -

I notice you are running in Thumb mode. Thumb instructions are 16bit not 32bit. I assume you are also compiling Thumb.

If so, you might try adding a nop to properly align the FIQ entry point.

Code:
   .word      REMAP_CHECK_VALUE    // address 0x0000 0014 = Reserved. Write REMAP CHECK value for remap testing.               
    ADD   pc,pc,#0x16            // address 0x0000 0018 = IRQ interrupt. Relative JUMP to RAM_IRQHandler is executed.
    MOV   r8,r8                       // nop - Used for Thumb compilation
                                           // to align the FIQ entry point
                                             // 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.


Regards,

_________________
Duane P. Fridley, IEEE CSDP
Viable Bytes, Inc.


Last edited by dfridley on Sun Sep 12, 2010 4:29 pm, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sun Sep 12, 2010 4:34 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
Hello, thank you for responding. I checked and i am not running in thumb mode. I am running in ARM only at the moment.
I think you mean the ADD pc,pc#0x16. instruction in the vector table.

I was a bit tired last night and forgot B branches are relative with respect to the pc. As such i placed an add to see if it works which afcourse did not help. I placed a B again because that should work fine.

Right now i am still figuring out what i have done wrong.
:(


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Sun Sep 12, 2010 4:46 pm 
Offline

Joined: Thu Feb 25, 2010 5:02 pm
Posts: 88
Opps.. sorry looking at the wrong version of code.

Regards,

_________________
Duane P. Fridley, IEEE CSDP
Viable Bytes, Inc.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Wed Sep 15, 2010 10:39 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
Well, I have not yet resolved the ram copy issue. I did found quite a few bugs and errors in my startup.s and the c sources program and solved them.

As such i worked on another solution i was working on.
I have programmed the TWI to use the interrupt on TXCOMP only.
I use the TWI to communicate with the MCP23008. And it works great. :)
I know that because of the NACK errata i cannot use the NACK flag.
I solved that issue by writing in configuration DEFVAL of the MCP23008 a value 0x55 and then i read it back. I do this once while i am configuring the MCP23008. Afcourse for safety guard i can do this on a regular basis once every few transfers. If i do not get the proper data back, i know there is something wrong. It is not perfect but it will allow me to know if i have the MCP23008 connected to the TWI / I2C bus and that the bus is working properly. If anyone uses an eeprom, this is an idea to use for small transfers. THis i solved and i am happy with the result.

What is my new issue :
I am now rewriting the interrupt part of my program. I use the AIC and have read the datasheet for the SAM7S from Atmel a few times.
I use the LDR instruction that Atmel recommends.

When i use the LDR PC,[PC,# -&F20] with the GNU compiler i get an error when i compile :

src/startup.s:86: Warning: Unary operator - ignored because bad operand follows
src/startup.s:87: Warning: Unary operator - ignored because bad operand follows
src/startup.s:86: Error: undefined symbol `F20' in operation
src/startup.s:403: Error: can't resolve value for symbol `L0'
src/startup.s:87: Error: undefined symbol `F20' in operation
src/startup.s:403: Error: can't resolve value for symbol `L0'


Does anybody know how to solve this ?
I am really happy with the AIC and i want to use it.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Wed Sep 15, 2010 10:54 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
Never mind.

LDR PC,[PC,# -&F20] = the same as LDR PC,[PC,# -0xF20]

The & is similar as 0x.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Fri Sep 17, 2010 6:40 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
I have not solved the issue with the code problem above. But i did however solve the entire problem differently and i think the way it should be done.

I will create a separate assembler file with the interrupt handlers in it. And the code in this file will be linked in such a way that it is stored in rom and loaded in ram as the examples from quantum leaps with respect to fast code. The assembler part of the handler is small and calls upon C functions also stored in the fastcode section. I also have now the AIC working, i have multiple interrupts running. When i have finished and tested the code, i will post it on sourceforge at my W-ARM project for those interested... All code that i will write i will post there once it is mature enough(Meaning i put in comments and took out bugs) to share with others (For free afcourse).

I am happy that i found the proper way. Now i do not have to think about memory addresses. I will let the linker worry about that. The linker is much better at it then i am.


Top
 Profile  
 
 Post subject: Re: What have i overlooked here with my FIQ interrupt ?
PostPosted: Fri Sep 17, 2010 11:17 pm 
Offline

Joined: Sun Jan 03, 2010 5:18 pm
Posts: 22
Yahoooo. :mrgreen: :mrgreen: :mrgreen: :mrgreen: :mrgreen: :mrgreen:

I have done it.

I have written all the code : ram vectors and interrupt handlers in assembler language and in c language stored in rom and it is loaded in ram as fastcode.
After that i do the copying of fastocde, data and bss. stack filling. in startup.s . Then i do in assembler the remapping of the ram to adress 0x0000 0000. just before i jump into my main. The increase in speed is very noticable. Now i see the raw speed of the SAM7S for the first time.
:twisted:

When i have put in the comments, i will place the example code on sourceforge and i will post here on the date of placement.
Now i have standard 9 interrupts running. 1 FIQ for system interrupt through the PIT and a maximum of 8 IRQ interrupts for devices as standard but can be expanded up to 32. I use the AIC. I use separate handlers for each interrupt for now but i will have to add the saving of the registers as well. I use the irq stack and not the system stack. I have the FIq stack, irq stack, supervisor stack and the user /system stack.

Later on i want to put the SWI handler as well inside the fastcode.
Time to sleep to load up for a programming challenge tomorrow.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: