diff --git a/Makefile b/Makefile index 13496ee..07e0b5e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ NAME=quad SSRCS=crt0.s -CSRCS=main.c i2c.c wmp.c timer.c +CSRCS=main.c i2c.c wmp.c timer.c interrupt.c uart.c COPTIM?=-O1 CFLAGS=-march=armv4t -msoft-float $(COPTIM) -Wall -Werror -Wextra diff --git a/crt0.s b/crt0.s index 94c3baa..28186e8 100644 --- a/crt0.s +++ b/crt0.s @@ -69,7 +69,7 @@ vectors: b prefetch_abort_handler b data_abort_handler nop /* reserved */ - b irq_handler + ldr pc, [pc, #-0xff0] /* branch through VICVectAddr register */ b fiq_handler @@ -177,7 +177,6 @@ undefined_handler: swi_handler: prefetch_abort_handler: data_abort_handler: -irq_handler: fiq_handler: __back: diff --git a/interrupt.c b/interrupt.c new file mode 100644 index 0000000..6bbc460 --- /dev/null +++ b/interrupt.c @@ -0,0 +1,84 @@ +#include "interrupt.h" + +#define VICBASE 0xFFFFF000 + +#define IRQStatus 0x00 +#define FIQStatus 0x04 +#define RawIntr 0x08 +#define IntSelect 0x0c +#define IntEnable 0x10 +#define IntEnClr 0x14 +#define SoftInt 0x18 +#define SoftIntClear 0x1c +#define Protection 0x20 +#define VectAddr 0x30 +#define DefVectAddr 0x34 +#define VectAddr0 0x100 +#define VectAddr1 0x104 +#define VectAddr2 0x108 +#define VectAddr3 0x10c +#define VectAddr4 0x110 +#define VectAddr5 0x114 +#define VectAddr6 0x118 +#define VectAddr7 0x11c +#define VectAddr8 0x120 +#define VectAddr9 0x124 +#define VectAddr10 0x128 +#define VectAddr11 0x12c +#define VectAddr12 0x130 +#define VectAddr13 0x134 +#define VectAddr14 0x138 +#define VectAddr15 0x13c +#define VectCntl0 0x200 +#define VectCntl1 0x204 +#define VectCntl2 0x208 +#define VectCntl3 0x20c +#define VectCntl4 0x210 +#define VectCntl5 0x214 +#define VectCntl6 0x218 +#define VectCntl7 0x21c +#define VectCntl8 0x220 +#define VectCntl9 0x224 +#define VectCntl10 0x228 +#define VectCntl11 0x22c +#define VectCntl12 0x230 +#define VectCntl13 0x234 +#define VectCntl14 0x238 +#define VectCntl15 0x23c + +#define VWREG(x) (((volatile unsigned int *)VICBASE)[(x)/sizeof(unsigned int)]) +#define VADDRREG(x) VWREG(VectAddr0 + (x) * 4) +#define VCNTLREG(x) VWREG(VectCntl0 + (x) * 4) + +#define IRQslot_en (1<<5) + + +void __attribute__((interrupt("IRQ"))) interrupt_default_handler(void); + + +void init_interrupt(void) +{ + VWREG(IntSelect) = 0; + VWREG(IntEnable) = 0; + VWREG(DefVectAddr) = (unsigned int) &interrupt_default_handler; +} + +void __attribute__((interrupt("IRQ"))) interrupt_default_handler(void) +{ + /* Do nothing. Assume that if there is a genuine interrupt + * request that it will be asserted again soon. + */ + interrupt_clear(); +} + + +/* Call as interrupt_register(SOURCE, fn) */ + +void interrupt_register_code(unsigned int source, unsigned int priority, + void(*handler)(void)) +{ + VADDRREG(priority) = (unsigned int) handler; + VCNTLREG(priority) = source | IRQslot_en; + VWREG(IntEnable) |= (1< 0); - - putstr(s+i); -} - -void puthex(unsigned int n) { - char s[9]; - int i; - - i = 8; - s[i] = '\0'; - - do { - int x = n % 16; - if (x > 9) - x += 'A' - '0' - 10; - s[--i] = x + '0'; - } while ((n /= 16) > 0); - - putstr(s+i); -} - -char getch(void) { - while (!U0DR); - return UREG(RBR); -} - void reply(char *str) { putstr(str); @@ -228,6 +152,7 @@ void average_sample(void) int main(void) { int i; + init_interrupt(); init_uart(); init_i2c(); init_pins(); @@ -330,6 +255,11 @@ int main(void) { puthex(timer_read()); reply("."); break; + case 'P': + putstr("Initialising timer... "); + timer_set_period(10000*TIMER_MS); + reply("done"); + break; default: reply("Unrecognised command."); break; diff --git a/timer.c b/timer.c index aab6ff3..188df64 100644 --- a/timer.c +++ b/timer.c @@ -1,4 +1,6 @@ #include "timer.h" +#include "interrupt.h" +#include "uart.h" #define TIMER0BASE 0xE0004000 #define TIMER1BASE 0xE0008000 @@ -28,14 +30,29 @@ #define TCR_ENABLE (1<<0) #define TCR_RESET (1<<1) +#define MR0I (1<<0) +#define MR0R (1<<1) +#define MR0S (1<<2) +#define MR1I (1<<3) +#define MR1R (1<<4) +#define MR1S (1<<5) +#define MR2I (1<<6) +#define MR2R (1<<7) +#define MR2S (1<<8) +#define MR3I (1<<9) +#define MR3R (1<<10) +#define MR3S (1<<11) + +void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void); + void init_timer(void) { TREG(TCR) = TCR_ENABLE | TCR_RESET; TREG(CTCR) = 0; /* Use PCLK */ - TREG(TC) = 0; - TREG(PR) = TIMER_PRESCALE ; - TREG(PC) = 0; + TWREG(TC) = 0; + TWREG(PR) = TIMER_PRESCALE ; + TWREG(PC) = 0; TREG(TCR) = TCR_ENABLE; } @@ -51,3 +68,24 @@ void timer_delay_clocks(unsigned int clocks) while (((signed int) (time-TWREG(TC))) > 0); } +void timer_set_period(unsigned int period) +{ + TWREG(MR0) = period; + TWREG(MCR) = MR0I | MR0R; + interrupt_register(TIMER0, timer_interrupt_handler); +} + +void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void) +{ + unsigned int ir; + ir = TREG(IR); + TREG(IR) = ir; + + if (ir & (1<<0)) { + /* Match channel 0 */ + putstr(" *timer0* "); + } + + interrupt_clear(); +} + diff --git a/timer.h b/timer.h index 0468c30..4dd8f8f 100644 --- a/timer.h +++ b/timer.h @@ -11,6 +11,7 @@ void init_timer(void); unsigned int timer_read(void); void timer_delay_clocks(unsigned int clocks); +void timer_set_period(unsigned int period); #define timer_delay_us(x) timer_delay_clocks((x)*TIMER_US) #define timer_delay_ms(x) timer_delay_clocks((x)*TIMER_MS) diff --git a/uart.c b/uart.c new file mode 100644 index 0000000..5c8e176 --- /dev/null +++ b/uart.c @@ -0,0 +1,79 @@ +#include "uart.h" + +#define UARTBASE 0xE000C000 + +#define RBR 0x00 +#define THR 0x00 +#define DLL 0x00 +#define DLM 0x04 +#define IER 0x04 +#define IIR 0x08 +#define FCR 0x08 + +#define LCR 0x0c +#define LSR 0x14 +#define SCR 0x1c +#define ACR 0x20 +#define FDR 0x28 +#define TER 0x30 + +#define UREG(x) (((volatile unsigned char *)UARTBASE)[x]) + +#define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */ +#define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */ + +void init_uart(void) +{ + UREG(FDR) = 0x10; /* DivAddVal = 0, MulVal = 1 */ + + UREG(LCR) = 0x80; + UREG(DLM) = 0x00; + UREG(DLL) = 0x08; /* 14745600 / (16*115200) */ + UREG(LCR) = 0x13; + UREG(FCR) = 0x07; +} + +void putch(char c) { + while (!U0THRE); + UREG(THR) = c; +} + +void putstr(char *s) { + while (*s) putch(*s++); +} + +void putint(unsigned int n) { + char s[11]; + int i; + + i = 10; + s[i] = '\0'; + + do { + s[--i] = n % 10 + '0'; + } while ((n /= 10) > 0); + + putstr(s+i); +} + +void puthex(unsigned int n) { + char s[9]; + int i; + + i = 8; + s[i] = '\0'; + + do { + int x = n % 16; + if (x > 9) + x += 'A' - '0' - 10; + s[--i] = x + '0'; + } while ((n /= 16) > 0); + + putstr(s+i); +} + +char getch(void) { + while (!U0DR); + return UREG(RBR); +} diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..9488888 --- /dev/null +++ b/uart.h @@ -0,0 +1,11 @@ +#ifndef __UART_H +#define __UART_H + +void init_uart(void); +void putch(char c); +void putstr(char *s); +void putint(unsigned int n); +void puthex(unsigned int n); +char getch(void); + +#endif /* __UART_H */