-
Notifications
You must be signed in to change notification settings - Fork 3
Timer's IRQ example
This example demonstrates the Timer's IRQ handling on EMSK board
- Demonstrates minimalistic CRT (C Run-Time) start-up code for EM4/EM6 core
- Demonstrates how to install handlers dynamically
- Demonstrates how to work with auxiliary registers in ARC GNU
- Demonstrates how to setup timers
- Demonstrates basic IRQ handling and configuration
- Demonstrates how to control EMSK LEDs
- The example requires ARC 4.8-R4 at least
- The example works only on EMSK configurations with full register set (reduced register set was not supported by compiler for now)
- cachectrl.c -- functions for I/D-cache invalidations
- cachectrl.h -- support header for cachectrl.c
- crt0.s -- minimalistic CRT (C Run-Time) start-up code for EM4/EM6 core
- leds.c -- LEDs initialization and control function
- leds.h -- support header for leds.c
- link_arcem4.ln -- linker script for EMSK EM4 configuration 0
- Makefile -- master makefile
- Makefile.os_specific -- support makefile with some OS (Windows/Linux) specific stuff
- setvect.c -- functions to set IRQ/Exceptions dynamically
- setvect.h -- support header for setvect.c
- test.c -- the test application
The initialization contains three parts:
-
LEDs initialization
First we need to obtain the GPIO base address.
ulGPIOBaseAddress = __builtin_arc_lr(PERIPHERAL_BASE_ADDRESS) + GPIO_BASE_ADDR;The ulGPIOBaseAddress contains the GPIO base address.
LEDs_Init(ulGPIOBaseAddress);The second, we need to setup GPIO as LEDs. So the LEDs_Init() setups the output direction for GPIO and clear LEDs. Please make sure that 1 in data register means the LED is off (inverted control).
-
IRQ controller initialization
First we need disable all interrupts before working with IRQ. Of course most of operations are atomic but this is good practice and allows avoid any possible issues.
__builtin_arc_clri();Second, setup IRQ handler dynamic. If the IVT locates in writable memory, the handler may be set dynamic in application flow. Otherwise the handler should be hard-coded in the IVT. Helper function _setvecti() set handler for desired IRQ number.
_setvecti(16, IRQ_Timer0); _setvecti(17, IRQ_Timer1);Also we configure hardware to store and restore all possible registers automatically.
__builtin_arc_sr(AUX_IRQ_CTRL_SAVE_ALL, AUX_IRQ_CTRL);Third, after all configurations (include LEDs and timers), we should enable interrupts and set the level of sensitive. The timers in EMSK 1.0 and 1.1 have levels 0 and 1, so it is enough to set sensitive to 2.
__builtin_arc_seti(ENABLE_INTERRUPTS | 2); -
Timers initialization We need to set limit, enable timer's interrupt and reset counter. User can chose the timer by changing the
TIMER_NUMBERif the design supports multiple timers.__builtin_arc_sr(0x1FFFFF, TIMER0_LIMIT);//set limit __builtin_arc_sr(TIMER_CONTROL_IE, TIMER0_CONTROL);//enable interrupt __builtin_arc_sr(0x00, TIMER0_COUNT);//reset counter
Main infinite loop writes current timer counter value (variable gn_TimerCount) to LEDs. Thus LEDs represents 9-bit binary value of counter.
while(1){ LEDs_Write(ulGPIOBaseAddress, ~gn_TimerCount);}
The timer's interrupt handlers are similar and have only one difference. The timer's 0 handler decrements gn_TimerCount. Otherwise timer's 1 handler increments gn_TimerCount.
The interrupt handler in opposite regular function uses special attribute in declaration:
void IRQ_Timer0(void) __attribute__ ((interrupt ("ilink")));
void IRQ_Timer1(void) __attribute__ ((interrupt ("ilink")));
Thus compiler insert special prologue (interrupt entry code) and epilog (interrupt exit code).
The interrupt handler for timer should clear pending flag inside handler. Otherwise the handler will be called after exit immediately.
unsigned int t_ctrl = __builtin_arc_lr(TIMER0_CONTROL);
t_ctrl &= ~TIMER_CONTROL_IP;//clear IP bit
__builtin_arc_sr(t_ctrl, TIMER0_CONTROL);
After that handler increments or decrements the gn_TimerCount.
The start-up code contains following major parts:
-
IVT table
-
Minimalistic start-up. It initialize stack pointer (SP) and global pointer (GP)
mov gp, @__SDATA_BEGIN__ mov sp, @__stack_topAnd jump to the
main. -
Default handlers for exceptions and interrupts. The handler halts CPU
_exit_halt: ; r0 contains exit code flag 0x01 ; halt CPU nop nop nop j @_exit_halt nop