我熟悉8051 C编程 . 现在我想学习ARM cortex M3编程 . 我有STM32F103C8T6开发板和ARM Cortex M3处理器,它是程序员和Keil编译器 . 我想用它做一些小项目,例如闪烁LED,SPI和I2C编程等 . 我对臂架构知之甚少 . 很多人在博客上说直接开始编程而不是阅读架构或阅读百页ARM数据表 . 我不明白怎么可能 .
那么我的第一步应该是什么?
-
我是否应该阅读STM32F103C8T6或ARM Cortex M3用户手册的数据表?
-
8051与ARM编程有很大区别 . 在8051中,我们不需要添加库/头文件 . 在ARM中,我们需要添加许多库/头文件 . 假设我想做盲目程序或学习SPI / I2C通信 . 在KEIL编译器或STM CubeMX中,这些头文件已经存在 . 但是如果我希望自己从头开始做所有事情(编写外设,I / O端口,SPI / I2C协议代码的头文件代码),它真的可能吗?如果是的话,我该怎么做呢?
我非常困惑和沮丧,因为我找不到合适的人来引导我
5 回答
如果您利用现有的库代码来处理架构,启动和外设驱动程序问题,则可能(即在没有详细的数据表和参考手册知识的情况下开始) . 对于ARM Cortex-M和STM32,具体包括那些(在各种抽象级别和范围内):
ARM CMSIS,
Mbed,
STM32F1xx standard peripheral library (largely deprecated),
STM32Cube .
商业工具供应商(例如Keil,IAR,Rowley,Green Hills)通常也提供示例项目和驱动程序库以及中间件,以帮助您入门 - 通常用于特定的开发板 .
这可能是您对ARM编程的看法
您根本不需要 - 但它们比8051更复杂,部件和供应商之间存在大量复杂的外围设备,您可以通过利用这些库节省大量时间和精力 .
请注意,ARM Cortex-M内核本身不包括微控制器外围设备和CPU以及NVIC中断控制器,并且在FPU的一些高端部件上,一切都是供应商特定的,并且供应商之间差异很大 - 这就是为什么你需要了解供应商文档,或利用芯片或工具供应商或社区提供的库 .
如果您想完全理解Cortex-M或STM32并充分利用它们,那么就无法替代阅读参考资料,但这并不是必须开始的 .
如果您希望Cortex-M比ARM参考资料更容易,那么Joseph Yiu的The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors是一个很好的来源,但除非您正在编写低级RTOS或裸机启动代码或其他系统级代码,否则您可以不需要那么多材料 . 本书的早期M3版本在some places中以PDF格式提供 .
芯片供应商的参考手册将描述供应商特定的功能,如存储器接口,存储器映射,电源管理功能,闪存编程,中断映射和硬件外设,也许是更有用的材料 .
对于STM32而言,Hitex的Trevor Martin有一个广泛的指南:The Insider's Guide To The STM32 ARM Based Microcontroller,这只是Trevor的一些出版物中的一个可能有用 .
我去过那里,经过一段时间后,我意识到从数据表开始总是更好,即使它是你的第一块板 .
数据表提供了电路板,引脚和基本通信的全面工作 . 这可能很乏味,但它值得,你会在开始编程时意识到 .
之后,您可以直接跳转到头文件,并查看基本功能的实现,这将提供有关优化技术,编程风格和最佳实践的大量见解 .
如果可能的话,找一些为该主板编写的代码(我总是在这里失败,如果你的主板很少见,这很难) .
有了这个,您应该准备好编写几乎所有代码 . 从眨眼开始(板的hello世界)
另外根据我的经验,我想告诉你,如果需要时间,也没关系 . 有耐心和坚持 .
作为C程序员,您不需要阅读有关CPU核心架构的内容,但我建议您简要阅读CPU手册 . 知道有哪些寄存器以及有哪些资源,数据缓存,指令缓存等,意味着您可以编写更高质量的C代码 . 然而,对于像8051这样可怕的坏核心来说,这一点更为重要 .
对于MCU外围硬件和内存,您需要阅读手册中的每一行,以了解您要使用的部件 . 这包括看门狗,时钟设置,MMU,中断处理等基础知识 . 然而,MCU的大多数工具链现在都带有某些糖衣库 . 他们会给你一个工作项目,其中包含大部分内容 . 这意味着您不必一次学习所有内容,但随着项目的进行,可以一点一点地学习 . 例如,要使一些LED闪烁,除了手册的GPIO部分之外,您应该能够执行此操作而不读取任何内容 .
您可能最终必须使用高质量代码替换预制的快速和脏库 . 这是因为提供这些库的硅制造商在编写软件时非常糟糕 . 在某些情况下,他们设法为您提供适当的MCU设置代码,但更多时候它们会为您提供低质量的代码 .
This大致是MCU设置的样子 . 您可以使用该列表来验证您从制造商处获得的内容是否有用,或者是否必须由专业嵌入式程序员重写 . 例如,ARM CMSIS可能或可能不够好,具体取决于应用程序要求 . 根据工具链的不同,它也有不同的风格 .
这是一些工作实例和建议,如果不是你想要的那么TL; DR不要打扰......
我建议您遵循各种途径,并定期重复 . 从理论上讲,您希望能够涵盖从数据表/原理图到供应商的 jar 头库以及freertos或其他解决方案的范围 . 我个人的偏好是数据表/原理图我发现这需要更少的时间,更清洁,更快,更可靠等... YMMV . 第一个规则是文档是错误的,第二个库是错误的(如果你看看内部可怕) . 有些供应商做得比较好,有些供应商往往没有那么好的工作,随着时间的推移,你可能会发现自己喜欢哪些供应商,而不是说你能够在专业上能够直到另外一个人,但是作为一个爱好的乐趣当然可以做到这一点 . 到目前为止,我不是在谈论arm vs 8051 vs其他,他们都有这个数据表vs库,buggy docs等等 . 无论如何所以有时你可能需要深入到图书馆或各种在线开源示例中找到失踪启用未在任何地方记录的位,发现可能存在一些命令,其中某些寄存器必须被编程,其他人可能已经掌握了内部知识或者只是运气不好 .
所以我会发布一个有点极小的例子,它应该适用于任何风格的arm-whatever-gcc / as / ld . (arm-linux-gnueabi arm-none-eabi等) . 和/或你可以像我定期那样从源代码构建你的gnu工具 . 一些预建的最佳开始虽然一次担心一个问题 .
您在照片中显示的棋盘也有特定的社区类型名称,即“蓝色药丸”或“stm32蓝色药丸” . 而且不像其他一些便宜的电路板,你可以在ebay或其他上找到这个已完成社区工作以适应ardunio沙箱,这是追求知识和经验的另一条途径,采取你不需要读取其他任何东西的arduino路径比谷歌stm32蓝色药丸,采取一些非常通用的几行代码,并把它们带到他们的沙箱,你有一个闪烁的领导 .
您将需要/需要具有stlink支持的openocd,因此无论是从源代码中查找二进制文件还是构建,都非常简单 . 我的偏好是从tcl目录中获取配置文件并随附我的项目并根据需要进行修改,而不是希望它们在那里并且没有从一个版本的openocd更改为另一个版本或从一台机器更改为另一台机器 . YMMV,这是个人偏好的事情 . 例如,我使用el-cheapo jlink克隆,ebay上的几块钱(紫色板) . 并有一个jlink.cfg
你图片中的板子是stlink风格之一,你可以通过反复试验或lsusb或其他手段找出 . 例如,它可能是这样的:
在我的情况下
其中target.cfg是一个单独的文件,其中包含来自openocd的各种stm32f1xxx配置文件 .
蓝色药丸在PC13上有一个LED,在该端口内有一个端口c引脚13 .
这里的示例不仅仅是裸机,而是包含引导代码,您不需要其他代码或 Headers ,只需要这些文件,以及gnu arm编译器或交叉编译器,具体取决于您是否在arm开发机器上运行它(raspberry pi计算机)等等)或其他东西(基于x86等) . 代码是为便携性和其他东西而设计的,而不是图书馆方法,一种让你以“我能做到这一点”的方式开始的方式,然后通过检查更复杂的解决方案来转移到你自己的个人偏好 .
sram.s
stm32f103 ...是基于cortex-m3的,你现在应该知道,因为你从数据表中得到了STM32F103C8T6文档,有引脚分布等,包装和部件号信息(告诉你你有多少闪存和ram等)和参考手册(一些供应商的数据表有所有的寄存器和描述,包括所有寄存器,地址空间和这些细节 . 在这些之间你发现它包含一个来自arm的cortex-m3,所以你去武器网站并获得cortex-m3的技术参考手册,你发现它基于armv7-m架构,并在武器网站上你获取armv7-m架构参考手册,这是您的CHIP的STARTING文档集,然后您可以尝试找到原理图或其他一些方法来确定PC13是LED的位置......
因此虽然armv7-m支持拇指指令集的更广泛的thumb2扩展数组,但我通常更喜欢从传统的拇指指令开始,从通用的框架开始,如下所示,如果需要(性能)通常)更改构建工具或代码以允许在armv7-m thumb2扩展,YMMV ...
blinker01.c
多年的芯片,电路板,芯片和电路板及外围设备仿真经验,以及我在航空航天业20多岁时的旧计时器,你想要强制执行指令,32位负载和存储,16位,等等 . 所以我使用asm来获得我想要的正确指令,并且有一个非常干净的抽象层(尽管性能成本,可以通过使用相同源代码的路上需要的宏来解决)用于连接模拟器,打卡通过操作系统等YMMV . 我有挥发性指针技巧失败BTW并产生错误的指令,我很少使用这个技巧 . 永远不要在编译域中使用结构并且不要滥用联合,我说这是因为这些天你几乎找到的所有解决方案都会违反这两个基本规则中的一个 . 使用此类库时,您将拥有该风险 . 但专业上你有时会不得不承担这种风险,因为这些图书馆可能是出于多种原因之一,个人偏好,老板这么说,保留遗留项目,没有时间/愿意重新编写tcp-ip堆栈或文件系统等
您可以看到这是一个详细的读 - 修改 - 写,将PC13配置为推挽输出 . 然后使用方便的位设置或复位寄存器来更改该端口中一个引脚的状态 . 在一个单独的优化域中使用dummy()会强制编译器必须生成该循环并烧掉该时间,以便我们可以看到led
优化,因为它什么都不做,以避免不要有意或无意地优化,或使x volatile表示编译器每次接触x时加载和存储,或调用另一个使用x的编译域中的函数强制编译器具有构建循环 . 以后你可以搞砸定时器 .
链接器脚本非常特定于工具链,你可以不使用gnu,但有时会发生一种奇怪的现象,我将让你找到(在这种情况下-Ttext = 0x20000000) . 你可以使它比这更简单,但大多数人使它变得更加复杂,YMMV .
我没有必要初始化.bss和.data所以我可以简单地删除所有这些要求附带的 Baggage . 违反C标准,我很满意这个例子 . 另请注意,我的入口点不是名为main()的至少一个工具链,因此必须假设其他人查找该功能名称并堆积在我们不想要的额外 Baggage 上 . 入口点名称应该是通用的 . 甚至_start,工具链使用它来标记入口点,好像这是一个要在操作系统上运行的二进制文件 . 不需要链接器可能会发出警告但仍会构建二进制文件 .
Build
我不再认为-nostdlib -nostartfiles -ffreestanding是必需的,这取决于我猜你正在使用的gnu工具的版本和风格 .
始终在第一次构建时检查反汇编,并在每次弄乱makefile / infrastructure时:
为了确保我们想要的入口点,我们预先想要的代码在那里并且正确构建,在这种情况下 .
打开几个命令行终端 . 通常你启动openocd的地方是它查找文件的地方的参考点,所以如果你在你的二进制文件所在的目录中启动,那么你不需要添加路径和/或复制你的二进制文件,在这种情况下,精灵版本是首选你启动openocd的地方 . 或者只输入路径,这是您的选择 . 另外,通过接管openocd配置文件,您可以将自己的脚本编写到配置中以自动执行这些步骤 .
在一个窗口中启动openocd
如果你没有结束x行断点,y观察点(对于一个手臂)那么你还没准备好继续前进,让你的调试器正确连线等等 . 注意调试器上的vcc线路并不是真的有用尽管他们对照片中你所说的那个特定的加密狗说了什么,我想我已经炸掉了第一个试图这样做的人 . 你想为目标供电,那么vcc线实际上是一个vcc检测线,它们驱动调试器上的IO电压,并为输入设置采样点 . 通用/历史上你可以在5.0v 3.3v 3.0v,1.8v等上使用这样的工具,使用v sense线来看看我们在这种情况下使用3.3v电平 . 检查您的接线检查电源,重新安装,从源构建等,直到openocd让您到达这一点 .
最简单的方法是telnet接口,我没有使用gdb,但这是下一级别的编译,除了在telnet接口工作之后 .
在您的其他命令行终端窗口中
然后
如果你停止后再次停止,你就不会得到那个输出 . 我在flash中有一个无限循环(以下面的示例并注释掉bl notmain)来向自己演示这个sram示例对你有用,除了堆栈指针以外,sram示例工作所需的闪存上没有任何东西 .
一旦停止,那么
领导应该开始慢慢眨眼 . 有人可能认为需要恢复0x20000001,但该工具恰好与0x20000000一起工作 .
这已经没用了sram,它通常比闪存小,但是你可以通过这种方式获得大量的教育,而不会冒险使用mcu(使用boot0引脚可以获得带有这些stm32设备的无监狱卡,适合您的对于没有用于备用/安全引导路径的带引脚的部件的自有项目,您应该尝试构建一个备用的,安全的引导路径,这样您就不会对芯片/板进行砖块化(意外地更改I / O引脚配置你依赖的jtag引脚进入芯片并更换固件,例如,有没有这样做)无论你有多少经验,它都会不时发生 . 我通常会购买至少两个,如果不是每个新的我董事会,以防万一 .
现在用flash做同样的事情
flash.s
处理器启动的方式非常特定于该处理器,只需读取文档,在这种情况下,它是一个向量表,而不仅仅是您刚刚开始执行的地址 . 这个ARE的详细信息在arm文档中,查找重置和异常以及向量和中断等字样,您将找到该表 . 注意这些cortex-m mcus可以有多达128个或256个以上的可能向量,取决于核心和芯片供应商,你不必指定比你正在使用更多的东西你可以逃避使用堆栈指针字的东西(可能你想要的堆栈指针初始化,并且必须有复位向量,除了它取决于你,你不提供硬故障或未定义的指令路径,并让它只是在代码中间,你的调用,你的调试 . 同时为中断设置向量(燃烧宝贵的闪存空间),你永远不会启用...你的调用,你的调试 .
flash.ld
(我回收我的通用示例/起始点,因此闪存/ ram的数量可能不会反映这个实际部分,根据需要进行调整) .
更改闪烁率,以便我可以看到Flash版本和sram版本之间的区别 .
Build
而且非常需要检查切入点
堆栈指针的初始值(向量表的反汇编是伪造的只是反汇编程序试图理解那些单词,值是我们关心的忽略反汇编)然后向量,复位向量是地址的重置处理程序ORRED与一个0x08000040 | 1 = 0x08000041,不要指望它启动否则,它将尝试进入故障处理程序,然后可能在那里失败 . 你不应该在这段代码中自己订购一个,如果你正在做一个跳转到其他地址的bootloader,你肯定需要一个orr . 我强烈反对添加一个,如果工具正确并且你添加了一个你现在搞砸了地址并且如果工具正确并且你或者那么你不会搞砸它就不会工作 .
现在这里是擦...
我有一些这些蓝色药丸闪存锁定,并有一个openocd方式摆脱,但我不知道我在哪里记录它,我确实修改我的基于uart的装载机来处理它,注意另一件事有在你的后袋中,这个设备和来自这个和其他供应商的大量其他mcus一起可能带有一个烧录的引导程序或其他非标记的方式进入芯片的电路,做一些尝试为该接口构建一个工具你可能有一天需要专业 . 在这种情况下,write unprotect命令实际上并没有执行文档所暗示的内容,它不会返回成功并且您必须重新启动芯片,但是它不受保护,您可以使用基于uart bootloader的工具或swd(jtag like)进入这一部分的工具 .
与使用openocd连接到部件中的调试器之前相同的交易 .
相反,如果你得到
你的部分是写保护的,你必须弄明白 . 如果我发现它,我会在这里发布,但因为我方便的部分没有受到保护我不能测试它 . 并不是真的想去购买更多零件希望他们受到保护只是为了展示你从某人那里购买这些蓝色药丸时会发现的东西 . 与此同时,我没有看到很多这样的例子用于处理这个问题,所以也许只有一个批次和/或一个制造商做了这个和我自己和另一个人在网上碰巧不幸 .
此时你可以
要么
按下复位按钮,跳线都移动到0侧 . 这表示boot0和boot1绑定为0(实际上只需要boot0为0) . 在你的图片中,你的跳线设置为1,你需要至少移动一个不在复位按钮旁边的跳线,复位按钮旁边的跳线被认为是boot1 .
并且led的闪烁速度应该是sram示例的两倍 . 当你再次打开电路板时,如果boot0 = 0,它将开始从闪存运行该程序 .
纯组装本来就更简单一个例子,易失性指针技巧稍微简单一些 . 但是,如果你不能让这个代码工作,你可能不会得到更复杂的工作 . 这很简单 .
再次注意这些示例不支持.data也不假设.bss为零,为了允许这些假设需要更多的代码和知识,我个人不依赖于那些并且不必使引导程序和链接描述文件复杂化(这是工具链特定的,不会端口),但这是个人喜好 .
google stm32 blue pill并在STM32duino上找到这样的页面,试试这些例子 . 可能有mbed支持另一个沙箱,这个支持购买或支持ARM,以及st至少有两种类型的库cmsis和一个遗留库 . 请注意,开展业务的芯片供应商通常会有一个库设置,并且出于营销和其他原因,继续流失这些,所以当HAL和CMSIS以及立方体和今天出现的任何内容时,期望一个,最终所有这些都是走在路上,甚至是CMSIS,部分原因是因为它有点混乱,没有真正的中央所有者 . 授予CMSIS可能会发展,但不要指望它保持其确切的形式 . 与此同时,这个行业的工作方式是理想情况下为您的产品购买一个相对较新和/或将在 生产环境 中的部件,只要您的产品希望在 生产环境 中,您编写/调试/构建固件和希望永远不必触摸它,所以你可以使用当今流行的/ FAD库,理想情况下保存从今天开始使用的构建机器以便将来使用,但希望你永远不必触摸它,今天最喜欢的库将工作足够长的时间让你去 生产环境 . 自己动手做的方法更容易维护,对于像gpio,spi,uart等简单的东西,IMO比库更容易,USB,以太网等东西可能更难,不是外围设备的接口,而是供应商库将包括一个usb堆栈,一个以太网ip堆栈,文件系统支持,它们可能大量集成到它们的外设库支持中,并且不一定值得分离以避免它们的外围库代码 .
在一天结束时,从专业角度来说,您应该假设您拥有所使用的所有代码,包括库 . 你的老板只会看到产品线发生故障,并不在乎它是你所选择的第三方库 .
如果您已经购买了开发套件,我会首先阅读用户手册,他们会在那里给出运行示例应用程序的步骤 . 按照步骤,从基本应用程序开始 . 理解代码 . 根据代码阅读数据表,了解IO和其他内部工作原理 . 您可能一开始并不了解所有内容,因为您有8051的经验,您将获得有关工作原理的要点 . 下一步是阅读精美的手臂教程/书籍,当您阅读那些尝试在开发板上执行或练习它们时 . 没有什么比学习和练习更好的了 . 祝一切顺利 .