您的位置:首页 > 编程语言

学习 ARM 系列 -- FS2410 开发板上的中断编程

2012-03-31 10:30 423 查看

学习 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 编写中断的流程了吗 :-)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息