s3c6410开发板LED驱动程序设计详细…

时间:2022-03-02 13:34:35

s3c6410开发板LED驱动程序设计详细…

s3c6410开发板LED驱动程序设计详细…

s3c6410开发板LED驱动程序设计详细…

s3c6410开发板LED驱动程序设计详细…s3c6410开发板LED驱动程序设计详细…

2 下面来看看tiny6410关于LED的原理图如图(1)所示:

s3c6410开发板LED驱动程序设计详细…

图1    LED原理图

3 LED实例,代码如下所示:(代码摘自\光盘4\实验代码\3-3-1\src\main.c)

main.c

  1. #include "def.h"
  2. #include "gpio.h"
  3. #define LED1_ON   ~(1<<4)
  4. #define LED2_ON   ~(1<<5)
  5. #define LED3_ON   ~(1<<6)
  6. #define LED4_ON   ~(1<<7)
  7. #define LED1_OFF   (1<<4)
  8. #define LED2_OFF   (1<<5)
  9. #define LED3_OFF   (1<<6)
  10. #define LED4_OFF   (1<<7)
  11. #define LEDALL_OFF (0xf<<4)
  12. //GPIO
  13. #define GPIO_BASE               (0x7F008000)
  14. //oGPIO_REGS类型在 gpio.h 中定义
  15. #define GPIO       (( volatile oGPIO_REGS *)GPIO_BASE)
  16. //函数声明
  17. void delay(int times);
  18. void LedPortInit(void);
  19. void LedRun(void);
  20. int main(void)
  21. {
  22. LedPortInit();
  23. LedRun();
  24. }
  25. void delay(int times)
  26. {
  27. int i;
  28. for(;times>0;times--)
  29. for(i=0;i<3000;i++);
  30. }
  31. void LedPortInit(void)
  32. {
  33. u32 uConValue;
  34. uConValue = GPIO->rGPIOKCON0;
  35. uConValue &= ~(0xffff<<16);
  36. uConValue |= 0x1111<<16;
  37. GPIO->rGPIOKCON0 = uConValue;
  38. }
  39. void LedRun(void)
  40. {
  41. GPIO->rGPIOKDAT |= LEDALL_OFF;
  42. while(1)
  43. {
  44. GPIO->rGPIOKDAT &= LED1_ON;
  45. delay(1000);
  46. GPIO->rGPIOKDAT |= LEDALL_OFF;
  47. GPIO->rGPIOKDAT &= LED2_ON;
  48. delay(1000);
  49. GPIO->rGPIOKDAT |= LEDALL_OFF;
  50. GPIO->rGPIOKDAT &= LED3_ON;
  51. delay(1000);
  52. GPIO->rGPIOKDAT |= LEDALL_OFF;
  53. GPIO->rGPIOKDAT &= LED4_ON;
  54. delay(1000);
  55. GPIO->rGPIOKDAT |= LEDALL_OFF;
  56. }
  57. }

4 程序代码分析:

首先来看一下宏定义部分:#define GPIO_BASE (0x7F008000) 
,此处定义了GPIO所有相关寄存器的初始地址,由芯片手册S3C6410X.pdf,第308页可以得到此地址。以下为手册截图。由下图2可以看出,GPIO相关寄存器的初始地址即为GPACON的地址0x7F008000。

s3c6410开发板LED驱动程序设计详细…

图2 GPIO的内存映射地址

了解#define
GPIO     ((
volatile oGPIO_REGS
*)GPIO_BASE)之前我们先来看看oGPIO_REGS的定义(代码摘自\光盘4\实验代码\3-3-1\src\peripheral\gpio.h)

gpio.h

  1. #ifndef __GPIO_H__
  2. #define __GPIO_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. #include "def.h"
  7. typedef struct tag_GPIO_REGS
  8. {
  9. u32 rGPIOACON;          //0x7F008000
  10. u32 rGPIOADAT;
  11. u32 rGPIOAPUD;
  12. u32 rGPIOACONSLP;
  13. u32 rGPIOAPUDSLP;
  14. u32 reserved1[3];
  15. u32 rGPIOBCON;          //0x7F008020
  16. u32 rGPIOBDAT;
  17. u32 rGPIOBPUD;
  18. u32 rGPIOBCONSLP;
  19. u32 rGPIOBPUDSLP;
  20. u32 reserved2[3];
  21. u32 rGPIOCCON;          //0x7F008040
  22. u32 rGPIOCDAT;
  23. u32 rGPIOCPUD;
  24. u32 rGPIOCCONSLP;
  25. u32 rGPIOCPUDSLP;
  26. u32 reserved3[3];
  27. u32 rGPIODCON;          //0x7F008060
  28. u32 rGPIODDAT;
  29. u32 rGPIODPUD;
  30. u32 rGPIODCONSLP;
  31. u32 rGPIODPUDSLP;
  32. u32 reserved4[3];
  33. u32 rGPIOECON;          //0x7F008080
  34. u32 rGPIOEDAT;
  35. u32 rGPIOEPUD;
  36. u32 rGPIOECONSLP;
  37. u32 rGPIOEPUDSLP;
  38. u32 reserved5[3];
  39. u32 rGPIOFCON;          //0x7F0080A0
  40. u32 rGPIOFDAT;
  41. u32 rGPIOFPUD;
  42. u32 rGPIOFCONSLP;
  43. u32 rGPIOFPUDSLP;
  44. u32 reserved6[3];
  45. u32 rGPIOGCON;          //0x7F0080C0
  46. u32 rGPIOGDAT;
  47. u32 rGPIOGPUD;
  48. u32 rGPIOGCONSLP;
  49. u32 rGPIOGPUDSLP;
  50. u32 reserved7[3];
  51. u32 rGPIOHCON0;         //0x7F0080E0
  52. u32 rGPIOHCON1;
  53. u32 rGPIOHDAT;
  54. u32 rGPIOHPUD;
  55. u32 rGPIOHCONSLP;
  56. u32 rGPIOHPUDSLP;
  57. u32 reserved8[2];
  58. u32 rGPIOICON;          //0x7F008100
  59. u32 rGPIOIDAT;
  60. u32 rGPIOIPUD;
  61. u32 rGPIOICONSLP;
  62. u32 rGPIOIPUDSLP;
  63. u32 reserved9[3];
  64. u32 rGPIOJCON;          //0x7F008120
  65. u32 rGPIOJDAT;
  66. u32 rGPIOJPUD;
  67. u32 rGPIOJCONSLP;
  68. u32 rGPIOJPUDSLP;
  69. u32 reserved10[3];
  70. u32 rGPIOOCON;          //0x7F008140
  71. u32 rGPIOODAT;
  72. u32 rGPIOOPUD;
  73. u32 rGPIOOCONSLP;
  74. u32 rGPIOOPUDSLP;
  75. u32 reserved11[3];
  76. u32 rGPIOPCON;          //0x7F008160
  77. u32 rGPIOPDAT;
  78. u32 rGPIOPPUD;
  79. u32 rGPIOPCONSLP;
  80. u32 rGPIOPPUDSLP;
  81. u32 reserved12[3];
  82. u32 rGPIOQCON;          //0x7F008180
  83. u32 rGPIOQDAT;
  84. u32 rGPIOQPUD;
  85. u32 rGPIOQCONSLP;
  86. u32 rGPIOQPUDSLP;
  87. u32 reserved13[3];
  88. u32 rSPCON;             //0x7F0081A0
  89. u32 reserved14[3];
  90. u32 rMEM0CONSTOP;       //0x7F0081B0
  91. u32 rMEM1CONSTOP;       //0x7F0081B4
  92. u32 reserved15[2];
  93. u32 rMEM0CONSLP0;       //0x7F0081C0
  94. u32 rMEM0CONSLP1;       //0x7F0081C4
  95. u32 rMEM1CONSLP;        //0x7F0081C8
  96. u32 reserved;
  97. u32 rMEM0DRVCON;        //0x7F0081D0
  98. u32 rMEM1DRVCON;        //0x7F0081D4
  99. u32 reserved16[10];
  100. u32 rEINT12CON;         //0x7f008200
  101. u32 rEINT34CON;         //0x7f008204
  102. u32 rEINT56CON;         //0x7f008208
  103. u32 rEINT78CON;         //0x7f00820C
  104. u32 rEINT9CON;          //0x7f008210
  105. u32 reserved17[3];
  106. u32 rEINT12FLTCON;      //0x7f008220
  107. u32 rEINT34FLTCON;      //0x7f008224
  108. u32 rEINT56FLTCON;      //0x7f008228
  109. u32 rEINT78FLTCON;      //0x7f00822C
  110. u32 rEINT9FLTCON;       //0x7f008230
  111. u32 reserved18[3];
  112. u32 rEINT12MASK;        //0x7f008240
  113. u32 rEINT34MASK;        //0x7f008244
  114. u32 rEINT56MASK;        //0x7f008248
  115. u32 rEINT78MASK;        //0x7f00824C
  116. u32 rEINT9MASK;         //0x7f008250
  117. u32 reserved19[3];
  118. u32 rEINT12PEND;        //0x7f008260
  119. u32 rEINT34PEND;        //0x7f008264
  120. u32 rEINT56PEND;        //0x7f008268
  121. u32 rEINT78PEND;        //0x7f00826C
  122. u32 rEINT9PEND;         //0x7f008270
  123. u32 reserved20[3];
  124. u32 rPRIORITY;          //0x7f008280
  125. u32 rSERVICE;           //0x7f008284
  126. u32 rSERVICEPEND;       //0x7f008288
  127. u32 reserved21;
  128. u32 reserved22[348];
  129. u32 rGPIOKCON0;         //0x7f008800
  130. u32 rGPIOKCON1;         //0x7f008804
  131. u32 rGPIOKDAT;          //0x7f008808
  132. u32 rGPIOKPUD;          //0x7f00880c
  133. u32 rGPIOLCON0;         //0x7f008810
  134. u32 rGPIOLCON1;         //0x7f008814
  135. u32 rGPIOLDAT;          //0x7f008818
  136. u32 rGPIOLPUD;          //0x7f00881c
  137. u32 rGPIOMCON;          //0x7f008820
  138. u32 rGPIOMDAT;          //0x7f008824
  139. u32 rGPIOMPUD;          //0x7f008828
  140. u32 reserved23;
  141. u32 rGPIONCON;          //0x7f008830
  142. u32 rGPIONDAT;          //0x7f008834
  143. u32 rGPIONPUD;          //0x7f008838
  144. u32 reserved24;
  145. u32 reserved25[16];
  146. u32 rSPCONSLP;          //0x7f008880
  147. u32 reserved26[31];
  148. u32 rEINT0CON0;         //0x7f008900
  149. u32 rEINT0CON1;         //0x7f008904
  150. u32 reserved27[2];
  151. u32 rEINT0FLTCON0;      //0x7f008910
  152. u32 rEINT0FLTCON1;      //0x7f008914
  153. u32 rEINT0FLTCON2;      //0x7f008918
  154. u32 rEINT0FLTCON3;      //0x7f00891c
  155. u32 rEINT0MASK;         //0x7f008920
  156. u32 rEINT0PEND;         //0x7f008924
  157. u32 reserved28[2];
  158. u32 rSLPEN;             //0x7f008930
  159. }
  160. oGPIO_REGS;
  161. #ifdef __cplusplus
  162. }
  163. #endif
  164. #endif //__GPIO_H__

由此可以看出oGPIO_REGS为一结构体,(( volatile oGPIO_REGS
*)GPIO_BASE)为指向此结构体的指针,该指针即GPIO指向的初始地址为GPIO_BASE(0x7F008000),通过使用此指针,可以遍历到从GPIO_BASE地址(0x7F008000)开始到0x7F008930地址处的所有寄存器。注意:上面结构体中所有元素,类型都是u32类型的,刚好四个字节,同时,由图2可知,如GPACON和GPADAT等寄存器地址都相差4,对于这段连续地址,如若中间没有对应某个寄存器,则用某些u32类型的数组填充,如u32
reserved1[3]等等。

下面开始看main.c中的main函数,main函数主要完成两个步骤,(1)LED初始化(LedPortInit()),(2)点亮LED(LedRun()).

LED初始化:

GPK总共有16个引脚,而每个引脚需要GPIO控制寄存器(GP*CON)使用4位来控制IO管脚的功能,即4*16=64位来控制所有GPK组的16个引脚。所以需要GPK使用了两个控制寄存器,GPKCON0和GPKCON1,从图1所示,我们使用的是GPK4,GPK5,GPK6,GPK7来控制LED灯的点亮与熄灭,所以此处我们只需使用GPKCON0来将GPK4,GPK5,GPK6,GPK7设置成输出功能。如图3所示,GPKCON寄存器配置如下:

s3c6410开发板LED驱动程序设计详细…

图3 GPKCON寄存器配置图

配置代码如下:

1 .      
u32 uConValue;

2 .
     
uConValue = GPIO->rGPIOKCON0;

3 .      
uConValue &=
~(0xffff<<16);     
0000 0000 0000 0000 1111 1111 1111 1111

4 .      
uConValue |= 0x1111<<16;

5 .      
GPIO->rGPIOKCON0 = uConValue;

首先我们要知道,在控制某个管脚的时候,我们不能去改变其它不使用管脚的状态,第二行获得GPKCON此时的状态将其赋给uConValue,第三行用于将GPKCON的高16位清零,低16位不变;第四行用于将GPKCON的高16为变为0001
0001 0001
0001(即GPK4,GPK5,GPK6,GPK7管脚都设置为输出模式),低16为仍然不变。最后将此值赋回到GPKCON寄存器当中。至此,完成整个LED的初始化工作。

点亮LED:注意GPKDAT为16位寄存器,虽然由gpio.h中看到rGPIOKDAT为32位,只是相当于我们忽略了其中的高16位,因为数据是从低地址往高地址处依次存放的。

GPIO->rGPIOKDAT |=
LEDALL_OFF;   
//4个灯全灭

while(1)
       
 {
                
GPIO->rGPIOKDAT &=
LED1_ON;         //GPK4管脚的灯亮

delay(1000);

GPIO->rGPIOKDAT |=
LEDALL_OFF;   //GPK4管脚的灯灭

GPIO->rGPIOKDAT &=
LED2_ON;     
//GPK5管脚的灯亮
                
delay(1000);
                
GPIO->rGPIOKDAT |=
LEDALL_OFF;  //GPK4管脚的灯灭

GPIO->rGPIOKDAT &=
LED3_ON;    
//GPK6管脚的灯亮
                
delay(1000);
                
GPIO->rGPIOKDAT |= LEDALL_OFF;  //GPK4管脚的灯灭

GPIO->rGPIOKDAT &=
LED4_ON;   //GPK7管脚的灯亮
                
delay(1000);
                
GPIO->rGPIOKDAT |= LEDALL_OFF; 
//GPK4管脚的灯灭
  }

首先通过如下宏定义来表明LED的亮与灭。

#define LED1_ON  
~(1<<4)          
执行步骤:1<<4  -> ~(1<<4)
,对应步骤为:0000 0000 0000 0001->0000 0000 0001
0000->1111 1111 1110
1111
#define LED2_ON  
~(1<<5)

#define LED3_ON  
~(1<<6)
#define LED4_ON  
~(1<<7)

#define LED1_OFF  
(1<<4)        
执行步骤:1<<4         对应步骤为:0000
0000 0000 0001->0000 0000 0001 0000
#define LED2_OFF  
(1<<5)
#define LED3_OFF  
(1<<6)
#define LED4_OFF  
(1<<7)
#define LEDALL_OFF
(0xf<<4)    
执行步骤:0xf<<4, 对应步骤为:0000 0000 0000 1111->0000 0000 1111 0000

下面完成整个程序的运行步骤:

1 打开rvds

s3c6410开发板LED驱动程序设计详细…

新建一个空的arm可执行镜像LED:

s3c6410开发板LED驱动程序设计详细…

在E:\tiny6410下自动多出一个LED目录

s3c6410开发板LED驱动程序设计详细…

目录下自动创建了如下一些文件及文件夹:

s3c6410开发板LED驱动程序设计详细…

将src目录和6410_scatter.txt拖入LED目录下:

s3c6410开发板LED驱动程序设计详细…

将src下的代码直接拖入rvds:

s3c6410开发板LED驱动程序设计详细…

得到如下添加代码后的工程,并打开main函数。

s3c6410开发板LED驱动程序设计详细…

开始配置工程:

s3c6410开发板LED驱动程序设计详细…

1 在汇编过程中选择处理器型号ARM1176JZF-S

s3c6410开发板LED驱动程序设计详细…

2 在编译中选择处理器型号ARM1176JZF-S

s3c6410开发板LED驱动程序设计详细…

3 在链接过程中选择scattered,文件选择scattered.txt

s3c6410开发板LED驱动程序设计详细…

保存后,编译程序,出现如下错误:

s3c6410开发板LED驱动程序设计详细…

解决方法:在配置框中的汇编的预处理中做如下设置:

s3c6410开发板LED驱动程序设计详细…

然后点击Add,将VIC_MODE预处理值设为1:

s3c6410开发板LED驱动程序设计详细…

保存后重新编译,编译通过,在Debug目录下会多出一个LED.axf文件,此文件为要运行在开发板的文件。

现在开始通过JLINK来调试开发板。首先链接开发板与jlink线。

将开发板上的S2拨到Nand
Flash启动那一侧,开启开发板电源,在超级终端上快速按下回车键,让U-Boot停留在功能选单上,不要让它进入Linux系统,如下图所示:

s3c6410开发板LED驱动程序设计详细…

在XP里,点击开始菜单,选择程序->SEGGER->J-Link ARM
V4.10i->J-Link GDB Server,启动画面如下所示:

s3c6410开发板LED驱动程序设计详细…

上图表明jlink已经正确链接上了。

然后需要配置AXD Debugge,让它使用J-Link来调试,通过以下方法启动AXD Debugger

s3c6410开发板LED驱动程序设计详细…

启动AXD Debugger后,在AXD
Debugger主界面上打开主菜单的Options -> Configure
Target,在弹出的Choose Target对话框中,点击Add,
将会弹出文件选择对话框,在文件打开对话框中,定位到J-Link的安装目录(默认是E:\Program
Files\SEGGER\JLinkARM_V410i),在目录中选择JLinkRDI.dll打开即可,如下图所示:

s3c6410开发板LED驱动程序设计详细…

可能AXD会提示找不到JLinkARM.DLL,如下图所示:

s3c6410开发板LED驱动程序设计详细…

解决方法是:先不理会这个对话框,打开我的电脑,再次定位到J-Link的安装目录(默认是E:\Program
Files\SEGGER\JLinkARM_V410i),将其中的JLinkARM.DLL文件拷贝到RVDS的安装目录下的Bin目录下(默认是C:\Program
Files\ARM\ADSv1_2\Bin),再在上面的对话框上点击“确定”即可。

下面通过File->Load  image,载入LED.axf文件,进行调试。