本次实验基于Tiny4412开发板,开发板上有四个可编程控制的LED、四个按键。来实现这样一种场景:每个按键控制一盏LED,每按一次则对应的LED状态发生改变,按一次开灯,再按一次关灯。核心控制为三星的Exynos4412芯片。

一、开发板介绍

1、开发板资源介绍

Tiny4412开发板开发板分为核心板和底板,两者需要组合起来使用,核心板可以搭配标准版底板和增强版底板。本次实验中使用到的四颗LED位于核心板上,四个按键位于底板上。另外Tiny4412开发板还有一块LCD显示屏,裸机试验中暂时不会使用到LCD屏幕,可以先拆下来,方便观察现象。底板下面有螺丝,拧下来就可以把LCD拆掉。

Tiny4412核心板

Tiny4412开发板标准版底板

2、芯片启动流程

在前几个GPIO实验中并没有去关注芯片的启动过程,直接就是C语言编写代码了,可是C语言编写的代码并不是芯片上电后启动的第一行代码。在使用Keil5开发AT89C51、STM32F401VE、LPC2138时,Keil5是集成开发环境,会自动将启动代码Startup.s和C语言代码进行连接,最后生成的hex可执行文件其实开始一段是汇编启动代码链接过来的,主要是进行设置C语言运行环境(初始化中断、设置栈等)、关闭看门狗(不关的话芯片会反复重启)、跳转main函数等操作。可是Keil5目前最多支持到ARM9系列芯片的开发,更高等级的芯片需要在Linux环境下,一步步从头开发。不过高等级的芯片大多不会直接使用裸机,而是会运行操作系统,如Linux、Android、QNX等,运行操作系统后会进入另一种领域——嵌入式开发。这里我们先讨论不上操作系统的裸机开发。

像Exynos4412这种高级货是有很多启动方式的,包括SD卡/EMMC/NAND启动等。以前有不少基于S3C2440的经典开发板,S3C2440是ARM9内核的,还不支持SD卡启动,需要用NOR FLash启动,一旦NOR Flash中的代码被破坏就需要使用JTAG/JLink等进行烧写。上图是SD卡启动时,SD卡中的可执行程序文件存储结构。

①、是谁把这些指令从 SD 卡读出来执行?

是固化在芯片内部ROM上的代码iROM ,iROM是三星公司事先烧写在芯片上的,无源码。iROM中的代码是4412芯片上电后首先执行的一段代码。iROM把启动设备上特定位置处的程序读入片内内存(iRAM)并执行它,这个程序被称为 BL1(Bootloader 1),BL1是三星公司提供的,无源码。接下来BL1又把启动设备上另一个特定位置处的程序读入片内内存,并执行它。这个被称为BL2(Bootloader2)。本场景中我们编写的源码编译后生成的可执行文件就放在这个位置。

②、在启动设备上哪个位置存放 BL1、BL2?把BL1、BL2读到iRAM哪个位置?

BL1位于SD卡偏移地址512字节处(即从第一个扇区(Block1)开始,前面的第0个扇区(Block0)保留,每个扇区512字节。为什么保留第0个扇区?像DOS分区表一样,第0个扇区是分区表的配置区。iROM从这个位置读入8K字节的数据,存在iRAM地址0x0202_1400位置处,所以BL1不能大于8K。BL2位于SD卡偏移地址(512+8K)字节处,BL1从这个位置读入16K字节的数据,存在iRAM地址0x0202_3400处。

③、iROM地址如何划分?BL1、BL2有效大小是多少?

安全BL1的大小为8192B。为了正确地执行iROM,应该在内部存储器的开始处保留5KB。安全BL1代码的上下文应该位于内存的0x0202_3000。BL2码的大小可由用户指定定义并依赖于BL1代码。然而,在S.LSI的参考代码BL1中,BL2代码的有效大小为小于14332B(14KB-4B),4B为校验和),如果BL2码的大小小于14332B,则为剩余区域直到14332B都应该用零填充。BL2的签名应该在内部的0x0202_6C00内存和BL2的校验和应该在S.LSI的参考代码中为0x0202_6BFC。

④、iROM执行流程图

上图是iROM的执行流程,可以看到做了关闭看门狗、关闭中断及MMU、关闭数据缓存、打开指令缓存、清除TLB等等操作,最后跳转到BL1。BL1再经过以下流程,转到执行BL2。

综上概括下:就是iROM中的程序做一些初始化操作,然后把BL1段程序从SD卡中拷贝到0x0202_1400地址处并跳转到该地址处执行,接着BL1段程序再做一些初始化操作,然后把BL2段程序从SD卡中拷贝到0x0202_3400处,并跳转到此处执行。在本实验场景中我们自己编写的程序就放在SD卡的BL2处(相当于BL2程序),BL2程序被拷贝到0x0202_3400地址处(记住这个地址,后边编译程序的时候会用到)。

二、电路图

芯片连接LED的引脚。GPM4_0 ~ GPM4_3四个引脚控制LED1 ~ LED4四个LED。

可以看到LED仍是共阳极接法,即引脚输出低电平时LED亮,输出高电平时LED熄灭。

KEY1 ~ KEY4分别连接GPX3_2 ~ GPX3_5(XEINT26 ~ XEINT)。

KEY引脚接了上拉电阻,就是默认高电平,按下的时候引脚接地,变为低电平,抬起后又恢复高电平。

三、地址映射

①、端口组GPM4配置寄存器

基地址: 0x1100_0000
GPM4CON寄存器地址:Base Address + 0x02E0
复位值:0x0000_0000
每4位控制一个引脚的配置,GPM4CON寄存器32位控制GPM4_0 ~ GPM4_7八个引脚,上图中列举出了GPM4_0 ~ GPM4_3四个引脚的控制位,其配置效果如上图所示。

②、端口组GPM4数据寄存器

基地址: 0x1100_0000
寄存器地址:Base Address + 0x02E4
复位值:Reset Value = 0x00

当端口配置为输入端口时,则对应的位为引脚状态。当配置为输出端口时,引脚状态应与相应的位一致。当端口被配置为功能引脚时,将读取未定义的值。

③、端口组GPX3配置寄存器

基地址: 0x1100_0000
寄存器地址:Base Address + 0x0C60
复位值:0x0000_0000
每4位控制一个引脚的配置,本场景中GPX3CON[2] ~ GPX3CON[5]。

④、端口组GPX3数据寄存器

基地址: 0x1100_0000
寄存器地址:Base Address + 0x0C64
复位值:0x00

当端口配置为输入端口时,则对应的位为引脚状态。当配置为输出端口时,引脚状态应与相应的位一致。当端口被配置为功能引脚时,将读取未定义的值。

四、驱动程序开发

使用Notepad++ "文件" --- "打开文件夹作为工作区",可以看到上图所示文件。总体上和前几期的GPIO实验差别不大。去掉了蜂鸣器驱动程序。APP由于较为简单,只有一个.c文件,所以APP中没有使用.h文件。驱动部分有led驱动、key驱动、延时函数。STARTUP中有个startup.s文件,是C语言程序启动前执行的汇编语言代码,在前几期中,启动程序都由Keil5自动处理了,但这里没有集成开发环境,startup.s需要自己写,其实就是一个简单的堆栈设置(C语言运行必须要有堆栈)和跳转,初始化运行环境的很多操作BL1都做过了,我们的程序是放在BL2位置的。还有个比较重要的文件“Makefile”,这个文件非常重要,以后开发大型程序,乃至跑操作系统的复杂嵌入式系统,处处都有这个文件。另外分析大型的复杂嵌入式软件系统,往往也是从这个文件开始的,后面会有更详细的解释。

1、启动代码

.text
.global _start/* 定义常量,用于初始化堆栈指针 */
#define STACK_SIZE  0x1000
#define STACK_BASE  0x02023400/* 定义C语言程序入口点 */
.extern main_start:/* 初始化堆栈指针 */ldr sp,=0x02024400/* 跳转到C语言程序入口点 */bl mainhalt_loop:b halt_loop

.text .global 是arm-linux-gcc编译器的关键词。
.text 指定了后续编译出来的内容放在代码段可执行。
.global 告诉编译器后续跟的是一个全局度可见的名字可能是变量,也可以是函数名。
start是一个函数的起始地址,也是编译、链接后程序的起始地址。由于程序是通过加载器来加载的,必须要找到_start名字的函数,因此_start必须定义成全局的。

接下来这几行是为了注释,在汇编代码中并不起作用,汇编代码中/*...*/或者在某行前面加"#"。都是注释的意思。
/* 定义常量,用于初始化堆栈指针 */
#define STACK_SIZE  0x1000
#define STACK_BASE  0x02023400

后面初始化堆栈指针,可以看到sp指针指向了STACK_BASE + STACK_SIZE处。堆栈使用时是从高地址向低地址增长的,此处我们把堆栈指针移向了STACK_BASE后4K字节处,大约(因为程序本身也会占一些空间,现在程序较小,所以占的很少)给程序分配了4K的堆栈空间,对于当前程序来说,完全足够用了。

在linux中
./  表示当前目录
../  表示当前目录的上级目录
../../  表示当前目录的上上级目录

2、LED驱动

led.h

#ifndef _LED_H_
#define _LED_H_void led_init();void led_on(unsigned char site);void led_off(unsigned char site);char get_led_status(unsigned char site);void led_operate(unsigned char site,unsigned char on_off);
#endif

led.c

#include "../include/led.h"#define GPM4CON (*(volatile unsigned long *)0x110002E0)
#define GPM4DAT (*(volatile unsigned long *)0x110002E4)void led_init(){//GPM4CON最后16位分别置0001 GPM4_0 ~GPM4_3为输出模式GPM4CON = GPM4CON | 0x1111;
}void led_on(unsigned char site){led_init();switch(site){case 0: GPM4DAT &= ~(0x01);    //P0.0置0break;case 1:GPM4DAT &= ~(0x01<<1); //P0.1置0break;case 2: GPM4DAT &= ~(0x01<<2); //P0.2置0break;case 3: GPM4DAT &= ~(0x01<<3); //P0.3置0break;default:break;}
}void led_off(unsigned char site){led_init();switch(site){case 0: GPM4DAT |= (0x01);     //P0.0置1break;case 1:GPM4DAT |= (0x01<<1); //P0.1置1break;case 2: GPM4DAT |= (0x01<<2); //P0.2置1break;case 3: GPM4DAT |= (0x01<<3); //P0.3置1break;default:break;}
}char get_led_status(unsigned char site){switch(site){case 0: return (GPM4DAT >> 0) & (0x01);case 1:return (GPM4DAT >> 1) & (0x01);case 2: return (GPM4DAT >> 2) & (0x01);case 3: return (GPM4DAT >> 3) & (0x01);default:return -1;}
}
//on_off 0:开灯 1:关灯
void led_operate(unsigned char site,unsigned char on_off){if(on_off == 0){led_on(site);}else if(on_off == 1){led_off(site);}
}

3、KEY驱动

key.h

#ifndef _KEY_H_
#define _KEY_H_void key_init();char scan_keyboard();
#endif

key.c

#include "../include/delay.h"
#include "../include/key.h"#define GPX3CON (*(volatile unsigned long *)0x11000C60)
#define GPX3DAT (*(volatile unsigned long *)0x11000C64)#define GET_GPX3DAT(x) ((GPX3DAT >> x) & (0x01))void key_init(){//GPX3CON第8~23位置0 GPX3CON[2] ~ GPX3CON[5]为输入模式GPX3CON = GPX3CON & 0xff0000ff;
}char scan_keyboard(){ //返回当前操作过的按键位置key_init();char site = -1;if(GET_GPX3DAT(2) == 0){delayms(10);if(GET_GPX3DAT(2) == 0){while(GET_GPX3DAT(2)==0);site = 0;}}else if(GET_GPX3DAT(3) == 0){delayms(10);if( GET_GPX3DAT(3) == 0){while(GET_GPX3DAT(3) == 0);site = 1;}}else if(GET_GPX3DAT(4) == 0){delayms(10);if( GET_GPX3DAT(4) == 0){while(GET_GPX3DAT(4) == 0);site = 2;}}else if(GET_GPX3DAT(5) == 0){delayms(10);if( GET_GPX3DAT(5) == 0){while(GET_GPX3DAT(5) == 0);site = 3;}}return site;
}

delay.h

#ifndef _DELAY_H_
#define _DELAY_H_void delayms(unsigned int xms);
#endif

delay.c

#include "../include/delay.h"void delayms(unsigned int xms){   //毫秒级延时函数unsigned int i,j;for(i=xms;i>0;i--){for(j=2500;j>0;j--);}
}

五、应用程序开发

application.c

#include "../../DRIVER/include/led.h"
#include "../../DRIVER/include/key.h"int main(void){led_operate(0,1);led_operate(1,1);led_operate(2,1);led_operate(3,1);while(1){unsigned char key_site = scan_keyboard();       //扫描按键状态char led_status = -1;switch(key_site){                             case 0:                                 //按键一被按了一次led_status = get_led_status(0);  if(led_status == 0){              led_operate(0,1);           //D1状态改变}else if(led_status == 1){        led_operate(0,0);           //D1状态改变}                                   break;                              case 1:                                 led_status = get_led_status(1);    if(led_status == 0){              led_operate(1,1);           //D2状态改变}else if(led_status == 1){        led_operate(1,0);           //D2状态改变}                                   break;                              case 2:                                 led_status = get_led_status(2);    if(led_status == 0){              led_operate(2,1);           //D3状态改变}else if(led_status == 1){        led_operate(2,0);           //D3状态改变}                                   break;                              case 3:                                 led_status = get_led_status(3);    if(led_status == 0){              led_operate(3,1);           //D4状态改变}else if(led_status == 1){        led_operate(3,0);           //D4状态改变}break;default:break;}}return 0;
}

六、Makefile编写

Exynos4412_GPIO.bin:startup.o application.o led.o key.o delay.oarm-linux-ld -Ttext 0x02023400 -g startup.o application.o led.o key.o delay.o -o Exynos4412_GPIO_elfarm-linux-objcopy -O binary -S Exynos4412_GPIO_elf Exynos4412_GPIO.binarm-linux-objdump -D -m arm Exynos4412_GPIO_elf > Exynos4412_GPIO.disstartup.o:./STARTUP/startup.sarm-linux-gcc -g -c -o startup.o ./STARTUP/startup.sapplication.o:./APP/source/application.c ./DRIVER/include/led.h ./DRIVER/include/key.harm-linux-gcc -g -c -o application.o ./APP/source/application.cled.o:./DRIVER/source/led.c ./DRIVER/include/led.harm-linux-gcc -g -c -o led.o ./DRIVER/source/led.ckey.o:./DRIVER/source/key.c ./DRIVER/include/key.h    ./DRIVER/include/delay.harm-linux-gcc -g -c -o key.o ./DRIVER/source/key.cdelay.o:./DRIVER/source/delay.c ./DRIVER/include/delay.harm-linux-gcc -g -c -o delay.o ./DRIVER/source/delay.cclean:rm -f Exynos4412_GPIO.dis Exynos4412_GPIO.bin Exynos4412_GPIO_elf *.o

Makefile的编写规则类似以下过程:

包子:面粉 水 蔬菜 肉类 调料
            择菜 --- 洗菜 --- 绞肉 --- 做馅儿 --- 和面 --- 包包子 --- 蒸包子 --- 出锅

面粉:小麦
            耕种 --- 施肥 --- 浇水 --- 收获 --- 磨面

调料:粮食 水

粮食 --- 发酵  --- 勾兑

......

包子是我们最终要的,要得到包子需要依赖面粉、水、蔬菜、肉类、调料这些原料,这些原料经过一系列加工过程变成了包子。但这些原料也不是本来就有的,比如面粉是由小麦这种原料做的,小麦经过一系列过程变成了面粉。

对照程序Makefile,我们最终要的是Exynos4412_GPIO.bin,它依赖startup.o application.o led.o key.o delay.o这些原料经过下面arm-linux-xxx的一系列加工过程,原料变成了我们想要的东西。接着startup.o这种原料不是本来就有的,它依赖./STARTUP/startup.s这种原料,经过arm-linux-gcc -g -c -o startup.o ./STARTUP/startup.s加工过程,得到了startup.o。其他的以此类推。最后的那个clean含义特殊,它下面是一条linux中的删除命令,删除.bin文件和编译过程中产生的文件,执行“make clean”命令时对应的clean下面的指令。Makefile文件编写好后,编译的时候直接执行"make"就可以生成我们最终想要的Exynos4412_GPIO.bin文件了,想要重新编译的话先执行“make clean”删除当前的编译成果,然后再执行"make"。

上面的Makefile中涉及到arm-linux-gcc、arm-linux-ld、arm-linux-objcopy 、arm-linux-objdump编译命令,Makefile这些命令的含义请自行学习。"arm-linux-ld -Ttext 0x02023400"指定的是程序的运行起始地址,本次编写的GPIO实验程序放置到BL2段,其运行起始地址为0x02023400。此处没有定义数据段、bss段的起始地址,它们被依次放在代码段的后面。后面程序复杂了之后,可通过.lds文件指定各段的地址,在链接的时候需要把.lds文件配置进去。

七、Linux虚拟机安装

Linux虚拟机的安装和Linux基础命令请自行学习。Linux有很多发行版,推荐使用Ubuntu。

可参考:

VMware虚拟机安装Linux教程(超详细)_虚拟机安装linux系统_七维大脑的博客-CSDN博客

Linux基础(超级无敌认真好用,万字收藏篇!!!!)_@活着笑的博客-CSDN博客

Linux 教程 | 菜鸟教程

《鸟哥的Linux私房菜》

八、交叉编译与程序烧录

1、安装交叉编译工具

Tiny4412开发板或同类别开发板官方提供的资料中通常都有这些工具,从光盘中找到文件“arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz”,把它拷贝到Linux根目录下("/"目录)。执行“tar -zxvf arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz” 命令,将文件解压缩,解压缩之后,在Linux的/opt目录下会出现一个“FriendlyARM”文件夹,进去文件夹,一路进入下级文件夹,会跟踪到“/opt/FriendlyARM/toolschain/4.5.1/bin”。到这里可以看到这个bin文件夹下面有大量的arm-linux-xxx命令,这些就是交叉编译工具

为什么要是用交叉编译工具,而不能直接使用linux下面的编译工具gcc呢?这个也很容易理解,我们的电脑CPU都是X86架构的,CPU指令集属于CISC指令集,而要运行程序的开发板属于ARM架构,为RISC指令集。编译的目的是最终把源码转换成CPU能理解的能执行的程序,ARM架构的CPU是看不懂X86架构的指令集的。如果直接使用gcc进行编译,就把源程序编译成了X86架构的CPU才能认识的可执行程序,而交叉编译工具则是在电脑上把源码编译成了能在开发板上运行的可执行程序。所以叫做交叉编译。

完成解压缩后,运行“ echo $PATH”查看一下现在的环境变量,可以看到路径“/opt/FriendlyARM/toolschain/4.5.1/bin”还没有加入到环境变量中。运行“vim /etc/bash.bashrc”编辑/etc/bash.bashrc文件,在最后一行添加“export PATH=/opt/FriendlyARM/toolschain/4.5.1/bin:$PATH

注意最后的那个“:$PATH”是必须的,否则就把以前的环境变量都清空了。添加并保存后执行命令“source /etc/bash.bashrc”使配置生效。再执行“ echo $PATH”就可以看到交叉编译文件路径已经被添加进去了。运行“arm-linux-gcc -v”可以查看编译工具版本。

意味着交叉编译环境已经配置完成。交叉编译工具已生效。

2、编译源码

Exynos4412_GPIO_Project目录下直接执行make命令,生成了Exynos4412_GPIO.bin文件。

3、SD卡启动制作工具

从开发板官方提供的资料中找到“uboot_tiny4412-20130729.tgz”,这玩意是uboot,是启动操作系统用的。像Cortex-A系列这种高级货生来就是为了跑操作系统用的,在实际运用中几乎不会见到拿Cortex-A系列的芯片作为裸机使用,现在的实验是为了更熟悉它,为以后的系统移植做准备。uboot本身是跑在裸机上的,也是对应BL2。所以在uboot_tiny4412-20130729.tgz包中包含了一个sd卡启动制作工具。

把“uboot_tiny4412-20130729.tgz”拷贝到你在Linux上的工作目录(自建一个目录,或者看哪个顺眼都行,我的是“/opt/Exynos4412”)下,运行“tar -zxvf uboot_tiny4412-20130729.tgz”解压缩,之后找到"uboot_tiny4412/sd_fuse",它就是可以把sd制作成启动卡的工具。

目录下文件如图所示,先打开V310-EVT1-mkbl2.c文件,注释掉46~62行,并增加以下红框中的内容。因为在烧写sd卡的脚本uboot_tiny4412/sd_fuse/tiny4412/sd_fusing.sh中有./mkbl2 xxx(要放置到BL2位置的文件) bl2.bin 14336命令。如果不修改V310-EVT1-mkbl2.c源码,那么编译出的mkbl2工具就会按照14K大小计算校验码,Exynos4412_GPIO.bin显然没有14K这么大,会发生数据溢出,无法把我们的Exynos4412_GPIO.bin制作成bl2.bin文件。

之后,在“uboot_tiny4412/sd_fuse”目录下执行“make”命令。

可以看到生成了mkbl2、sd_fdisk工具。接着进入 tiny4412目录。

这个目录下有BL1的可执行文件E4412_N.bl1.bin 和SD卡烧录脚本sd_fusing.sh。

打开sd_fusing.sh,第44行可以看到,脚本默认使用u-boot.bin生成bl2.bin文件,这里替换成本次要逻辑运行的可执行程序Exynos4412_GPIO.bin。

修改前

修改后

4、制作SD卡

SD卡插入到电脑上,选择连接到虚拟机,这时候在Linux系统的/dev文件夹下会生成对应的设备文件,找到这个设备文件(看时间,刚生成的那个就是。或者插拔一下SD卡,看看多出来的是哪个设备文件,通常是/dev/sdb)。执行命令 “./sd_fusing.sh /dev/xxx(sd卡的设备文件)”,会看到BL1和BL2烧录进去了。

取下SD卡插回开发板,选择开关拨到从SD卡启动,重启开发板。这时候按键就可以控制对应LED的亮灭了。

九、资料下载

Exynos4412裸机开发参考资料和必备资源:https://download.csdn.net/download/qq_54140018/87706193

实验源码(基于Tiny4412开发板):https://download.csdn.net/download/qq_54140018/87706199

从51到ARM裸机开发实验(006)Exynos4412 GPIO实验相关推荐

  1. 从51到ARM裸机开发实验(003) AT89C51 GPIO实验

    所谓GPIO,就是通用型输入输出(General Purpose Input/Output),GPIO试验是单片机引脚的基本输入输出功能.现在来实现这样一个场景:四个按键作为开关.四个LED作为响应, ...

  2. 从51到ARM裸机开发实验(002) Keil5的安装与配置

    Keil可以说是单片机开发最好用的集成开发工具了,支持从51到ARM7.ARM9.Cortex-M.Cortex-R为内核的大量ARM系列单片机.Keil分C51版.MDK版等,如果想要共存需要做一些 ...

  3. ARM裸机开发——双机异步串行通信

    写在前面  本报告因为期末将至,后续还需要完成一次课程设计,故本次实验较为简单,完成的时间也非常匆忙,故文章内容较为单薄,也可能有着更多疏忽之处,还望大家海涵. 1. 项目任务  1) 利用S3C24 ...

  4. ARM裸机开发:主频与时钟

    文章目录 ARM裸机开发:主频与时钟 一.时钟系统 1.1 外部时钟电路 1.2 7路PLL时钟源 1.3 时钟树概览 二.时钟配置 2.1 内核时钟设置 2.2 PFD时钟设置 2.3 AHB.IP ...

  5. Linux学习——总结ARM裸机开发步骤

    本文仅介绍一些基础概念. 我们常用的开发平台是在x86,这个是Intel推出的架构.在x86平台上的开发步骤,不管是什么软件,无外乎建立工程->写代码->保存->编译->运行, ...

  6. ARM裸机开发——Linux环境搭建和LED灯闪烁实验

    写在前面  本文为学校开展的嵌入式系统设计课程,本文主要是记录课程中的相关作业与学习记录,本课程采用了S3C2440A嵌入式系统开发板,由于主要以学校开展课程为主,本文内容可能有一定的课程资料辅助以及 ...

  7. 基于Cortex-A7架构的嵌入式linux ARM裸机开发<2>——LED灯闪烁(C版本)

    文章目录 一.利用汇编初始化C环境 二.C语言部分实验程序编写 三.Makefile程序编写 四.链接脚本程序编写 五.编译及烧录 利用汇编编写LED灯点亮程序我们已经实现过了,所以这里不再着重讲解基 ...

  8. ARM裸机开发篇3:ARM汇编语言程序设计

    写在前面: 本文章为<ARM Cortex-A7裸机开发篇>系列中的一篇,全系列总计11篇.笔者使用的开发平台为华清远见FS-MP1A开发板(STM32MP157开发板). 针对FS-MP ...

  9. ARM裸机开发篇2:ARM微处理器指令系统

    目录 ARM微处理器指令系统 ARM处理器寻址方式 数据处理指令寻址方式 内存访问指令寻址方式 ARM处理器指令集 数据操作指令 乘法指令 Load/Store指令 跳转指令 状态操作指令 协处理器指 ...

最新文章

  1. 网络工程师_要记录下来的一些题_4
  2. 22/11/2010
  3. Leetcode 129. 求根到叶子节点数字之和 解题思路及C++实现
  4. 《精通Spring4.X企业应用开发实战》读后感第五章(注入参数详解)
  5. PHP图片内容以二进制数据流的形式发送(CurlFile使用)
  6. linux 安装vbox增强工具
  7. java正则表达式及api_Java API 之 正则表达式
  8. Discrete Logging POJ - 2417(BSGS)
  9. vue 怎么设置 项目ico_vue项目如何优雅地设置favicon.ico
  10. QT/QML Text 部分功能(自动省略 自动换行 自动调节字体大小 调节行间距
  11. 【1】windows下IOS开发基础环境搭建
  12. 给CentOS 6.7 配置IP地址
  13. CodeForces 621C Wet Shark and Flowers
  14. 2021年中国直播电商投融资情况及行业发展中存在的问题、发展趋势和对策分析[图]
  15. 软件测试功能测试全套常见面试题【功能测试】面试总结4-2
  16. 小白文件管理器共享服务器,在WIN7下使用小白文件管理器局域网功能(SMB)的教程...
  17. linux查看硬盘插槽_Linux下查看CPU型号,内存大小,硬盘空间的命令(详解)
  18. 梯度提升(Gradient Boosting)算法
  19. 2014年总结和2015年的规划
  20. Dubbo之服务导入流程解析

热门文章

  1. mac 上的开发语言
  2. 应用计算机测导热系数,导热系数方法简介
  3. C++ 生产者消费者模式
  4. 萌新的第二周技术总结
  5. Adobe Premiere Pro CS4默认快捷键
  6. 51单片机串口通信模板_51单片机串口通讯UART
  7. twisted 实现UDP服务
  8. 【Dev Summit】2020 年 TensorFlow 开发者峰会总结
  9. ubuntu 18.04安装owncloud 搭建自己的私有云盘
  10. 基于微信小程序宠物交易小程序——计算机毕业设计