initial interrupt stuff
taken from Contiki
This commit is contained in:
parent
d25385d2aa
commit
e012142abe
5 changed files with 579 additions and 0 deletions
84
src/interrupt-utils.c
Normal file
84
src/interrupt-utils.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $RCSfile: interrupt-utils.c,v $
|
||||
* $Revision: 1.2 $
|
||||
*
|
||||
* This module provides the interface routines for setting up and
|
||||
* controlling the various interrupt modes present on the ARM processor.
|
||||
* Copyright 2004, R O SoftWare
|
||||
* No guarantees, warrantees, or promises, implied or otherwise.
|
||||
* May be used for hobby or commercial purposes provided copyright
|
||||
* notice remains intact.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#include "interrupt-utils.h"
|
||||
|
||||
#define IRQ_MASK 0x00000080
|
||||
#define FIQ_MASK 0x00000040
|
||||
#define INT_MASK (IRQ_MASK | FIQ_MASK)
|
||||
|
||||
static inline unsigned __get_cpsr(void)
|
||||
{
|
||||
unsigned long retval;
|
||||
asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline void __set_cpsr(unsigned val)
|
||||
{
|
||||
asm volatile (" msr cpsr_c, %0" : /* no outputs */ : "r" (val) );
|
||||
}
|
||||
|
||||
unsigned disableIRQ(void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr | IRQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned restoreIRQ(unsigned oldCPSR)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr((_cpsr & ~IRQ_MASK) | (oldCPSR & IRQ_MASK));
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned enableIRQ(void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr & ~IRQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned disableFIQ(void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr | FIQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned restoreFIQ(unsigned oldCPSR)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr((_cpsr & ~FIQ_MASK) | (oldCPSR & FIQ_MASK));
|
||||
return _cpsr;
|
||||
}
|
||||
|
||||
unsigned enableFIQ(void)
|
||||
{
|
||||
unsigned _cpsr;
|
||||
|
||||
_cpsr = __get_cpsr();
|
||||
__set_cpsr(_cpsr & ~FIQ_MASK);
|
||||
return _cpsr;
|
||||
}
|
272
src/interrupt-utils.h
Normal file
272
src/interrupt-utils.h
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Defines and Macros for Interrupt-Service-Routines
|
||||
* collected and partly created by
|
||||
* Martin Thomas <mthomas@rhrk.uni-kl.de>
|
||||
*
|
||||
* Copyright 2005 M. Thomas
|
||||
* No guarantees, warrantees, or promises, implied or otherwise.
|
||||
* May be used for hobby or commercial purposes provided copyright
|
||||
* notice remains intact.
|
||||
*/
|
||||
|
||||
#ifndef interrupt_utils_
|
||||
#define interrupt_utils_
|
||||
|
||||
/*
|
||||
The following defines are usefull for
|
||||
interrupt service routine declarations.
|
||||
*/
|
||||
|
||||
/*
|
||||
RAMFUNC
|
||||
Attribute which defines a function to be located
|
||||
in memory section .fastrun and called via "long calls".
|
||||
See linker-skript and startup-code to see how the
|
||||
.fastrun-section is handled.
|
||||
The definition is not only useful for ISRs but since
|
||||
ISRs should be executed fast the macro is defined in
|
||||
this header.
|
||||
*/
|
||||
#define RAMFUNC __attribute__ ((long_call, section (".fastrun")))
|
||||
|
||||
|
||||
/*
|
||||
INTFUNC
|
||||
standard attribute for arm-elf-gcc which marks
|
||||
a function as ISR (for the VIC). Since gcc seems
|
||||
to produce wrong code if this attribute is used in
|
||||
thumb/thumb-interwork the attribute should only be
|
||||
used for "pure ARM-mode" binaries.
|
||||
*/
|
||||
#define INTFUNC __attribute__ ((interrupt("IRQ")))
|
||||
|
||||
|
||||
/*
|
||||
NACKEDFUNC
|
||||
gcc will not add any code to a function declared
|
||||
"nacked". The user has to take care to save registers
|
||||
and add the needed code for ISR functions. Some
|
||||
macros for this tasks are provided below.
|
||||
*/
|
||||
#define NACKEDFUNC __attribute__((naked))
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MACRO Name: ISR_STORE()
|
||||
*
|
||||
* Description:
|
||||
* This MACRO is used upon entry to an ISR with interrupt nesting.
|
||||
* Should be used together with ISR_ENABLE_NEST(). The MACRO
|
||||
* performs the following steps:
|
||||
*
|
||||
* 1 - Save the non-banked registers r0-r12 and lr onto the IRQ stack.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#define ISR_STORE() asm volatile( \
|
||||
"STMDB SP!,{R0-R12,LR}\n" )
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MACRO Name: ISR_RESTORE()
|
||||
*
|
||||
* Description:
|
||||
* This MACRO is used upon exit from an ISR with interrupt nesting.
|
||||
* Should be used together with ISR_DISABLE_NEST(). The MACRO
|
||||
* performs the following steps:
|
||||
*
|
||||
* 1 - Load the non-banked registers r0-r12 and lr from the IRQ stack.
|
||||
* 2 - Adjusts resume adress
|
||||
*
|
||||
*****************************************************************************/
|
||||
#define ISR_RESTORE() asm volatile( \
|
||||
"LDMIA SP!,{R0-R12,LR}\n" \
|
||||
"SUBS R15,R14,#0x0004\n" )
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MACRO Name: ISR_ENABLE_NEST()
|
||||
*
|
||||
* Description:
|
||||
* This MACRO is used upon entry from an ISR with interrupt nesting.
|
||||
* Should be used after ISR_STORE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#define ISR_ENABLE_NEST() asm volatile( \
|
||||
"MRS LR, SPSR \n" \
|
||||
"STMFD SP!, {LR} \n" \
|
||||
"MSR CPSR_c, #0x1f \n" \
|
||||
"STMFD SP!, {LR} " )
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MACRO Name: ISR_DISABLE_NEST()
|
||||
*
|
||||
* Description:
|
||||
* This MACRO is used upon entry from an ISR with interrupt nesting.
|
||||
* Should be used before ISR_RESTORE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#define ISR_DISABLE_NEST() asm volatile( \
|
||||
"LDMFD SP!, {LR} \n" \
|
||||
"MSR CPSR_c, #0x92 \n" \
|
||||
"LDMFD SP!, {LR} \n" \
|
||||
"MSR SPSR_cxsf, LR \n" )
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The following marcos are from the file "armVIC.h" by:
|
||||
*
|
||||
* Copyright 2004, R O SoftWare
|
||||
* No guarantees, warrantees, or promises, implied or otherwise.
|
||||
* May be used for hobby or commercial purposes provided copyright
|
||||
* notice remains intact.
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MACRO Name: ISR_ENTRY()
|
||||
*
|
||||
* Description:
|
||||
* This MACRO is used upon entry to an ISR. The current version of
|
||||
* the gcc compiler for ARM does not produce correct code for
|
||||
* interrupt routines to operate properly with THUMB code. The MACRO
|
||||
* performs the following steps:
|
||||
*
|
||||
* 1 - Adjust address at which execution should resume after servicing
|
||||
* ISR to compensate for IRQ entry
|
||||
* 2 - Save the non-banked registers r0-r12 and lr onto the IRQ stack.
|
||||
* 3 - Get the status of the interrupted program is in SPSR.
|
||||
* 4 - Push it onto the IRQ stack as well.
|
||||
*
|
||||
*****************************************************************************/
|
||||
#define ISR_ENTRY() asm volatile(" sub lr, lr,#4\n" \
|
||||
" stmfd sp!,{r0-r12,lr}\n" \
|
||||
" mrs r1, spsr\n" \
|
||||
" stmfd sp!,{r1}")
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MACRO Name: ISR_EXIT()
|
||||
*
|
||||
* Description:
|
||||
* This MACRO is used to exit an ISR. The current version of the gcc
|
||||
* compiler for ARM does not produce correct code for interrupt
|
||||
* routines to operate properly with THUMB code. The MACRO performs
|
||||
* the following steps:
|
||||
*
|
||||
* 1 - Recover SPSR value from stack
|
||||
* 2 - and restore its value
|
||||
* 3 - Pop the return address & the saved general registers from
|
||||
* the IRQ stack & return
|
||||
*
|
||||
*****************************************************************************/
|
||||
#define ISR_EXIT() asm volatile(" ldmfd sp!,{r1}\n" \
|
||||
" msr spsr_c,r1\n" \
|
||||
" ldmfd sp!,{r0-r12,pc}^")
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function Name: disableIRQ()
|
||||
*
|
||||
* Description:
|
||||
* This function sets the IRQ disable bit in the status register
|
||||
*
|
||||
* Calling Sequence:
|
||||
* void
|
||||
*
|
||||
* Returns:
|
||||
* previous value of CPSR
|
||||
*
|
||||
*****************************************************************************/
|
||||
unsigned disableIRQ(void);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function Name: enableIRQ()
|
||||
*
|
||||
* Description:
|
||||
* This function clears the IRQ disable bit in the status register
|
||||
*
|
||||
* Calling Sequence:
|
||||
* void
|
||||
*
|
||||
* Returns:
|
||||
* previous value of CPSR
|
||||
*
|
||||
*****************************************************************************/
|
||||
unsigned enableIRQ(void);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function Name: restoreIRQ()
|
||||
*
|
||||
* Description:
|
||||
* This function restores the IRQ disable bit in the status register
|
||||
* to the value contained within passed oldCPSR
|
||||
*
|
||||
* Calling Sequence:
|
||||
* void
|
||||
*
|
||||
* Returns:
|
||||
* previous value of CPSR
|
||||
*
|
||||
*****************************************************************************/
|
||||
unsigned restoreIRQ(unsigned oldCPSR);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function Name: disableFIQ()
|
||||
*
|
||||
* Description:
|
||||
* This function sets the FIQ disable bit in the status register
|
||||
*
|
||||
* Calling Sequence:
|
||||
* void
|
||||
*
|
||||
* Returns:
|
||||
* previous value of CPSR
|
||||
*
|
||||
*****************************************************************************/
|
||||
unsigned disableFIQ(void);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function Name: enableFIQ()
|
||||
*
|
||||
* Description:
|
||||
* This function clears the FIQ disable bit in the status register
|
||||
*
|
||||
* Calling Sequence:
|
||||
* void
|
||||
*
|
||||
* Returns:
|
||||
* previous value of CPSR
|
||||
*
|
||||
*****************************************************************************/
|
||||
unsigned enableFIQ(void);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Function Name: restoreFIQ()
|
||||
*
|
||||
* Description:
|
||||
* This function restores the FIQ disable bit in the status register
|
||||
* to the value contained within passed oldCPSR
|
||||
*
|
||||
* Calling Sequence:
|
||||
* void
|
||||
*
|
||||
* Returns:
|
||||
* previous value of CPSR
|
||||
*
|
||||
*****************************************************************************/
|
||||
unsigned restoreFIQ(unsigned oldCPSR);
|
||||
|
||||
|
||||
#endif
|
||||
|
100
src/sys-interrupt.c
Normal file
100
src/sys-interrupt.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include <sys-interrupt.h>
|
||||
#include <interrupt-utils.h>
|
||||
#include <AT91SAM7S64.h>
|
||||
|
||||
#define ATTR
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
|
||||
static SystemInterruptHandler *handlers = NULL;
|
||||
|
||||
static void
|
||||
system_int_safe (void) __attribute__((noinline));
|
||||
|
||||
static void
|
||||
system_int_safe (void)
|
||||
{
|
||||
SystemInterruptHandler *h;
|
||||
h = handlers;
|
||||
while (h) {
|
||||
if (h->handler()) break;
|
||||
h = h->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void NACKEDFUNC ATTR
|
||||
system_int (void) /* System Interrupt Handler */
|
||||
{
|
||||
ISR_ENTRY();
|
||||
system_int_safe();
|
||||
*AT91C_AIC_EOICR = 0; /* End of Interrupt */
|
||||
ISR_EXIT();
|
||||
}
|
||||
|
||||
static unsigned int enabled = 0; /* Number of times the system
|
||||
interrupt has been enabled */
|
||||
|
||||
#define DIS_INT *AT91C_AIC_IDCR = (1 << AT91C_ID_SYS)
|
||||
#define EN_INT if (enabled > 0) *AT91C_AIC_IECR = (1 << AT91C_ID_SYS)
|
||||
|
||||
void
|
||||
sys_interrupt_enable()
|
||||
{
|
||||
if (enabled++ == 0) {
|
||||
/* Level trigged at priority 5 */
|
||||
AT91C_AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 5;
|
||||
/* Interrupt vector */
|
||||
AT91C_AIC_SVR[AT91C_ID_SYS] = (unsigned long) system_int;
|
||||
/* Enable */
|
||||
EN_INT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sys_interrupt_disable()
|
||||
{
|
||||
if (--enabled == 0) {
|
||||
DIS_INT;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
sys_interrupt_append_handler(SystemInterruptHandler *handler)
|
||||
{
|
||||
SystemInterruptHandler **h = &handlers;
|
||||
while(*h) {
|
||||
h = &(*h)->next;
|
||||
}
|
||||
DIS_INT;
|
||||
*h = handler;
|
||||
handler->next = NULL;
|
||||
EN_INT;
|
||||
}
|
||||
|
||||
void
|
||||
sys_interrupt_prepend_handler(SystemInterruptHandler *handler)
|
||||
{
|
||||
DIS_INT;
|
||||
handler->next = handlers;
|
||||
handlers = handler;
|
||||
EN_INT;
|
||||
}
|
||||
|
||||
void
|
||||
sys_interrupt_remove_handler(SystemInterruptHandler *handler)
|
||||
{
|
||||
SystemInterruptHandler **h = &handlers;
|
||||
while(*h) {
|
||||
if (*h == handler) {
|
||||
DIS_INT;
|
||||
*h = handler->next;
|
||||
EN_INT;
|
||||
break;
|
||||
}
|
||||
h = &(*h)->next;
|
||||
}
|
||||
}
|
31
src/sys-interrupt.h
Normal file
31
src/sys-interrupt.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef __SYS_INTERRUPT_H__QIHZ66NP8K__
|
||||
#define __SYS_INTERRUPT_H__QIHZ66NP8K__
|
||||
|
||||
|
||||
/* Returns true if it handled an activbe interrupt */
|
||||
typedef int (*SystemInterruptFunc)();
|
||||
|
||||
typedef struct _SystemInterruptHandler SystemInterruptHandler;
|
||||
struct _SystemInterruptHandler
|
||||
{
|
||||
SystemInterruptHandler *next;
|
||||
SystemInterruptFunc handler;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
sys_interrupt_enable();
|
||||
|
||||
void
|
||||
sys_interrupt_disable();
|
||||
|
||||
void
|
||||
sys_interrupt_append_handler(SystemInterruptHandler *handler);
|
||||
|
||||
void
|
||||
sys_interrupt_prepend_handler(SystemInterruptHandler *handler);
|
||||
|
||||
void
|
||||
sys_interrupt_remove_handler(SystemInterruptHandler *handler);
|
||||
|
||||
#endif /* __SYS_INTERRUPT_H__QIHZ66NP8K__ */
|
92
tests/tmr-ints.c
Normal file
92
tests/tmr-ints.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* Timer registers are all 16-bit wide with 16-bit access only */
|
||||
#define TMR_OFFSET (0x20)
|
||||
#define TMR_BASE (0x80007000)
|
||||
#define TMR0_BASE (TMR_BASE)
|
||||
#define TMR1_BASE (TMR_BASE + TMR_OFFSET*1)
|
||||
#define TMR2_BASE (TMR_BASE + TMR_OFFSET*2)
|
||||
#define TMR3_BASE (TMR_BASE + TMR_OFFSET*3)
|
||||
|
||||
#define TMR_REGOFF_COMP1 (0x0)
|
||||
#define TMR_REGOFF_COMP2 (0x2)
|
||||
#define TMR_REGOFF_CAPT (0x4)
|
||||
#define TMR_REGOFF_LOAD (0x6)
|
||||
#define TMR_REGOFF_HOLD (0x8)
|
||||
#define TMR_REGOFF_CNTR (0xa)
|
||||
#define TMR_REGOFF_CTRL (0xc)
|
||||
#define TMR_REGOFF_SCTRL (0xe)
|
||||
#define TMR_REGOFF_CMPLD1 (0x10)
|
||||
#define TMR_REGOFF_CMPLD2 (0x12)
|
||||
#define TMR_REGOFF_CSCTRL (0x14)
|
||||
#define TMR_REGOFF_ENBL (0x1e)
|
||||
|
||||
/* Timer 0 registers */
|
||||
#define TMR0_COMP1 (TMR0_BASE + TMR_REGOFF_COMP1)
|
||||
#define TMR0_COMP_UP TMR0_COMP1
|
||||
#define TMR0_COMP2 (TMR0_BASE + TMR_REGOFF_COMP2)
|
||||
#define TMR0_COMP_DOWN TMR0_COMP2
|
||||
#define TMR0_CAPT (TMR0_BASE + TMR_REGOFF_CAPT)
|
||||
#define TMR0_LOAD (TMR0_BASE + TMR_REGOFF_LOAD)
|
||||
#define TMR0_HOLD (TMR0_BASE + TMR_REGOFF_HOLD)
|
||||
#define TMR0_CNTR (TMR0_BASE + TMR_REGOFF_CTRL)
|
||||
#define TMR0_CTRL (TMR0_BASE + TMR_REGOFF_CTRL)
|
||||
#define TMR0_SCTRL (TMR0_BASE + TMR_REGOFF_SCTRL)
|
||||
#define TMR0_CMPLD1 (TMR0_BASE + TMR_REGOFF_CMPLD1)
|
||||
#define TMR0_CMPLD2 (TMR0_BASE + TMR_REGOFF_CMPLD2)
|
||||
#define TMR0_CSCTRL (TMR0_BASE + TMR_REGOFF_CSCTRL)
|
||||
|
||||
/* one enable register to rule them all */
|
||||
#define TMR_ENBL TMR0_BASE + TMR_REGOFF_ENBL
|
||||
|
||||
#define MBAR_GPIO 0x80000000
|
||||
#define GPIO_PAD_DIR0 0x80000000
|
||||
#define GPIO_DATA0 0x80000008
|
||||
#define UART1_DATA 0x80005008
|
||||
#define DELAY 400000
|
||||
|
||||
#define reg32(x) (*(volatile uint32_t *)(x))
|
||||
#define reg16(x) (*(volatile uint16_t *)(x))
|
||||
|
||||
#include "embedded_types.h"
|
||||
|
||||
__attribute__ ((section ("startup")))
|
||||
void main(void) {
|
||||
|
||||
/* pin direction */
|
||||
reg32(GPIO_PAD_DIR0) = 0x00000400;
|
||||
|
||||
/* timer setup */
|
||||
/* CTRL */
|
||||
#define COUNT_MODE 1 /* use rising edge of primary source */
|
||||
#define PRIME_SRC 0xf /* Perip. clock with 128 prescale (for 24Mhz = 187500Hz)*/
|
||||
#define SEC_SRC 0 /* don't need this */
|
||||
#define ONCE 0 /* keep counting */
|
||||
#define LEN 1 /* count until compare then reload with value in LOAD */
|
||||
#define DIR 0 /* count up */
|
||||
#define CO_INIT 0 /* other counters cannot force a re-initialization of this counter */
|
||||
#define OUT_MODE 0 /* OFLAG is asserted while counter is active */
|
||||
|
||||
reg16(TMR_ENBL) = 0; /* tmrs reset to enabled */
|
||||
reg16(TMR0_SCTRL) = 0;
|
||||
reg16(TMR0_LOAD) = 0; /* reload to zero */
|
||||
reg16(TMR0_COMP_UP) = 18750; /* trigger a reload at the end */
|
||||
reg16(TMR0_CMPLD1) = 18750; /* compare 1 triggered reload level, 10HZ maybe? */
|
||||
reg16(TMR0_CNTR) = 0; /* reset count register */
|
||||
reg16(TMR0_CTRL) = (COUNT_MODE<<13) | (PRIME_SRC<<9) | (SEC_SRC<<7) | (ONCE<<6) | (LEN<<5) | (DIR<<4) | (CO_INIT<<3) | (OUT_MODE);
|
||||
reg16(TMR_ENBL) = 0xf; /* enable all the timers --- why not? */
|
||||
|
||||
while(1) {
|
||||
|
||||
/* blink on */
|
||||
reg32(GPIO_DATA0) = 0x00000400;
|
||||
|
||||
while((reg16(TMR0_SCTRL)>>15) == 0) { continue; }
|
||||
reg16(TMR0_SCTRL) = 0; /*clear bit 15, and all the others --- should be ok, but clearly not "the right thing to do" */
|
||||
|
||||
/* blink off */
|
||||
reg32(GPIO_DATA0) = 0x00000000;
|
||||
|
||||
while((reg16(TMR0_SCTRL)>>15) == 0) { continue; }
|
||||
reg16(TMR0_SCTRL) = 0; /*clear bit 15, and all the others --- should be ok, but clearly not "the right thing to do" */
|
||||
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue