青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 60, 文章 - 0, 評論 - 197, 引用 - 0
數據加載中……

學習 ARM 系列 -- FS2410 開發板上的中斷編程

一、目的
   中斷服務程序在操作系統中無疑占有非常重要的地位,編寫中斷程序不僅要會運用底層的
匯編語言,還要了解 ARM 的體系架構。那這一節我們就通過中斷編程來響應 FS2410開發板
上的 16 個按鍵,實現依次按下16個鍵時,D9~D12 四個 Led 從 0~15 進行計數,并通
過上個實驗實現的 uart_printf 向串口發送數據 Kn is pressed!。


二、代碼
   我們直接分析代碼,代碼中只有簡略的注釋,必要時我會在整個代碼文件的后面對相應的細節
進行解釋。先來分析 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 }^
  

呵呵,不知不覺 head.s 的代碼已經很長了,我們來看一下它的執行流程:
(1) 設置中斷向量表。你也許在這里有疑問,為什么一開始就有 8 個分支跳轉指令?我們
    先來研究一下 ARM 如何響應異常/中斷,看下表:

      -------------------------------------------------------------
          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 種異常/中斷,每種異常/中斷都有固定的地址,這個地址叫
    中斷向量,一般我們會在這個地址放一條分支跳轉指令,當異常/中斷發生時,ARM 就
    到這個地址執行這個跳轉指令,從而調用相應的中斷服務程序。

    等等,這里是不是有點問題?呵呵,你也許已經發現了,這里只有 7 種異常/中斷,那
    我們的程序怎么會有 8 條分支跳轉指令呢? 因為中斷向量即地址 0x00000014 被ARM
    保留用做將來擴展之用,但我們還需用一條指令(4字節)來填充這個位置,只不過它不會
    被 ARM 執行。

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

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


   @ 文件 flash.s
   @ 作用:設置 Nand Flash 的控制寄存器、讀取 Nand Flash
   @ 中的代碼到 SDRAM 的指定位置,更多細節請參考我前面的隨筆
   .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 中讀取一塊數據到 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
    * 作用:定義相關寄存器、UART 初始化函數聲明、串口讀寫函數的聲明
    */  
   #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
    * 作用:對外提供調用接口 uart_printf
    */  
   #ifndef __PRINTF_HH__
   #define __PRINTF_HH__
  
   void uart_printf(char *fmt, ...);
  
   #endif

  
   /*
    * 文件 printf.c
    * 文件中大部分代碼來自 linux 0.11 內核的 vsprintf.c, 只是作了相應的刪減,
    * <<Linux 內核完全注釋>> 上有更詳細的解釋
    */
   #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, 注意我們將參數輸出到串口 UART0,而非標準輸出*/
   void uart_printf(char *fmt, ...)
   {
     va_list args;
  
     va_start(args, fmt);
     __vsprintf(sprint_buf, fmt,args);
     va_end(args);
  
     /* 將緩沖區的字符輸出到串口*/
     uart_puts(sprint_buf);
   }


   /*
    * 文件 interrupt.c
    * 作用:設置并響應按鍵中斷
    */
   #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;
   }

這個文件里大部分代碼都是依芯片手冊來設置,請自行查找對照吧。


   /*
    * 文件 main.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)

 


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

     K2 is pressed!

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

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

評論

# re: 學習 ARM 系列 -- FS2410 開發板上的中斷編程  回復  更多評論   

樓主太強大了!
2008-01-18 19:28 | playboy

# re: 學習 ARM 系列 -- FS2410 開發板上的中斷編程  回復  更多評論   

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

# re: 學習 ARM 系列 -- FS2410 開發板上的中斷編程  回復  更多評論   

摟住真強人阿
2008-01-24 17:20 | niube' son
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            午夜精品亚洲一区二区三区嫩草| 日韩午夜中文字幕| 欧美激情综合| 欧美黄色片免费观看| 亚洲美女啪啪| 亚洲精品极品| 亚洲欧美日韩国产一区二区三区| 国产精品成人免费| 午夜久久美女| 久久免费视频观看| 亚洲欧美成人一区二区在线电影| 欧美一区二区精品| 日韩天堂在线观看| 久久成人精品一区二区三区| 亚洲人成网站在线播| 亚洲在线成人| 亚洲特黄一级片| 欧美插天视频在线播放| 欧美一区二区视频免费观看| 另类春色校园亚洲| 久久视频国产精品免费视频在线| 欧美日韩国产精品| 最近看过的日韩成人| 亚洲激情在线视频| 一区二区三区国产在线观看| 欧美成人国产va精品日本一级| 99re6这里只有精品视频在线观看| 亚洲午夜av| 在线观看一区视频| 久久精品国产亚洲高清剧情介绍| 亚洲影院在线| 欧美成人免费全部| 亚洲精品久久久久中文字幕欢迎你| 在线成人免费视频| 久久午夜羞羞影院免费观看| 久久精品国产一区二区三区免费看| 欧美高清自拍一区| 亚洲国内自拍| 激情欧美一区二区三区| 一区二区av在线| 午夜精品久久久久久久99水蜜桃| 国产精一区二区三区| 久久国产精品黑丝| 欧美成人dvd在线视频| 136国产福利精品导航网址| 欧美99久久| 欧美一级夜夜爽| 欧美风情在线| 久久精品女人的天堂av| 91久久综合| 国产一区二区三区自拍| 欧美精品999| 久久久久国产精品厨房| 日韩亚洲视频| 亚洲国产99| 麻豆精品网站| 久久精品二区三区| 99视频+国产日韩欧美| 欧美午夜一区| 蜜臀久久99精品久久久久久9| 一本久久a久久精品亚洲| 欧美a一区二区| 亚洲欧美视频在线观看视频| 国一区二区在线观看| 国产精品99免费看| 免费一级欧美片在线观看| 一个色综合导航| 亚洲国产老妈| 免费成人黄色片| 欧美成年人视频网站| 久久综合激情| 欧美bbbxxxxx| 欧美日产在线观看| 欧美日韩亚洲高清| 国产精品美女| 国产精品三上| 国产欧美一区二区精品秋霞影院 | 亚洲国产婷婷综合在线精品| 99精品视频免费在线观看| 国产精品成人aaaaa网站| 欧美精品一区二区三区在线播放| 免费国产一区二区| 免费成人美女女| 国产精品久久久久久久久果冻传媒 | 国产欧美日韩综合精品二区| 国产精品高潮在线| 国产精品久久久久久久久久免费 | 亚洲国产另类久久久精品极度| 久久综合亚洲社区| 欧美一区在线直播| 免费成人高清视频| 亚洲美女毛片| 久久亚洲国产精品日日av夜夜| 欧美精品一线| 国产精品青草久久| 亚洲国语精品自产拍在线观看| 日韩一区二区精品视频| 欧美一区二区三区视频免费播放 | 国产日韩精品一区二区三区在线| 国产精品网曝门| 日韩视频一区二区在线观看| 香蕉乱码成人久久天堂爱免费| 久久久久9999亚洲精品| 91久久午夜| 欧美xart系列高清| 国产欧美一区二区三区久久 | 久久天堂国产精品| 亚洲精品资源美女情侣酒店| 欧美在线视频在线播放完整版免费观看 | 国产日韩综合一区二区性色av| 亚洲免费久久| 亚洲日本欧美日韩高观看| 欧美在线视频播放| 国产精品女主播在线观看| 亚洲视频一区二区| 一本一本久久a久久精品牛牛影视| 欧美日韩麻豆| 午夜电影亚洲| 午夜在线观看欧美| 狠狠色丁香婷综合久久| 欧美 亚欧 日韩视频在线| 免费亚洲电影在线观看| 亚洲精品久久7777| av成人国产| 黄网站免费久久| 亚洲成人在线视频网站| 欧美日韩伦理在线| 欧美在线观看一区二区| 久久精品一区二区三区不卡牛牛 | 欧美在线观看日本一区| 狠狠色综合播放一区二区| 欧美激情中文不卡| 国产毛片一区二区| 欧美成人在线网站| 国产精品女主播在线观看 | 欧美成人精品1314www| 欧美激情一二区| 欧美在线影院在线视频| 欧美日韩精品在线观看| 久久色中文字幕| 中文日韩电影网站| 欧美一区二区三区免费视频| 日韩午夜在线| 久久久免费观看视频| 性久久久久久| 欧美视频在线观看 亚洲欧| 欧美成人一二三| 激情一区二区| 性色av香蕉一区二区| 欧美在线亚洲一区| 国产精品超碰97尤物18| 亚洲精品免费在线| 亚洲激情亚洲| 欧美精品亚洲精品| 欧美国产日韩a欧美在线观看| 国内久久视频| 老司机一区二区三区| 免播放器亚洲一区| 91久久精品国产91性色tv| 久久久久在线| 亚洲丶国产丶欧美一区二区三区| 国产欧美精品一区| 久久免费99精品久久久久久| 久久精品99| 亚洲黄一区二区三区| 麻豆成人小视频| 日韩一本二本av| 巨胸喷奶水www久久久免费动漫| 国产热re99久久6国产精品| 欧美亚洲系列| 亚洲激情成人在线| 中国成人黄色视屏| 国产欧美日韩一区| 欧美成在线观看| 一本大道久久a久久精品综合| 亚洲性人人天天夜夜摸| 国产情人综合久久777777| 久久综合狠狠| 亚洲在线观看免费| 欧美福利电影网| 久久er99精品| av成人免费| 亚洲国产三级网| 国产精品麻豆成人av电影艾秋| 久久精品一区| 欧美一区免费| 一区二区三区国产在线| 免费国产一区二区| 久久精品人人做人人综合| 日韩亚洲欧美一区二区三区| 麻豆精品视频在线观看视频| 99riav久久精品riav| 亚洲精品国产精品乱码不99按摩| 欧美电影资源| 久久久午夜电影| 中文日韩欧美| 猫咪成人在线观看| 亚洲综合精品自拍| 这里只有精品视频在线| 国产精品每日更新|