开源Marlin2.x源代码架构学习笔记

Posted Engineer-Bruce_Yang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了开源Marlin2.x源代码架构学习笔记相关的知识,希望对你有一定的参考价值。

点击上方「嵌入式云IOT技术圈」,选择「置顶公众号」第一时间查看嵌入式笔记!

最近两个月MBA美帝在职研的课程即将结束,经过个人的努力,目前两门课:全球商务、定量决策均分绩点如下,基本上逼近满分(凡尔赛了,哈哈哈),光鲜亮丽的背后,带领小组始终冲在了班级的最前面,同时也付出了不少精力和汗水,通宵了不知道多少个夜晚,交完学期项目以后就结课啦,开始进入下一门课的学习!所以开始有时间可以折腾新东西啦:(不少同学应该知道我开了个知识星球,专门分享这些内容,这里就不好放出来啦,有兴趣和我说即可)

Marlin相当庞大,自2.x版本开始,陆陆续续开始集成了32位机,主流的STM32、LPC等高性能MCU逐渐取代了以Arduino2560等8位机的3D打印机方案。Marlin,庞大到让每个初学者开始学习看代码都会觉得闻风丧胆,当然我刚开始接触的时候也不例外,但是不管是学什么东西,只要把大方向掌握了,那么细节的东西用到了再慢慢研究也不迟,同时,Marlin的文档非常少,对于初学者来说,是非常不友好的!以下这些介绍也是Marlin刚开放不久的说明文档,笔者英语水平有限,如有翻译失误,尽情纠正与谅解!

1、Marlin代码工程架构

以下是原版的Marlin固件解压下来的显示情况:

当使用 PlatformIO 构建Marlin时,它会在.pio此处创建一个文件夹,并且在shell中使用git的时候,这 是当前的工作目录,如下图所示:

1.2、 buildroot 文件夹

该目录包含开发人员的帮助脚本、字体工具、CI测试工具、Marlin图标和其它数据

1.3、 buildroot/share/PlatformIO 文件夹

电路板定义、环境变量、链接脚本和构建脚本会存放在这个地方,这个文件夹内的构建环境会经常引用 ini文件夹

1.4、 ini 文件夹

包含按 MCU 类型组织的所有 PlatformIO 环境设置, platformio.ini 文件将这些引入为 PlatformIO 提供构建/上传/调试设置,有一个文件特别有用:即是Marlin自定义构建脚本 features.ini 在构建开 始时用于根据启用的功能过滤源文件,因此构建能够完成得更快。

1.5、 Marlin 文件夹

构建Marlin时,配置文件就放在这个位置:

1.6、 Marlin/src 文件夹

包含Marlin应用程序,Marlin基于 Arduino 框架进行开发,所以它含有 Arduino 框架的setup() 和 loop() 功能。

2、Marlin应用源代码Marlin/src 文件夹

Marlin应用源代码主要由以上文件夹组成,核心的入口程序文件是 MarlinCore.cpp ,MarlinCore.h 会做一些宏和变量以及函数的声明,在这个文件中可以找到基于 Arduino 框架的 setup() 和 loop() 函 数,其余的文件夹包含的源码主要的作用如下:

  • core文件夹

包含Marlin源文件需要的类型、宏、使用程序功能等等,大多数源文件只需要包含 inc/MarlinConfig.h 就可以确保这些文件按预期顺序包含在内。

  • feature文件夹

包含一些可选功能的支持代码,当然这个文件夹下的代码有些功能是非常简单的,只需要添加一个 G代码或者在公共代码中插入更改即可完成。如果一个特性需要定义一个类或者一组函数,这些附 加的文件将放在这个位置。

  • gcode 文件夹

包含GCodeParser 类的定义以及所有G代码命令的实现(有一些不在这里实现,但大部分是的),这 些功能都被包装在一个名为 GcodeSuite 的类里,G代码实现的文件被捆绑在多个类别的子文件夹 中,这些文件被命令为具体的G代码,因此可以使用 IDE 的查找功能找到它们。

  • HAL文件夹

每个控制器系列都提供控制硬件的功能,但并非所有控制器系列都使用相同的接口, Marlin2.x 版本实现了硬件抽象层,更好的屏蔽了平台的差异性,使其它的平台更好的兼容 Arduino 框架。

  • inc文件夹

包含了Marlin版本、配置条件等等的基本内容,请注意,每个HAL还包含自己的 Conditionals*.h 和 SanityCheck.h文件 。

  • lcd 文件夹

所有与 LCDTFTOLED、编码器、按钮和串行控制器的相关代码都放在这里,语言翻译通常仅 适用于外部控制器,因此语言翻译也放在这里。

  • libs文件夹

任何通用数据函数实现或者与硬件库代码都放在这里,如蜂鸣器代码、 CRC16 校验和实现、 3X3 矩阵、数字到字符串的转换功能、用于二进制传输的 HeatShrink ,甚至还有几个 EEPROM 。

  • module文件夹

这里定义了机器的所有典型功能,包括 3D 打印机拥有的所有的组件,例如:加热器和传感器、热 床探测、路径规划算法、将命令转换为分段运动的高级运动功能、将毫米分段快速转换为步进块的 运动路径规划,以及将块段转换为中断时序和STEP信号的步进器 ISR 。

  • pins文件夹

Marlin所有的板定义都在这个文件夹中,这里有不同的硬件架构,每个架构下的每块板都有自己独 特的引脚文件, pins.h 根据 MOTHERBOARD 设置进行包含,由于 pins.h 是 MarlinConfig.h 的包 含文件注意,因此它不会包含在其它的地方。

  • sd 目录

在这里您可以找到所有实现实际文件和文件夹的高级文件系统代码。 CardReader 类是Marlin用 于导航目录、打开G-code文件和从SD卡(或其他媒体)打印的主界面。自从Marlin 2.0.8以来,所有 的媒体类型都派生自 DiskIODriver 抽象类。

3、Marlin的配置

马林是高度可配置的。您将在源代码的许多地方发现应用配置选项来打开和关闭代码、更改行为和提供 值。

  • Marlin源文件如何获得它需要的所有配置值?

首先,当您构建一个c++程序时,第一阶段是分别构建所有的. C和 .cpp 文件。这些文件中的每一个都 必须是完整的,并且每个文件都负责包含它需要的头文件。在大型项目中,这可能会很乏味,所以很多 编译器都允许您创建“预编译头文件”( .PCH 文件),包括所有公共头文件。Marlin不使用 PCH 文件,而是 使用以类似方式工作的常规头文件。

在inc、core、HAL和pins文件夹中头文件的包含顺序很重要,因为每个头文件都是建立在其前身文件之 上的。为了确保始终遵循正确的包含顺序,任何需要配置和条件文件(直到conditionals_ad.h)的代码都 必须包含 inc/ marlinconfigpreh ,而任何需要完全实现的硬件配置的代码都必须包含 inc/MarlinConfig.h

让我们仔细看看每个文件包含的头文件。

3.1、 MarlinConfigPre.h

3.2、 MarlinConfig.h

4、一个典型的源文件

将这些内容放在一起,典型的源文件至少将包含 marlinconfigpreh ,以便它可以预先检查一些配置 值。只有在需要时,才会包含其他头文件。有些源文件包含一些特性的头文件是很常见的。

/**
* (c) 2021 Marlin Firmware
* A typical Marlin source.cpp file.
*/
#include "inc/MarlinConfigPre.h"
#if ENABLED(MY_COOL_FEATURE)
#if ENABLED(EXTENSIBLE_UI)
 #include "lcd/extui/ui_api.h"
#endif
#endif // MY_COOL_FEATURE

5、典型的头文件

Marlin头文件不会像源文件一样使用 #if…#endif 来包装。相反,如果不需要头文件,那么它就不会被 包含。Marlin还避免使用c风格的 #ifdef 包装器,并且只在自己的头文件上使用 #pragma 一次。

/**
* (c) 2021 Marlin Firmware
* A typical Marlin header.h file.
*/
#pragma once
extern int my_feature_var;
void do_feature_stuff();

当该特性被禁用时,一些头文件将提供空函数。这使得在单个点关闭东西更容易,并且可以使其他地方 的代码更整洁。

/**
* (c) 2021 Marlin Firmware
* A typical Marlin header.h file.
*/
#pragma once
#include "inc/MarlinConfigPre.h"
#if ENABLED(MY_COOL_FEATURE)
 extern int my_feature_var;
 void do_feature_stuff();
#else
 inline void do_feature_stuff() {}
#endif

6、Marlin的构建过程

一个Marlin式的结构可能需要一段时间,但它像其他任何草图一样工作。Marlin中的所有 .cpp 文件及 其依赖项都将被编译,以及它们包含的任何内容。使用 PlatformIO 的Marlin构建将使用 ini 文件夹中 的文件以及 buildroot/share/PlatformIO 中的脚本,根据您的配置过滤掉未使用的源文件,从而使 其更快。

7、程序和命令流程

Marlin程序的执行从 MarlinCore.cpp 开始,setup()函数初始化,loop()函数主循环,就像 Arduino 草 图一样。loop()函数非常小,主要负责调用idle(),然后在队列前面运行下一个G-code命令。

Marlin中的大多数任务都是通过空闲函数执行的,该函数调用 manage_inactivity 和 thermalManager.manage_heater 。您将看到许多对空闲的调用,因为所有等待循环都使用它来保持 机器运行。如果Marlin太长时间没有呼叫空闲,看门狗就会被触发,为了安全重新启动机器。

这个程序架构需要一些注意,因为我们不希望某个函数被idle本身调用,直到堆栈爆炸为止。在Marlin 只有少数的再入守卫,所以在实践中它工作得很好。

从空闲状态跟踪函数调用,可以很直观地看到Marlin是如何使所有设备和特性在程序上下文中运行的。一些特性一直在进行活动,但是Marlin所做的大部分工作都是由G-code命令发起的。

8、中断服务例程

Marlin定义了一些中断服务例程( ISRs ):

  • 步进 ISR 反复运行,通过向步进电机的STEP和DIR引脚发送脉冲以高速移动规划队列和步进电机。这种中断的频率与移动速度有关。

  • 温度 ISR 以接近 1KHz 的频率读取温度传感器,并在读数准备好时向主程序发送信号。它还管理不 需要非常高基频的加热器和风扇配置的软件/慢 PWM 。

  • 终止 ISR 可以被激活,如果终止引脚是中断能力的。它只在结束引脚的输入状态改变时触发。

  • Tone Timer由 Arduino 为某些平台定义,由Marlin为其他平台定义。它处理脉冲压电蜂鸣器来创 建音调,它运行的频率是当前音调的两倍。

  • 伺服定时器提供了用于伺服系统的 PWM 信号。

平台还将为Serial UART和其他设备定义中断,所以Marlin必须小心选择它使用的中断和计时器。

9、G代码的处理

接下来,让我们看看如何处理 G 代码并遵循程序流程。

  • 0.紧急解析器

当命令队列被阻塞,但是机器需要用户以某种形式输入时,您可以做什么?紧急解析器是一个简单的状态机,它在串行代码的低级别上运行,监视某些命令。当它看到 M108、M112 等时,它立即采取行动来处理代码。

  • 1.从Serial和SD读取

manage_inactivity函数调用queue.get_available_commands(),该函数检查即时缓冲区,查询串行 端口,并读取活动的SD打印文件,将行复制到命令队列中,目的是使其充满。

  • 2.弹出G代码

主循环()调用queue.advance()获取队列前面的命令并立即运行它。在命令完成之前,Marlin不会返回到loop()。注意```queue.advance() ````在队列之前运行内部命令,因此Marlin可以命令自身在常规命令流中 执行一些操作。

  • 3.预扫描G代码

一旦queue.advance()选择了下一个命令,它就调用解析器对G-code行进行预处理。预处理程序验证行号和校验和,如果一切正常,它会在调用特定的G-code处理程序之前对参数进行快速预扫描。

  • 4.处理G代码

所有的G-code处理程序都封装在 GcodeSuite 类中(例如, GcodeSuite::G28() ),尽管有一些在其他地方实现。G-code处理程序是一个简单的没有返回值的void方法。它不是从函数调用中获取参数,而是查询 GCodeParser 类来检查参数并读取它们的值。例如,处理程序使用parser.seen('X')来检查'X'参数是否存在,然后调用parser.value_float()以浮点数的形式获取其数值。请参阅gcode/parser.h获取所有可用的方法。

G-code处理程序几乎可以做任何事情,所以它们被分成单独的文件,每个文件只包含它需要的头文件。所有处理程序必须包括gcode.h,这将包括parser.h

  • 5.命令阻塞

当一个 G1 命令的移动队列被加入时,它就被认为是完成的,所以它可以立即返回。在实践中,特别是 在床水平启用时,每一次线性移动都有可能填满规划队列,并阻塞长时间等待空间打开。

当一个命令需要等待计划器或用户反馈中的空闲空间等内容时,它将调用空闲函数以保持机器的活动和 运行。idle函数甚至会将传入的命令读取到队列中,但是由于idle函数并不会分发g代码或推进队列,所 以在处理程序结束并返回之前,队列不能获得任何空的命令。

往期精彩

步进电机驱动在3D打印应用的学习笔记(一)

光固化3D打印悬空和支撑讲解

3D打印过程与最近的学习成果

两个最常用的3D打印机切片软件

3D打印机marlin固件框架与GCode命令总结

3D打印机Marlin固件串口功能解析和程序移植

让野火F103开发板支持Marlin2.0固件是什么体验?3D打印主控板成员+1

C语言映射表在嵌入式串口解析、UI设计中的应用(值得收藏并实践的精华帖)

觉得本次分享的文章对您有帮助,随手点[在看]并转发分享,也是对我的支持。

以上是关于开源Marlin2.x源代码架构学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

带你了解一下!

如何打造属于自己的3D打印机上位机?这篇文章带你了解一下!

学习笔记:python3,代码片段(2017)

[原创]java WEB学习笔记61:Struts2学习之路--通用标签 property,uri,param,set,push,if-else,itertor,sort,date,a标签等(代码片段

我起飞了呀!阿里P8架构师把 JDK 源码技术精髓整合成一份 10W 字笔记,最近开源了!

已献出膝盖!阿里大佬全新开源Android核心源码学习笔记,限时免费分享!