这次是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
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))
- //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<RX0_FIFO_SIZE; i++){
- ch = URXH0;
- putchar_uart0_fifo(ch);
- }
- }
- else{ //rx0 fifo is not full
- //blink();
- fifo_count = ((UFSTAT0 & (0b111111<<0)) >> 0); //get the data length in fifo
- for(i=0; i<fifo_count; i++){
- ch = URXH0;
- putchar_uart0_fifo(ch);
- }
- }
- }
- SUBSRCPND = SUBSRCPND;
- }
- 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
- //puts_uart0_fifo("Hello world\r\n");
- //puts_uart0_fifo("this is a test of uart0\r\n");
- }
- return 0;
- }