Piconomic Logo www.piconomic.co.za

Atmel AT91SAM quick start guide

This is a quick start guide for the person with general embedded programming experience that wants to switch to the Atmel AT91SAM series microcontroller and learns by example.

The following free software tools are needed:
  • YAGARTO GNU ARM toolchain 01.05.2010 : a suite of executable, open source software development tools for ARM microcontrollers hosted on the Windows platform. It includes the GNU GCC compiler for C and C++.
  • WinAVR 20100110 : packaged with many native Win32 GNU programs and utilities including make and bash.
  • OpenOCD 0.4.0 : JTAG software to program and debug 32-bit microcontrollers.
  • Atmel AT91 Software Library v1.5 : contains board and device specific files (C-Startup files, low level initialization, register description files), peripheral APIs, on-board components configuration files, USB Framework and utilities.
  • Tera Term 4.66 : Free terminal emulation software for Windows.
  • or PuTTY : a free SSH and telnet client for Windows.

Note! OpenOCD 0.4.0 is built with the open source libftdi + libusb-win32 libraries. Read Sparkfun Forum > OpenOCD 0.2.0 - Windows installer. It is recommended that you follow the steps in How to build OpenOCD with FTDI's CDM driver for Windows.

Reference documentation:
Other resources:
Books:
Sections:
Tutorials:
/tutorials : Atmel AT91SAM tutorials
Examples:
/examples : Atmel AT91SAM examples

Introduction

With increased flexiblity comes increased complexity. The learning curve for 32-bit ARM microcontrollers is much steeper than for example 8-bit Atmel AVR microcontrollers. To become really proficient one needs to learn how to use several new tools and syntaxes:
Tip: it is advised that if your time equals money and you would rather spend your time developing and debugging new firmware applications then you should turn to a cost effective toolchain with board support packages from Rowley Crossworks and buy a CrossConnect JTAG debugger.

C Run time initialisation (arm_crt0.S)

99% of the magic happens before your main() function is called. This is the place where most things can go wrong and also the hardest to debug. With this library, assembler start up code is provided that:
1. Routes the exception vectors to handlers
2. Copies the exception vector code to internal SRAM in preparation for remapping
3. Copies specific C functions or global variables to internal SRAM (with __attribute__ ((section (".text.sram"))))
4. Calls a low level board initialisation routine written in C (board_lowlevel_init())
5. Initialises the DATA section (C variables with initial values)
6. Clears the BSS section (C variables that should be set to zero)
7. Initialises a stack for each processor mode (FIQ, IRQ, UND, ABT, SVC, SYS)
8. Puts the processor in SYSTEM mode and enables IRQ and FIQ
9. Calls the C function main()
The file arch/arm/arm.c contains the default exception handlers. These handlers are defined as "weak" so that they can be redefined.
References:
File (extract): arch/arm/arm_crt0.S
.section .vectors, "ax" /* Declare that the following code goes into the .vectors segment */
.code 32                /* Select ARM instruction set */

.global _start          /* Specify global symbol */
_start:

/* 
 * Exception handling vector table
 * See [2], Table 2-3 "Exception processing modes", page A2-13
 */
#ifdef ARM_DEBUG_WAIT
vect_rst:  ldr pc, =vect_rst            /* 0x00 : Reset */
#else
vect_rst:  ldr pc, =arm_crt0_rst        /* 0x00 : Reset */
#endif

vect_und:  ldr pc, =arm_handler_und     /* 0x04 : Undefined Instruction */

vect_swi:  ldr pc, =arm_handler_swi     /* 0x08 : Software Interrupt (SWI) */

vect_pref: ldr pc, =arm_handler_pref    /* 0x0C : Prefetch Abort (instruction fetch memory abort) */

vect_data: ldr pc, =arm_handler_data    /* 0x10 : Data Abort (data access memory abort) */

vect_rsvd: nop                          /* 0x14 : Reserved */

#ifdef ARM_AUTO_VECTORING_IRQ
vect_irq:  ldr pc, [pc,#-0xF20]         /* 0x18 : IRQ (interrupt request) */
#else
vect_irq:  ldr pc, =arm_handler_irq     /* 0x18 : IRQ (interrupt request) */
#endif

vect_fiq:  ldr pc, =arm_handler_fiq     /* 0x1C : FIQ (fast interrupt request) */

/* Literal pool (constants) */
.ltorg

/* _____SECTION______________________________________________________________ */

.section .init, "ax" /* Declare that the following code goes into the .init segment */
.code 32             /* Specify ARM instruction set */

arm_crt0_rst:
#ifdef str912fw44
        /* Wait for oscillator to stabilise - required for STR91x */
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
#endif

        /* Initialise stack pointer temporarily to the top of the stack */
        ldr     sp, =_stack

#ifdef DEBUG
        /*
         * Set stack limit to the bottom of the stack if stack checking is enabled.
         * See [6], §3.18 "Options for Code Generation Conventions", gcc switch -fstack-check
         */
        ldr     sl, =__stack_start

        /*
         * Initialise frame pointer to zero to support stack frames for debugger
         * See [5], §6.1 "Stack frames"
         *
         * R7 is used as the Thumb frame pointer.
         */
        mov     fp, #0
        mov     r7, #0
#endif

#ifndef ARM_NO_REMAP
        /* Remapping support: Copy .vectors segment to .vectors.sram */
        ldr     r0, =__vectors_load
        ldr     r1, =__vectors_start
        ldr     r2, =__vectors_end
1:
        cmp     r1, r2
        ldrlo   r3, [r0], #4
        strlo   r3, [r1], #4
        blo     1b

        /* Copy executable code to .text.sram segment */
        ldr     r0, =__text_sram_load
        ldr     r1, =__text_sram_start
        ldr     r2, =__text_sram_end
1:
        cmp     r1, r2
        ldrlo   r3, [r0], #4
        strlo   r3, [r1], #4
        blo     1b
#endif

        /*
         * Initialise low level hardware by calling board_lowlevel_init().
         * 
         * ARM-Thumb Procedure calling standard (ATPCS) is followed for 
         * ARM/Thumb interworking code, to support case where board_lowlevel_init() 
         * is compiled in thumb mode WITH interworking.
         *
         * The return address (arm_crt0_init) is explicitely hard-coded ("mov lr,pc" not used)
         * to keep code position independant.
         */
        ldr     r0, =board_lowlevel_init
        ldr     lr, =arm_crt0_init
        bx      r0

arm_crt0_init:
        /* Copy initialisation values to .data segment */
        ldr     r0, =__data_load
        ldr     r1, =__data_start
        ldr     r2, =_edata
1:
        cmp     r1, r2
        ldrlo   r3, [r0], #4
        strlo   r3, [r1], #4
        blo     1b

        /* Clear the .bss segment */
        ldr     r0, =__bss_start__
        ldr     r1, =__bss_end__
        mov     r2, #0
1:
        cmp     r0, r1
        strlo   r2, [r0], #4
        blo     1b

#ifdef DEBUG
        /* Fill the .stack segment with magic values to debug stack overflows */
        ldr     r0, =__stack_start
        ldr     r1, =_stack
        ldr     r2, =0xCCCCCCCC
1:
        cmp     r0, r1
        strlo   r2, [r0], #4
        blo     1b
#endif

        /* Change modes (with IRQ and FIQ disabled) to setup stacks */
        msr     CPSR_c, #ARM_MODE_FIQ | ARM_I_BIT | ARM_F_BIT
        ldr     sp, =__stack_fiq_top

        msr     CPSR_c, #ARM_MODE_IRQ | ARM_I_BIT | ARM_F_BIT
        ldr     sp, =__stack_irq_top

        msr     CPSR_c, #ARM_MODE_UND | ARM_I_BIT | ARM_F_BIT
        ldr     sp, =__stack_und_top

        msr     CPSR_c, #ARM_MODE_ABT | ARM_I_BIT | ARM_F_BIT
        ldr     sp, =__stack_abt_top

        msr     CPSR_c, #ARM_MODE_SVC | ARM_I_BIT | ARM_F_BIT
        ldr     sp, =__stack_svc_top

        msr     CPSR_c, #ARM_MODE_SYS | ARM_I_BIT | ARM_F_BIT
        ldr     sp, =__stack_sys_usr_top

        /* End in SYSTEM mode with interrupts enabled */
        msr     CPSR_c, #ARM_MODE_SYS

        /*
         * Call main() using ATPCS
        */
        ldr     r0, =main
        ldr     lr, =_fini
        bx      r0

/* Literal pool (constants) */
.ltorg

/* _____SECTION______________________________________________________________ */

.section .fini, "ax"  /* Declare that the following code goes into the .fini segment */
.code 32              /* Select ARM instruction set */

.global _fini         /* Specify global symbol */
_fini:
        /* Loop forever */
        b       _fini

.end

IRQ Handler (arm_irq.S)

A handler is provided that allows nested interrupts. This means that while an interrupt handler is executing, it may be interrupted by a higher priority interrupt and resumed after the higher priority interrupt has finished.
The IRQ exception handler will change to SYSTEM mode with IRQ and FIQ enabled before calling an ordinary C function handler. The SYSTEM stack will be used, not the IRQ stack.
Example of writing an interrupt handler in C:
References:
File (extract): arch/arm/AT91/arm_irq.S
.section .text.sram, "ax" /* Declare that the following code goes into the SRAM segment */
.code 32                  /* Select ARM instruction set */

.global arm_handler_irq
arm_handler_irq:
        /* 
         * Adjust LR_IRQ to correct return adres (compensate for pipelining) 
         * and save on the IRQ stack.
         */
        sub     lr, lr, #4
        stmfd   sp!, {lr}

        /* Make a copy of SPSR_IRQ (R14 = LR) */
        mrs     r14, SPSR

        /*
         * See if IRQ happened just as it was being disabled. Refer to [2]
         *
         * If this is the case return immediately. The interrupt will remain
         * pending since it has not been acknowledged. It will be reissued 
         * when interrupts are next enabled.
         */
        tst     r14, #ARM_I_BIT
        ldmnefd sp!, {pc}^

        /* Save R12 and R14(SPSR_IRQ) on the IRQ stack */
        stmfd   sp!, {r12, r14}

        /* 
         * Read the Interrupt Vector Registor (IVR) to determine which 
         * C handler to call.
         */
        ldr     r14, =AT91C_BASE_AIC
        ldr     r12, [r14, #AIC_IVR]

#ifdef DEBUG
        /* Write to the IVR to support Protect Mode */
        str     r12, [r14, #AIC_IVR]
#endif

#ifdef ARM_NO_NESTED_IRQ
        /* Change to SYSTEM mode (FIQ enabled) */
        msr     CPSR_c, #ARM_MODE_SYS | ARM_I_BIT
#else
        /* Change to SYSTEM mode (IRQ and FIQ enabled) */
        msr     CPSR_c, #ARM_MODE_SYS
#endif

        /*
         * Call C Handler in SYSTEM mode.
         *
         * All AAPCS registers used are saved to the SYSTEM stack, except
         * for R12 which is already saved to the IRQ stack. The handler must
         * save and restore other registers (if used).
         *
         * ARM-Thumb interworking is supported with "bx" instruction.
         *
         */        
        stmfd   sp!, {r0-r3, lr}
        mov     lr, pc
        bx      r12

        /* Restore AAPCS registers (except R12) from SYSTEM stack */            
        ldmfd   sp!, {r0-r3, lr}

        /* Return to IRQ mode with IRQ disabled (FIQ enabled) */
        msr     CPSR_c, #ARM_MODE_IRQ | ARM_I_BIT

        /* Acknowledge interrupt by writing to AIC_EOICR */
        ldr     r14, =AT91C_BASE_AIC
        str     r14, [r14, #AIC_EOICR]

        /* Restore R12 and R14 from IRQ stack */
        ldmfd   sp!, {r12, r14}

        /* Restore SPSR_IRQ */
        msr     SPSR_cxsf, r14

        /* Return and change mode (CPSR = SPSR_IRQ) */
        ldmfd   sp!, {pc}^

/* Literal pool (constants) */
.ltorg

.end

Linker scripts

Linker scripts defines the address and size of memory sections. It also dictates where each section should be placed in memory and defines symbols to mark specific memory locations.
File (extract): arch/arm/AT91/boards/linker_scripts/at91sam7s256-rom.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm","elf32-littlearm")

/*
 * Specify the output machine architecture.
 */
OUTPUT_ARCH(arm)

/*
 * Specify the program entry point (first instruction to be executed)
 */
ENTRY(_start)

/*
 * Describe the location and size of blocks of memory in the target
 */
MEMORY
{
    FLASH (rx)   : ORIGIN = 0x00100000, LENGTH = 256k
    SRAM  (w!rx) : ORIGIN = 0x00200000, LENGTH = 64k
}

/*
 * Define stack sizes
 */
STACK_SIZE_SYS_USR = 2048;
STACK_SIZE_SVC     = 0;
STACK_SIZE_ABT     = 0;
STACK_SIZE_UND     = 0;
STACK_SIZE_IRQ     = 8*12; /* 8 level deep nested IRQ stack, 3 registers pushed on stack */
STACK_SIZE_FIQ     = 0;

/* 
 * Inform linker how to map input sections into output sections, and how to 
 * place the output sections in memory.
 */
SECTIONS
{
  /*
   * VECTORS section holds the ARM exception vectors.
   * These instructions are executed at 0x0 (VMA), but loaded at the start of FLASH (LMA)
   */
  .vectors 0x00000000 :
  {
        __vectors_load  = LOADADDR(.vectors);
        KEEP (*(.vectors))
        . = ALIGN(4);
  } AT>FLASH

  /* Remapping support: Allocate space for VECTORS copied to SRAM */
  .vectors.sram :
  {
        __vectors_start = . ;
        . += SIZEOF(.vectors);
        __vectors_end = . ;
  } > SRAM

  /* 
   * Code in internal SRAM normally execute faster than in FLASH.
   * This is the prefered location for code that is frequently executed 
   * or needs to execute fast, e.g. IRQ and FIQ handler.
   * Code can be placed in this section by using the following C attribute:
   * __attribute__ ((section (".text.sram")))
   */
  .text.sram :
  {
        __text_sram_load = LOADADDR(.text.sram);
        __text_sram_start = . ;
        *(.text.sram .text.sram*)

        /* Prefered location of ARM-Thumb interworking veneers */
        *(.glue_7t)
        *(.glue_7)
        . = ALIGN(4);
        __text_sram_end = . ;
  } > SRAM AT>FLASH

  /*
   * INIT section holds executable instructions that contribute to the process
   * initialization code.
   */
  .init :
  {
        *(.init)
        . = ALIGN(4);
  } > FLASH

  /*
   * TEXT segment holds executable instructions
   */
  .text :
  {
        *(.text .stub .text.* .gnu.linkonce.t.*)

        /* ARM-Thumb interworking veneers */
        *(.glue_7t)
        *(.glue_7)
        *(.vfp11_veneer)
        . = ALIGN(4);
  } > FLASH

  /*
   * FINI section holds executable instructions that contribute to the process
   * termination code.
   */
  .fini :
  {
        *(.fini)
        . = ALIGN(4);
  } > FLASH  

  /*
   * RODATA and RODATA1 sections hold read-only data (constants).
   */
  .rodata :
  { 
        *(.rodata .rodata.* .gnu.linkonce.r.*)
        *(.rodata1)
        . = ALIGN(4);
  } > FLASH

  /*
   * DATA section holds initialized data; initialised on startup.
   * Initialisation values is stored in FLASH (LMA) and copied to SRAM (VMA)
   */
  .data :
  {
        __data_load  = LOADADDR(.data);
        __data_start = . ;
        
        *(.data .data.* .gnu.linkonce.d.*)
        KEEP (*(.gnu.linkonce.d.*personality*))
        SORT(CONSTRUCTORS)
        *(.data1)
        . = ALIGN(4);
        
        _edata = .;
        PROVIDE (edata = .);
  } > SRAM AT>FLASH

  /*
   * BSS section holds uninitialized data ; set to zero on startup.
   */
  .bss (NOLOAD) :
  {
        __bss_start   = .;
        __bss_start__ = .;
        *(.dynbss)
        *(.bss .bss.* .gnu.linkonce.b.*)
        *(COMMON)
        . = ALIGN(4);

        _bss_end__  = . ;
        __bss_end__ = . ;
  } > SRAM

  /*
   * STACK section holds the stack for each processor mode.
   */
  .stack :
  {
        __stack_start = . ;

        /* FIQ Stack */
        . += STACK_SIZE_FIQ;
        .  = ALIGN(4);
        __stack_fiq_top = . ;

        /* IRQ Stack */
        . += STACK_SIZE_IRQ;
        .  = ALIGN(4);
        __stack_irq_top = . ;

        /* UND Stack */
        . += STACK_SIZE_UND;
        .  = ALIGN(4);
        __stack_und_top = . ;

        /* ABT Stack */
        . += STACK_SIZE_ABT;
        .  = ALIGN(4);
        __stack_abt_top = . ;

        /* SVC Stack */
        . += STACK_SIZE_SVC;
        .  = ALIGN(4);
        __stack_svc_top = . ;

        /* SYS/USR Stack */
        . += STACK_SIZE_SYS_USR;
        .  = ALIGN(4);
        __stack_sys_usr_top = . ;
        
        _stack = . ;
  } > SRAM

  /* Mark the start of heap (if used) */
  __end__ = . ;
  _end    = . ;
  PROVIDE (end = . );

  /* Mark the end of SRAM */
  PROVIDE (__sram_end = ORIGIN(SRAM) + LENGTH(SRAM) );

  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }

Makefile

A Makefile template has been included that is based on the WinARM and WinAVR Makefile template. To use it, make a copy to your project directory (renamed to "Makefile") and edit to add the project files.
File: arch/ARM/Makefile.Template
It has the following features:
  • Allows a debug or release build (make CFG=debug | make CFG=release)
  • Allows an ARM instruction set only build, or mixed ARM/Thumb instruction set (USE_THUMB_MODE = YES | NO)
  • Allows specification of the MCU (e.g. MCU = arm7tdmi)
  • Generates various output files:
    • ELF File that can be used for programming and debugging (*.elf)
    • Intel HEX File that can be used for programming (*.hex)
    • Binary file that can be used for programming (*.bin)
    • Extended assembly listing file that can be used to verify that code has been correctly generated (*.lss)
    • Symbol file that can be used to verify the location (address) of functions and variables (*.sym)
  • GDB debugging support:
    • make gdb (Create a GDB init file, launch OpenOCD and GDB)
    • make openocd (Launch OpenOCD)
    • make telnet (Start telnet session with OpenOCD)
    • Allows OpenOCD to be launched within GDB or separately as a GDB server (DEBUG_PIPE = YES | NO)
  • Produces human readable output; see below
Build example (arch/arm/AT91/examples/led_blink):
-------- begin [build : debug] --------

arm-none-eabi-gcc (GCC) 4.5.0
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


Assembling (ARM): ../../../../../../../piconomic_fwlib/trunk/arch/arm/arm_crt0.S
arm-none-eabi-gcc -c -marm -mcpu=arm7tdmi -mthumb-interwork -I. -x assembler-with-cpp -Dat91sam7s256 -D__ASSEMBLY__ -DDEBUG -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -Wa,-adhlns=DEBUG/arm_crt0.lst,--gdwarf-2,--listing-cont-lines=100,-mfpu=fpa ../../../../../../../piconomic_fwlib/trunk/arch/arm/arm_crt0.S -o DEBUG/arm_crt0.o

Assembling (ARM): ../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91/arm_irq.S
arm-none-eabi-gcc -c -marm -mcpu=arm7tdmi -mthumb-interwork -I. -x assembler-with-cpp -Dat91sam7s256 -D__ASSEMBLY__ -DDEBUG -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -Wa,-adhlns=DEBUG/arm_irq.lst,--gdwarf-2,--listing-cont-lines=100,-mfpu=fpa ../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91/arm_irq.S -o DEBUG/arm_irq.o

Compiling (ARM): ../../../../../../../piconomic_fwlib/trunk/arch/arm/arm.c
arm-none-eabi-gcc -c -marm -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/arm.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/arm.o.d ../../../../../../../piconomic_fwlib/trunk/arch/arm/arm.c -o DEBUG/arm.o 

Compiling (THUMB): main.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/main.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/main.o.d main.c -o DEBUG/main.o 

Compiling (THUMB): board.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/board.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/board.o.d board.c -o DEBUG/board.o 

Compiling (THUMB): ../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91/systmr.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/systmr.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/systmr.o.d ../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91/systmr.c -o DEBUG/systmr.o 

Compiling (THUMB): ../../../../../../../piconomic_fwlib/trunk/general/tmr.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/tmr.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/tmr.o.d ../../../../../../../piconomic_fwlib/trunk/general/tmr.c -o DEBUG/tmr.o 

Compiling (THUMB): ../../../../../../../atmel_at91lib/peripherals/aic/aic.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/aic.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/aic.o.d ../../../../../../../atmel_at91lib/peripherals/aic/aic.c -o DEBUG/aic.o 

Compiling (THUMB): ../../../../../../../atmel_at91lib/peripherals/pit/pit.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/pit.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/pit.o.d ../../../../../../../atmel_at91lib/peripherals/pit/pit.c -o DEBUG/pit.o 

Compiling (THUMB): ../../../../../../../atmel_at91lib/boards/at91sam7s-ek/board_lowlevel.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/board_lowlevel.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/board_lowlevel.o.d ../../../../../../../atmel_at91lib/boards/at91sam7s-ek/board_lowlevel.c -o DEBUG/board_lowlevel.o 

Compiling (THUMB): ../../../../../../../atmel_at91lib/boards/at91sam7s-ek/board_memories.c
arm-none-eabi-gcc -c -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/board_memories.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/board_memories.o.d ../../../../../../../atmel_at91lib/boards/at91sam7s-ek/board_memories.c -o DEBUG/board_memories.o 

Linking: DEBUG/PROJECT.elf
arm-none-eabi-gcc -mthumb -mcpu=arm7tdmi -mthumb-interwork -I. -Dat91sam7s256 -Dtrace_LEVEL=3 -DNOTRACE -DDEBUG -mlong-calls -ffunction-sections -Wall  -fgnu89-inline -Wa,-adhlns=DEBUG/DEBUG/PROJECT.lst -I../../../../../../../atmel_at91lib -I../../../../../../../atmel_at91lib/peripherals -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek -I../../../../../../../atmel_at91lib/boards/at91sam7s-ek/at91sam7s256 -I../../../../../../../piconomic_fwlib/trunk -I../../../../../../../piconomic_fwlib/trunk/general -I../../../../../../../piconomic_fwlib/trunk/arch/arm -I../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91 -std=gnu99 -g -O0 -MMD -MP -MF DEBUG/PROJECT.elf.d DEBUG/arm_crt0.o DEBUG/arm_irq.o DEBUG/arm.o DEBUG/main.o DEBUG/board.o DEBUG/systmr.o DEBUG/tmr.o DEBUG/aic.o DEBUG/pit.o DEBUG/board_lowlevel.o DEBUG/board_memories.o --output DEBUG/PROJECT.elf -nostartfiles  -nodefaultlibs -Wl,-Map=DEBUG/PROJECT.map,--cref,--gc-sections  -lnosys -lm -lgcc -T ../../../../../../../piconomic_fwlib/trunk/arch/arm/AT91/boards/linker_scripts/at91sam7s256-rom.lds

Creating load file for Flash: DEBUG/PROJECT.hex
arm-none-eabi-objcopy -O ihex DEBUG/PROJECT.elf DEBUG/PROJECT.hex

Creating load file for Flash: DEBUG/PROJECT.bin
arm-none-eabi-objcopy -O binary DEBUG/PROJECT.elf DEBUG/PROJECT.bin

Creating Extended Listing: DEBUG/PROJECT.lss
arm-none-eabi-objdump -h -S DEBUG/PROJECT.elf > DEBUG/PROJECT.lss

Creating Symbol Table: DEBUG/PROJECT.sym
arm-none-eabi-nm -n DEBUG/PROJECT.elf > DEBUG/PROJECT.sym

Size after:
DEBUG/PROJECT.elf  :
section             size       addr
.vectors            0x3c        0x0
.vectors.sram       0x3c   0x200000
.text.sram          0x54   0x20003c
.init              0x140   0x100090
.text              0x600   0x1001d0
.fini                0x4   0x1007d0
.bss                 0x4   0x200090
.stack             0x460   0x200094
.comment            0x11        0x0
.debug_aranges     0x2a8        0x0
.debug_pubnames    0x3b0        0x0
.debug_info       0x16f5        0x0
.debug_abbrev      0x70f        0x0
.debug_line        0xc93        0x0
.debug_frame       0x62c        0x0
.debug_str         0x977        0x0
.debug_loc         0x90c        0x0
.debug_pubtypes    0x2db        0x0
.debug_ranges      0x1f0        0x0
.ARM.attributes     0x2c        0x0
Total             0x5b1a




-------- end [build : debug] --------

Extended assembly listing file

The Makefile also generates an extended assembly listing file from the generated ELF file:
   > arm-elf-objdump -h -S DEBUG/PROJECT.elf > DEBUG/PROJECT.lss 
It is advised that this file must be inspected to verify that the code has been correctly generated. Various errors can be detected this way. e.g.:
  • a section has been placed at the incorrect address (LMA or VMA)
  • sections overlap
  • startup code is not placed at the reset vector, i.e. 0x00000000
  • wrong absolute adresses
Example:
C_board_init.elf:     file format elf32-littlearm

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .vectors      00000054  00000000  00100000  00008000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .init         00000020  00100054  00100054  00008054  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .text         00000044  00100074  00100074  00008074  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  3 .stack        00000400  00200000  00200000  00010000  2**0
                  ALLOC
  4 .comment      00000011  00000000  00000000  000080b8  2**0
                  CONTENTS, READONLY
  5 .ARM.attributes 0000002c  00000000  00000000  000080c9  2**0
                  CONTENTS, READONLY

Disassembly of section .vectors:

00000000 <_start>:
   0:   e59ff030    ldr pc, [pc, #48]   ; 38 <arm_handler_fiq+0x4>

00000004 <vect_und>:
   4:   e59ff030    ldr pc, [pc, #48]   ; 3c <arm_handler_fiq+0x8>

00000008 <vect_swi>:
   8:   e59ff030    ldr pc, [pc, #48]   ; 40 <arm_handler_fiq+0xc>

0000000c <vect_pref>:
   c:   e59ff030    ldr pc, [pc, #48]   ; 44 <arm_handler_fiq+0x10>

00000010 <vect_data>:
  10:   e59ff030    ldr pc, [pc, #48]   ; 48 <arm_handler_fiq+0x14>

00000014 <vect_rsvd>:
  14:   e1a00000    nop         ; (mov r0, r0)

00000018 <vect_irq>:
  18:   e59ff02c    ldr pc, [pc, #44]   ; 4c <arm_handler_fiq+0x18>

0000001c <vect_fiq>:
  1c:   e59ff02c    ldr pc, [pc, #44]   ; 50 <arm_handler_fiq+0x1c>

00000020 <arm_handler_und>:
  20:   eafffffe    b   20 <arm_handler_und>

00000024 <arm_handler_swi>:
  24:   eafffffe    b   24 <arm_handler_swi>

00000028 <arm_handler_pref>:
  28:   eafffffe    b   28 <arm_handler_pref>

0000002c <arm_handler_data>:
  2c:   eafffffe    b   2c <arm_handler_data>

00000030 <arm_handler_irq>:
  30:   eafffffe    b   30 <arm_handler_irq>

00000034 <arm_handler_fiq>:
  34:   eafffffe    b   34 <arm_handler_fiq>
  38:   00100054    .word   0x00100054
  3c:   00000020    .word   0x00000020
  40:   00000024    .word   0x00000024
  44:   00000028    .word   0x00000028
  48:   0000002c    .word   0x0000002c
  4c:   00000030    .word   0x00000030
  50:   00000034    .word   0x00000034

Disassembly of section .init:

00100054 <arm_crt0_rst>:
  100054:   e59fd010    ldr sp, [pc, #16]   ; 10006c <arm_crt0_rst+0x18>
  100058:   e59f0010    ldr r0, [pc, #16]   ; 100070 <arm_crt0_rst+0x1c>
  10005c:   e1a0e00f    mov lr, pc
  100060:   e12fff10    bx  r0
  100064:   e1a00000    nop         ; (mov r0, r0)
  100068:   eafffffd    b   100064 <arm_crt0_rst+0x10>
  10006c:   00200400    .word   0x00200400
  100070:   00100074    .word   0x00100074

Disassembly of section .text:

00100074 <board_lowlevel_init>:
  100074:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
  100078:   e28db000    add fp, sp, #0
  10007c:   e3a0320a    mov r3, #-1610612736    ; 0xa0000000
  100080:   e1a039c3    asr r3, r3, #19
  100084:   e3a02001    mov r2, #1
  100088:   e5832000    str r2, [r3]
  10008c:   e3a0320a    mov r3, #-1610612736    ; 0xa0000000
  100090:   e1a039c3    asr r3, r3, #19
  100094:   e3a02001    mov r2, #1
  100098:   e5832010    str r2, [r3, #16]
  10009c:   e3a0320a    mov r3, #-1610612736    ; 0xa0000000
  1000a0:   e1a039c3    asr r3, r3, #19
  1000a4:   e3a02001    mov r2, #1
  1000a8:   e5832034    str r2, [r3, #52]   ; 0x34
  1000ac:   e28bd000    add sp, fp, #0
  1000b0:   e8bd0800    pop {fp}
  1000b4:   e12fff1e    bx  lr

The Red Hat newlib C Library

Most GCC compilers targeted for ARM, including Yagarto, is packaged with Newlib as the standard C library (libc.a and libm.a)
The C library depends on a handful of subroutine calls for operating system services. On a "bare board" system, without an operating system, do-nothing stubs (or subroutines with minimal functionality) must be provided to allow programs to link with the subroutines in libc.a
For example, if your program calls printf and your linker complains with:
   ... undefined reference to 'puts'
It means that you need specify to the linker (in the Makefile) that libc.a must be linked:
   #LDFLAGS += -nodefaultlibs
   or
   LDFLAGS += -lc
If libc.a is linked and the linker complains with:
   ... libg.a(lib_a-sbrkr.o): In function `_sbrk_r':
   ... newlib-1.18.0/newlib/libc/reent/sbrkr.c:60: undefined reference to `_sbrk'
   ... libg.a(lib_a-writer.o): In function `_write_r':
   ... newlib-1.18.0/newlib/libc/reent/writer.c:58: undefined reference to `_write'
   ... libg.a(lib_a-closer.o): In function `_close_r':
   ... newlib-1.18.0/newlib/libc/reent/closer.c:53: undefined reference to `_close'
   ... libg.a(lib_a-fstatr.o): In function `_fstat_r':
   ... newlib-1.18.0/newlib/libc/reent/fstatr.c:62: undefined reference to `_fstat'
   ... libg.a(lib_a-isattyr.o): In function `_isatty_r':
   ... newlib-1.18.0/newlib/libc/reent/isattyr.c:58: undefined reference to `_isatty'
   ... libg.a(lib_a-lseekr.o): In function `_lseek_r':
   ... newlib-1.18.0/newlib/libc/reent/lseekr.c:58: undefined reference to `_lseek'
   ... libg.a(lib_a-readr.o): In function `_read_r':
   ... newlib-1.18.0/newlib/libc/reent/readr.c:58: undefined reference to `_read'
It means that you need specify do-nothing stubs or subroutines with minimal functionality. See:
Documents:

JTAG Programming and debugging with OpenOCD

A word of warning first. The learning curve to use OpenOCD properly is steep, because one needs expert knowledge of the CPU too. If you are lucky, OpenOCD will work "out of the box", which it does for well supported targets. If not, be prepared to spend a fair bit of time to work out how to get OpenOCD working.
Support for OpenOCD is built into the Makefile template (arch/arm/Makefile.Template). As an example see /led_blink.
To start the OpenOCD server using Make:
   > make openocd
The Makefile generates a configuration file called "openocd.cfg" to select the JTAG interface, JTAG speed and board configuration script, which OpenOCD automatically detects and loads upon start up:
   source [find interface/olimex-jtag-tiny.cfg]
   source [find board/atmel_at91sam7s-ek.cfg]
   jtag_khz 3000
Alternatively, OpenOCD can be launched from the command line with:
   > openocd -f interface/olimex-jtag-tiny.cfg -f board/atmel_at91sam7s-ek.cfg -c "jtag_khz 3000"
openocd.png

OpenOCD server command line screenshot

To start a telnet session (interactive command line client) with the OpenOCD server using Make (requires Tera Term):
   > make telnet
Alternatively, Tera Term can be launched from the command line with:
   > ttermpro /T=1 telnet://localhost:4444/
telnet.png

Telnet interactive command line client screenshot

To start GDB (and launch OpenOCD if not already running) using Make:
   > make gdb
The Makefile launches GDB with a GDB script ("init.gdb"):
   # Connect to OpenOCD
   target remote localhost:3333
   # Resets and initialises the CPU (e.g. enable the crystal and PLL,...) 
   monitor reset init
   # Programs the FLASH with the new image and verify
   file DEBUG/PROJECT.elf
   load
   compare-sections
   # Run to main()
   thbreak main
   continue
Alternatively, GDB can be launched from the command line:
   > arm-none-eabi-gdb --command=init.gdb
gdb.png

GDB debug session screenshot

GDB and OpenOCD forms the pillars upon which an IDE like Eclipse builds to provide an ARM debugging platform. You are now ready to set up Eclipse:


OpenOCD Trouble shooting guide

Part 1:
Verify that OpenOCD can halt, reset, initialise and program a target.
Steps:
  • Make sure the board is powered!
  • Start OpenOCD
         > make openocd
    
  • OpenOCD can be configured to write debug output to a file for later examination and to file a bug report. Edit the Makefile:
         openocd -f $(DEBUG_INTERFACE) -f $(DEBUG_TARGET) -d 3 -l log.txt
    
  • Start a telnet session
         > make telnet
    
    • Get a list of commands
                > help
      
    • Can the target be halted?
                > halt
      
    • Reset the target
                > reset init
      
    • Is the target in the proper initialised reset state? Check crystal, PLL, peripherals,...Examine TCL script, e.g. target/at91sam7sx.cfg:
                $_TARGETNAME configure -event reset-init {
                    soft_reset_halt
                    # RSTC_CR : Reset peripherals
                    mww 0xfffffd00 0xa5000004
                    # disable watchdog
                    mww 0xfffffd44 0x00008000
                    # enable user reset
                    mww 0xfffffd08 0xa5000001
                    # CKGR_MOR : enable the main oscillator
                    mww 0xfffffc20 0x00000601
                    sleep 10
                    # CKGR_PLLR: 96.1097 MHz
                    mww 0xfffffc2c 0x00481c0e
                    sleep 10
                    # PMC_MCKR : MCK = PLL / 2 ~= 48 MHz
                    mww 0xfffffc30 0x00000007
                    sleep 10
                    # MC_FMR: flash mode (FWS=1,FMCN=73)
                    mww 0xffffff60 0x00490100
                    sleep 100
                    }
      
    • Is the JTAG frequency 6 times slower than the CPU frequency (for an interface that does not support adaptive clocking)?
                > jtag_khz
      
    • Test SRAM
                > mdw 0x00200000
                > mww 0x00200000 0xdeadbeef
                > mdw 0x00200000
      
    • Is the flash interface working?
                > flash probe 0
                > flash info 0
      
    • Can the flash be programmed?
                > flash write_image erase ./DEBUG/PROJECT.bin 0x00100000 bin
      
    • Is the image written to flash correct?
                > verify_image ./DEBUG/PROJECT.bin 0x00100000 bin
      
    • Stop telnet and OpenOCD
                > shutdown
      
Part 2:
Verify that C Run time initialisation (arm_crt0.S) works correctly.
Steps:
  • Create a GDB init script ("init.gdb")
          > make gdb-config
    
  • Edit "init.gdb" to stop at at 0x00000000 (global symbol "_start"):
          target remote localhost:3333
          monitor reset init
          file DEBUG/PROJECT.elf
          load
          compare-sections
          thbreak *0x00000000 # or thbreak _start
          continue
    
  • Launch OpenOCD
          > make openocd
    
  • Launch GDB manually (so that the Makefile does not overwrite "init.gdb"):
          > arm-none-eabi-gdb --command=init.gdb
    
    • To be safe, slow down the JTAG communication speed. This is to ensure that the JTAG communication is always 6 times slower than the CPU, which probably starts at 32kHz, and changes frequency during the low level C initialisation routine board_lowlevel_init().
                > monitor jtag_khz 8
      
    • You should now be in "arm_crt0.S". Single step through start up code
                > s
      
    • Step to just before the call to "board_lowlevel_init()"
    • Place a breakpoint after the call
                > b arm_crt0_init
      
    • Continue and see if the breakpoint is reached
                > c
      
Part 3:
Sometimes the code programmed on to the target may put it in an unknown or bad state before it can be halted by OpenOCD. To make code execution wait at the reset vector, the following steps must be followed:
  • #define ARM_DEBUG_WAIT (used in "arm_crt0.S") by editing the Makefile:
          # Place -D or -U options here for ASM sources
          ADEFS  = -D$(CHIP) -D__ASSEMBLY__ -DARM_DEBUG_WAIT
    
  • Rebuid project
          > make clean
          > make
    
  • Launch GDB manually as shown in part 2 with the following modified GDB init script:
          target remote localhost:3333
          monitor reset init
          file DEBUG/PROJECT.elf
          load
          compare-sections
          thbreak arm_crt0_rst
          jump arm_crt0_rst
    
Tip: the Makefile may be modified so that this becomes the standard way of debugging code, i.e. the code will always wait for the debugger to start.
Generated on Fri Aug 13 16:50:36 2010 for Piconomic Firmware Library by doxygen 1.6.3