ARM裸机开发-点亮LED灯

发布时间:2026/9/28 11:14:30
ARM裸机开发-点亮LED灯 目录背景介绍底板原理图一.引脚复用功能引脚电气属性IOMUXC 32)1.IOMUXC_SW_MUX_CTL_PAD:引脚复用功能2.IOMUXC_SW_PAD_CTL_PAD:电气属性3.代码二.GPIO模块(GPIO 28)1.DR2.GDIR3.PSR4.ICR与EDGE5.IMR6.ISR7.总结8.代码三.时钟模块CCM 18)1.简介2.代码四.全局代码五.环境搭建1.安装FileZilla与SSH服务器2.Ubuntu3.编译4.烧录背景介绍本文开始在VScode上使用IMX6ULL以真机进行学习注意创建的.S文件在本篇学习时注意大写在编译时会进行部分预处理操作小写则.s文件会跳过预处理阶段。芯片原理图参考如下。其中SOC IMX6ULL NXP核心处理器这是整块板子的“大脑”。NXP恩智浦的 IMX6ULL 基于ARM Cortex-A7架构主频通常在 528MHz 或 800MHz。DDR3 512MB运行内存 / RAM相当于电脑的内存条。它是掉电丢失的。当 Linux 系统启动时内核kernel会被加载到这块 DDR3 里运行它负责临时存放程序运行时产生的大量数据。EMMC nand flash 8GB存储 / ROM相当于电脑的硬盘。它是掉电不丢失的。用来永久存放系统镜像uboot、kernel、设备树、rootfs文件系统和用户程序。蜂鸣器贴纸有“”号表示有源蜂鸣器上电即可工作左下角BOOT拨码开关设置启动模式将17位拉高则开机。底板原理图其中两列引脚通过板子的两列白色插座接入核心板故核心板自然会将插座的引脚接入SOC内部该芯片GPIO分为5组GPIO1、GPIO2、GPIO3、GPIO4、GPIO5.若为图中LED0所在的GPIO 3则表示默认为GPIO1组注意中间有空格其中DCDC表示直流供电LED1是物理设备编号LED0则是引脚工作名称由原理图可知被接入到GPIO1组的03号引脚显然右边接入高电平控制LED0输出低电平则灯亮故本文后续点灯操作将围绕此展开。一.引脚复用功能引脚电气属性IOMUXC 32)点灯第一步先配置引脚复用功能以及电气属性1.IOMUXC_SW_MUX_CTL_PAD:引脚复用功能SION为控制输入功能1开启0关闭。而当采用GPIO1_IO03功能时输入输出默认打开而当采用其他七种模式时默认关闭MUX_MODE为引脚复用的功能易知共有八种模式而该引脚默认为0101即GPIO1_IO03功能2.IOMUXC_SW_PAD_CTL_PAD:电气属性HYS:仅输入功能使用用于过滤波形整形。(点灯为输出功能故暂不使用PUS:仅输入可用控制上拉下拉电阻。PUE:仅输入可用,控制引脚使用上拉还是保持电压PKE:打开PUE的开关为1表示PUE上拉保持功能开ODE:控制输出模式默认为0即推挽输出。漏级开漏输出引脚是高阻态可以输出低电平但无法输出高电平除非外部接入上拉电阻推挽输出驱动能力强既可输出高电平也可输出低电平SPEED:控制输出速度合适即可高速EMI电磁干扰会增加功耗DSE:驱动能力表示驱动多强的外部设备电阻越小电流越大驱动变强但同时功耗变大芯片发烫。给高电平有效对点灯无用默认即可SRE:从低电平变为高电平需要时间压摆率越高曲线越陡适用高速设备USBCAN网口对于点灯而言电气属性设置为默认值即可由图易知默认值0X10B0配置之后该引脚则为GPIO功能。3.代码_led_init: // 配置引脚复用功能:GPIO1_IO03 ldr r0, 0x020E0068 mov r1, #0x05 str r1, [r0] // 配置引脚电气属性:默认属性(0x10B0) ldr r0, 0x020E02F4 ldr r1, 0x10B0 str r1, [r0]二.GPIO模块(GPIO 28)1.DRGPIOx_DR:控制第几组的GPIO引脚DR控制引脚高低电平例如本篇要点亮的LED灯为GPIO1组的IO03引脚则让bit3置0灯亮2.GDIRGDIR(GPIO direction register)GPIO方向寄存器即控制输入/输出模式对应LED,GPIO_03显然该寄存器应置13.PSRPSR:只读读取引脚电平1为高0为低电平同时DR也可读4.ICR与EDGEICR1:配置引脚中断方式的寄存器从0-31一共32位每两位控制一个引脚的中断触发方式寄存器编号即引脚编号显然要配置GPIO03号引脚则应配置6.7位.对应具体设置位依次为低电平触发高电平触发上升沿触发下降沿触发。ICR1为0-15位引脚ICP2为16-31位引脚。ICR2原理同上此外EDGE寄存器则可控制为双边沿触发5.IMRIMR:控制中断是否屏蔽显然要将LED灯对应的bit3为置1表示开中断6.ISRISR查询引脚是否产生中断1表示产生中断7.总结GPIOx_DR:向GPIOx组某个引脚写0或1(低电平/高电平)GPIOx_GDIR:设置GPIOx组某个引脚方向(输入0和输出1)GPIOx_PSR(只读):读取GPIOx组某个引脚的状态GPIOxICR:设置GPIOx组某个引脚中断触发方式(低电平、高电平、下降沿、上升沿)GPIOx_IMR:设置GPIOx组某个引脚中断屏蔽/允许GPIOx_ISR:用来查询GPIOx组某个引脚是否产生中断GPIOx_EDGE_SEL:设置中断触发方式为双边沿触发以上则为GPIO模块的相关寄存器解析对于点灯功能而言无需中断此处了解即可后续开发将会详细介绍。点灯仅需设置GPIOx_DR与GPIOx_GDIR寄存器将引脚置低电平且设置为输出方向。8.代码_led_init: // 配置引脚方向(GDIR)输出模式 ldr r0, 0x0209C004 ldr r1, [r0] orr r1, r1, #(1 3) str r1, [r0] bx lr _led_on: //给DR bit3位低电平 ldr r0, 0x0209C000 ldr r1, [r0] bic r1, r1, #(1 3) str r1, [r0] bx lr三.时钟模块CCM 18)1.简介外设工作需要时钟不同外设工作频率不同需要的时钟频率则也不同故点灯则也需设置对应时钟频率。右侧为外设cgclock gate为控制外设开关ARM处理器中为了保证低功耗每个外设门都是关闭的要实现点灯则首先打开对应的cg开关。CCGRx即为控制外设cg的寄存器每两位控制一个外设置11即为开启。为方便后续开发将CCM_CCGR0-CCM_CCGR6都置为全1即0xFFFF FFFF表示打开所有外设时钟门。2.代码_enable_clocks: // CCM_CCGR0 clock enable ldr r0, 0x020C4068 ldr r1, 0xFFFFFFFF str r1, [r0] // CCM_CCGR1 clock enable ldr r0, 0x020C406C str r1, [r0] // CCM_CCGR2 clock enable ldr r0, 0x020C4070 str r1, [r0] // CCM_CCGR3 clock enable ldr r0, 0x020C4074 str r1, [r0] // CCM_CCGR4 clock enable ldr r0, 0x020C4078 str r1, [r0] // CCM_CCGR5 clock enable ldr r0, 0x020C407C str r1, [r0] // CCM_CCGR6 clock enable ldr r0, 0x020C4080 str r1, [r0] bx lr四.全局代码系统初次复位时在SVC模式复位异常位于0x00地址此时若执行一条跳转指令到复位异常函数处则可完成一些初始化工作。此外SVC模式仅在刚复位时使用此后大多时候在system进行工作故再不做过多阐述。可参考上篇启动代码的学习异常复位函数.global _start _start: ldr pc, _reset_handler ldr pc, _undefine_handler ldr pc, _software_handler ldr pc, _prefetch_abort_handler ldr pc, _data_abort_handler ldr pc, _reserved_handler ldr pc, _irq_handler ldr pc, _fiq_handler _fiq_handler: ldr pc, _fiq_handler _irq_handler: ldr pc, _irq_handler _reserved_handler: ldr pc, _reserved_handler _data_abort_handler: ldr pc, _data_abort_handler _prefetch_abort_handler: ldr pc, _prefetch_abort_handler _software_handler: ldr pc, _software_handler _undefine_handler: ldr pc, _undefine_handler finished: b finished复位函数其中 _enable_clocks_led_init _led_on函数均以在上述中实现。_reset_handler: // 设置irq模式 mrs r0, cpsr bic r0, r0, #0x1F orr r0, r0, #0x12 msr cpsr, r0 // 设置irq模式下的栈(32M) ldr sp, 0x86000000 // 设置system模式相比user模式多了特权模式 mrs r0, cpsr bic r0, r0, #0x1F orr r0, r0, #0x1F msr cpsr, r0 // 设置system模式下的栈 ldr sp, 0x84000000 // 打开所有外设时钟门 bl _enable_clocks // 初始化led bl _led_init // led亮 bl _led_on b finished上篇由于是仿真学习使用的是芯片内部的RAM而本芯片SOC内部的RAM不允使用故使用DDR3的内存而该芯片规定该内存起始地址为0X8000 0000,大小512MB即到0XA000 0000在这中间可自行根据七种异常栈分配内存。五.环境搭建1.安装FileZilla与SSH服务器由于在Ubuntu中运行VScode比较卡顿故选择在Windows上的VScode进行代码编写再将代码工程传输到Ubuntu中进行编译下载。首先为了方便从Windows和Ubuntu之间的文件传输我们需要在Windows下安装FileZilla该软件下载地址如下https://www.filezilla.cn/download。 FileZilla作为客户端Ubuntu作为服务端。该软件底层通过采用应用层的FTP协议实现文件传输。操作过程如下此外还需要在Ubuntu下安装SSH服务器sudo apt-get install vsftpd并配置文件 sudo vi/etc/vsftpd.conf 。使能本地功能和写入功能最后执行 sudo /etc/init.d/vsftpd restart刷新使配置文件生效2.Ubuntu1.设置NAT模式分配了虚拟IP,只要Windows能上网Ubuntu就能上网sudo /etc/init.d/networking restart //执行此代码重启网络桥接模式虚拟机就像你家里的另一台独立电脑。它和你的 Windows 宿主机平起平坐共用同一个真实路由器你之前连的手机热点。NAT模式虚拟机就像一个住在你 Windows 宿主机里面的“租客”。它通过宿主机代理上网外部网络手机热点根本看不见它。对比维度桥接模式VMnet0NAT模式VMnet8IP地址来源由外部路由器分配你之前是手机热点给的10.138.48.x由VMware虚拟路由器分配现在是192.168.85.x网络地位和宿主机Windows是平等的同学是宿主机的下属宿主机通信直接通过局域网通信但受限于外部路由器通过宿主机虚拟网卡192.168.85.1通信外网通信直接暴露在局域网中占用一个外部IP经过宿主机 NAT网络地址转换转发共用宿主机IP外部设备访问虚拟机能如果局域网没做隔离比如你之前手机热点的问题不能直接访问除非在VMware里设置端口转发虚拟机访问宿主机能但需要依赖外部路由器的配置能直接 ping192.168.85.1即可2.安装ARM编译器由于Ubuntu位X86架构gcc为对应的编译指令而要在ARM芯片上运行则需要安装对应ARM架构的编译器 。将该编译器拷贝至Ubuntu的家目录下再切换至根目录的/usr/local目录下创建arm文件夹再将家目录的编译器安装包复制于当前arm文件夹sudo mv ~/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz .再解压压缩包 sudo tar -xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz。解压后会产生对应文件夹进入其中的bin目录其中为arm编译的工具链pwd打印出当前目录路径复制保存再sudo vim ~/.bashrc进入配置文件配置刚才复制的路径如下最后sudo reboot重启虚拟机即可最后arm-linux-gnueabihf-gcc -v查看安装编译器版本3.编译家目录下创建imx6ull/led_asm对应的芯片文件夹保存编译文件,通过FileZilla上传VScode上写的start.S文件至此编译三步骤编译arm-linux-gnueabihf-gcc -g -c start.S -o start.o其中“-g”选项是产生调试信息GDB 能够使用这些调试信息进行代码调试。“-c”选项是编译源文件但是不链接。“-o”选项是指定编译产生的文件名字这里我们指定 start.s 编译完成以后的文件名字为start.o。执行上述命令以后就会编译生成一个start.o 文件链接arm-linux-gnueabihf-ld -Ttext 0X87800000start.o -ostart.elf本次课程中我们所有的裸机例程都是烧写到 SD 卡中上电以后 I.MX6U 的内部 boot rom 程 序会将可执 行文件拷贝 到链接地址 处这个链 接地址可以 在 I.MX6U 的内部 128KBRAM 中 (0X900000~0X91FFFF)也可以在外部的 DDR 中。本次课程中所有裸机例程的链接地址都在 DDR中链 接起始地址为 0X87800000。I.MX6U-ALPHA 开发板的 DDR 容量有两种512MB 和256MB起始地址都为 0X80000000只不过 512MB 的终止地址为0X9FFFFFFF而 256MB 容量的终止地址为 0X8FFFFFFF。之所以选择 0X87800000 这个地址是因为后面要讲的 Uboot 其链接地址就是 0X87800000 这样我们统一使用 0X87800000 这个链接地址不容易记混。格式转换arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin我们需要用它将 start.elf 文件转换为start.bin 文件。上述命令中“-O”选项指定以什么格式输出后面的“binary”表示以二进制格式输出选项“-S”表示不要复制源文件中的重定位信息和符号信息“-g”表示不复制源文件中的调试信息。上述命令执行完成以后就会在工程目录下多一个 start.bin 文件。至此我们终于等到了想要的东西—start.bin 文件反汇编arm-linux-gnueabihf-objdump -D led.elf led.dis可不用大多数情况下我们都是用 C 语言写试验例程的有时候需要查看其汇编代码来调试代码因此就需要进行反汇编当然这个工作目前对于我们不是必须的。一般来说可以将 elf 文件反汇编。上述代码中的“-D”选项表示反汇编所有的段反汇编完成以后就会在当前目录下出现一个名为 start.dis 文件。我们可以打开这个文件查看其中的内容可以发 现这里面都是汇编代码。注意通过 start.dis 这个反汇编文件可以明显的看出我们的代码已经链接到了以​​​​0X87800000 为起始地址的区域。4.烧录装入SD卡插入读卡器连接到虚拟机ls /dev/sd*查看已有设备例如我这里看到的结果是/dev/sda /dev/sda1 /dev/sda2 /dev/sda3 四个文件分别代 表Ubuntu下的磁盘和三个分区然后将imxdownload文件上传至led_asm,执行chmod 0777 imxdownload给予权限使用命令./imxdownload start.bin /dev/sdb烧录注意不要写为./imxdownload led.bin /dev/sda,sda是系统磁盘会造成Ubuntu损坏.当出现此界面时下载成功注意下载速度为KB/S若为MB/S单位则下载失败拔卡重启虚拟机再插卡注意保证读卡器没有损坏部分廉价读卡器在插入时易因为静电烧坏。若是插入新读卡器则可能会出现自动挂载情况输入lsblk查看例如sdb挂载到boot与rootfs文件。执行下面指令卸载挂载因为 Linux 系统为了安全不允许对已经挂载的分区进行dd裸写入。如果不卸载你执行烧录会直接报Device or resource busy错误。sudo umount /dev/sdb1 sudo umount /dev/sdb2 //或者一句 sudo umount /dev/sdb*最后再进行烧录看到进度条跑完、提示烧录成功后。然后安全弹出读卡器把 SD 卡插回 i.MX6ULL 开发板拨到 SD 卡启动模式上电sudo ./imxdownload start.bin /dev/sdb至此灯亮了路也就清晰了前路漫漫亦灿灿与所有在嵌入式路上摸黑前行的朋友共勉。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询