Marlin 固件 TEENSY35_36 HAL 深度解析:面向 Teensy 3.5 / 3.6 的 Cortex-M4 平台移植指南

发布时间:2026/9/13 11:53:38
Marlin 固件 TEENSY35_36 HAL 深度解析:面向 Teensy 3.5 / 3.6 的 Cortex-M4 平台移植指南 Marlin 固件 TEENSY35_36 HAL 深度解析面向 Teensy 3.5 / 3.6 的 Cortex-M4 平台移植指南【免费下载链接】MarlinMarlin is a firmware for RepRap 3D printers optimized for both 8 and 32 bit microcontrollers. Marlin supports all common platforms. Many commercial 3D printers come with Marlin installed. Check with your vendor if you need source code for your specific machine.项目地址: https://gitcode.com/GitHub_Trending/ma/Marlin导读本文以仓库内 TEENSY35_36 HAL 工作笔记 为核心系统讲解 Marlin 固件如何为 PJRC Teensy 3.5MK64FX512与 Teensy 3.6MK66FX1M0两块 ARM Cortex-M4 芯片提供硬件抽象层。你将掌握该 HAL 的构建与测试流程、与上游 Teensyduino 框架的集成边界以及 EEPROM 仿真、双 ADC 查表、Kinetis 看门狗、原生串口/SPI 封装等关键实现的底层原理并了解移植维护时必须遵守的代码约定。一、平台总览一块 HAL 目录两颗 Kinetis 芯片Marlin/src/HAL/TEENSY35_36/是 Marlin 为Teensy 3.5与Teensy 3.6共用的唯一 HAL 目录两板均基于 ARM Cortex-M4开发板主控芯片Flash关键区别Teensy 3.5MK64FX512512 KB容量更小是移植的瓶颈约束Teensy 3.6MK66FX1M01 MB容量翻倍功能超集两块芯片不通过运行时判断区分而是由编译器宏决定PlatformIO 的teensy35/teensy36板级 JSON 分别注入__MK64FX512__/__MK66FX1M0__宏。这一约定直接体现在 HAL.h 中#ifdef __MK66FX1M0__ #define IS_TEENSY36 1 #else // __MK64FX512__ #define IS_TEENSY35 1 #endif由于 3.5 只有 512 KB Flash社区维护的准则是如果固件在 3.5 上放得下3.61 MB一定也没问题因此 3.5 是一切适配工作的硬约束。二、构建与测试闭环mftest 与 teensy35/36 环境2.1 推荐使用 mftest 验证HAL 工作笔记明确要求使用mftest做验证因为它会为每个测试目标重新生成Marlin/Configuration.h而裸跑pio run -e无法可靠完成这一步cd $(git rev-parse --show-toplevel) buildroot/bin/mftest -t teensy35 -n1 -y # Teensy 3.5MK64FX512 buildroot/bin/mftest -t teensy35 -n8 -y # 双 Z 限位Dual-Z压力测试配置其中-t指定测试目标、-n指定第几个配置、-y跳过确认提示。2.2 测试配置分布只有 teensy35没有 teensy36该 HAL 的全部真实测试目标集中在buildroot/tests/teensy35/config-01…config-08共 8 套配置它们全部声明motherboard BOARD_TEENSY35_36。仓库中不存在buildroot/tests/teensy36/目录——3.6 构建与 3.5 共用同一 HAL 与板卡宏唯一差异来自 PlatformIO 的board teensy36注入__MK66FX1M0__。因此想覆盖共享代码跑teensy35测试目标即可想专门验证 3.6 专属路径用构建环境pio run -e teensy36对应 ini/teensy.ini 中的[env:teensy36]board teensy36。板卡选择宏BOARD_TEENSY35_36定义在 Marlin/src/core/boards.h编号 5101。2.3 强制重建的安全姿势工作笔记特别警告不要用rm -rf .pio/build/...强制重建——仓库的跨配置写保护会拦截该命令且这样做不安全。正确做法是pio run -e env -t clean # 只清除构建产物或者直接让mftest自行触发重建。三、框架集成边界上游 Teensyduino而非仓库内置与仓库自带的 AT32 框架不同Teensy 的 Arduino 内核是PlatformIO 提供的上游 Teensyduino 软件包并未 vendored 到buildroot/share/PlatformIO/下。其版本约束写在 ini/teensy.iniplatform teensy~4.12.0teensy_arm环境会拉取 Teensyduino 的cores/teensy3/其中提供寄存器头文件kinetis.h、pins_teensy.h原生串口对象Serial1…、SerialUSB、裸Serial原生SPI、Wireavr/eeprom.h的仿真实现见下文。Marlin 的胶水代码全部位于本 HAL 目录外加板级引脚定义 Marlin/src/pins/teensy3/pins_TEENSY35_36.h。由于没有安装包 vs 仓库的镜像步骤那条警告仅适用于 vendored 的 AT32 框架构建层面的改动就是直接编辑Marlin/src/HAL/TEENSY35_36/下的源码与buildroot/脚本。四、六个源码里看不出来的坑Gotchas4.1 芯片由编译期宏选择绝不运行时分支HAL.h 用#ifdef __MK66FX1M0__区分 3.5/3.6且目录内每个.cpp都以#if defined(__MK64FX512__) || defined(__MK66FX1M0__)包裹参见 HAL.cpp、eeprom.cpp、timers.cpp。3.5 与 3.6 的区别纯粹来自board teensy35/board teensy36两块 PlatformIO JSON——不要为芯片差异添加运行时分支。4.2 没有物理 EEPROM内核在 Flash 中仿真Kinetis 芯片没有物理 EEPROMTeensyduino 在程序 Flash 中提供仿真 EEPROM。Marlin 的 eeprom.cpp 通过USE_WIRED_EEPROM与#include avr/eeprom.h接入这套仿真MARLIN_EEPROM_SIZE默认取E2END 1。最关键的细节在write_data()中由于 Flash 写周期很慢HAL 在每写一个字节之间插入delay(2)/safe_delay(2)专门用来避免在长 EEPROM 写入期间触发看门狗复位。这段延迟是承重代码移植时务必保留eeprom_write_byte(p, v); if (written 0x7F) delay(2); else safe_delay(2); // 避免长时间 EEPROM 写入触发看门狗另外写入前会先eeprom_read_byte(p)比较新旧值只有字节确实变化才写——因为 EEPROM 只有约 10 万次写寿命写后还会回读校验并打印STR_ERR_EEPROM_WRITE。4.3 裸 Kinetis 寄存器名来自 Teensyduino 内核HAL.cpp 中直接引用的RCM_SRS0、WDOG_TOVALH、WDOG_STCTRLH、WDOG_REFRESH、ADC0_SC3、ADC1_SC3、IRQ_FTM1、NVIC_ENABLE_IRQ以及 fastio.h 里的CORE_PIN…系列宏全部由 Teensyduino 的cores/teensy3/定义Marlin 不重定义它们。如果编译报找不到RCM_SRS0说明选错了内核而不是缺 Marlin 头文件。4.4 双 ADC 物理引脚→SC1A 查表adc_start()用一个静态pin2sc1a[]数组在 HAL.cpp 中按物理引脚号索引 ADC 通道数字专用引脚映射为255此时adc_select -1表项最高位0x80标志 ADC1否则走 ADC0const uint16_t pin pin2sc1a[adc_pin]; if (pin 0xFF) adc_select -1; // 纯数字引脚 else if (pin 0x80) { adc_select 1; ADC1_SC1A pin 0x7F; } else { adc_select 0; ADC0_SC1A pin; }adc_value()则依据adc_select读ADC0_RA或ADC1_RA。引脚→ADC 通道的连线由 Teensy 3.5/3.6 硅片决定若需修改必须对照 Teensyduino 的pins_teensy.h编号。此外adc_init()会调用analog_init()并等待 ADC0/ADC1 校准完成ADC0_SC3 ADC_SC3_CAL最后使能IRQ_FTM1。HAL.h 中定义了 ADC 参考电压HAL_ADC_VREF_MV 3300与分辨率HAL_ADC_RESOLUTION 10。4.5 看门狗是 Kinetis WDOG双写刷新序列Teensy 3.x 没有独立的 CortexWDT因此不能照搬 STM32 风格看门狗代码。Marlin 的看门狗实现见 HAL.cpp#define WDT_TIMEOUT_MS TERN(WATCHDOG_DURATION_8S, 8000, 4000) // 4 或 8 秒超时 void MarlinHAL::watchdog_init() { WDOG_TOVALH 0; WDOG_TOVALL WDT_TIMEOUT_MS; WDOG_STCTRLH WDOG_STCTRLH_WDOGEN; } void MarlinHAL::watchdog_refresh() { // 看门狗刷新序列硬件强制顺序 WDOG_REFRESH 0xA602; WDOG_REFRESH 0xB480; }刷新必须依次写0xA602再写0xB480到WDOG_REFRESH顺序由硬件强制缺一不可。超时时间由WATCHDOG_DURATION_8S决定4 秒或 8 秒。4.6 原生串口对象无需自定义 Serial 全局与 AT32 HAL 不同Teensyduino 已内置Serial1…Serial3、SerialUSB与裸Serial。HAL.h 只做转发声明#define Serial0 Serial #define _DECLARE_SERIAL(X) \ typedef ForwardSerial1Classdecltype(Serial##X) DefaultSerial##X; \ extern DefaultSerial##X MSerial##X typedef ForwardSerial1Classdecltype(SerialUSB) USBSerialType; extern USBSerialType USBSerial; #define SERIAL_INDEX_MIN 0 #define SERIAL_INDEX_MAX 3SERIAL_PORT、SERIAL_PORT_2/3、MMU_SERIAL_PORT、LCD_SERIAL_PORT在 HAL.cpp 中按需实例化USBSerial包装原生SerialUSB。不需要HardwareSerial Serial Serial1;这类别名 hack。五、其余核心实现计时器、SPI、快速 IO 与重启5.1 FTM 计时器双通道分工timers.h 与 timers.cpp 使用两块 FTM 硬件定时器角色定时器预分频时钟对应 ISR步进电机MF_TIMER_STEP0FTM0860 MHz / 8 7.5 MHzftm0_isr温度采样MF_TIMER_TEMP1FTM1460 MHz / 4 15 MHzftm1_isrTEMP_TIMER_FREQUENCY固定为 1000 Hz。HAL_timer_start()按 65535 最大模数配置通道比较值HAL_timer_disable_interrupt()在NVIC_DISABLE_IRQ后强制执行__DSB()/__ISB()内存屏障确保中断真正被禁用代码中注释引用了 ARM Cortex-M NVIC 禁用的经典坑。ISR 前导HAL_timer_isr_prologue()负责清零计数与溢出/比较标志。5.2 SPI包装原生 SPIClassMarlinSPI.h 一行完成别名using MarlinSPI SPIClass;HAL_SPI.cpp 通过SPISettings/SPI.transfer驱动SPI.h的全局SPI对象速率映射完整覆盖 Marlin 的分级常量case SPI_FULL_SPEED: clock 10000000; break; // 10 MHz case SPI_HALF_SPEED: clock 5000000; break; // 5 MHz case SPI_QUARTER_SPEED: clock 2500000; break; case SPI_EIGHTH_SPEED: clock 1250000; break; case SPI_SPEED_5: clock 625000; break; case SPI_SPEED_6: clock 312500; break; default: clock 4000000; // SPI 库默认 4 MHzspiBegin()把 SD 引脚配置为 GPIOSD_SS拉高、SCK 输出、MISO 输入、MOSI 输出。注意spiSendBlock()中仍残留直接写SPDR寄存器与SPI.transfer()混用的代码——功能可用但不要把这个模式复制到别处。5.3 快速 IOCortex-M 位带操作fastio.h 基于 ARM Cortex-M 的**位带bit-band**特性实现高速 IO#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)(reg) - 0x40000000) * 32 (bit) * 4 0x42000000) #define GPIO_BITBAND(reg, bit) (*(uint32_t *)GPIO_BITBAND_ADDR((reg), (bit)))WRITE/READ/TOGGLE/SET_INPUT/SET_OUTPUT等宏均展开为对CORE_PINxx_PORTCLEAR/PORTSET/CONFIG/DDRREG的单指令访问并直接操作PORT_PCR_MUX/PORT_PCR_SRE/PORT_PCR_DSE引脚控制寄存器避免 ArduinodigitalWrite的函数调用开销。5.4 重启与复位源reboot()调用 Teensyduino 内核提供的_reboot_Teensyduino_()见 HAL.cpp而非手写SCB-AIRCR跳转——保持使用内核辅助函数即可。get_reset_source()读取RCM_SRS0复位状态寄存器映射为RST_POWER_ON值 128、RST_EXTERNAL64、RST_WATCHDOG32。5.5 自由内存探测freeMemory()通过链接器符号__bss_end、__heap_start与__brkval计算栈底与堆顶之间的可用 SRAMHAL.cpp 末尾用于运行时内存告警。六、端限位中断把轮询节省到底endstop_interrupts.h提供基于attachInterrupt(..., CHANGE)的端限位中断方案。它的意义在于没有中断时端限位引脚必须在温度 ISR 里被endstops.update()持续轮询大多数时候毫无变化、纯耗 CPU启用后只有端限位真正跳变才调用endstops.update()。所有用到的限位引脚X/Y/Z 各 MIN/MAX、双 Z、探针Z_MIN_PROBE、校准引脚、I/J/K/U/V/W 轴等逐一挂上统一的中断处理函数endstop_ISR()。前提是这些引脚都能产生外部中断可用buildroot/share/pin_interrupt_test/pin_interrupt_test.ino烧录验证。七、维护约定与代码归属从工作笔记可以提炼出以下必须遵守的约定宏守卫统一所有 HAL 源文件以#if defined(__MK64FX512__) || defined(__MK66FX1M0__)包裹该家族没有ARDUINO_ARCH_*守卫芯片宏由 PlatformIO 板卡 JSON 注入。改动归属清晰HAL 逻辑改动放在Marlin/src/HAL/TEENSY35_36/引脚改动放在Marlin/src/pins/teensy3/pins_TEENSY35_36.h板卡选择BOARD_TEENSY35_36在Marlin/src/core/boards.h。不 vendor 框架本目录没有README.md也没有 vendored 框架框架/平台集成行为属于上游 Teensyduino不要试图在buildroot/share/PlatformIO/打补丁。八、关联资源同族 HAL 与共享层该 HAL 复用了Marlin/src/HAL/shared/的共享 APIserial_ports.h、HAL_SPI.h、eeprom_api.h并与其他两个 Teensy HAL 构成同族Marlin/src/HAL/TEENSY31_32/ — Teensy 3.1/3.2不同硅片、不同宏Marlin/src/HAL/TEENSY40_41/ — Teensy 4.0/4.1Cortex-M7宏体系完全不同。理解这三个 HAL 的差异尤其是宏命名与内核依赖是维护 Marlin 多平台支持的捷径TEENSY35_36 走 KinetisWDOG FTM 位带 IO 的老派 Cortex-M4 路线而 40_41 则是 NXP i.MX RT 的现代架构。结语TEENSY35_36 HAL 是用最少胶水对接最强原生内核的典型编译期宏选芯片、复用 Teensyduino 的串口/SPI/EEPROM 仿真、只补上 Kinetis 特有的看门狗、FTM 定时器与位带快速 IO。无论你是要为新 Teensy 3.5/3.6 机器板卡适配 Marlin还是想理解 Cortex-M4 HAL 的通用移植套路本文梳理的构建流程、六条核心坑位与代码归属约定都是可以直接落地的第一手依据。【免费下载链接】MarlinMarlin is a firmware for RepRap 3D printers optimized for both 8 and 32 bit microcontrollers. Marlin supports all common platforms. Many commercial 3D printers come with Marlin installed. Check with your vendor if you need source code for your specific machine.项目地址: https://gitcode.com/GitHub_Trending/ma/Marlin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考