Gpio实验
一 用汇编点亮一个led
1 看原理图 GPK4=0 ,led亮GPK4=1,led灭
2 怎么让GPK4输出高低电平 (看芯片手册,操作寄存器实现)
配置功能:输入/输出/其他
设置其输出高/低电平
3 查看用户手册
GPK4[19:16]
0000 = Input 0001 = Output
0010 = Host I/F DATA[4] 0011 = HSI TX READY
0100 = Reserved 0101 = DATA_CF[4]
0110 = Reserved 0111 = Reserved
GPKDAT 在第4位写写0就对应GPK4
GPK[15:0] [15:0]
When the port is configured as input port, the correspondingbit is the pin state.
When the port is configured as output port, the pin state isthe same as the
corresponding bit. When the port is configured as functionalpin, the undefined
value will be read.
Register Address R/W Description ResetValue
GPKCON0 0x7F008800 R/WPortK Configuration Register 00x22222222
GPKCON1 0x7F008804 R/W PortK Configuration Register 10x22222222
GPKDAT 0x7F008808R/W Port K Data Register Undefined
GPKPUD 0x7F00880C R/W Port K Pull-up/downRegister 0x55555555
协处理器
查看arm11芯片手册:
Cpu 访问的地址:内存0-0x6fff ffff
外设0x7000 0000-0x7fff ffff
c15 0 c2 4 Peripheral Port Memory
Remap
R/W, B, X R/W 0x00000000 page3-174
CRn Op1 CRm Op2 Register oroperation S type
NS
type
Reset
value
Page
b10011 = 256MB
For example:
MRC p15, 0, <Rd>, c15, c2,4 ; Read Peripheral Port Memory Remap Register
MCR p15, 0, <Rd>, c15, c2,4 ; Write Peripheral Port Memory Remap Register
查看6410用户手册
Register AddressR/W Description Reset Value
WTCON 0x7E004000 R/W Watchdogtimer control register 0x8021
示例代码如下:
start.S文件
.globl _start
_start:
/*硬件的相关设置:把外设的基地址告诉cpu*/
ldr r0,=0x70000000 @伪汇编指令
orrr0,r0,#0x13 @按位逻辑或操作
mcrp15,0,r0,c15,c2,4 @b10011 = 256MB ,arm寄存器到协处理寄存器的数据传输
/*关闭看门狗*/
/*往往WTCON(0x7E004000)写0*/
ldrr0,=0x7E004000 @字数据读取指令
mov r1,#0@数据传送指令
strr1,[r0] @将寄存器中数据写入到内存单元
/*设置GPKCON GPK4作为输出引脚*/
ldr r1,=0x7F008800 @gpkcon的地址
movr0,#0x10000000 @设为输出引角
strr0,[r1] @将寄存器数据写入到内存单元
/*设置GPKDAT让GPK4输出0*/
ldr r1,=0x7F008808 @gpkdat的地址
mov r0,#0
str r0,[r1]
halt:
b halt
Makefile文件
1 Windows下的makefile文件
all : led.bin
led.bin:start.o
arm-elf-ld -Ttext 0 -o led.elf start.o
arm-elf-objcopy -O binary led.elf led.bin
arm-elf-objdump -D led.elf > led.dis
start.o :start.S
arm-elf-gcc -o start.o start.S -c
clean:
rm *.o led.elf led.bin led.dis
2 Linux下的makefile文件
led.bin: start.o
@-Ttext 0 表示代码段的地址为0
@nandFlash前4k数据会放到sram中,cpu从0地址开始读取
arm-linux-ld-Ttext 0 -o led.elf start.o
@输出二进制文件
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led.dis
start.o : start.S
arm-linux-gcc-o start.o start.S -c
clean:
rm *.o led.elfled.bin led.dis
编译 make
将编译好的文件烧写到开发板的两种方法:
1 将led_on.bin烧写到nandflash中,如同烧写linux类似,将led_on.bin放到images目录下
修改friendlyARM.ini
Action=install
OS=UserBin
UserBin-Image=led_on.bin
2 使用openjtag烧写
a进入应用目录D:\c_porjects\6410\1th_led,执行make命令编译程序
b 开发板烧写的是linux系统,
c打开openODC程序指定开发板型号,设定工作目录,然后点击connect
此时可能有很多警告提示,先设为SD卡启动(不需插SD卡),再点connect,正常后直接
带电拔到NAND启动
d 点击tellnet,执行以下命令
注:如果点击telnet没有反应,可以在windows命令窗口执行如下命令:
Telnet 127.0.0.1 4444
二 点亮四个led灯,示例代码如下:
start.S文件
.globl _start
_start:
/*硬件相关设置*/
ldrr0,=0x70000000
orr r0,r0,#0x13
mcr p15,0,r0,c15,c2,4
/*关闭看门狗*/
ldrr0,=0x7e004000
mov r1,#0
str r1,[r0]
/*设置GPKCON GPK4/5/6/7作为输出*/
ldrr1,=0x7F008800
ldrr0,=0x11110000
str r0,[r1]
/*设置GPKDAT让GPK4输出0*/
ldrr1,=0x7F008808
mov r0,#0
loop:
str r0,[r1]
add r0,r0,#1
cmp r0,#16
moveq r0,#0
bl delay
b loop
delay:
movr2,#0x10000000
delay_loop:
sub r2,r2,#1
cmp r2,#0
bne delay_loop
mov pc,lr
halt:
b halt
Makefile文件同上
三 用c语言来实现点灯
1 硬件相关设置
2 调用c函数
示例代码如下:
void delay(){
volatile inti=0x10000;
while (i--);
}
int main(){
int i=0;
//volatile作用是不让编译器不要优化变量
volatileunsigned long *gpkcon = (volatile unsigned long *)0x7F008800;
volatileunsigned long *gpkdat = (volatile unsigned long *)0x7F008808;
*gpkcon=0x11110000;
while(1){
*gpkdat=i;
i++;
if(i==16)
i=0;
delay();
}
return 0;
}
启动文件,示例代码如下:
.globl _start
_start:
/*硬件相关设置*/
ldrr0,=0x70000000
orrr0,r0,#0x13
mcr p15,0,r0,c15,c2,4
/*关看门狗*/
ldrr0,=0x7E004000
mov r1,#0
str r1,[r0]
/*设置栈*/
ldr sp,=8*1024
bl main @跳转到main处执行,并将返回地址保存到LR寄存器(R14link @register链接寄存器)中
Halt:
Bhalt
Makefile文件内容如下:
led.bin: start.o led.o
arm-linux-ld-Ttext 0 -o led.elf start.o led.o
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led.dis
start.o : start.S
arm-linux-gcc-o start.o start.S -c
led.o:led.c
arm-linux-gcc-o led.o led.c -c
clean:
rm *.o led.elfled.bin led.dis
编译 make
烧写到开发板,方法同上
查看反汇编程序 led.dis,文件内容如下:
led.elf: fileformat elf32-littlearm
Disassembly of section .text:
00000000 <_start>:
//关看门狗
0: e3a00207 mov r0, #1879048192 ;0x70000000
4: e3800013 orr r0, r0, #19 ;0x13
8: ee0f0f92 mcr 15, 0, r0, cr15, cr2, {4}
c: e59f0010 ldr r0, [pc, #16] ;24 <halt+0x4>
10: e3a01000 mov r1, #0 ;0x0
14: e5801000 str r1, [r0]
//设置栈
18: e3a0da02 mov sp, #8192 ;0x2000
1c: eb00000e bl 5c <main>
00000020 <halt>:
20: eafffffe b 20 <halt>
24: 7e004000 .word 0x7e004000
00000028 <delay>:
28: e1a0c00d mov ip, sp
//将四个寄存器保存到栈中
2c: e92dd800 push {fp, ip, lr, pc}
30: e24cb004 sub fp, ip, #4 ;0x4
34: e24dd004 sub sp, sp, #4 ;0x4
38: e3a03801 mov r3, #65536 ;0x10000
3c: e50b3010 str r3, [fp, #-16]
40: e51b3010 ldr r3, [fp, #-16]
44: e2433001 sub r3, r3, #1 ;0x1
48: e50b3010 str r3, [fp, #-16]
4c: e51b3010 ldr r3, [fp, #-16]
50: e3730001 cmn r3, #1 ;0x1
54: 1afffff9 bne 40 <delay+0x18>
//从栈中恢复寄存器
58: e89da808 ldm sp, {r3, fp, sp, pc}
0000005c <main>:
5c: e1a0c00d mov ip, sp
60: e92dd800 push {fp, ip, lr, pc}
64: e24cb004 sub fp, ip, #4 ;0x4
68: e24dd00c sub sp, sp, #12 ;0xc
6c: e3a03000 mov r3, #0 ;0x0
70: e50b3018 str r3, [fp, #-24]
74: e3a0347f mov r3, #2130706432 ;0x7f000000
78: e2833b22 add r3, r3, #34816 ;0x8800
7c: e50b3014 str r3, [fp, #-20]
80: e3a0347f mov r3, #2130706432 ;0x7f000000
84: e2833b22 add r3, r3, #34816 ;0x8800
88: e2833008 add r3, r3, #8 ;0x8
8c: e50b3010 str r3, [fp, #-16]
90: e51b2014 ldr r2, [fp, #-20]
94: e3a03411 mov r3, #285212672 ;0x11000000
98: e2833811 add r3, r3, #1114112 ; 0x110000
9c: e5823000 str r3, [r2]
a0: e51b2018 ldr r2, [fp, #-24]
a4: e51b3010 ldr r3, [fp, #-16]
a8: e5832000 str r2, [r3]
ac: e51b3018 ldr r3, [fp, #-24]
b0: e2833001 add r3, r3, #1 ;0x1
b4: e50b3018 str r3, [fp, #-24]
b8: e51b3018 ldr r3, [fp, #-24]
bc: e3530010 cmp r3, #16 ;0x10
c0: 1a000001 bne cc <main+0x70>
c4: e3a03000 mov r3, #0 ;0x0
c8: e50b3018 str r3, [fp, #-24]
cc: ebffffd5 bl 28 <delay>
d0: eafffff2 b a0 <main+0x44>
Disassembly of section .comment:
00000000 <.comment>:
0: 43434700 movtmi r4, #14080 ;0x3700
4: 4728203a undefined
8: 2029554e eorcs r5, r9, lr, asr #10
c: 2e322e34 mrccs 14, 1, r2, cr2, cr4, {1}
10: Address 0x00000010 is out of bounds.
Disassembly of section .ARM.attributes:
00000000 <_stack-0x80000>:
0: 00000f41 andeq r0, r0, r1, asr #30
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 00000005 andeq r0, r0, r5
四 轮流点亮led灯,启动文件和makefile文件与上面相同
示例代码如下:
/*初始化led寄存器指针*/
#define gpkcon (*(volatile unsigned long *)0x7F008800)
#define gpkdat (*(volatile unsigned long *)0x7F008808)
#define gpk4_out (1<<(4*4))
#define gpk5_out (1<<(5*4))
#define gpk6_out (1<<(6*4))
#define gpk7_out (1<<(7*4))
void delay(volatile unsigned long dly)
{
for(;dly>0;dly--);
}
int main(void)
{
int i = 0;
/*初始化gpk4,5,6,7 */
//*gpkcon =0x11110000;
gpkcon=gpk4_out|gpk5_out|gpk6_out|gpk7_out;
while (1)
{
delay(30000);
gpkdat = (~(i<<4));
if (++i == 16)
{
i= 0;
}
}
return 0;
}
五 按键按制led灯
查看原理图
Eint0 Eint1 Eint2 Eint3对应按键k1 k2 k3 k4
对应的寄存器为 GPN0-3
查看芯片手册
配置key为输入,led为输出
读key值,根据值来设置led引脚
Led.c示例代码如下,启动文件同以上两个程序
/*初始化led寄存器指针*/
#define gpkcon (*(volatile unsigned long *)0x7F008800)
#define gpkdat (*(volatile unsigned long *)0x7F008808)
#define gpk4_out (1<<(4*4))
#define gpk5_out (1<<(5*4))
#define gpk6_out (1<<(6*4))
#define gpk7_out (1<<(7*4))
#define gpk4_msk (15<<(4*4))
#define gpk5_msk (15<<(5*4))
#define gpk6_msk (15<<(6*4))
#define gpk7_msk (15<<(7*4))
/*初始化key寄存器指针*/
#define gpncon (*(volatile unsigned long *)0x7F008830)
#define gpndat (*(volatile unsigned long *)0x7F008834)
#define gpn0_in (0<<(0*2))
#define gpn1_in (0<<(1*2))
#define gpn2_in (0<<(2*2))
#define gpn3_in (0<<(3*2))
#define gpn0_msk (3<<(0*2))
#define gpn1_msk (3<<(1*2))
#define gpn2_msk (3<<(2*2))
#define gpn3_msk (3<<(3*2))
int main(void)
{
unsigned longdwDat;
/*初始化gpk4,5,6,7 四根引脚设为输出*/
//*gpkcon =0x11110000;
gpkcon &= ~(gpk4_msk | gpk5_msk | gpk6_msk| gpk7_msk);
gpkcon |= gpk4_out | gpk5_out | gpk6_out |gpk7_out;
//gpkcon=gpk4_out|gpk5_out|gpk6_out|gpk7_out;
/*初始化keygpn 0,1,2,3 四根引脚设为输入*/
gpncon &=~(gpn0_msk | gpn1_msk | gpn2_msk | gpn3_msk);
gpncon |= gpn0_in | gpn1_in | gpn2_in |gpn3_in;
while (1)
{
//如果kn为0(表示按下),则令led为0(点亮)
//读取gpk管脚电平状态
dwDat=gpndat;
if(dwDat & (1<<0)){ //s1没有按下
gpkdat|= (1<<4); //led1灭
}else{
gpkdat&= ~(1<<4);//led1亮
}
if(dwDat & (1<<1)){ //s1没有按下
gpkdat|= (1<<5); //led2灭
}else{
gpkdat&= ~(1<<5);//led2亮
}
if(dwDat & (1<<2)){ //s1没有按下
gpkdat|= (1<<6); //led3灭
}else{
gpkdat&= ~(1<<6);//led3亮
}
if(dwDat & (1<<3)){ //s1没有按下
gpkdat|= (1<<7); //led4灭
}else{
gpkdat&= ~(1<<7);//led4亮
}
}
return 0;
}