Interrupts

The FT90x interrupt controller handles 32 interrupt inputs. When an interrupt occurrs, the Interrupt Service Route (ISR) will process this event via the CPU.
The ISR vector range is from 0 to 31, which corresponds to interrupt 0 to 31.

Each interrupt shall be assigned the interrupt vector number and priority before using. By default, the highest priority interrupt is interrupt 0, and the lowest is interrupt 31.
However, the interrupt priority can be rearranged by register settings and also allows multiple interrupts at the same priority.

Nested interrupts are allowed if enabled (by default they are disabled). Up to 16 levels of nesting is allowed which defaults to only 1 level if nesting is enabled.
When nesting is enabled, only interrupts with higher priorities can interrupt the current interrupt. Interrupts of same or lower priorities will be queued as long as the interrupt sources are not cleared.

Peripheral of Interrupt Interrupt Vector Index Default Priority
Power Management 0 0 (Non-Maskable)
EHCI Host Controller 1 1
USB2.0 Peripheral Controller 2 2
Ethernet Controller 3 3
SD Host Controller 4 4
CAN Bus 0 5 5
CAN Bus 1 6 6
Camera 7 7
SPI Master 8 8
SPI Slave 0 9 9
SPI Slave 1 10 10
I2C 0 11 11
I2C 1 12 12
UART 0 13 13
UART 1 14 14
I2S Bus 15 15
PWM 16 16
Timers 17 17
GPIO 18 18
RTC 19 19
ADC 20 20
DAC 21 21
Slow Clock Timer 22 22
UNUSED 23-31 23-31

FT90x default interrupt and priority table

Interrupt Service Routine

Interrupt service routine is defined in this way :

void interrupt() iv IVT_TIMERS_IRQ ics ICS_OFF {
  // Interrupt service routine code
}

where :

User can explicitly declare starting interrupt routine address using org directive :

void interrupt() org 0x0288 iv IVT_TIMERS_IRQ ics ICS_OFF {
  // Interrupt service routine code
}

Function Calls from Interrupt

Calling functions from within the interrupt routine is possible. The compiler takes care about the registers being used, both in "interrupt" and in "main" thread, and performs "smart" context-switching between two of them, saving only the registers that have been used in both threads. It is not recommended to use a function call from interrupt. In case of doing that take care of stack depth.

Disable Context Saving

Use the #pragma disablecontextsaving to instruct the compiler not to automatically perform context-switching.
This means that no register will be saved/restored by the compiler on entrance/exit from interrupt service routine.


This enables the user to manually write code for saving registers upon entrance and to restore them before exit from interrupt.

Interrupt Example

Here is a simple example of handling the interrupts from TimerA (if no other interrupts are allowed):

volatile char val;

// Timer interrupt function
void Timer_Interrupt() iv IVT_TIMERS_IRQ{
  // Toggle led value
  val = ~val;
  GPIO_PIN60_bit = val;
  GPIO_PIN17_bit = val;

  // Clear Timer A interrupt
  TIMER_INT.B0 = 1;
}

void main() {
  // Initialize LD1 as digital output
  GPIO_Pin_Digital_Output(_GPIO_PIN_NUM_60);
  // Initialize LD2 as digital output
  GPIO_Pin_Digital_Output(_GPIO_PIN_NUM_17);

  GPIO_PIN60_bit = 0;
  GPIO_PIN17_bit = 0;

  val = 0;

  // Enable the Timer module
  TIMER_CONTROL_0 = 2;

  // Select Timer A
  TIMER_SELECT = 0;

  // Write prescaler for Timer A
  TIMER_PRESC_LS = 10000;
  TIMER_PRESC_MS = 10000 >> 8;

  // Write start value
  TIMER_WRITE_LS = 10000;
  TIMER_WRITE_MS = 10000 >> 8;
  
  // Set continuous mode and direction down
  TIMER_CONTROL_3 = 0;
  
  // Trigger clearing timer A and prescaler
  TIMER_CONTROL_4 = 0x11;
  
  // Enable prescaler for Timer A
  TIMER_CONTROL_2 = 0x10;

  // Enable Timer A interrupt
  TIMER_INT.B1 = 1;

  // Enable global interrupts
  FT900_INTR_CTRL.B31 = 0;

  // Start timer A
  TIMER_CONTROL_1 = 1;

  while(1)
    ;
}
Copyright (c) 2002-2015 mikroElektronika. All rights reserved.
What do you think about this topic ? Send us feedback!
Want more examples and libraries? 
Find them on LibStock - A place for the code