Makefile
uart_interrupt.bin : start.s function.c
arm-linux-gcc -g -c -o start.o start.s
arm-linux-gcc -g -c -o function.o function.c
arm-linux-ld -Ttext 0x30000000 -g start.o function.o -o uart_interrupt.elf
arm-linux-objcopy -O binary -S uart_interrupt.elf uart_interrupt.bin
arm-linux-objdump -D -m arm uart_interrupt.elf > uart_interrupt.dis
clean :
rm -f *.o *.bin *.dis
start.s
.text
.global _start
_start:
b reset
b .
b .
b .
b .
b .
b handle_irq
b .
reset:
@shut down the watchdog
ldr r0, =0x53000000
ldr r1, =0x00000000
str r1, [r0]
@init the stack address
ldr r1, =4096
ldr r0, =0x40000000
add sp, r1, r0
bl init_led
bl init_clock
bl display_led1
bl init_sdram
bl display_led2
@reset the stack pointer
ldr sp, =0x34000000 @change stack to the end of sdram
msr cpsr_c, #0xd2
ldr sp, =0x33F00000 @change the stack pointer of irq mode
msr cpsr_c, #0xd3 @change cpu back to svc mode
bl copy_code2sdram @copy 8KB data from norflash to sdram
ldr pc, =on_sdram
on_sdram:
bl init_uart0
bl init_interrupt
msr cpsr_c, #0x53 @clear the irq disable bit in cpsr
bl main
halt_loop:
b halt_loop
handle_irq:
sub lr, lr, #4 @set the address(int main function) to return when handle_irq ends
stmdb sp!, {r0-r12, lr} @save the universal registers and lr_irq to the stack of irq mode
bl handle_irq_func @branch to the irq handleing function achieved in function.c
ldmia sp!, {r0-r12, pc}^ @resume the universal registers and save lr to pc while copying spsr to cpsr
function.c
//gpb registers
#define GPBCON (*((volatile unsigned long *)0x56000010))
#define GPBDAT (*((volatile unsigned long *)0x56000014))
//mem controler registers
#define BWSCON (*((volatile unsigned long *)0x48000000))
#define BANKCON0 (*((volatile unsigned long *)0x48000004))
#define BANKCON1 (*((volatile unsigned long *)0x48000008))
#define BANKCON2 (*((volatile unsigned long *)0x4800000C))
#define BANKCON3 (*((volatile unsigned long *)0x48000010))
#define BANKCON4 (*((volatile unsigned long *)0x48000014))
#define BANKCON5 (*((volatile unsigned long *)0x48000018))
#define BANKCON6 (*((volatile unsigned long *)0x4800001C))
#define BANKCON7 (*((volatile unsigned long *)0x48000020))
#define REFRESH (*((volatile unsigned long *)0x48000024))
#define BANKSIZE (*((volatile unsigned long *)0x48000028))
#define MRSRB6 (*((volatile unsigned long *)0x4800002C))
#define MRSRB7 (*((volatile unsigned long *)0x48000030))
//gpg registers
#define GPGCON (*((volatile unsigned long *)0x56000060))
//gph registers
#define GPHCON (*((volatile unsigned long *)0x56000070))
#define GPHUP (*((volatile unsigned long *)0x56000078))
//interrupt related registers
#define EINTMASK (*((volatile unsigned long *)0x560000A4))
#define INTMSK (*((volatile unsigned long *)0x4A000008))
#define INTMOD (*((volatile unsigned long *)0x4A000004))
#define INTOFFSET (*((volatile unsigned long *)0x4A000014))
#define SRCPND (*((volatile unsigned long *)0x4A000000))
#define INTPND (*((volatile unsigned long *)0x4A000010))
#define EINTPEND (*((volatile unsigned long *)0x560000A8))
#define INTSUBMSK (*((volatile unsigned long *)0x4A00001C))
#define SUBSRCPND (*((volatile unsigned long *)0x4A000018))
//PLL related registers
#define LOCKTIME (*((volatile unsigned long *)0x4C000000))
#define MPLLCON (*((volatile unsigned long *)0x4C000004))
#define CLKDIVN (*((volatile unsigned long *)0x4C000014))
//uart related registers
#define ULCON0 (*((volatile unsigned long *)0x50000000))
#define UCON0 (*((volatile unsigned long *)0x50000004))
#define UFCON0 (*((volatile unsigned long *)0x50000008))
#define UMCON0 (*((volatile unsigned long *)0x5000000C))
#define UBRDIV0 (*((volatile unsigned long *)0x50000028))
#define UTRSTAT0 (*((volatile unsigned long *)0x50000010))
#define URXH0 (*((volatile unsigned char *)0x50000024))
#define UTXH0 (*((volatile unsigned char *)0x50000020))
void blink(void);
void display_led(int);
void init_sdram(){
BWSCON = 0x22011110;
BANKCON0 = 0x00000700;
BANKCON1 = 0x00000700;
BANKCON2 = 0x00000700;
BANKCON3 = 0x00000700;
BANKCON4 = 0x00000700;
BANKCON5 = 0x00000700;
BANKCON6 = 0x00018005;
BANKCON7 = 0x00018005;
//when hcls is 12MHz
//REFRESH = 0x008C07A3;
//when hckl is 100MHz
REFRESH = 0x008C04F4;
BANKSIZE = 0x000000B1;
MRSRB6 = 0x00000030;
MRSRB7 = 0x00000030;
}
void init_interrupt(){
//set the gpio pins of the six keys to interrupt mode
GPGCON = (1<<(0*2+1) | 1<<(3*2+1) | 1<<(5*2+1) | 1<<(6*2+1) | 1<<(7*2+1) | 1<<(11*2+1));
//set EINTMASK register to enable external interrupt
EINTMASK &= (~(1<<8 | 1<<11 | 1<<13 | 1<<14 | 1<<15 | 1<<19));
//set INTMSK register to enable eint8_23
INTMSK &= (~(1<<5));
//enable uart0 interrupt
INTMSK &= (~(1<<28));
//enable rxd0 interrupt and txd0 interrupt
INTSUBMSK &= (~(0b11));
//set INTMOD register to set int8_23 to irq mode
INTMOD &= (~(1<<5));
}
void init_uart0(){
GPHCON |= ( (1<<5) | (1<<7) );
GPHCON &= ~( (1<<4) | (1<<6) );
GPHUP |= ( (1<<2) | (1<<3) );
ULCON0 = 0x03; //8 data bits, 1 stop bits, no check
UCON0 = 0X05; //polling mode or interrupt mode
UFCON0 = 0x00;
UMCON0 = 0x00;
UBRDIV0 = 0x1A; //bit rate is 115200(pclk is 50MHz)
}
unsigned char getchar_uart0(){
blink();
while( !(UTRSTAT0&1) );
return URXH0;
}
void putchar_uart0(unsigned char ch){
while( !(UTRSTAT0&4) );
UTXH0 = ch;
blink();
}
void handle_key(){
int eint_v;
eint_v = EINTPEND;
if(eint_v & (1<<8)){
display_led(1);
EINTPEND = 1<<8;
return;
}
if(eint_v & (1<<11)){
display_led(2);
EINTPEND = 1<<11;
return;
}
if(eint_v & (1<<13)){
display_led(3);
EINTPEND = 1<<13;
return;
}
if(eint_v & (1<<14)){
display_led(4);
EINTPEND = 1<<14;
return;
}
if(eint_v & (1<<15)){
display_led(5);
EINTPEND = 1<<15;
return;
}
if(eint_v & (1<<19)){
display_led(6);
EINTPEND = 1<<19;
return;
}
}
void handle_uart0_interrupt(){
unsigned char ch;
if(SUBSRCPND & (1<<0)){ //rxd0 interrupt
ch = getchar_uart0();
SUBSRCPND |= (1<<0);
putchar_uart0(ch);
}
else if(SUBSRCPND & (1<<1)){ //txd0 itnerrupt
//do nothing
SUBSRCPND |= (1<<1);
}
}
void handle_irq_func(){
int offset_v;
offset_v = INTOFFSET;
switch(offset_v){
case 5: //external interrupt
handle_key();
break;
case 28:
handle_uart0_interrupt();
break;
default:
break;
}
//clear the interrupt
SRCPND = 1<<offset_v;
INTPND = 1<<offset_v;
}
void delay(int n){
int i, j;
for(i=0; i<n; i++){
for(j=0; j<1000; j++){}
}
}
void blink(){
GPBDAT = 0xffffffff;
GPBDAT = 0x00000000;
delay(1);
GPBDAT = 0xffffffff;
delay(1);
}
void display_led1(){
GPBDAT = ~(1<<5);
delay(1);
}
void display_led2(){
GPBDAT = ~(3<<5);
delay(1);
}
void display_led3(){
GPBDAT = ~(7<<5);
delay(1);
}
void display_led4(){
GPBDAT = ~(15<<5);
delay(1);
}
void display_led(int n){
GPBDAT = ~(n<<5);
}
void copy_code2sdram(){
int size, i;
unsigned char *src, *des;
size = 8*1024;
des = (unsigned char*)(0x30000000);
src = (unsigned char *)(0x00000000);
for(i=0; i<size; i++){
*(des++) = *(src++);
}
}
void init_led(){
GPBCON = 0x00015400;
GPBDAT &= ~(0x0f<<5);
}
//initialize the clock of soc
void init_clock(){
LOCKTIME = 0xffffffff;
CLKDIVN = 0X03; //fclk:hclk:pclk=1:2:4
__asm__
(
"mrc p15, 0, r1, c1, c0, 0\n"
"orr r1, r1, #0xc0000000\n"
"mcr p15, 0, r1, c1, c0, 0\n"
);
MPLLCON = (92<<12)|(1<<4)|(2<<0); //fclk=200M, hclk=100M, pclk=50M
}
/*
int main(void){
int i;
GPBCON = 0x00015400;
i = 0;
while(1){
GPBDAT = ~(1<<(i+5));
delay(1);
i = (i+1)%4;
}
return 0;
}
*/
int main(void){
display_led3();
while(1){
//waiting for interrupt
}
return 0;
}