• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 60, 文章 - 0, 評(píng)論 - 197, 引用 - 0
            數(shù)據(jù)加載中……

            學(xué)習(xí) ARM 系列 -- FS2410 開(kāi)發(fā)板上的中斷編程

            一、目的
               中斷服務(wù)程序在操作系統(tǒng)中無(wú)疑占有非常重要的地位,編寫(xiě)中斷程序不僅要會(huì)運(yùn)用底層的
            匯編語(yǔ)言,還要了解 ARM 的體系架構(gòu)。那這一節(jié)我們就通過(guò)中斷編程來(lái)響應(yīng) FS2410開(kāi)發(fā)板
            上的 16 個(gè)按鍵,實(shí)現(xiàn)依次按下16個(gè)鍵時(shí),D9~D12 四個(gè) Led 從 0~15 進(jìn)行計(jì)數(shù),并通
            過(guò)上個(gè)實(shí)驗(yàn)實(shí)現(xiàn)的 uart_printf 向串口發(fā)送數(shù)據(jù) Kn is pressed!。


            二、代碼
               我們直接分析代碼,代碼中只有簡(jiǎn)略的注釋,必要時(shí)我會(huì)在整個(gè)代碼文件的后面對(duì)相應(yīng)的細(xì)節(jié)
            進(jìn)行解釋。先來(lái)分析 head.s:
              
               @文件 head.s
               .text
               .global _start
               _start:
                    @ Set vector table for interrupt
                b reset                
                b HandleIRQ            
                b HandleIRQ            
                b HandleIRQ            
                b HandleIRQ            
                b HandleIRQ            
                b HandleIRQ             @ handle irq interrupt here            
                b HandleIRQ
               reset:
                ldr r0, =0x53000000 @ Close Watch Dog Timer
                mov r1, #0x0
                str r1, [r0]
                
                @ disable all interrupts
                mov r1, #0x4A000000
                mov r2, #0xffffffff
                str r2, [r1, #0x08]     @ set INTMSK
                ldr r2, =0x7ff
                str r2, [r1, #0x1C]     @ set INTSUBMSK
              
                bl  memory_setup @ Initialize memory setting
                bl  flash_to_sdram @ Copy code to sdram
              
                msr cpsr_c, #0xd2 @ set irq mode stack
                    ldr pc, =set_sp         @ jump to addr 0x3000000
               set_sp:
                ldr sp, =0x31000000
                msr cpsr_c, #0xdf @ set system mode stack
                ldr sp, =0x32000000
                bl  init_irq            @ Call init_irq
                msr cpsr_c, #0x5f @ set system mode and open the irq
                
                    ldr sp, =0x34000000 @ Set stack pointer
                bl  main
               loop:
                b loop
               HandleIRQ:
                sub   lr,  lr,#4         @ get the return addr
                stmdb sp!, { r0-r12,lr } @ store used registers in stack
                ldr   lr,  =int_return   @ set retrun addr
                ldr   pc,  =EINT_Handle  @ jump to the interrup processing function
               int_return:
                ldmia sp!, { r0-r12,pc }^
              

            呵呵,不知不覺(jué) head.s 的代碼已經(jīng)很長(zhǎng)了,我們來(lái)看一下它的執(zhí)行流程:
            (1) 設(shè)置中斷向量表。你也許在這里有疑問(wèn),為什么一開(kāi)始就有 8 個(gè)分支跳轉(zhuǎn)指令?我們
                先來(lái)研究一下 ARM 如何響應(yīng)異常/中斷,看下表:

                  -------------------------------------------------------------
                      Exception               Mode              Address
                  -------------------------------------------------------------
                      Reset                      Supervisor       0x00000000   
                      Undefined               Undefined        0x00000004   
                      Software Interupt    Supervistor      0x00000008   
                      Prefetch Abort        Abort              0x0000000C   
                      Data Abort             Abort              0x00000010   
                      IRQ (interupt)         IRQ                0x00000018   
                      FIQ (fast interupt)   FIQ                0x0000001C   
                  -------------------------------------------------------------

                可以看出 ARM 支持 7 種異常/中斷,每種異常/中斷都有固定的地址,這個(gè)地址叫
                中斷向量,一般我們會(huì)在這個(gè)地址放一條分支跳轉(zhuǎn)指令,當(dāng)異常/中斷發(fā)生時(shí),ARM 就
                到這個(gè)地址執(zhí)行這個(gè)跳轉(zhuǎn)指令,從而調(diào)用相應(yīng)的中斷服務(wù)程序。

                等等,這里是不是有點(diǎn)問(wèn)題?呵呵,你也許已經(jīng)發(fā)現(xiàn)了,這里只有 7 種異常/中斷,那
                我們的程序怎么會(huì)有 8 條分支跳轉(zhuǎn)指令呢? 因?yàn)橹袛嘞蛄考吹刂?0x00000014 被ARM
                保留用做將來(lái)擴(kuò)展之用,但我們還需用一條指令(4字節(jié))來(lái)填充這個(gè)位置,只不過(guò)它不會(huì)
                被 ARM 執(zhí)行。

            (2) 關(guān)閉看門(mén)狗
            (3) 暫時(shí)屏蔽所有中斷。
                1.地址 0x4A000008 是中斷屏寄存器 INTMSK 的端口地址,復(fù)位 INTMSK 會(huì)導(dǎo)致所有
                  的中斷源被屏掉。
                2.地址 0x4A00001C 是子中斷屏寄存器 INTSUBMSK 的端口地址,它的低 11 位對(duì)應(yīng)外
                  部 11 個(gè)中斷源,高 21 位保留不用。復(fù)位它的低 11 位會(huì)導(dǎo)致相應(yīng)的外部中斷被屏。
            (4) 初始化內(nèi)存 SDRAM 設(shè)置
            (5) Self-copying: 從 Nand Flash 將自身復(fù)制到 SDRAM
            (6) 進(jìn)入 IRQ 模式,設(shè)置 IRQ 模式下的堆棧寄存器
            (7) 進(jìn)入系統(tǒng)模式,并設(shè)置系統(tǒng)模式下的堆棧寄存器
            (8) 系統(tǒng)模式下調(diào)用 init_irq,這個(gè)函數(shù)用于初始化一些用于響應(yīng)按鍵的中斷寄存器
            (9) 再次進(jìn)入系統(tǒng)模式,并打開(kāi)當(dāng)前程序狀態(tài)寄存器 cpsr 的 IRQ 中斷位,這樣 ARM 就能
                響應(yīng) IRQ 中斷了
            (10)執(zhí)行主函數(shù) main 后返回,然后進(jìn)入死循環(huán),等待中斷發(fā)生
            (11)中斷發(fā)生時(shí),ARM 響應(yīng)中斷并于 0x00000018 處執(zhí)行 b HandleIRQ 跳轉(zhuǎn)指令調(diào)用中斷服
                務(wù)程序,處理完畢后返回循環(huán)處再等待下次中斷的發(fā)生,如此往復(fù)...

            這就是中斷處理的基本流程了 :-), 以下文件的代碼在前面隨筆均有詳細(xì)說(shuō)明,這里就僅附
            簡(jiǎn)略注釋了


               @ 文件 flash.s
               @ 作用:設(shè)置 Nand Flash 的控制寄存器、讀取 Nand Flash
               @ 中的代碼到 SDRAM 的指定位置,更多細(xì)節(jié)請(qǐng)參考我前面的隨筆
               .equ NFCONF, 0x4e000000
               .equ NFCMD,  0x4e000004
               .equ NFADDR, 0x4e000008
               .equ NFDATA, 0x4e00000c
               .equ NFSTAT, 0x4e000010
               .equ NFECC,  0x4e000014
               .global flash_to_sdram
               flash_to_sdram:
                    @ Save return addr
                    mov r10,lr
                
                    @ Initialize Nand Flash
                    mov r0,#NFCONF
                    ldr r1,=0xf830
                    str r1,[r0]
               
                    @ First reset and enable Nand Flash
                    ldr r1,[r0]
                    bic r1, r1, #0x800
                    str r1,[r0]
               
                    ldr r2,=NFCMD
                    mov r3,#0xff
                    str r3,[r2]
                
                    @ for delay
                    mov r3, #0x0a
               1:
                    subs r3, r3, #1
                    bne 1b
              
               @ Wait until Nand Flash bit0 is 1
               wait_nfstat:
                    ldr r2,=NFSTAT
                    ldr r3,[r2]
                    tst r3,#0x01
                    beq wait_nfstat
                      
                @ Disable Nand Flash
                ldr r0,=NFCONF
                ldr r1,[r0]
                orr r1,r1,#0x8000
                str r1,[r0]
               
                @ Initialzie stack
                ldr sp,=4096
              
                @ Set arguments and call
                    @ function nand_read defined in nand_read.c
                ldr r0,=0x30000000
                mov r1,#0
                mov r2,#1024*40
                bl nand_read
              
                    @ return
                mov pc,r10


               /* 文件 nand_read.c
                * 作用:從 Nand Flash 中讀取一塊數(shù)據(jù)到 SDRAM 中的指定位置
                */
               #define NFCONF (*(volatile unsigned long *)0x4e000000)
               #define NFCMD  (*(volatile unsigned long *)0x4e000004)
               #define NFADDR (*(volatile unsigned long *)0x4e000008)
               #define NFDATA (*(volatile unsigned long *)0x4e00000c)
               #define NFSTAT (*(volatile unsigned long *)0x4e000010)
               #define NFECC  (*(volatile unsigned long *)0x4e000014)
              
               #define NAND_SECTOR_SIZE 512
               #define NAND_BLOCK_MASK  0x1ff
              
               void wait_idle() {
                 int i;
                 for (i = 0; i < 50000; ++i) ;
               }
              
               int nand_read(unsigned char *buf, unsigned long start_addr, int size){
                 int i, j;
                 /*
                  * detect the argument
                  */ 
                 if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
                   return -1;    
                 }
               
                 /* chip Enable */
                 NFCONF &= ~0x800;
                 for (i=0; i<10; i++) {
                   ;
                 }
               
                 for (i=start_addr; i < (start_addr + size); i+=NAND_SECTOR_SIZE) {
                   NFCMD = 0;
               
                   /* Write Address */
                   NFADDR = i & 0xff;
                   NFADDR = (i >> 9)  & 0xff;
                   NFADDR = (i >> 17) & 0xff;
                   NFADDR = (i >> 25) & 0xff;
               
                   wait_idle();
               
                   for(j=0; j < NAND_SECTOR_SIZE; j++) {
                     *buf++ = (NFDATA & 0xff);
                   }
                 }
               
                 NFCONF |= 0x800;    /* chip disable */
                 return 0;
               }


               /* 頭文件 serl.h
                * 作用:定義相關(guān)寄存器、UART 初始化函數(shù)聲明、串口讀寫(xiě)函數(shù)的聲明
                */  
               #ifndef __SERL_H__
               #define __SERL_H__
              
               #define GPHCON  (*(volatile unsigned long *)0x56000070)
              
               /* PORT PULL-UP REGISTER*/
               #define GPHUP   (*(volatile unsigned long *)0x56000078)
              
               /* UART FIFO control register 0*/
               #define UFCON0  (*(volatile unsigned long *)0x50000008)
              
               /* UART line control register 0*/
               #define ULCON0  (*(volatile unsigned long *)0x50000000)
              
               /* UART CONTROL REGISTER 0*/
               #define UCON0   (*(volatile unsigned long *)0x50000004)
              
               /* UART modem control register 0*/
               #define UMCON0  (*(volatile unsigned long *)0x5000000C)
              
               /* UART baud rate divisor register 0*/
               #define UBRDIV0 (*(volatile unsigned long *)0x50000028)
              
               /* UART TX/RX STATUS REGISTER 0*/
               #define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
              
              
               #define UTXH0 (*(volatile unsigned char *)0x50000020)
               #define URXH0 (*(volatile unsigned char *)0x50000024)
              
              
               #define TXD0_READY 0x2
               #define RXD0_READY 0x1
              
               void init_uart();
               unsigned char uart_getc();
               void uart_putc(unsigned char ch);
               void uart_puts(unsigned char* src);
              
               #endif


               /* 文件 serl.c*/
               #include "serl.h"
              
               void init_uart() {
                 GPHCON |= 0xa0; /* GPH2, GPH3 used as RXD0, TXD0*/
                 GPHUP = 0x0c;   /* GPH2, GPH3 poll-up */
              
                 ULCON0 = 0x03;  /* normal mode, no parity, one stop bit, 8-bit*/
                 UCON0 = 0x05;   /* Loopback mode*/
                 UFCON0 = 0x00;  /* not use FIFO*/
                 UMCON0 = 0x00;  /* disable flow control*/
                 UBRDIV0 = 12;   /* baud rate 57600*/
               }
              
               void uart_putc(unsigned char ch) {
                 while (!(UTRSTAT0 & TXD0_READY));
                 UTXH0 = ch;
               }
              
               unsigned char uart_getc(){
                 while (! (UTRSTAT0 & RXD0_READY));
                 return URXH0;
               }
              
               void uart_puts(unsigned char* src) {
                 unsigned char *p = src;
                 while (*p != '\0') {
                   if (*p == 0x0a)
                     uart_putc(0x0d);
                   uart_putc(*p);
                   p++;
                 }
               }
              

               /*
                * 頭文件 printf.h
                * 作用:對(duì)外提供調(diào)用接口 uart_printf
                */  
               #ifndef __PRINTF_HH__
               #define __PRINTF_HH__
              
               void uart_printf(char *fmt, ...);
              
               #endif

              
               /*
                * 文件 printf.c
                * 文件中大部分代碼來(lái)自 linux 0.11 內(nèi)核的 vsprintf.c, 只是作了相應(yīng)的刪減,
                * <<Linux 內(nèi)核完全注釋>> 上有更詳細(xì)的解釋
                */
               #include <stdarg.h>
               #include <linux/types.h>
               #include <linux/ctype.h>
               #include "printf.h"
               #include "serl.h"
              
               #define ZEROPAD 1 /* pad with zero */
               #define SIGN         2 /* unsigned/signed long */
               #define PLUS         4 /* show plus */
               #define SPACE 8 /* space if plus */
               #define LEFT         16 /* left justified */
               #define SPECIAL 32 /* 0x */
               #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
              
               #define is_digit(c) ((c) >= '0' && (c) <= '9')

               #define do_div(n,base) ({    \
                     int __res;     \
                     __res = ((unsigned long) n) % (unsigned) base; \
                     n = ((unsigned long) n) / (unsigned) base; \
                     __res; })
              
               static unsigned char sprint_buf[1024];
              
               int strnlen(const char * s, int count)
               {
                 const char *sc;
              
                 for (sc = s; count-- && *sc != '\0'; ++sc)
                   /* nothing */;
                 return sc - s;
               }
              
               unsigned char _ctype[] = {
                 _C,_C,_C,_C,_C,_C,_C,_C,   /* 0-7 */
                 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
                 _C,_C,_C,_C,_C,_C,_C,_C,   /* 16-23 */
                 _C,_C,_C,_C,_C,_C,_C,_C,   /* 24-31 */
                 _S|_SP,_P,_P,_P,_P,_P,_P,_P,  /* 32-39 */
                 _P,_P,_P,_P,_P,_P,_P,_P,   /* 40-47 */
                 _D,_D,_D,_D,_D,_D,_D,_D,   /* 48-55 */
                 _D,_D,_P,_P,_P,_P,_P,_P,   /* 56-63 */
                 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
                 _U,_U,_U,_U,_U,_U,_U,_U,   /* 72-79 */
                 _U,_U,_U,_U,_U,_U,_U,_U,   /* 80-87 */
                 _U,_U,_U,_P,_P,_P,_P,_P,   /* 88-95 */
                 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
                 _L,_L,_L,_L,_L,_L,_L,_L,   /* 104-111 */
                 _L,_L,_L,_L,_L,_L,_L,_L,   /* 112-119 */
                 _L,_L,_L,_P,_P,_P,_P,_C,   /* 120-127 */
                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 128-143 */
                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 144-159 */
                 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
                 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
                 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
                 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
                 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
                 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
              
               static int skip_atoi(const char **s)
               {
                 int i=0;
              
                 while (is_digit(**s))
                   i = i*10 + *((*s)++) - '0';
                 return i;
               }
              
               static char * number(char * str, long num, int base, int size, int precision
                      ,int type)
               {
                 char c,sign,tmp[66];
                 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
                 int i;
              
                 if (type & LARGE)
                   digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                 if (type & LEFT)
                   type &= ~ZEROPAD;
                 if (base < 2 || base > 36)
                   return 0;
                 c = (type & ZEROPAD) ? '0' : ' ';
                 sign = 0;
                 if (type & SIGN) {
                   if (num < 0) {
                     sign = '-';
                     num = -num;
                     size--;
                   } else if (type & PLUS) {
                     sign = '+';
                     size--;
                   } else if (type & SPACE) {
                     sign = ' ';
                     size--;
                   }
                 }
                 if (type & SPECIAL) {
                   if (base == 16)
                     size -= 2;
                   else if (base == 8)
                     size--;
                 }
                 i = 0;
                 if (num == 0)
                   tmp[i++]='0';
                 else while (num != 0)
                 tmp[i++] = digits[do_div(num,base)];
                 if (i > precision)
                   precision = i;
                 size -= precision;
                 if (!(type&(ZEROPAD+LEFT)))
                   while(size-->0)
                     *str++ = ' ';
                 if (sign)
                   *str++ = sign;
                 if (type & SPECIAL) {
                   if (base==8)
                     *str++ = '0';
                   else if (base==16) {
                     *str++ = '0';
                     *str++ = digits[33];
                   }
                 }
                 if (!(type & LEFT))
                   while (size-- > 0)
                     *str++ = c;
                 while (i < precision--)
                   *str++ = '0';
                 while (i-- > 0)
                   *str++ = tmp[i];
                 while (size-- > 0)
                   *str++ = ' ';
                 return str;
               }
              
               int __vsprintf(char *buf, const char *fmt, va_list args)
               {
                 int len;
                 unsigned long num;
                 int i, base;
                 char * str;
                 const char *s;
              
                 int flags;  /* flags to number() */
              
                 int field_width; /* width of output field */
                 int precision; /* min. # of digits for integers; max
                     number of chars for from string */
                 int qualifier; /* 'h', 'l', or 'L' for integer fields */
              
                 for (str=buf ; *fmt ; ++fmt) {
                   if (*fmt != '%') {
                     *str++ = *fmt;
                     continue;
                   }
                  
                   /* process flags */
                   flags = 0;
                 repeat:
                   ++fmt;  /* this also skips first '%' */
                   switch (*fmt) {
                   case '-': flags |= LEFT; goto repeat;
                   case '+': flags |= PLUS; goto repeat;
                   case ' ': flags |= SPACE; goto repeat;
                   case '#': flags |= SPECIAL; goto repeat;
                   case '0': flags |= ZEROPAD; goto repeat;
                   }
                 
                   /* get field width */
                   field_width = -1;
                   if (is_digit(*fmt))
                     field_width = skip_atoi(&fmt);
                   else if (*fmt == '*') {
                     ++fmt;
                     /* it's the next argument */
                     field_width = va_arg(args, int);
                     if (field_width < 0) {
                   field_width = -field_width;
                   flags |= LEFT;
                     }
                   }
              
                   /* get the precision */
                   precision = -1;
                   if (*fmt == '.') {
                     ++fmt; 
                     if (is_digit(*fmt))
                   precision = skip_atoi(&fmt);
                     else if (*fmt == '*') {
                   ++fmt;
                   /* it's the next argument */
                   precision = va_arg(args, int);
                     }
                     if (precision < 0)
                   precision = 0;
                   }
              
                   /* get the conversion qualifier */
                   qualifier = -1;
                   if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
                     qualifier = *fmt;
                     ++fmt;
                   }
              
                   /* default base */
                   base = 10;
              
                   switch (*fmt) {
                   case 'c':
                     if (!(flags & LEFT))
                   while (--field_width > 0)
                     *str++ = ' ';
                     *str++ = (unsigned char) va_arg(args, int);
                     while (--field_width > 0)
                   *str++ = ' ';
                     continue;
              
                   case 's':
                     s = va_arg(args, char *);
                     if (!s)
                   s = "<NULL>";
              
                     len = strnlen(s, precision);
              
                     if (!(flags & LEFT))
                   while (len < field_width--)
                     *str++ = ' ';
                     for (i = 0; i < len; ++i)
                   *str++ = *s++;
                     while (len < field_width--)
                   *str++ = ' ';
                     continue;
              
                   case 'p':
                     if (field_width == -1) {
                   field_width = 2*sizeof(void *);
                   flags |= ZEROPAD;
                     }
                     str = number(str,
                    (unsigned long) va_arg(args, void *), 16,
                    field_width, precision, flags);
                     continue;
              
              
                   case 'n':
                     if (qualifier == 'l') {
                   long * ip = va_arg(args, long *);
                   *ip = (str - buf);
                     } else {
                   int * ip = va_arg(args, int *);
                   *ip = (str - buf);
                     }
                     continue;
              
                     /* integer number formats - set up the flags and "break" */
                   case 'o':
                     base = 8;
                     break;
              
                   case 'X':
                     flags |= LARGE;
                   case 'x':
                     base = 16;
                     break;
              
                   case 'd':
                   case 'i':
                     flags |= SIGN;
                   case 'u':
                     break;
              
                   default:
                     if (*fmt != '%')
                   *str++ = '%';
                     if (*fmt)
                   *str++ = *fmt;
                     else
                   --fmt;
                     continue;
                   }
                   if (qualifier == 'l')
                     num = va_arg(args, unsigned long);
                   else if (qualifier == 'h') {
                     num = (unsigned short) va_arg(args, int);
                     if (flags & SIGN)
                num = (short) num;
                   } else if (flags & SIGN)
                     num = va_arg(args, int);
                   else
                     num = va_arg(args, unsigned int);
                   str = number(str, num, base, field_width, precision, flags);
                 }
                 *str = '\0';
                 return str-buf;
               }
              
               /* 這就我們的 printf, 注意我們將參數(shù)輸出到串口 UART0,而非標(biāo)準(zhǔn)輸出*/
               void uart_printf(char *fmt, ...)
               {
                 va_list args;
              
                 va_start(args, fmt);
                 __vsprintf(sprint_buf, fmt,args);
                 va_end(args);
              
                 /* 將緩沖區(qū)的字符輸出到串口*/
                 uart_puts(sprint_buf);
               }


               /*
                * 文件 interrupt.c
                * 作用:設(shè)置并響應(yīng)按鍵中斷
                */
               #include "printf.h"
              
               #define GPECON (*(volatile unsigned long *)0x56000040)
               #define GPEDAT (*(volatile unsigned long *)0x56000044)
               #define GPEUP  (*(volatile unsigned long *)0x56000048)
               #define GPFCON (*(volatile unsigned long *)0x56000050)
               #define GPFDAT (*(volatile unsigned long *)0x56000054)
               #define GPFUP  (*(volatile unsigned long *)0x56000058)
               #define GPGCON (*(volatile unsigned long *)0x56000060)
               #define GPGDAT (*(volatile unsigned long *)0x56000064)
               #define GPGUP  (*(volatile unsigned long *)0x56000068)
               #define EINTMASK (*(volatile unsigned long *)0x560000a4)
               #define INTMSK   (*(volatile unsigned long *)0X4a000008)
               #define PRIORITY (*(volatile unsigned long *)0x4a00000c)
               #define EINTPEND (*(volatile unsigned long *)0x560000a8)
               #define INTPND   (*(volatile unsigned long *)0X4a000010)
               #define SRCPND   (*(volatile unsigned long *)0X4a000000)
              
               #define BIT_EINT0 (0x1 << 0)
               #define BIT_EINT2 (0x1 << 2)
               #define BIT_EINT8_23 (0x1 << 5)
              
               #define SET_KEY_INTERRUPT_REG() ({     \
                  GPGCON = (GPGCON & (~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) ; \
                  GPGDAT = GPGDAT & (~((1<<6)|(1<<2)));    \
                  GPECON = (GPECON & (~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22)); \
                  GPEDAT = GPEDAT & (~((1<<13)|(1<<11)));    \
                  GPGCON = (GPGCON & (~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) ; \
                  GPFCON = (GPFCON & (~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) ; \
                })
              
               __inline void ClearPending(int bit)
               {
                 SRCPND = bit;
                 INTPND = bit;
               }
              
               void init_irq( ) {
                 GPFCON = ((0x1<<8) | (0x1 << 10) | (0x1 << 12) | (0x1 << 14));      // Set the led D9~D12 output
                 /*
                 GPGCON = (GPGCON & (~((3<<12)|(3<<4)))) | ((1<<12)|(1<<4)) ;  // GPGCON6,2 set output
                                                                                     // GPGCON6:KSCAN1
                                                                                     // GPGCON2:KSCAN3
                 GPGDAT = GPGDAT & (~((1<<6)|(1<<2)));                   // GPGDAT6,2 output 0
              
                 GPECON = (GPECON & (~((3<<26)|(3<<22)))) | ((1<<26)|(1<<22));  // GPECON13,11 set output
                 GPEDAT = GPEDAT & (~((1<<13)|(1<<11)));                   // GPEDAT13,11 output 0
              
                 GPGCON = (GPGCON & (~((3<<22)|(3<<6)))) | ((2<<22)|(2<<6)) ;  // GPGCON11,3 set EINT
                 GPFCON = (GPFCON & (~((3<<4)|(3<<0)))) | ((2<<4)|(2<<0)) ;          // GPFDAT2,0 set EINT
                 */
                 // Use the defined micro instead of above code
                 SET_KEY_INTERRUPT_REG();
              
                 GPFUP |= (1<<0) | (1<<2);                       // Up
                 GPGUP |= (1<<3) | (1<<11);                      // Up 
              
                 EINTPEND |= (1 << 19) | (1 << 11);              // Clear eint 11,19
                 EINTMASK &= (~((1 << 19) | (1 << 11)));         // Enable EINT11,19
              
                 ClearPending(BIT_EINT0|BIT_EINT2|BIT_EINT8_23); // Enable EINT0,2 and the EINT8_23
                 INTMSK &= (~0x25);                       
                 return;
               }
              
               int Key_Scan( void )
               {
                 int i;
                 for(i = 0; i < 1000 ;i++) ;
                 GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (1<<6) | (0<<2) ;  //GPG6,2 output 0
                 GPEDAT = (GPEDAT &(~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) ; //GPE13,11 output 0
                 if(      (GPFDAT&(1<< 0)) == 0 )  return 16 ;
                 else if( (GPFDAT&(1<< 2)) == 0 )  return 15 ;
                 else if( (GPGDAT&(1<< 3)) == 0 )  return 14 ;
                 else if( (GPGDAT&(1<<11)) == 0 )  return 13 ;
              
                 GPGDAT = (GPGDAT &(~((1<<6)|(1<<2)))) | (0<<6) | (1<<2) ;  //GPG6,2 output 0
                 GPEDAT = (GPEDAT & (~((1<<13)|(1<<11)))) | (1<<13) | (1<<11) ; //GPE13,11 output 0
                 if(      (GPFDAT&(1<< 0)) == 0 )  return 11 ;
                 else if( (GPFDAT&(1<< 2)) == 0 )  return 8 ;
                 else if( (GPGDAT&(1<< 3)) == 0 )  return 5 ;
                 else if( (GPGDAT&(1<<11)) == 0 )  return 2 ;
              
                 GPGDAT = (GPGDAT & (~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) ;  //GPG6,2 output 0
                 GPEDAT = (GPEDAT & (~((1<<13)|(1<<11)))) | (1<<13) | (0<<11) ; //GPE13,11 output 0
                 if(      (GPFDAT&(1<< 0)) == 0 )  return 10 ;
                 else if( (GPFDAT&(1<< 2)) == 0 )  return 7 ;
                 else if( (GPGDAT&(1<< 3)) == 0 )  return 4 ;
                 else if( (GPGDAT&(1<<11)) == 0 )  return 1 ;
              
                 GPGDAT = (GPGDAT & (~((1<<6)|(1<<2)))) | (1<<6) | (1<<2) ;  //GPG6,2 output 0
                 GPEDAT = (GPEDAT & (~((1<<13)|(1<<11)))) | (0<<13) | (1<<11) ; //GPE13,11 output 0
                 if(      (GPFDAT&(1<< 0)) == 0 )  return 12 ;
                 else if( (GPFDAT&(1<< 2)) == 0 )  return 9 ;
                 else if( (GPGDAT&(1<< 3)) == 0 )  return 6 ;
                 else if( (GPGDAT&(1<<11)) == 0 )  return 3 ;
                 else return 0xff ;
               }
              
               void EINT_Handle( void ) {
                 GPGCON = (GPGCON & (~((3<<22)|(3<<6)))) | ((0<<22)|(0<<6)) ; //GPG11,3 set input
                 GPFCON = (GPFCON & (~((3<<4)|(3<<0)))) | ((0<<4)|(0<<0)) ;         //GPF2, 0 set input
              
                 if(INTPND==BIT_EINT8_23) {
                   if(EINTPEND&(1<<11))
                     EINTPEND |= 1<< 11;
              
                   if(EINTPEND&(1<<19))   
                     EINTPEND |= 1<< 19;
              
                   ClearPending(BIT_EINT8_23);
                 }
                 else if(INTPND==BIT_EINT0) {
                   ClearPending(BIT_EINT0); 
                 } else if(INTPND==BIT_EINT2) {
                   ClearPending(BIT_EINT2);
                 }
                
                 int key = Key_Scan() ;
                 if( key != 0xff ) {
                   uart_printf( "K%d is pressed!\n", key ) ;
                   GPFDAT = ~(key << 4);
                 }
              
                 SET_KEY_INTERRUPT_REG();
                 return;
               }

            這個(gè)文件里大部分代碼都是依芯片手冊(cè)來(lái)設(shè)置,請(qǐng)自行查找對(duì)照吧。


               /*
                * 文件 main.c
                * 作用:測(cè)試代碼
                */
               #include "serl.h"
               #include "printf.h"
              
               #define GPFCON (*(volatile unsigned long *)0x56000050)
               #define GPFDAT (*(volatile unsigned long *)0x56000054)
              
               int main()
               {
                 init_uart();
                 GPFDAT = 0x0;
                 uart_printf("starting:\n");
                 return 0;
               }

             

               # Makefile for compiling ARM program
               # Author: Jianbin Wang
               CC=arm-linux-gcc
               CFLAGS=-Wall -g -c
               LD=arm-linux-ld
               LDFLAGS:=$(LDFLAGS) -Ttext 0x30000000
              
               INCLUDES=-I./
               CFLAGS:=$(CFLAGS) $(INCLUDES)
               LIBS=-lgcc -L/usr/local/arm/3.3.2/lib/gcc-lib/arm-linux/3.3.2
              
               CONVERT=arm-linux-objcopy
               CVFLAGS=-O binary -S
               RM=rm -f
              
               SRCDIRS=.
               TARGET=main
               TMPOBJ=$(TARGET)_tmp.o
               SRCS=$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c $(dir)/*.s))
               OBJS=head.o mem.o flash.o nand_read.o main.o printf.o serl.o interrupt.o
              
               all:$(TARGET)
              
               $(TARGET):$(OBJS)
                $(LD) $(LDFLAGS) -o $(TMPOBJ) $(OBJS) $(LIBS)
                $(CONVERT) $(CVFLAGS) $(TMPOBJ) $(TARGET)
              
               $(OBJS):$(SRCS)
                $(CC) $(CFLAGS) $(SRCS)
              
               clean:
                $(RM) $(TARGET)
                $(RM) $(TMPOBJ)
                $(RM) $(OBJS)

             


            三、編譯、燒寫(xiě)、測(cè)試
               Make 一下就會(huì)生成我們要的文件 main, 將其通過(guò) JTAG 燒入 Nand Flash。用超級(jí)終
            連接到開(kāi)發(fā)板,注意波特率設(shè)為 57600,數(shù)據(jù)位 8,無(wú)奇偶校正,停止位1,無(wú)數(shù)據(jù)流控制。現(xiàn)
            在 Reset 一下的開(kāi)發(fā)板,然后靜靜的等待吧,生成的二進(jìn)制文件 main 有 39K 大呢,要等它
            完全復(fù)制到 SDRAM 至少要兩三分鐘...哈哈,你會(huì)發(fā)現(xiàn) D9~D12 四個(gè)led 燈被點(diǎn)亮了,并且
            當(dāng)你按下某個(gè)按鍵時(shí),這四個(gè)燈會(huì)指示你按下的是第幾個(gè)鍵,你還會(huì)發(fā)超級(jí)終端上有文字顯示,
            例如當(dāng)你按下按鍵 2 時(shí):

                 K2 is pressed!

            呵呵,是不是很酷,你明白為 ARM 編寫(xiě)中斷的流程了嗎 :-)

            posted on 2008-01-18 19:24 Normandy 閱讀(2262) 評(píng)論(3)  編輯 收藏 引用 所屬分類: Embeded Area

            評(píng)論

            # re: 學(xué)習(xí) ARM 系列 -- FS2410 開(kāi)發(fā)板上的中斷編程  回復(fù)  更多評(píng)論   

            樓主太強(qiáng)大了!
            2008-01-18 19:28 | playboy

            # re: 學(xué)習(xí) ARM 系列 -- FS2410 開(kāi)發(fā)板上的中斷編程  回復(fù)  更多評(píng)論   

            我對(duì)樓主的敬仰之情有如滔滔江水,連~綿不絕
            2008-01-18 19:29 | abcdefg

            # re: 學(xué)習(xí) ARM 系列 -- FS2410 開(kāi)發(fā)板上的中斷編程  回復(fù)  更多評(píng)論   

            摟住真強(qiáng)人阿
            2008-01-24 17:20 | niube' son
            亚洲va中文字幕无码久久不卡| 久久精品国产免费观看三人同眠| 久久99精品国产麻豆宅宅| 久久se这里只有精品| 久久成人国产精品二三区| 久久午夜无码鲁丝片| 性色欲网站人妻丰满中文久久不卡| 亚洲欧美另类日本久久国产真实乱对白 | 99久久精品免费看国产免费| 77777亚洲午夜久久多喷| 久久av无码专区亚洲av桃花岛| 亚洲精品国产字幕久久不卡| 综合久久国产九一剧情麻豆 | 久久精品中文无码资源站| 偷偷做久久久久网站| 久久综合偷偷噜噜噜色| 久久精品国产日本波多野结衣| 亚洲AV无码久久精品蜜桃| 久久精品无码一区二区无码| 97久久超碰国产精品2021| yellow中文字幕久久网| 久久久久久极精品久久久| 亚洲国产精品无码久久九九| 亚洲中文字幕无码久久2017| 丰满少妇高潮惨叫久久久| 精品久久久久久久久久久久久久久| 国产精品伊人久久伊人电影| 性高朝久久久久久久久久| 99久久99久久精品国产片果冻 | 国产精品久久久天天影视| 国产精品伊人久久伊人电影| 综合久久精品色| 久久久久久久久久久久中文字幕| 国产情侣久久久久aⅴ免费| 国产精品成人99久久久久| 亚洲成av人片不卡无码久久| 99久久国产宗和精品1上映| 久久综合九色综合97_久久久| 蜜桃麻豆www久久国产精品| 久久久久无码精品国产不卡| 国产农村妇女毛片精品久久|