Monday, February 1, 2016

ARM ::: A- Application; R Series - Exceptional performance for real-time applications ; M-Micro-controller

A = applicationR = real timeM = microcontroller
To the context ARM M resets when any exception rises, only 2 modes. 
The processor supports two operation modes, Thread mode and Handler mode. Thread mode is entered on reset and normally on return from an exception. When in Thread mode, code can be executed as either Privileged or Unprivileged.
Handler mode will be entered as a result of an exception. Code in Handler mode is always executed as Privileged, therefore the core will automatically switch to Privileged mode when exceptions occur.
You can change between Privileged Thread mode and User Thread mode when returning from an exception by modifying theEXC_RETURN value in the link register (R14). You can also change from Privileged Thread to User Thread mode by clearingCONTROL[0] using an MSR instruction. However, you cannot directly change to privileged mode from unprivileged mode without going through an exception, for example an SVC.

Main and Process Stacks

The Cortex-M3 supports two different stacks, a main stack and a process stack. To support this the Cortex-M3 has two stack pointers (R13). One of these is banked out depending on the stack in use. This means that only one stack pointer at a time is visible as R13. However, both stack pointers can be accessed using the MRS and MSR instructions.
The main stack is used at reset, and is always used in Handler mode (when entering an exception handler). The process stack pointer is only available as the current stack pointer when in Thread mode. You can select which stack pointer (main or process) is used in Thread mode in one of two ways, either by using the EXC_RETURN value when exiting from Handler Mode or while in Thread Mode by writing to CONTROL[1] using an MSR instruction.

Note

The process stack pointer will need to be initialized by your context switch code or your initialization code.
Super Muaahhh...
Application Note 179Cortex™-M3 Embedded Software Development

Exception handling

Writing the exception table

The easiest way to populate the vector table is to use a scatter file to place a C array of function pointers at memory address 0x0. The C array can be used to configure the initial stack pointer, image entry point and the addresses of the exception handlers.

Example 1. Example C structure for exception handlers
/* Filename: exceptions.c */
typedef void(* const ExecFuncPtr)(void) __irq;

/* Place table in separate section */
#pragma arm section rodata="exceptions_area"

ExecFuncPtr exception_table[] = {
 (ExecFuncPtr)&Image$$ARM_LIB_STACKHEAP$$ZI$$Limit,
 (ExecFuncPtr)__main, /* Initial PC, set to entry point */
 NMIException,
 HardFaultException,
 MemManageException,
 BusFaultException,
 UsageFaultException,
 0, 0, 0, 0, /* Reserved */
 SVCHandler,
 DebugMonitor,
 0, /* Reserved */
 PendSVC,SysTickHandler,

 /* Configurable interrupts start here...*/
 InterruptHandler0,
 InterruptHandler1,
 InterruptHandler2

 /*
 …
 */
};

#pragma arm section

Note

Note that the first two items in this structure are the initial stack pointer and the image entry point. The initial stack pointer is generated using a linker defined symbol. See Stack and heap configuration for details. Example 1 uses the C library entry point (__main) as the entry point for the image.
The exception table has also been placed in its own section. This has been done using #pragma arm section rodata="exceptions_area". This directive instructs the compiler to place all the RO (read-only) data between #pragma arm section rodata="exceptions_area"and #pragma arm sectioninto its own section called exceptions_area. This section can then be referred to in the scatter file. The exception table is then placed at the correct location in the memory map, at address0x0.

Writing the exception handlers

The core saves the system state when an exception occurs and restores it on return. The exception handlers do not therefore need to save or restore the system state and can be written as an ordinary ABI-compliant C function. However, we recommend that you use the __irq qualifier to aid clarity of code. The keyword is also used by the compiler to maintain eight-byte alignment of the stack where necessary. See Eight byte stack alignment for further details.

Example 2. Simple C exception handler
__irq void SysTickHandler(void)
{ printf("----- SysTick Interrupt -----");}

Note

Clearing of an interrupt source must be handled by the ISR.
On the Cortex-M3, exception prioritization, nesting of exceptions, and saving of corruptible registers is handled entirely by the core to permit efficient handling. This means that interrupts remain enabled by the core on entry to every exception handler.

Placing the exception table

Because the exception table has been placed in its own section in the object it can be easily placed at 0x0 using a scatter file as shown in Example 3.

Example 3.  Placing exception table in scatterfile
LOAD_REGION 0x00000000 0x00200000
{ ;; Maximum of 256 exceptions (256*4 bytes == 0x400)
 VECTORS 0x0 0x400 {  exceptions.o (exceptions_area, +FIRST) }}

Note

+FIRST is used to ensure that exceptions_area is placed at the very beginning of the region. It also prevents the vector table from being removed by the unused section elimination mechanism of the linker.

Configuring the System Control Space (SCS) registers

The SCS registers are located at 0xE000E000. As there are a large number of individual registers, it is best to use a structure to represent them. This can then be positioned in the correct memory location by adding this structure to the scatter file, using a similar method to the exception table. Example 4 shows an example structure for the SCS registers.

Example 4. SCS Register Structure
typedef volatile struct {
    int MasterCtrl;
    int IntCtrlType;    int zReserved008_00c[2];
         /* Reserved space */    struct {        int Ctrl;        int Reload;        int Value;        int Calibration;
    } SysTick;    int zReserved020_0fc[(0x100-0x20)/4];
            /* Reserved space */

    /* Offset 0x0100 */    struct {        int Enable[32];        int Disable[32];        int Set[32];        int Clear[32];        int Active[64];        int Priority[64];    } NVIC;    int zReserved0x500_0xcfc[(0xd00-0x500)/4];
            /* Reserved space */

    /* Offset 0x0d00 */    int CPUID;    int IRQcontrolState;    int ExceptionTableOffset;    int AIRC;    int SysCtrl;    int ConfigCtrl;    int SystemPriority[3];    int SystemHandlerCtrlAndState;    int ConfigurableFaultStatus;    int HardFaultStatus;    int DebugFaultStatus;    int MemManageAddress;    int BusFaultAddress;    int AuxFaultStatus;    int zReserved0xd40_0xd90[(0xd90-0xd40)/4];        
            /* Reserved space */

    /* Offset 0x0d90 */    struct {        int Type;        int Ctrl;        int RegionNumber;        int RegionBaseAddr;        int RegionAttrSize;
    } MPU;
} SCS_t;

Note

This register structure might not contain all of the SCS registers in your device. See the reference manual provided by the silicon manufacturer of your device.

Configuring individual IRQs

Each IRQ has an individual enable bit in the Interrupt Set Enable Registers, part of theNVIC registers. To enable an interrupt you need to set the corresponding bit in the Interrupt Set Enable Register. See the reference manual provided by the silicon manufacturer of the device you are using for specific details on the Interrupt Set Enable Register.
Example 5 shows interrupt enable code for the SCS structure shown in Example 4.

Example 5. IRQ enable function
void NVIC_enableISR(unsigned isr){ /* The isr argument is the number of the interrupt to enable. */ SCS.NVIC.Enable[ (isr/32) ] = 1<<(isr % 32);}

Note

Some registers in the SCS region can only be accessed from Privileged mode. Individual IRQs can be disabled by setting the appropriate bit in the Interrupt Clear Enable Registers.
Interrupt priorities
Each individual interrupt can be assigned a priority level via the Interrupt Priority Registers. Depending on the implementation, up to 256 different priority levels can be assigned to each individual interrupt. The priority levels are represented using up to 8 bits. Groups of four interrupt priorities are stored in each word of memory.
The lower the assigned priority number, the higher the priority of the interrupt. Therefore 0 is the highest priority and 255 the lowest.

Data alignment in Structure Padding doesn't have as much as importance on ARM as the compiler itself doesn't know, unlike the case of X86, pipe lining plays a role.

Example of calling an SVC from C code
#define SVC_00 0x00#define SVC_01 0x01void __svc(SVC_00) svc_zero(const char *string);void __svc(SVC_01) svc_one(const char *string);int call_system_func(void){    svc_zero("String to pass to SVC handler zero");    svc_one("String to pass to a different OS function");}


POINTER-BASED ADDRESSING MODES
We have already introduced addressing modes. Here we discuss the ARM processor’s register indirect
addressing mode that supports several variations. This is an important topic because it’s essential to the
efficient manipulation of data structures such as tables, arrays, matrixes, and vectors.
Let’s first review the basic concept of register indirect, or pointer-based, addressing. Indirect addressing specifies a pointer to
the actual operand which is invariably in a register. For example, the instruction, LDR r0,[r1], first reads the contents of
register r1 to obtain the pointer that gives you the address of the actual operand in memory. It then reads the memory location
specified by the pointer in r1 to get the required data. This addressing mode requires three memory accesses; the first is to read
the instruction to identify the register containing the pointer, the second is to read the contents of the register to get the pointer.
And the third is to get the desired operand at the location specified by the pointer.
You can easily see why this addressing mode is called indirect because the address register specifies the operand indirectly by
telling you where it is, rather than what it is. This is the only form of addressing that the ARM processor can use to access
memory. The box below describes three variations on this addressing mode and gives their assembly language forms, defines
the addressing mode (using RTL), and gives them names. The naming of addressing modes is not always consistent in
computer science and manufacturers sometimes use different names for the same addressing mode.

ARM PROCESSOR POINTER-BASED ADDRESSING MODES
1. LDR r1,[r0] r0 points at the operand
[r1] ← [[r0]]
Base register addressing
2. LDR r1,[r0,#4] The operand is 4 bytes on from the location pointed at by r0
[r1] ← [[r0 + 4]]
Pre-indexed addressing
3. LDR r1,[r0,#4]! The operand is 4 bytes on from the location pointed at by r0. After loading
the operand, the pointer register is incremented by 4
[r1] ← [[r0 + 4]]
[r0] ← [r0 ] + 4
Pre-indexed addressing with writeback
Autoincrementing preindexed addressing
4. LDR r1,[r0],#4 The operand is pointed at by r0. After making the access, r0 is updated by 4.
[r1] ← [[r0]]
[r0] ← [r0 ] + 4
Post-indexed addressing


https://drive.google.com/file/d/0ByOCd3q11OzBeDJGZWFVX0Q5MG8/view?usp=sharing

https://drive.google.com/file/d/0ByOCd3q11OzBdXQxT2VkcmRSYjQ/view?usp=sharing

https://drive.google.com/file/d/0ByOCd3q11OzBeWcycktWd3ZnelE/view?usp=sharing
https://drive.google.com/file/d/0ByOCd3q11OzBTmlPekNJMU40ckk/view?usp=sharing

No comments:

Post a Comment