这次是S3C2440上面的uart0的FIFO模式的实验,程序设置串口0的输入fifo中包含的数据个数在从小于16字节的状态变换为大于等于16字节的状态的瞬间触发一个脉冲中断,在这个中断中,把输入fifo 中的数据全部写入到输出fifo中,在输出fifo 从非空状态变换成空的状态的瞬间会触发一个脉冲中断,在中断中我让灯闪一下,实验的正确现象是从超级终端往2440的串口0发数据,每发16个字节的数据,串口就会把这16个字节全部打印出来,同时由于输出fifo变空,会触发灯闪一下,经过测试,实验现象和上面说的是一致的。要注意在往utxh0寄存器写数据的时候要先检查输出fifo是不是已经满了,如果已经满了就要等待,否则会造成输出fifo对头的数据提前出队,出队的数据就丢掉了,输入fifo中的数据个数要从UFSTAT寄存器里面的相应字段去读,uart的dma模式怎么用的还需要研究一下。
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_fifo.elf
arm-linux-objcopy -O binary -S uart_fifo.elf uart_fifo.bin
arm-linux-objdump -D -m arm uart_fifo.elf > uart_fifo.dis
clean :
rm -f *.o *.bin *.dis *.elf
.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
//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))
//uart0 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))
#define UFSTAT0 (*((volatile unsigned long *)0x50000018))
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
UCON0 |= (1<<6); //enable rx0 time out interrupt
UFCON0 = 0b00100001; //enable fifo, set receive fifo trigger to be 16 bytes and set transport fifo trigger to zero
UMCON0 = 0x00; //disable AFC
UBRDIV0 = 0x1A; //bit rate is 115200(pclk is 50MHz)
}
unsigned char getchar_uart0(){
//while( !(UTRSTAT0&1) );
return URXH0;
}
void putchar_uart0_fifo(unsigned char ch){
while( UFSTAT0&(1<<6) ); //wait while transport fifo is full
UTXH0 = ch;
}
void puts_uart0_fifo(char *str){
int i;
for(i=0; str[i]!='\0'; i++){
putchar_uart0_fifo(str[i]);
}
}
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;
}
}
#define RX0_FIFO_SIZE 64
#define TX0_FIFO_SIZE 64
void handle_uart0_interrupt(){
int i, fifo_count;
unsigned char ch;
if(SUBSRCPND & (1<<1)){ //txd0 interrupt will happen when transport fifo is empty
//do nothing
if( (UFSTAT0&(0b111111<<8)) == 0 )
blink();
}
if(SUBSRCPND & (1<<0)){ //rxd0 interrupt
if( UFSTAT0 & (1<<6) ){ //rx0 fifo is full
for(i=0; i> 0); //get the data length in fifo
for(i=0; i