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