Files
bare-metal-pi/includes/rpi/interrupts.c
T
2016-10-19 00:23:03 -07:00

178 lines
4.4 KiB
C

#include <stdint.h>
#include <stdbool.h>
#include "armtimer.h"
#include "base.h"
#include "gpio.h"
#include "interrupts.h"
/** @brief The BCM2835/6 Interupt controller peripheral at it's base address */
static rpi_irq_controller_t* rpiIRQController =
(rpi_irq_controller_t*)RPI_INTERRUPT_CONTROLLER_BASE;
volatile int calculate_frame_count = 0;
/**
@brief Return the IRQ Controller register set
*/
rpi_irq_controller_t* RPI_GetIrqController( void )
{
return rpiIRQController;
}
/**
@brief The Reset vector interrupt handler
This can never be called, since an ARM core reset would also reset the
GPU and therefore cause the GPU to start running code again until
the ARM is handed control at the end of boot loading
*/
void __attribute__((interrupt("ABORT"))) reset_vector(void)
{
while( 1 )
{
LED_ON();
}
}
/**
@brief The undefined instruction interrupt handler
If an undefined intstruction is encountered, the CPU will start
executing this function. Just trap here as a debug solution.
*/
void __attribute__((interrupt("UNDEF"))) undefined_instruction_vector(void)
{
while( 1 )
{
/* Do Nothing! */
LED_ON();
}
}
/**
@brief The supervisor call interrupt handler
The CPU will start executing this function. Just trap here as a debug
solution.
*/
void __attribute__((interrupt("SWI"))) software_interrupt_vector(void)
{
while( 1 )
{
/* Do Nothing! */
LED_ON();
}
}
/**
@brief The prefetch abort interrupt handler
The CPU will start executing this function. Just trap here as a debug
solution.
*/
void __attribute__((interrupt("ABORT"))) prefetch_abort_vector(void)
{
while( 1 )
{
LED_ON();
}
}
/**
@brief The Data Abort interrupt handler
The CPU will start executing this function. Just trap here as a debug
solution.
*/
void __attribute__((interrupt("ABORT"))) data_abort_vector(void)
{
while( 1 )
{
LED_ON();
}
}
/**
@brief The IRQ Interrupt handler
This handler is run every time an interrupt source is triggered. It's
up to the handler to determine the source of the interrupt and most
importantly clear the interrupt flag so that the interrupt won't
immediately put us back into the start of the handler again.
*/
void __attribute__((interrupt("IRQ"))) interrupt_vector(void)
{
static int lit = 0;
static int ticks = 0;
static int seconds = 0;
/* Clear the ARM Timer interrupt - it's the only interrupt we have
enabled, so we want don't have to work out which interrupt source
caused us to interrupt */
RPI_GetArmTimer()->IRQClear = 1;
ticks++;
if( ticks > 1 )
{
ticks = 0;
/* Calculate the FPS once a minute */
seconds++;
if( seconds > 59 )
{
seconds = 0;
calculate_frame_count = 1;
}
}
/* Flip the LED */
if( lit )
{
LED_OFF();
lit = 0;
}
else
{
LED_ON();
lit = 1;
}
}
/**
@brief The FIQ Interrupt Handler
The FIQ handler can only be allocated to one interrupt source. The FIQ has
a full CPU shadow register set. Upon entry to this function the CPU
switches to the shadow register set so that there is no need to save
registers before using them in the interrupt.
In C you can't see the difference between the IRQ and the FIQ interrupt
handlers except for the FIQ knowing it's source of interrupt as there can
only be one source, but the prologue and epilogue code is quite different.
It's much faster on the FIQ interrupt handler.
The prologue is the code that the compiler inserts at the start of the
function, if you like, think of the opening curly brace of the function as
being the prologue code. For the FIQ interrupt handler this is nearly
empty because the CPU has switched to a fresh set of registers, there's
nothing we need to save.
The epilogue is the code that the compiler inserts at the end of the
function, if you like, think of the closing curly brace of the function as
being the epilogue code. For the FIQ interrupt handler this is nearly
empty because the CPU has switched to a fresh set of registers and so has
not altered the main set of registers.
*/
void __attribute__((interrupt("FIQ"))) fast_interrupt_vector(void)
{
}