irq_cm3.c

Go to the documentation of this file.
00001 
00038 #include <cfg/debug.h> /* ASSERT() */
00039 #include <cfg/log.h> /* LOG_ERR() */
00040 #include <cpu/irq.h>
00041 #include "irq_cm3.h"
00042 
00043 static void (*irq_table[NUM_INTERRUPTS])(void)
00044             __attribute__((section("vtable")));
00045 
00046 /* Priority register / IRQ number table */
00047 static const uint32_t nvic_prio_reg[] =
00048 {
00049     /* System exception registers */
00050     0, NVIC_SYS_PRI1, NVIC_SYS_PRI2, NVIC_SYS_PRI3,
00051 
00052     /* External interrupts registers */
00053     NVIC_PRI0, NVIC_PRI1, NVIC_PRI2, NVIC_PRI3,
00054     NVIC_PRI4, NVIC_PRI5, NVIC_PRI6, NVIC_PRI7,
00055     NVIC_PRI8, NVIC_PRI9, NVIC_PRI10, NVIC_PRI11,
00056     NVIC_PRI12, NVIC_PRI13
00057 };
00058 
00059 /* Unhandled IRQ */
00060 static NAKED NORETURN void unhandled_isr(void)
00061 {
00062     register uint32_t reg;
00063 
00064     asm volatile ("mrs %0, ipsr" : "=r"(reg));
00065     LOG_ERR("unhandled IRQ %lu\n", reg);
00066     while (1)
00067         PAUSE;
00068 }
00069 
00070 void sysirq_setPriority(sysirq_t irq, int prio)
00071 {
00072     uint32_t pos = (irq & 3) * 8;
00073     reg32_t reg = nvic_prio_reg[irq >> 2];
00074     uint32_t val;
00075 
00076     val = HWREG(reg);
00077     val &= ~(0xff << pos);
00078     val |= prio << pos;
00079     HWREG(reg) = val;
00080 }
00081 
00082 static void sysirq_enable(sysirq_t irq)
00083 {
00084     /* Enable the IRQ line (only for generic IRQs) */
00085     if (irq >= 16 && irq < 48)
00086         NVIC_EN0_R = 1 << (irq - 16);
00087     else if (irq >= 48)
00088         NVIC_EN1_R = 1 << (irq - 48);
00089 }
00090 
00091 void sysirq_setHandler(sysirq_t irq, sysirq_handler_t handler)
00092 {
00093     cpu_flags_t flags;
00094 
00095     ASSERT(irq < NUM_INTERRUPTS);
00096 
00097     IRQ_SAVE_DISABLE(flags);
00098     irq_table[irq] = handler;
00099     sysirq_setPriority(irq, IRQ_PRIO);
00100     sysirq_enable(irq);
00101     IRQ_RESTORE(flags);
00102 }
00103 
00104 void sysirq_freeHandler(sysirq_t irq)
00105 {
00106     cpu_flags_t flags;
00107 
00108     ASSERT(irq < NUM_INTERRUPTS);
00109 
00110     IRQ_SAVE_DISABLE(flags);
00111     irq_table[irq] = unhandled_isr;
00112     IRQ_RESTORE(flags);
00113 }
00114 
00115 void sysirq_init(void)
00116 {
00117     cpu_flags_t flags;
00118     int i;
00119 
00120     IRQ_SAVE_DISABLE(flags);
00121     for (i = 0; i < NUM_INTERRUPTS; i++)
00122         irq_table[i] = unhandled_isr;
00123 
00124     /* Update NVIC to point to the new vector table */
00125     NVIC_VTABLE_R = (size_t)irq_table;
00126     IRQ_RESTORE(flags);
00127 }