├── grblHAL_Teensy4 ├── src │ ├── my_machine.h │ ├── littlefs_hal.h │ ├── grblHAL_Teensy4.h │ ├── uart.h │ ├── enet.h │ ├── main.c │ ├── littlefs │ │ ├── lfs_util.c │ │ └── lfs_util.h │ ├── usb_serial_ard.h │ ├── t4_spi.h │ ├── usb_serial_pjrc.h │ ├── i2c.h │ ├── .settings │ │ ├── language.settings.xml │ │ └── org.eclipse.cdt.codan.core.prefs │ ├── pwm.h │ ├── .project │ ├── t4_spi.cpp │ ├── boards │ │ ├── generic_map.h │ │ ├── T40X101_map.h │ │ ├── cnc_boosterpack_map.h │ │ ├── E5XMCS_T41_map.h │ │ ├── GRBLHAL2000_map.h │ │ ├── T41U5XBB_map.h │ │ ├── T41U5XBB_ss_map.h │ │ └── T41BB5X_Pro_map.h │ ├── littlefs_hal.c │ ├── ioports_analog.c │ ├── ioports.c │ ├── tmc_spi.c │ ├── usb_serial_ard.cpp │ ├── usb_serial_pjrc.c │ ├── .cproject │ ├── neopixel_uart.cpp │ ├── driver.h │ ├── pwm.c │ └── i2c.c ├── library.properties ├── library.json ├── examples │ └── grblHAL_Teensy4_Upload │ │ └── grblHAL_Teensy4_Upload.ino └── platformio.ini ├── .gitattributes ├── .gitignore ├── platformio.tpl ├── .gitmodules ├── driver.json └── README.md /grblHAL_Teensy4/src/my_machine.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grblHAL/iMXRT1062/HEAD/grblHAL_Teensy4/src/my_machine.h -------------------------------------------------------------------------------- /grblHAL_Teensy4/library.properties: -------------------------------------------------------------------------------- 1 | name=grblHAL for Teensy 4.x 2 | version=1.1.7 3 | author=Terje Io 4 | maintainer=Terje Io 5 | sentence=grblHAL for Teensy 4.x 6 | paragraph= 7 | category=Other 8 | url=https://github.com/terjeio/grblHAL 9 | architectures=* 10 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grblHAL for Teensy 4.x", 3 | "frameworks": "Arduino", 4 | "platforms": "Twensy 4.0 - 4.1", 5 | "keywords": "grbl, CNC", 6 | "description": "grblHAL for Teensy 4.x", 7 | "version": "1.1.7", 8 | "authors": 9 | { "name": "Terje Io", 10 | "maintainer": true 11 | }, 12 | "repository": 13 | { "type": "git", 14 | "url": "https://github.com/terjeio/grblHAL" 15 | }, 16 | "examples": "examples/*/*.ino" 17 | } 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto eol=lf 3 | 4 | 5 | # Custom for Visual Studio 6 | *.cs diff=csharp 7 | 8 | # Standard to msysgit 9 | *.doc diff=astextplain 10 | *.DOC diff=astextplain 11 | *.docx diff=astextplain 12 | *.DOCX diff=astextplain 13 | *.dot diff=astextplain 14 | *.DOT diff=astextplain 15 | *.pdf diff=astextplain 16 | *.PDF diff=astextplain 17 | *.rtf diff=astextplain 18 | *.RTF diff=astextplain 19 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/littlefs_hal.h: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 1883 Thomas Edison - All Rights Reserved 2 | * You may use, distribute and modify this code under the 3 | * terms of the BSD 3 clause license, which unfortunately 4 | * won't be written for another century. 5 | * 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | * 8 | * A little flash file system for the Raspberry Pico 9 | * 10 | */ 11 | 12 | #ifndef __LITTLEFS_HAL_H__ 13 | #define __LITTLEFS_HAL_H__ 14 | 15 | #include "littlefs/lfs.h" 16 | 17 | struct lfs_config *t4_littlefs_hal (void); 18 | 19 | #endif // __LITTLEFS_HAL_H__ 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail cache files 2 | Thumbs.db 3 | ehthumbs.db 4 | ehthumbs_vista.db 5 | 6 | # Folder config file 7 | Desktop.ini 8 | 9 | # Recycle Bin used on file shares 10 | $RECYCLE.BIN/ 11 | 12 | # Windows Installer files 13 | *.cab 14 | *.msi 15 | *.msm 16 | *.msp 17 | 18 | # Windows shortcuts 19 | *.lnk 20 | 21 | # Subversion folders 22 | 23 | .svn 24 | 25 | # Build folder 26 | 27 | build 28 | .pio* 29 | .pioenvs 30 | .piolibdeps 31 | 32 | # 33 | # ========================= 34 | # Operating System Files 35 | # ========================= 36 | 37 | .vscode/settings.json 38 | .vscode/c_cpp_properties.json 39 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/grblHAL_Teensy4.h: -------------------------------------------------------------------------------- 1 | /* 2 | grblHAL_Teensy4.h - Arduino library wrapper (Teensy4.x version) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2019-2020 Terje Io 7 | 8 | Grbl is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Grbl is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Grbl. If not, see . 20 | */ 21 | 22 | #include "grbl/grbllib.h" 23 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/uart.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | uart.h - driver code for IMXRT1062 processor (on Teensy 4.0 board) 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2020-2023 Terje Io 8 | 9 | Grbl is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | Grbl is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with Grbl. If not, see . 21 | */ 22 | 23 | #ifndef _HAL_SERIAL_H_ 24 | #define _HAL_SERIAL_H_ 25 | 26 | void serialRegisterStreams (void); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /platformio.tpl: -------------------------------------------------------------------------------- 1 | # 2 | # Template for Web Builder, iMXRT1062 3 | # 4 | 5 | [platformio] 6 | src_dir = src 7 | include_dir = src 8 | 9 | [common] 10 | build_flags = 11 | -I bluetooth # workaround for relative 3rd party plugin includes starting with ../ 12 | -g3 13 | -fmax-errors=5 14 | -fno-strict-aliasing 15 | -D OVERRIDE_MY_MACHINE 16 | 17 | lib_archive = no 18 | lib_deps = 19 | extra_scripts = 20 | src_filter = + 21 | 22 | [env] 23 | framework = arduino 24 | extra_scripts = ${common.extra_scripts} 25 | build_flags = ${common.build_flags} 26 | lib_deps = ${common.lib_deps} 27 | monitor_speed = 250000 28 | monitor_flags = 29 | 30 | [eth_networking] 31 | build_flags = 32 | lib_deps = /home/webbuilder/grblHAL/teensy41_ethernet 33 | 34 | [env:%env_name%] 35 | board = %board% 36 | platform = teensy@4.16 37 | build_flags = ${common.build_flags} 38 | %build_flags% 39 | lib_deps = ${common.lib_deps} 40 | %lib_deps% 41 | /home/webbuilder/grblHAL/uSDFS 42 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/enet.h: -------------------------------------------------------------------------------- 1 | /* 2 | enet.h - lwIP driver glue code for IMXRT1062 processor (on Teensy 4.1 board) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2020-2021 Terje Io 7 | 8 | Grbl is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Grbl is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Grbl. If not, see . 20 | */ 21 | 22 | #ifndef __ENET_H__ 23 | #define __ENET_H__ 24 | 25 | #include "driver.h" 26 | 27 | bool grbl_enet_init (void); 28 | bool grbl_enet_start (void); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/examples/grblHAL_Teensy4_Upload/grblHAL_Teensy4_Upload.ino: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | grblHAL_Teensy4_Upload.ino - upload code for iMRXT1062 processor on a Teensy4.x board 4 | 5 | Part of GrblHAL 6 | 7 | Copyright (c) 2020 Terje Io 8 | 9 | Grbl is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | Grbl is distributed in the hope that it will be useful,ss 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with Grbl. If not, see . 21 | 22 | */ 23 | 24 | // Double tap reset to enter bootloader mode - select bootloader port for programming 25 | 26 | #include "grblHAL_Teensy4.h" 27 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | main.ino - startup code for iMXRT1062 processor (on Teensy 4.0 board) 4 | 5 | Part of Grbl 6 | 7 | Copyright (c) 2020 Terje Io 8 | 9 | Grbl is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | Grbl is distributed in the hope that it will be useful,ss 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with Grbl. If not, see . 21 | 22 | */ 23 | 24 | // Double tap reset to enter bootloader mode - select bootloader port for programming 25 | 26 | #include "grbl/grbllib.h" 27 | 28 | void setup () 29 | { 30 | grbl_enter(); 31 | } 32 | 33 | void loop () 34 | { 35 | } 36 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/littlefs/lfs_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * lfs util functions 3 | * 4 | * Copyright (c) 2022, The littlefs authors. 5 | * Copyright (c) 2017, Arm Limited. All rights reserved. 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | */ 8 | #include "lfs_util.h" 9 | 10 | // Only compile if user does not provide custom config 11 | #ifndef LFS_CONFIG 12 | 13 | 14 | // Software CRC implementation with small lookup table 15 | uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size) { 16 | static const uint32_t rtable[16] = { 17 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 18 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 19 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 20 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c, 21 | }; 22 | 23 | const uint8_t *data = buffer; 24 | 25 | for (size_t i = 0; i < size; i++) { 26 | crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf]; 27 | crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf]; 28 | } 29 | 30 | return crc; 31 | } 32 | 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/usb_serial_ard.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | usb_serial_ard.h - driver code for IMXRT1062 processor (on Teensy 4.0 board) 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2018-2021 Terje Io 8 | 9 | Grbl is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | Grbl is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with Grbl. If not, see . 21 | 22 | */ 23 | 24 | #ifndef _USB_SERIAL_H_ 25 | #define _USB_SERIAL_H_ 26 | 27 | #include 28 | #include 29 | 30 | #include "grbl/hal.h" 31 | 32 | const io_stream_t *usb_serialInit(void); 33 | int usb_serial_input(void); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/t4_spi.h: -------------------------------------------------------------------------------- 1 | /* 2 | t4_spi.h - SPI support for Trinamic plugin 3 | 4 | Part of grblHAL driver for iMXRT1062 5 | 6 | Copyright (c) 2020-2025 Terje Io 7 | 8 | Grbl is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Grbl is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Grbl. If not, see . 20 | */ 21 | 22 | #ifndef _GRBL_SPI_H_ 23 | #define _GRBL_SPI_H_ 24 | 25 | void t4_spi_init (void); 26 | uint32_t spi_set_speed (uint32_t prescaler); 27 | uint8_t spi_get_byte (void); 28 | uint8_t spi_put_byte (uint8_t byte); 29 | void spi_write (uint8_t *data, uint16_t len); 30 | void spi_read (uint8_t *data, uint16_t len); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/usb_serial_pjrc.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | usb_serial.h - driver code for IMXRT1062 processor (on Teensy 4.0 board) 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2020-2021 Terje Io 8 | 9 | Grbl is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | Grbl is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with Grbl. If not, see . 21 | 22 | */ 23 | 24 | #ifndef _USB_SERIAL_H_ 25 | #define _USB_SERIAL_H_ 26 | 27 | #include 28 | #include 29 | 30 | #include "usb_serial.h" 31 | 32 | #include "grbl/hal.h" 33 | 34 | #define usb_serial_input() usb_serial_available() 35 | 36 | const io_stream_t *usb_serialInit(void); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/i2c.h: -------------------------------------------------------------------------------- 1 | /* 2 | i2c.h - I2C interface 3 | 4 | Driver code for IMXRT1062 processor (on Teensy 4.x board) 5 | 6 | Part of grblHAL 7 | 8 | Copyright (c) 2020-2023 Terje Io 9 | 10 | Grbl is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | Grbl is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with Grbl. If not, see . 22 | */ 23 | 24 | #ifndef __I2C_DRIVER_H__ 25 | #define __I2C_DRIVER_H__ 26 | 27 | #include "driver.h" 28 | #include "grbl/plugins.h" 29 | 30 | #if TRINAMIC_ENABLE && TRINAMIC_I2C 31 | 32 | #include "trinamic/trinamic2130.h" 33 | #include "trinamic/TMC2130_I2C_map.h" 34 | 35 | #define I2C_ADR_I2CBRIDGE 0x47 36 | 37 | void I2C_DriverInit (TMC_io_driver_t *drv); 38 | 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/.settings/language.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/pwm.h: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | pwm.h - driver code for iMXRT1062 ARM processor 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2025 Terje Io 8 | 9 | grblHAL is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | grblHAL is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with grblHAL. If not, see . 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | #include 27 | 28 | struct pwm_pin_info_struct; 29 | 30 | typedef struct pwm_pin_info_struct pwm_signal_t; 31 | 32 | const pwm_signal_t *pwm_claim (void *port, uint8_t pin); 33 | bool pwm_enable (const pwm_signal_t *pwm); 34 | bool pwm_config (const pwm_signal_t *pwm, uint32_t prescaler, uint32_t period, bool inverted); 35 | bool pwm_out (const pwm_signal_t *pwm, uint32_t pwm_value); 36 | bool pwm_is_available (void *port, uint8_t pin); 37 | uint32_t pwm_get_clock_hz (const pwm_signal_t *pwm); 38 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/platformio.ini: -------------------------------------------------------------------------------- 1 | [platformio] 2 | src_dir = src 3 | include_dir = src 4 | default_envs = teensy41 5 | 6 | [common] 7 | build_flags = -g3 8 | -fmax-errors=5 9 | lib_archive = no 10 | lib_deps = 11 | extra_scripts = 12 | src_filter = + 13 | 14 | # 15 | # Default values apply to all 'env:' prefixed environments 16 | # 17 | [env] 18 | framework = arduino 19 | extra_scripts = ${common.extra_scripts} 20 | build_flags = ${common.build_flags} 21 | -include src/my_machine.h 22 | lib_deps = ${common.lib_deps} 23 | monitor_speed = 250000 24 | 25 | # Common values for Teensy based boards 26 | [common_teensy] 27 | platform = teensy 28 | upload_protocol = teensy-cli 29 | build_flags = ${env.build_flags} 30 | lib_deps = 31 | https://github.com/grblHAL/teensy41_ethernet 32 | https://github.com/grblHAL/uSDFS 33 | 34 | # Included as a stub-example for showing how to structure common environments 35 | [env:teensy40] 36 | board = teensy40 37 | platform = ${common_teensy.platform} 38 | upload_protocol = ${common_teensy.upload_protocol} 39 | build_flags = ${common_teensy.build_flags} 40 | lib_deps = ${common_teensy.lib_deps} 41 | 42 | [env:teensy41] 43 | board = teensy41 44 | # platform = ${common_teensy.platform} NOTE: the latest version is broken as of 2022-10-21 45 | platform = ${common_teensy.platform}@4.18.0 46 | upload_protocol = ${common_teensy.upload_protocol} 47 | build_flags = ${common_teensy.build_flags} 48 | lib_deps = ${common_teensy.lib_deps} 49 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Driver Teensy4 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.core.ccnature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | 29 | ARDUINOPATH 30 | file:/C:/Program%20Files%20(x86)/Arduino 31 | 32 | 33 | COMPILER_LOC 34 | file:/C:/Program%20Files%20(x86)/Arduino/hardware/tools/arm/arm-none-eabi 35 | 36 | 37 | ETHERNET_LIB 38 | file:/C:/users/terjeio/Documents/Arduino/libraries/teensy41_ethernet-master/src 39 | 40 | 41 | TEENSY4_CORE 42 | file:/C:/Program%20Files%20(x86)/Arduino/hardware/teensy/avr/cores/teensy4 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "grblHAL_Teensy4/src/grbl"] 2 | path = grblHAL_Teensy4/src/grbl 3 | url = https://github.com/grblHAL/core 4 | [submodule "grblHAL_Teensy4/src/eeprom"] 5 | path = grblHAL_Teensy4/src/eeprom 6 | url = https://github.com/grblHAL/Plugin_EEPROM 7 | [submodule "grblHAL_Teensy4/src/keypad"] 8 | path = grblHAL_Teensy4/src/keypad 9 | url = https://github.com/grblHAL/Plugin_I2C_keypad 10 | [submodule "grblHAL_Teensy4/src/networking"] 11 | path = grblHAL_Teensy4/src/networking 12 | url = https://github.com/grblHAL/Plugin_networking 13 | [submodule "grblHAL_Teensy4/src/sdcard"] 14 | path = grblHAL_Teensy4/src/sdcard 15 | url = https://github.com/grblHAL/Plugin_SD_card 16 | [submodule "grblHAL_Teensy4/src/spindle"] 17 | path = grblHAL_Teensy4/src/spindle 18 | url = https://github.com/grblHAL/Plugins_spindle 19 | [submodule "grblHAL_Teensy4/src/odometer"] 20 | path = grblHAL_Teensy4/src/odometer 21 | url = https://github.com/grblHAL/Plugin_odometer 22 | [submodule "grblHAL_Teensy4/src/encoder"] 23 | path = grblHAL_Teensy4/src/encoder 24 | url = https://github.com/grblHAL/Plugin_encoder 25 | [submodule "grblHAL_Teensy4/src/laser"] 26 | path = grblHAL_Teensy4/src/laser 27 | url = https://github.com/grblHAL/Plugins_laser 28 | [submodule "grblHAL_Teensy4/src/plasma"] 29 | path = grblHAL_Teensy4/src/plasma 30 | url = https://github.com/grblHAL/Plugin_plasma 31 | [submodule "grblHAL_Teensy4/src/openpnp"] 32 | path = grblHAL_Teensy4/src/openpnp 33 | url = https://github.com/grblHAL/Plugin_OpenPNP 34 | [submodule "grblHAL_Teensy4/src/bluetooth"] 35 | path = grblHAL_Teensy4/src/bluetooth 36 | url = https://github.com/grblHAL/Plugins_Bluetooth 37 | [submodule "grblHAL_Teensy4/src/fans"] 38 | path = grblHAL_Teensy4/src/fans 39 | url = https://github.com/grblHAL/Plugin_fans 40 | [submodule "grblHAL_Teensy4/src/webui"] 41 | path = grblHAL_Teensy4/src/webui 42 | url = https://github.com/grblHAL/Plugin_WebUI 43 | [submodule "grblHAL_Teensy4/src/embroidery"] 44 | path = grblHAL_Teensy4/src/embroidery 45 | url = https://github.com/grblHAL/Plugin_embroidery 46 | [submodule "grblHAL_Teensy4/src/plugins"] 47 | path = grblHAL_Teensy4/src/plugins 48 | url = https://github.com/grblHAL/Plugins_misc/ 49 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/t4_spi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | t4_spi.c - SPI support for Trinamic plugin 3 | 4 | Part of grblHAL driver for iMXRT1062 5 | 6 | Copyright (c) 2025 Terje Io 7 | 8 | Grbl is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | Grbl is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with Grbl. If not, see . 20 | */ 21 | 22 | #include "driver.h" 23 | 24 | #if SPI_ENABLE 25 | 26 | #include 27 | #include "Arduino.h" 28 | 29 | #ifndef SPI_FREQ 30 | #define SPI_FREQ 8000000 31 | #endif 32 | 33 | static SPISettings cfg(SPI_FREQ, MSBFIRST, SPI_MODE3); 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | void t4_spi_init (void) 40 | { 41 | static bool init = false; 42 | 43 | if(!init) { 44 | 45 | init = true; 46 | 47 | PROGMEM static const periph_pin_t sck = { 48 | .function = Output_SPICLK, 49 | .group = PinGroup_SPI, 50 | .port = NULL, 51 | .pin = 13, 52 | .mode = { .mask = PINMODE_OUTPUT } 53 | }; 54 | 55 | PROGMEM static const periph_pin_t sdo = { 56 | .function = Input_MISO, 57 | .group = PinGroup_SPI, 58 | .port = NULL, 59 | .pin = 12, 60 | .mode = { .mask = PINMODE_NONE } 61 | }; 62 | 63 | PROGMEM static const periph_pin_t sdi = { 64 | .function = Output_MOSI, 65 | .group = PinGroup_SPI, 66 | .port = NULL, 67 | .pin = 11, 68 | .mode = { .mask = PINMODE_NONE } 69 | }; 70 | 71 | hal.periph_port.register_pin(&sck); 72 | hal.periph_port.register_pin(&sdo); 73 | hal.periph_port.register_pin(&sdi); 74 | 75 | SPI.begin(); 76 | } 77 | } 78 | 79 | uint32_t spi_set_speed (uint32_t f_hz) 80 | { 81 | static uint32_t cur = SPI_FREQ; 82 | 83 | if(f_hz != cur) { 84 | // SPI.setFrequency(f_hz); 85 | f_hz = cur; 86 | } 87 | 88 | return cur; 89 | } 90 | 91 | uint8_t spi_get_byte (void) 92 | { 93 | SPI.beginTransaction(cfg); 94 | uint8_t data = SPI.transfer(0xFF); 95 | SPI.endTransaction(); 96 | 97 | return data; 98 | } 99 | 100 | uint8_t spi_put_byte (uint8_t byte) 101 | { 102 | SPI.beginTransaction(cfg); 103 | 104 | byte = SPI.transfer(byte); 105 | 106 | SPI.endTransaction(); 107 | 108 | return byte; 109 | } 110 | 111 | void spi_write (uint8_t *data, uint16_t len) 112 | { 113 | if(len) { 114 | 115 | SPI.beginTransaction(cfg); 116 | 117 | do { 118 | SPI.transfer(*data++); 119 | } while(--len); 120 | 121 | SPI.endTransaction(); 122 | } 123 | } 124 | 125 | void spi_read (uint8_t *data, uint16_t len) 126 | { 127 | if(len) { 128 | 129 | SPI.beginTransaction(cfg); 130 | 131 | do { 132 | *data++ = SPI.transfer(0); 133 | } while(--len); 134 | 135 | SPI.endTransaction(); 136 | } 137 | } 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif // SPI_ENABLE 144 | -------------------------------------------------------------------------------- /driver.json: -------------------------------------------------------------------------------- 1 | { 2 | "caps": 3 | { 4 | "informal": 1, 5 | "axes": 6, 6 | "usb_cdc": 1, 7 | "uart": 1, 8 | "spindle_pwm": 1, 9 | "spindle_dir": 1, 10 | "spindle_sync": 1, 11 | "serial_ports": 1, 12 | "eeprom": 1, 13 | "i2c_strobe": 1, 14 | "ganged_axes": 1, 15 | "auto_square": 1, 16 | "littlefs": 1, 17 | "digital_in": 8, 18 | "digital_out": 8, 19 | "probe": 1, 20 | "safety_door": 1, 21 | "estop": 1, 22 | "mpg_mode": 1, 23 | "sdcard": 1, 24 | "ethernet": 1, 25 | "mcp3221_adc": 1, 26 | "pio_board": "teensy41", 27 | "build_dir": "grblHAL_Teensy4", 28 | "plugins": [ 29 | { "id": "spindle" }, 30 | { "id": "modbus" }, 31 | { "id": "eeprom" }, 32 | { "id": "sdcard" }, 33 | { "id": "webui" }, 34 | { "id": "networking" }, 35 | { "id": "keypad" }, 36 | { "id": "macros" }, 37 | { "id": "plasma" }, 38 | { "id": "laser_ppi" }, 39 | { "id": "laser_cluster" }, 40 | { "id": "laser_coolant" }, 41 | { "id": "laser_overdrive" }, 42 | { "id": "fans" }, 43 | { "id": "odometer" }, 44 | { "id": "openpnp" }, 45 | { "id": "bluetooth" }, 46 | { "id": "embroidery" } 47 | ] 48 | }, 49 | "boards": [ 50 | { 51 | "name": "T41U5XBB", 52 | "symbol": "BOARD_T41U5XBB", 53 | "URL": "https://github.com/phil-barrett/grbl-teensy-4", 54 | "MAP": "grblHAL_Teensy4/src/boards/T41U5XBB_map.h", 55 | "caps": { 56 | "axes": 5, 57 | "ganged_axes": 2, 58 | "auto_square": 2, 59 | "digital_in": 4, 60 | "digital_out": 3, 61 | "i2c_strobe": 1, 62 | "serial_ports": 1, 63 | "spindle_pwm": 2, 64 | "sdcard": 1, 65 | "ethernet": 1, 66 | "eeprom": 1 67 | } 68 | }, 69 | { 70 | "name": "T41U5XBB Spindle Sync", 71 | "symbol": "BOARD_T41U5XBB_SS", 72 | "URL": "https://www.grbl.org/single-post/modifying-a-t41u5xbb-for-lathe-spindle-sync", 73 | "MAP": "grblHAL_Teensy4/src/boards/T41U5XBB_ss_map.h", 74 | "caps": { 75 | "axes": 5, 76 | "ganged_axes": 2, 77 | "auto_square": 2, 78 | "digital_in": 4, 79 | "digital_out": 3, 80 | "i2c_strobe": 1, 81 | "serial_ports": 1, 82 | "sdcard": 1, 83 | "ethernet": 1, 84 | "eeprom": 1, 85 | "spindle_sync": 1 86 | } 87 | }, 88 | { 89 | "name": "T41BB5X Pro", 90 | "symbol": "BOARD_T41BB5X_PRO", 91 | "URL": "https://github.com/phil-barrett/grbl-teensy-4", 92 | "MAP": "grblHAL_Teensy4/src/boards/T41BB5X_Pro_map.h", 93 | "caps": { 94 | "axes": 5, 95 | "ganged_axes": 2, 96 | "auto_square": 2, 97 | "digital_in": 4, 98 | "digital_out": 3, 99 | "i2c_strobe": 1, 100 | "serial_ports": 1, 101 | "spindle_pwm": 2, 102 | "sdcard": 1, 103 | "ethernet": 1, 104 | "eeprom": 1, 105 | "spindle_sync": 1 106 | } 107 | }, 108 | { 109 | "name": "E5XMCS_T41", 110 | "symbol": "BOARD_E5XMCS_T41", 111 | "URL": "https://www.makerstore.com.au/product/elec-e5xmcst41/", 112 | "MAP": "grblHAL_Teensy4/src/boards/E5XMCS_T41_map.h", 113 | "caps": { 114 | "axes": 5, 115 | "ganged_axes": 2, 116 | "auto_square": 2, 117 | "digital_in": 4, 118 | "digital_out": 4, 119 | "i2c_strobe": 1, 120 | "serial_ports": 1, 121 | "sdcard": 1, 122 | "ethernet": 1, 123 | "eeprom": 0, 124 | "i2c": 1, 125 | "spindle_sync": 0 126 | } 127 | }, 128 | { "name": "GRBLHAL2000 - PRINTNC", 129 | "symbol": "BOARD_GRBLHAL2000", 130 | "URL": "https://github.com/Expatria-Technologies/grblhal_2000_PrintNC", 131 | "MAP": "grblHAL_Teensy4/src/boards/GRBLHAL2000_map.h", 132 | "caps": { 133 | "axes": 5, 134 | "digital_in": 4, 135 | "digital_out": 3, 136 | "i2c_strobe": 1, 137 | "serial_ports": 1, 138 | "sdcard": 1, 139 | "ethernet": 1, 140 | "eeprom": 1, 141 | "fram": 1, 142 | "spindle_sync": 1 143 | } 144 | }, 145 | { 146 | "name": "T40X101", 147 | "symbol": "BOARD_T40X101", 148 | "URL": "https://github.com/phil-barrett/grbl-teensy-4", 149 | "MAP": "grblHAL_Teensy4/src/boards/T40X101_map.h", 150 | "pio_board": "teensy40", 151 | "caps": { 152 | "axes": 4, 153 | "serial_ports": 1 154 | } 155 | } 156 | ] 157 | } 158 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/boards/generic_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | generic_map.h - driver code for IMXRT1062 processor (on Teensy 4.x board) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2020-2024 Terje Io 7 | 8 | grblHAL is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | grblHAL is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with grblHAL. If not, see . 20 | */ 21 | 22 | #if N_ABC_MOTORS > 2 23 | #error "Axis configuration is not supported!" 24 | #endif 25 | 26 | #if SPINDLE_SYNC_ENABLE 27 | #error "Spindle sync is not supported" 28 | #endif 29 | 30 | // Define step pulse output pins. 31 | #define X_STEP_PIN (2u) 32 | #define Y_STEP_PIN (4u) 33 | #define Z_STEP_PIN (6u) 34 | 35 | // Define step direction output pins. 36 | #define X_DIRECTION_PIN (3u) 37 | #define Y_DIRECTION_PIN (5u) 38 | #define Z_DIRECTION_PIN (7u) 39 | 40 | // Define stepper driver enable/disable output pin(s). 41 | #define STEPPERS_ENABLE_PIN (10u) 42 | 43 | // Define homing/hard limit switch input pins. 44 | #define X_LIMIT_PIN (20u) 45 | #define Y_LIMIT_PIN (21u) 46 | #define Z_LIMIT_PIN (22u) 47 | 48 | // Define ganged axis or A axis step pulse and step direction output pins. 49 | #if N_ABC_MOTORS > 0 50 | #define M3_AVAILABLE 51 | #define M3_STEP_PIN (8u) 52 | #define M3_DIRECTION_PIN (9u) 53 | #define M3_LIMIT_PIN (23u) 54 | #endif 55 | 56 | // Define ganged axis or B axis step pulse and step direction output pins. 57 | #if N_ABC_MOTORS == 2 58 | #define M4_AVAILABLE 59 | #define M4_STEP_PIN (26u) 60 | #define M4_DIRECTION_PIN (27u) 61 | #define M4_LIMIT_PIN (28u) 62 | #endif 63 | 64 | // Define auxiliary output pins 65 | #define AUXOUTPUT0_PIN (13u) // Spindle PWM 66 | #define AUXOUTPUT1_PIN (11u) // Spindle direction 67 | #define AUXOUTPUT2_PIN (12u) // Spindle enable 68 | #define AUXOUTPUT3_PIN (19u) // Coolant flood 69 | #define AUXOUTPUT4_PIN (18u) // Coolant mist 70 | 71 | // Define driver spindle pins 72 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_ENA 73 | #define SPINDLE_ENABLE_PIN AUXOUTPUT2_PIN 74 | #endif 75 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_PWM 76 | #define SPINDLE_PWM_PIN AUXOUTPUT0_PIN 77 | #endif 78 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_DIR 79 | #define SPINDLE_DIRECTION_PIN AUXOUTPUT1_PIN 80 | #endif 81 | 82 | // Define flood and mist coolant enable output pins. 83 | #if COOLANT_ENABLE & COOLANT_FLOOD 84 | #define COOLANT_FLOOD_PIN AUXOUTPUT3_PIN 85 | #endif 86 | #if COOLANT_ENABLE & COOLANT_MIST 87 | #define COOLANT_MIST_PIN AUXOUTPUT4_PIN 88 | #endif 89 | 90 | // Define auxiliary input pins 91 | #if !QEI_ENABLE 92 | #define AUXINPUT0_PIN (0u) 93 | #define AUXINPUT1_PIN (3u) 94 | #endif 95 | #define AUXINPUT2_PIN (1u) 96 | #define AUXINPUT3_PIN (29u) // Safety door 97 | #define AUXINPUT4_PIN (15u) // Probe 98 | #define AUXINPUT5_PIN (14u) // Reset/EStop 99 | #define AUXINPUT6_PIN (16u) // Feed hold 100 | #define AUXINPUT7_PIN (17u) // Cycle start 101 | 102 | // Define user-control controls (cycle start, reset, feed hold) input pins. 103 | #if CONTROL_ENABLE & CONTROL_HALT 104 | #define RESET_PIN AUXINPUT5_PIN 105 | #endif 106 | #if CONTROL_ENABLE & CONTROL_FEED_HOLD 107 | #define FEED_HOLD_PIN AUXINPUT6_PIN 108 | #endif 109 | #if CONTROL_ENABLE & CONTROL_CYCLE_START 110 | #define CYCLE_START_PIN AUXINPUT7_PIN 111 | #endif 112 | 113 | #if PROBE_ENABLE 114 | #define PROBE_PIN AUXINPUT4_PIN 115 | #endif 116 | 117 | #if SAFETY_DOOR_ENABLE 118 | #define SAFETY_DOOR_PIN AUXINPUT3_PIN 119 | #elif MOTOR_FAULT_ENABLE 120 | #define MOTOR_FAULT_PIN AUXINPUT3_PIN 121 | #endif 122 | 123 | // Define probe switch input pin. 124 | 125 | #if I2C_ENABLE 126 | #define I2C_PORT 4 127 | #define I2C_SCL4 (24u) // Not referenced, for info only 128 | #define I2C_SDA4 (25u) // Not referenced, for info only 129 | #endif 130 | 131 | #if QEI_ENABLE 132 | #define QEI_A_PIN (0) 133 | #define QEI_B_PIN (3) 134 | #define QEI_SELECT_PIN AUXINPUT2_PIN 135 | #endif 136 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/littlefs_hal.c: -------------------------------------------------------------------------------- 1 | // littlefs HAL for grblHAL VFS 2 | // Most of the code has been exctracted from https://github.com/PaulStoffregen/LittleFS 3 | 4 | /* LittleFS for Teensy 5 | * Copyright (c) 2020, Paul Stoffregen, paul@pjrc.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice, development funding notice, and this permission 15 | * notice shall be included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #include "driver.h" 27 | 28 | #if LITTLEFS_ENABLE 29 | 30 | #include "littlefs_hal.h" 31 | 32 | #if defined(ARDUINO_TEENSY40) 33 | #define FLASH_SIZE 0x1F0000 34 | #define SECTOR_SIZE 32768 35 | #elif defined(ARDUINO_TEENSY41) 36 | #define FLASH_SIZE 0x7C0000 37 | #define SECTOR_SIZE 65536 38 | #elif defined(ARDUINO_TEENSY_MICROMOD) 39 | #define FLASH_SIZE 0xFC0000 40 | #define SECTOR_SIZE 65536 41 | #endif 42 | 43 | #ifndef LFS_SIZE_KB 44 | #define LFS_SIZE_KB 512 45 | #endif 46 | #define FS_SIZE (LFS_SIZE_KB * 1024) 47 | 48 | #if (FS_SIZE & (SECTOR_SIZE - 1)) || FS_SIZE > (FLASH_SIZE - (512 * 1024)) 49 | #error "Illegal littlefs file system size!" 50 | #endif 51 | 52 | extern void eepromemu_flash_write (void *addr, const void *data, uint32_t len); 53 | extern void eepromemu_flash_erase_sector (void *addr); 54 | extern void eepromemu_flash_erase_32K_block (void *addr); 55 | extern void eepromemu_flash_erase_64K_block (void *addr); 56 | 57 | static uint32_t baseaddr = 0; 58 | 59 | extern unsigned long _flashimagelen; 60 | 61 | static int t4_hal_read (const struct lfs_config *c, lfs_block_t block, lfs_off_t offset, void *buffer, lfs_size_t size) 62 | { 63 | const uint8_t *p = (uint8_t *)(baseaddr + block * c->block_size + offset); 64 | 65 | memcpy(buffer, p, size); 66 | 67 | return LFS_ERR_OK; 68 | } 69 | 70 | static int t4_hal_prog (const struct lfs_config *c, lfs_block_t block, lfs_off_t offset, const void *buffer, lfs_size_t size) 71 | { 72 | uint8_t *p = (uint8_t *)(baseaddr + block * c->block_size + offset); 73 | 74 | eepromemu_flash_write(p, buffer, size); 75 | 76 | return LFS_ERR_OK; 77 | } 78 | 79 | static int t4_hal_erase (const struct lfs_config *c, lfs_block_t block) 80 | { 81 | uint8_t *p = (uint8_t *)(baseaddr + block * c->block_size); 82 | 83 | #if SECTOR_SIZE == 4096 84 | eepromemu_flash_erase_sector(p); 85 | #elif SECTOR_SIZE == 32768 86 | eepromemu_flash_erase_32K_block(p); 87 | #elif SECTOR_SIZE == 65536 88 | eepromemu_flash_erase_64K_block(p); 89 | #else 90 | #error "Program SECTOR_SIZE must be 4096, 32768, or 65536" 91 | #endif 92 | 93 | return LFS_ERR_OK; 94 | } 95 | 96 | static int t4_hal_sync (const struct lfs_config *c) 97 | { 98 | (void)c; 99 | 100 | return LFS_ERR_OK; 101 | } 102 | 103 | static struct lfs_config t4_cfg = { 104 | // block device operations 105 | .read = t4_hal_read, 106 | .prog = t4_hal_prog, 107 | .erase = t4_hal_erase, 108 | .sync = t4_hal_sync, 109 | // block device configuration 110 | .read_size = 128, 111 | .prog_size = 128, 112 | .block_size = SECTOR_SIZE, 113 | .block_count = FS_SIZE / SECTOR_SIZE, 114 | .cache_size = 128, 115 | .lookahead_size = 128, 116 | .block_cycles = 800 117 | }; 118 | 119 | struct lfs_config *t4_littlefs_hal (void) 120 | { 121 | const uint32_t program_size = (uint32_t)&_flashimagelen; 122 | if (program_size >= FLASH_SIZE) 123 | return NULL; 124 | 125 | const uint32_t available_space = FLASH_SIZE - program_size; 126 | if (FS_SIZE > available_space) 127 | return NULL; 128 | 129 | baseaddr = 0x60000000 + FLASH_SIZE - FS_SIZE - SECTOR_SIZE; 130 | 131 | return &t4_cfg; 132 | } 133 | 134 | #endif // LITTLEFS_ENABLE 135 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/boards/T40X101_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | T40X101_map.h - driver code for IMXRT1062 processor (on Teensy 4.0 board) 3 | 4 | Part of grblHAL 5 | 6 | Board by Phil Barrett: https://github.com/phil-barrett/grblHAL-teensy-4.x 7 | 8 | Copyright (c) 2020-2024 Terje Io 9 | 10 | grblHAL is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | grblHAL is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with grblHAL. If not, see . 22 | */ 23 | 24 | #define BOARD_NAME "T40X101" 25 | #define BOARD_URL "https://github.com/phil-barrett/grbl-teensy-4" 26 | 27 | #if N_ABC_MOTORS > 2 28 | #error "Axis configuration is not supported!" 29 | #endif 30 | 31 | #if QEI_ENABLE 32 | #error "No pins available for encoder input!" 33 | #endif 34 | 35 | #if SPINDLE_SYNC_ENABLE 36 | #error "Spindle sync is not supported for T40X101!" 37 | #endif 38 | 39 | #define X_STEP_PIN (2u) 40 | #define X_DIRECTION_PIN (3u) 41 | #define X_LIMIT_PIN (20u) 42 | 43 | #define Y_STEP_PIN (4u) 44 | #define Y_DIRECTION_PIN (5u) 45 | #define Y_LIMIT_PIN (21u) 46 | 47 | #define Z_STEP_PIN (6u) 48 | #define Z_DIRECTION_PIN (7u) 49 | #define Z_LIMIT_PIN (22u) 50 | 51 | // Define ganged axis or A axis step pulse and step direction output pins. 52 | #if N_ABC_MOTORS > 0 53 | #define M3_AVAILABLE 54 | #define M3_STEP_PIN (8u) 55 | #define M3_DIRECTION_PIN (9u) 56 | #define M3_LIMIT_PIN (23u) 57 | #endif 58 | 59 | // Define ganged axis or B axis step pulse and step direction output pins. 60 | #if N_ABC_MOTORS == 2 61 | #define M4_AVAILABLE 62 | #define M4_STEP_PIN (26u) 63 | #define M4_DIRECTION_PIN (27u) 64 | #define M4_LIMIT_PIN (28u) 65 | #define M4_ENABLE_PIN (37u) 66 | #endif 67 | 68 | // Define stepper driver enable/disable output pin(s). 69 | #define STEPPERS_ENABLE_PIN (10u) 70 | 71 | // Define auxiliary output pins 72 | #define AUXOUTPUT0_PIN (12u) // Spindle enable 73 | #define AUXOUTPUT1_PIN (11u) // Spindle direction 74 | #define AUXOUTPUT2_PIN (13u) // Spindle PWM 75 | #define AUXOUTPUT3_PIN (19u) // Coolant flood 76 | #define AUXOUTPUT4_PIN (18u) // Coolant mist 77 | 78 | // Define driver spindle pins 79 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_ENA 80 | #define SPINDLE_ENABLE_PIN AUXOUTPUT0_PIN 81 | #endif 82 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_PWM 83 | #define SPINDLE_PWM_PIN AUXOUTPUT2_PIN 84 | #endif 85 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_DIR 86 | #define SPINDLE_DIRECTION_PIN AUXOUTPUT1_PIN 87 | #endif 88 | 89 | // Define flood and mist coolant enable output pins. 90 | #if COOLANT_ENABLE & COOLANT_FLOOD 91 | #define COOLANT_FLOOD_PIN AUXOUTPUT3_PIN 92 | #endif 93 | #if COOLANT_ENABLE & COOLANT_MIST 94 | #define COOLANT_MIST_PIN AUXOUTPUT4_PIN 95 | #endif 96 | 97 | // Define auxiliary input pins 98 | #if !defined(M4_LIMIT_PIN) 99 | #define AUXINPUT0_PIN (28u) // MPG mode 100 | #endif 101 | #define AUXINPUT1_PIN (29u) // Safety door 102 | #define AUXINPUT2_PIN (15u) // Probe 103 | #define AUXINPUT3_PIN (14u) // Reset/EStop 104 | #define AUXINPUT4_PIN (16u) // Feed hold 105 | #define AUXINPUT5_PIN (17u) // Cycle start 106 | 107 | // Define user-control controls (cycle start, reset, feed hold) input pins. 108 | #if CONTROL_ENABLE & CONTROL_HALT 109 | #define RESET_PIN AUXINPUT3_PIN 110 | #endif 111 | #if CONTROL_ENABLE & CONTROL_FEED_HOLD 112 | #define FEED_HOLD_PIN AUXINPUT4_PIN 113 | #endif 114 | #if CONTROL_ENABLE & CONTROL_CYCLE_START 115 | #define CYCLE_START_PIN AUXINPUT5_PIN 116 | #endif 117 | 118 | #if PROBE_ENABLE 119 | #define PROBE_PIN AUXINPUT2_PIN 120 | #endif 121 | 122 | #if SAFETY_DOOR_ENABLE 123 | #define SAFETY_DOOR_PIN AUXINPUT1_PIN 124 | #elif MOTOR_FAULT_ENABLE 125 | #define MOTOR_FAULT_PIN AUXINPUT1_PIN 126 | #endif 127 | 128 | #if MPG_ENABLE == 1 && !defined(AUXINPUT0_PIN) 129 | #define MPG_MODE_PIN AUXINPUT0_PIN 130 | #endif 131 | 132 | #if I2C_ENABLE 133 | #define I2C_PORT 4 134 | #define I2C_SCL4 (24u) // Not referenced, for info only 135 | #define I2C_SDA4 (25u) // Not referenced, for info only 136 | #endif 137 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/boards/cnc_boosterpack_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | cnc_boosterpack_map.h - driver code for IMXRT1062 processor (on Teensy 4.0 board) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2020-2024 Terje Io 7 | 8 | grblHAL is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | grblHAL is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with grblHAL. If not, see . 20 | */ 21 | 22 | #define BOARD_NAME "CNC BoosterPack" 23 | #define BOARD_URL "https://github.com/terjeio/CNC_Boosterpack" 24 | 25 | #if N_ABC_MOTORS 26 | #error "Axis configuration is not supported!" 27 | #endif 28 | 29 | #if SPINDLE_SYNC_ENABLE 30 | #error "Spindle sync is not supported for CNC BoosterPack" 31 | #endif 32 | 33 | #ifdef EEPROM_ENABLE 34 | #undef EEPROM_ENABLE 35 | #endif 36 | #define EEPROM_ENABLE 16 // CNC BoosterPack has on-board EEPROM 37 | 38 | #if I2C_ENABLE 39 | #define I2C_PORT 0 40 | #define I2C_SCL0 (19u) // Not referenced, for info only 41 | #define I2C_SDA0 (18u) // Not referenced, for info only 42 | #endif 43 | 44 | #define SERIAL_PORT 8 45 | #define UART_RX5 (21u) // Not referenced, for info only 46 | #define UART_TX5 (20u) // Not referenced, for info only 47 | 48 | // Define step pulse output pins. 49 | #define X_STEP_PIN (32u) 50 | #define Y_STEP_PIN (30u) 51 | #define Z_STEP_PIN (26u) 52 | 53 | // Define step direction output pins. 54 | #define X_DIRECTION_PIN (5u) 55 | #define Y_DIRECTION_PIN (33u) 56 | #define Z_DIRECTION_PIN (13u) 57 | 58 | // Define stepper driver enable/disable output pin(s). 59 | #define STEPPERS_ENABLE_PIN (24u) 60 | #define Z_ENABLE_PIN (8u) 61 | 62 | // Define homing/hard limit switch input pins. 63 | #define X_LIMIT_PIN (10u) 64 | #define Y_LIMIT_PIN (1u) 65 | #define Z_LIMIT_PIN (0u) 66 | 67 | // Define auxiliary output pins 68 | #define AUXOUTPUT0_PIN (12u) // Spindle PWM 69 | #define AUXOUTPUT1_PIN (16u) // Spindle direction 70 | #define AUXOUTPUT2_PIN (14u) // Spindle enable 71 | #define AUXOUTPUT3_PIN (4u) // Coolant flood 72 | #define AUXOUTPUT4_PIN (31u) // Coolant mist 73 | 74 | // Define driver spindle pins 75 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_ENA 76 | #define SPINDLE_ENABLE_PIN AUXOUTPUT2_PIN 77 | #endif 78 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_PWM 79 | #define SPINDLE_PWM_PIN AUXOUTPUT0_PIN 80 | #endif 81 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_DIR 82 | #define SPINDLE_DIRECTION_PIN AUXOUTPUT1_PIN 83 | #endif 84 | 85 | // Define flood and mist coolant enable output pins. 86 | #if COOLANT_ENABLE & COOLANT_FLOOD 87 | #define COOLANT_FLOOD_PIN AUXOUTPUT3_PIN 88 | #endif 89 | #if COOLANT_ENABLE & COOLANT_MIST 90 | #define COOLANT_MIST_PIN AUXOUTPUT4_PIN 91 | #endif 92 | 93 | #if !QEI_ENABLE 94 | #define AUXINPUT0_PIN (3u) 95 | #endif 96 | #define AUXINPUT1_PIN (29u) 97 | #define AUXINPUT2_PIN (27u) 98 | #if !QEI_ENABLE 99 | #define AUXINPUT3_PIN (2u) 100 | #endif 101 | #define AUXINPUT4_PIN (28u) // I2C strobe 102 | #define AUXINPUT5_PIN (9u) // Safety door 103 | #define AUXINPUT6_PIN (15u) // Probe 104 | #define AUXINPUT7_PIN (11u) // Reset/EStop 105 | #define AUXINPUT8_PIN (7u) // Feed hold 106 | #define AUXINPUT9_PIN (6u) // Cycle start 107 | 108 | // Define user-control controls (cycle start, reset, feed hold) input pins. 109 | #if CONTROL_ENABLE & CONTROL_HALT 110 | #define RESET_PIN AUXINPUT7_PIN 111 | #endif 112 | #if CONTROL_ENABLE & CONTROL_FEED_HOLD 113 | #define FEED_HOLD_PIN AUXINPUT8_PIN 114 | #endif 115 | #if CONTROL_ENABLE & CONTROL_CYCLE_START 116 | #define CYCLE_START_PIN AUXINPUT9_PIN 117 | #endif 118 | 119 | #if PROBE_ENABLE 120 | #define PROBE_PIN AUXINPUT6_PIN 121 | #endif 122 | 123 | #if SAFETY_DOOR_ENABLE 124 | #define SAFETY_DOOR_PIN AUXINPUT5_PIN 125 | #endif 126 | 127 | #if I2C_STROBE_ENABLE 128 | #define I2C_STROBE_PIN AUXINPUT4_PIN 129 | #endif 130 | 131 | #if QEI_ENABLE 132 | #define QEI_A_PIN (3u) 133 | #define QEI_B_PIN (2u) 134 | // #define QEI_INDEX_PIN GPIO2_PIN 135 | #define QEI_SELECT_PIN AUXINPUT1_PIN 136 | #endif 137 | 138 | /* EOF */ 139 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/boards/E5XMCS_T41_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | E5XMCS_T41_map.h - driver code for IMXRT1062 processor (on Teensy 4.1 board) 3 | 4 | Part of grblHAL 5 | 6 | Board by Maker Store: https://www.makerstore.com.au/product/elec-e5xmcst41/ 7 | 8 | Copyright (c) 2020-2024 Terje Io 9 | 10 | grblHAL is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | grblHAL is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with grblHAL. If not, see . 22 | */ 23 | 24 | #if N_ABC_MOTORS > 2 25 | #error "Axis configuration is not supported!" 26 | #endif 27 | 28 | #if SPINDLE_SYNC_ENABLE 29 | #error "Spindle sync is not supported for E5XMCS_T41!" 30 | #endif 31 | 32 | #define BOARD_NAME "E5XMCS_T41" 33 | #define BOARD_URL "https://www.makerstore.com.au/product/elec-e5xmcst41/" 34 | 35 | #define X_STEP_PIN (2u) 36 | #define X_DIRECTION_PIN (3u) 37 | #define X_ENABLE_PIN (10u) 38 | #define X_LIMIT_PIN (20u) 39 | 40 | #define Y_STEP_PIN (4u) 41 | #define Y_DIRECTION_PIN (5u) 42 | #define Y_ENABLE_PIN (40u) 43 | #define Y_LIMIT_PIN (21u) 44 | 45 | #define Z_STEP_PIN (6u) 46 | #define Z_DIRECTION_PIN (7u) 47 | #define Z_ENABLE_PIN (39u) 48 | #define Z_LIMIT_PIN (22u) 49 | 50 | // Define ganged axis or A axis step pulse and step direction output pins. 51 | #if N_ABC_MOTORS > 0 52 | #define M3_AVAILABLE 53 | #define M3_STEP_PIN (8u) 54 | #define M3_DIRECTION_PIN (9u) 55 | #define M3_LIMIT_PIN (23u) 56 | #define M3_ENABLE_PIN (38u) 57 | #endif 58 | 59 | // Define ganged axis or B axis step pulse and step direction output pins. 60 | #if N_ABC_MOTORS == 2 61 | #define M4_AVAILABLE 62 | #define M4_STEP_PIN (26u) 63 | #define M4_DIRECTION_PIN (27u) 64 | #define M4_LIMIT_PIN (28u) 65 | #define M4_ENABLE_PIN (37u) 66 | #endif 67 | 68 | // Define auxiliary output pins 69 | #define AUXOUTPUT0_PIN (31u) // AUX0 70 | #define AUXOUTPUT1_PIN (32u) // AUX1 71 | #define AUXOUTPUT2_PIN (33u) // AUX2 72 | #define AUXOUTPUT3_PIN (12u) // Spindle enable 73 | #define AUXOUTPUT4_PIN (11u) // Spindle direction 74 | #define AUXOUTPUT5_PIN (13u) // Spindle PWM 75 | #define AUXOUTPUT6_PIN (19u) // Coolant flood 76 | #define AUXOUTPUT7_PIN (18u) // Coolant mist 77 | 78 | // Define driver spindle pins 79 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_ENA 80 | #define SPINDLE_ENABLE_PIN AUXOUTPUT3_PIN 81 | #endif 82 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_PWM 83 | #define SPINDLE_PWM_PIN AUXOUTPUT5_PIN 84 | #endif 85 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_DIR 86 | #define SPINDLE_DIRECTION_PIN AUXOUTPUT4_PIN 87 | #endif 88 | 89 | // Define flood and mist coolant enable output pins. 90 | #if COOLANT_ENABLE & COOLANT_FLOOD 91 | #define COOLANT_FLOOD_PIN AUXOUTPUT6_PIN 92 | #endif 93 | #if COOLANT_ENABLE & COOLANT_MIST 94 | #define COOLANT_MIST_PIN AUXOUTPUT7_PIN 95 | #endif 96 | 97 | // Define auxiliary input pins 98 | #define AUXINPUT0_PIN (36u) // ST0 99 | #if !QEI_ENABLE 100 | #define AUXINPUT1_PIN (30u) // ST1 101 | #define AUXINPUT2_PIN (34u) // ST2 102 | #endif 103 | #define AUXINPUT3_PIN (35u) // ST3 104 | #define AUXINPUT4_PIN (41u) // I2C strobe 105 | #if !defined(M4_LIMIT_PIN) 106 | #define AUXINPUT5_PIN (28u) // MPG mode 107 | #endif 108 | #define AUXINPUT6_PIN (29u) // Safety door 109 | #define AUXINPUT7_PIN (15u) // Probe 110 | #define AUXINPUT8_PIN (14u) // Reset/EStop 111 | #define AUXINPUT9_PIN (16u) // Feed hold 112 | #define AUXINPUT10_PIN (17u) // Cycle start 113 | 114 | // Define user-control controls (cycle start, reset, feed hold) input pins. 115 | #if CONTROL_ENABLE & CONTROL_HALT 116 | #define RESET_PIN AUXINPUT8_PIN 117 | #endif 118 | #if CONTROL_ENABLE & CONTROL_FEED_HOLD 119 | #define FEED_HOLD_PIN AUXINPUT9_PIN 120 | #endif 121 | #if CONTROL_ENABLE & CONTROL_CYCLE_START 122 | #define CYCLE_START_PIN AUXINPUT10_PIN 123 | #endif 124 | 125 | #if PROBE_ENABLE 126 | #define PROBE_PIN AUXINPUT7_PIN 127 | #endif 128 | 129 | #if SAFETY_DOOR_ENABLE 130 | #define SAFETY_DOOR_PIN AUXINPUT6_PIN 131 | #endif 132 | 133 | #if I2C_STROBE_ENABLE 134 | #define I2C_STROBE_PIN AUXINPUT4_PIN 135 | #endif 136 | 137 | #if MOTOR_FAULT_ENABLE 138 | #define MOTOR_FAULT_PIN AUXINPUT0_PIN 139 | #endif 140 | 141 | #if MOTOR_WARNING_ENABLE && defined(AUXINPUT1_PIN) 142 | #define MOTOR_WARNING_PIN AUXINPUT1_PIN 143 | #endif 144 | 145 | #if MPG_ENABLE == 1 && defined(AUXINPUT5_PIN) 146 | #define MPG_MODE_PIN AUXINPUT5_PIN 147 | #endif 148 | 149 | #if QEI_ENABLE 150 | #define QEI_A_PIN (30u) // ST1 151 | #define QEI_B_PIN (34u) // ST2 152 | #define QEI_SELECT_PIN AUXINPUT3_PIN // ST3 153 | #endif 154 | 155 | #if I2C_ENABLE 156 | #define I2C_PORT 4 157 | #define I2C_SCL4 (24u) // Not referenced, for info only 158 | #define I2C_SDA4 (25u) // Not referenced, for info only 159 | #endif 160 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/boards/GRBLHAL2000_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | GRBLHAL2000_map.h - driver code for IMXRT1062 processor (on Teensy 4.1 board) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2021-2024 Terje Io 7 | 8 | grblHAL is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | grblHAL is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with grblHAL. If not, see . 20 | */ 21 | 22 | #define BOARD_NAME "GRBLHAL2000 - PRINTNC" 23 | #define BOARD_URL "https://github.com/Expatria-Technologies/grblhal_2000_PrintNC" 24 | #define HAS_BOARD_INIT 25 | 26 | #if !(MODBUS_ENABLE & MODBUS_RTU_ENABLED) 27 | #define SERIAL_PORT 5 28 | #endif 29 | 30 | #ifdef NETWORK_HOSTNAME 31 | #undef NETWORK_HOSTNAME 32 | #define NETWORK_HOSTNAME "GRBLHAL2000" 33 | #endif 34 | 35 | #if N_AXIS > 5 36 | #error Max number of axes is 5 for UniversalCNC 37 | #endif 38 | 39 | #if QEI_ENABLE && SPINDLE_SYNC_ENABLE 40 | #error Quadrature encoder and spindle sync cannot be enabled at the same time 41 | #endif 42 | 43 | #define X_STEP_PIN (2u) 44 | #define X_DIRECTION_PIN (3u) 45 | #define X_ENABLE_PIN (10u) 46 | #define X_LIMIT_PIN (20u) 47 | 48 | #define Y_STEP_PIN (4u) 49 | #define Y_DIRECTION_PIN (5u) 50 | #define Y_ENABLE_PIN (10u) 51 | #define Y_LIMIT_PIN (21u) 52 | 53 | #define Z_STEP_PIN (6u) 54 | #define Z_DIRECTION_PIN (7u) 55 | #define Z_ENABLE_PIN (39u) 56 | #define Z_LIMIT_PIN (22u) 57 | 58 | // Define ganged axis or A axis step pulse and step direction output pins. 59 | #if N_ABC_MOTORS > 0 60 | #define M3_AVAILABLE 61 | #define M3_STEP_PIN (8u) 62 | #define M3_DIRECTION_PIN (9u) 63 | #define M3_LIMIT_PIN (23u) 64 | #define M3_ENABLE_PIN (10u) 65 | #endif 66 | 67 | // Define ganged axis or B axis step pulse and step direction output pins. 68 | #if N_ABC_MOTORS == 2 69 | #define M4_AVAILABLE 70 | #define M4_STEP_PIN (26u) 71 | #define M4_DIRECTION_PIN (27u) 72 | #define M4_LIMIT_PIN (28u) 73 | #define M4_ENABLE_PIN (10u) 74 | #endif 75 | 76 | // Define auxiliary output pins 77 | #define AUXOUTPUT0_PIN (37u) 78 | #define AUXOUTPUT1_PIN (32u) 79 | #define AUXOUTPUT2_PIN (33u) 80 | #define AUXOUTPUT3_PIN (38u) 81 | #define AUXOUTPUT4_PIN (12u) // Spindle enable 82 | #define AUXOUTPUT5_PIN (11u) // Spindle direction 83 | #define AUXOUTPUT6_PIN (13u) // Spindle PWM 84 | #define AUXOUTPUT7_PIN (19u) // Coolant flood 85 | #define AUXOUTPUT8_PIN (18u) // Coolant mist 86 | 87 | // Define driver spindle pins 88 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_ENA 89 | #define SPINDLE_ENABLE_PIN AUXOUTPUT4_PIN 90 | #endif 91 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_PWM 92 | #define SPINDLE_PWM_PIN AUXOUTPUT6_PIN 93 | #endif 94 | #if DRIVER_SPINDLE_ENABLE & SPINDLE_DIR 95 | #define SPINDLE_DIRECTION_PIN AUXOUTPUT5_PIN 96 | #endif 97 | 98 | // Define flood and mist coolant enable output pins. 99 | #if COOLANT_ENABLE & COOLANT_FLOOD 100 | #define COOLANT_FLOOD_PIN AUXOUTPUT7_PIN 101 | #endif 102 | #if COOLANT_ENABLE & COOLANT_MIST 103 | #define COOLANT_MIST_PIN AUXOUTPUT8_PIN 104 | #endif 105 | 106 | // Define auxiliary input pins 107 | #if !QEI_ENABLE 108 | #define AUXINPUT0_PIN (36u) // ST0 109 | #define AUXINPUT1_PIN (30u) // ST1 110 | #endif 111 | #if !SPINDLE_SYNC_ENABLE 112 | #define AUXINPUT2_PIN (31u) // ST2 113 | #define AUXINPUT3_PIN (14u) // ST3 114 | #endif 115 | #define AUXINPUT4_PIN (29u) // Safety door 116 | #define AUXINPUT5_PIN (41u) // I2C strobe 117 | #define AUXINPUT6_PIN (15u) // Probe 118 | #define AUXINPUT7_PIN (40u) // Reset/EStop 119 | #define AUXINPUT8_PIN (16u) // Feed hold 120 | #define AUXINPUT9_PIN (17u) // Cycle start 121 | 122 | // Define user-control controls (cycle start, reset, feed hold) input pins. 123 | #if CONTROL_ENABLE & CONTROL_HALT 124 | #define RESET_PIN AUXINPUT7_PIN 125 | #endif 126 | #if CONTROL_ENABLE & CONTROL_FEED_HOLD 127 | #define FEED_HOLD_PIN AUXINPUT8_PIN 128 | #endif 129 | #if CONTROL_ENABLE & CONTROL_CYCLE_START 130 | #define CYCLE_START_PIN AUXINPUT9_PIN 131 | #endif 132 | 133 | #if PROBE_ENABLE 134 | #define PROBE_PIN AUXINPUT6_PIN 135 | #endif 136 | 137 | #if SAFETY_DOOR_ENABLE 138 | #define SAFETY_DOOR_PIN AUXINPUT4_PIN 139 | #elif MOTOR_FAULT_ENABLE 140 | #define MOTOR_FAULT_PIN AUXINPUT4_PIN 141 | #endif 142 | 143 | #if I2C_STROBE_ENABLE 144 | #define I2C_STROBE_PIN AUXINPUT5_PIN 145 | #endif 146 | 147 | #if QEI_ENABLE 148 | #define QEI_A_PIN (36u) 149 | #define QEI_B_PIN (30u) 150 | #if defined(AUXINPUT2_PIN) 151 | #define QEI_SELECT_PIN AUXINPUT2_PIN 152 | #endif 153 | #endif 154 | 155 | #if SPINDLE_SYNC_ENABLE 156 | #define SPINDLE_INDEX_PIN (31u) // ST2 157 | #define SPINDLE_PULSE_PIN (14u) // ST3 158 | #endif 159 | 160 | #if I2C_ENABLE 161 | #define I2C_PORT 4 162 | #define I2C_SCL4 (24u) // Not used, for info only 163 | #define I2C_SDA4 (25u) // Not used, for info only 164 | #endif 165 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/boards/T41U5XBB_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | T41U5XBB_map.h - driver code for IMXRT1062 processor (on Teensy 4.1 board) 3 | 4 | Part of grblHAL 5 | 6 | Board by Phil Barrett: https://github.com/phil-barrett/grblHAL-teensy-4.x 7 | 8 | Copyright (c) 2020-2024 Terje Io 9 | 10 | grblHAL is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | grblHAL is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with grblHAL. If not, see . 22 | */ 23 | 24 | #if N_ABC_MOTORS > 2 25 | #error "Axis configuration is not supported!" 26 | #endif 27 | 28 | #if SPINDLE_SYNC_ENABLE 29 | #error "Spindle sync is not supported for T41U5XBB!" 30 | #endif 31 | 32 | #define BOARD_NAME "T41U5XBB" 33 | #define BOARD_URL "https://github.com/phil-barrett/grbl-teensy-4" 34 | 35 | #define X_STEP_PIN (2u) 36 | #define X_DIRECTION_PIN (3u) 37 | #define X_ENABLE_PIN (10u) 38 | #define X_LIMIT_PIN (20u) 39 | 40 | #define Y_STEP_PIN (4u) 41 | #define Y_DIRECTION_PIN (5u) 42 | #define Y_ENABLE_PIN (40u) 43 | #define Y_LIMIT_PIN (21u) 44 | 45 | #define Z_STEP_PIN (6u) 46 | #define Z_DIRECTION_PIN (7u) 47 | #define Z_ENABLE_PIN (39u) 48 | #define Z_LIMIT_PIN (22u) 49 | 50 | // Define ganged axis or A axis step pulse and step direction output pins. 51 | #if N_ABC_MOTORS > 0 52 | #define M3_AVAILABLE 53 | #define M3_STEP_PIN (8u) 54 | #define M3_DIRECTION_PIN (9u) 55 | #define M3_LIMIT_PIN (23u) 56 | #define M3_ENABLE_PIN (38u) 57 | #endif 58 | 59 | // Define ganged axis or B axis step pulse and step direction output pins. 60 | #if N_ABC_MOTORS == 2 61 | #define M4_AVAILABLE 62 | #define M4_STEP_PIN (26u) 63 | #define M4_DIRECTION_PIN (27u) 64 | #define M4_LIMIT_PIN (28u) 65 | #define M4_ENABLE_PIN (37u) 66 | #endif 67 | 68 | // Define auxiliary output pins 69 | #define AUXOUTPUT0_PIN (31U) 70 | #define AUXOUTPUT1_PIN (32U) 71 | #if SPINDLE_ENABLE & (1<. 24 | */ 25 | 26 | // Boar modification info: https://www.grbl.org/single-post/modifying-a-t41u5xbb-for-lathe-spindle-sync 27 | 28 | #if N_ABC_MOTORS > 2 29 | #error "Axis configuration is not supported!" 30 | #endif 31 | 32 | #if QEI_ENABLE && SPINDLE_SYNC_ENABLE 33 | #error "Quadrature encoder and spindle sync cannot be enabled at the same time!" 34 | #endif 35 | 36 | #define BOARD_NAME "T41U5XBB" 37 | #define BOARD_URL "https://github.com/phil-barrett/grbl-teensy-4" 38 | 39 | #define X_STEP_PIN (2u) 40 | #define X_DIRECTION_PIN (3u) 41 | #define X_ENABLE_PIN (10u) 42 | #define X_LIMIT_PIN (20u) 43 | 44 | #define Y_STEP_PIN (4u) 45 | #define Y_DIRECTION_PIN (5u) 46 | #define Y_ENABLE_PIN (40u) 47 | #define Y_LIMIT_PIN (21u) 48 | 49 | #define Z_STEP_PIN (6u) 50 | #define Z_DIRECTION_PIN (7u) 51 | #define Z_ENABLE_PIN (39u) 52 | #define Z_LIMIT_PIN (22u) 53 | 54 | // Define ganged axis or A axis step pulse and step direction output pins. 55 | #if N_ABC_MOTORS > 0 56 | #define M3_AVAILABLE 57 | #define M3_STEP_PIN (8u) 58 | #define M3_DIRECTION_PIN (9u) 59 | #define M3_LIMIT_PIN (23u) 60 | #define M3_ENABLE_PIN (38u) 61 | #endif 62 | 63 | // Define ganged axis or B axis step pulse and step direction output pins. 64 | #if N_ABC_MOTORS == 2 65 | #define M4_AVAILABLE 66 | #define M4_STEP_PIN (26u) 67 | #define M4_DIRECTION_PIN (27u) 68 | #define M4_LIMIT_PIN (28u) 69 | #define M4_ENABLE_PIN (37u) 70 | #endif 71 | 72 | // Define auxiliary output pins 73 | #define AUXOUTPUT0_PIN (31U) 74 | #define AUXOUTPUT1_PIN (32U) 75 | #if SPINDLE_ENABLE & (1<. 22 | */ 23 | 24 | #if N_ABC_MOTORS > 2 25 | #error "Axis configuration is not supported!" 26 | #endif 27 | 28 | #define BOARD_NAME "T41BB5X Pro" 29 | #define BOARD_URL "https://github.com/phil-barrett/grbl-teensy-4" 30 | 31 | #if N_AXIS > 5 32 | #error Max number of axes is 5 for T41U5XBB 33 | #endif 34 | 35 | #if QEI_ENABLE && SPINDLE_SYNC_ENABLE 36 | #error Quadrature encoder and spindle sync cannot be enabled at the same time 37 | #endif 38 | 39 | // Board has 2K FRAM 40 | /* supply problems... 41 | #undef EEPROM_ENABLE 42 | #undef EEPROM_IS_FRAM 43 | #define EEPROM_ENABLE 1 44 | #define EEPROM_IS_FRAM 1 45 | */ 46 | #define X_STEP_PIN (2u) 47 | #define X_DIRECTION_PIN (3u) 48 | #define X_ENABLE_PIN (10u) 49 | #define X_LIMIT_PIN (20u) 50 | 51 | #define Y_STEP_PIN (4u) 52 | #define Y_DIRECTION_PIN (5u) 53 | #define Y_ENABLE_PIN (35u) 54 | #define Y_LIMIT_PIN (21u) 55 | 56 | #define Z_STEP_PIN (6u) 57 | #define Z_DIRECTION_PIN (7u) 58 | #define Z_ENABLE_PIN (39u) 59 | #define Z_LIMIT_PIN (22u) 60 | 61 | // Define ganged axis or A axis step pulse and step direction output pins. 62 | #if N_ABC_MOTORS > 0 63 | #define M3_AVAILABLE 64 | #define M3_STEP_PIN (8u) 65 | #define M3_DIRECTION_PIN (9u) 66 | #define M3_LIMIT_PIN (23u) 67 | #define M3_ENABLE_PIN (38u) 68 | #endif 69 | 70 | // Define ganged axis or B axis step pulse and step direction output pins. 71 | #if N_ABC_MOTORS == 2 72 | #define M4_AVAILABLE 73 | #define M4_STEP_PIN (26u) 74 | #define M4_DIRECTION_PIN (27u) 75 | #define M4_LIMIT_PIN (28u) 76 | #define M4_ENABLE_PIN (37u) 77 | #endif 78 | 79 | // Define auxiliary output pins 80 | #define AUXOUTPUT0_PIN (34U) 81 | #define AUXOUTPUT1_PIN (32U) 82 | #if SPINDLE_ENABLE & (1<. 20 | */ 21 | 22 | #include "pwm.h" 23 | #include "driver.h" 24 | 25 | #include "core_pins.h" 26 | 27 | #include "grbl/ioports.h" 28 | 29 | typedef struct { 30 | const pwm_signal_t *pwm; 31 | ioports_pwm_t pwm_data; 32 | float pwm_value; 33 | } pwm_ch_t; 34 | 35 | static io_ports_data_t analog; 36 | static input_signal_t *aux_in_analog; 37 | static output_signal_t *aux_out_analog; 38 | static pwm_ch_t *pwm_channels; 39 | 40 | // Code lifted from PJRC, pwm.c 41 | 42 | static void set_pwm_cap (xbar_t *output, bool servo_pwm) 43 | { 44 | if(output && output->id < analog.out.n_ports) { 45 | aux_out_analog[output->id].mode.pwm = !servo_pwm; 46 | aux_out_analog[output->id].mode.servo_pwm = servo_pwm; 47 | } 48 | } 49 | 50 | static uint_fast16_t set_pwm_channels (pwm_config_t *config, ioports_pwm_t *pwm_data) 51 | { 52 | bool ok; 53 | uint_fast16_t prescaler = 2, divider = 0b1001; 54 | 55 | if((ok = ioports_precompute_pwm_values(config, pwm_data, F_BUS_ACTUAL / prescaler))) 56 | while(pwm_data->period > 65534 && divider < 15) { 57 | prescaler <<= 1; 58 | divider++; 59 | ioports_precompute_pwm_values(config, pwm_data, F_BUS_ACTUAL / prescaler); 60 | } 61 | 62 | return ok ? divider : 0; 63 | } 64 | 65 | FLASHMEM static bool init_pwm (xbar_t *output, pwm_config_t *config, bool persistent) 66 | { 67 | uint32_t prescaler; 68 | 69 | pwm_ch_t *ch = (pwm_ch_t *)output->port; 70 | 71 | if((prescaler = set_pwm_channels(config, &ch->pwm_data)) && pwm_config(ch->pwm, prescaler, ch->pwm_data.period, config->invert)) 72 | set_pwm_cap(output, config->servo_mode); 73 | 74 | return prescaler != 0; 75 | } 76 | 77 | static float pwm_get_value (xbar_t *output) 78 | { 79 | return pwm_channels && output->id < analog.out.n_ports ? pwm_channels[output->id].pwm_value : -1.0f; 80 | } 81 | 82 | static bool analog_out (uint8_t port, float value) 83 | { 84 | if(port < analog.out.n_ports) { 85 | 86 | pwm_ch_t ch = pwm_channels[aux_out_analog[port].pwm_idx]; 87 | 88 | pwm_out(ch.pwm, ioports_compute_pwm_value(&ch.pwm_data, value)); 89 | } 90 | 91 | return port < analog.out.n_ports; 92 | } 93 | 94 | static int32_t wait_on_input (uint8_t port, wait_mode_t wait_mode, float timeout) 95 | { 96 | int32_t value = -1; 97 | 98 | return value; 99 | } 100 | 101 | static bool set_function (xbar_t *port, pin_function_t function) 102 | { 103 | if(port->mode.input) 104 | aux_out_analog[port->id].id = function; 105 | 106 | return port->mode.input; 107 | } 108 | 109 | static xbar_t *get_pin_info (io_port_direction_t dir, uint8_t port) 110 | { 111 | static xbar_t pin; 112 | 113 | xbar_t *info = NULL; 114 | 115 | memset(&pin, 0, sizeof(xbar_t)); 116 | 117 | switch(dir) { 118 | 119 | case Port_Output: 120 | if(port < analog.out.n_ports) { 121 | pin.id = port; 122 | pin.mode = aux_out_analog[pin.id].mode; 123 | pin.mode.pwm = !pin.mode.servo_pwm; //?? for easy filtering 124 | XBAR_SET_CAP(pin.cap, pin.mode); 125 | pin.function = aux_out_analog[pin.id].id; 126 | pin.group = aux_out_analog[pin.id].group; 127 | pin.pin = aux_out_analog[pin.id].pin; 128 | pin.description = aux_out_analog[pin.id].description; 129 | pin.set_function = set_function; 130 | if(pin.mode.pwm || pin.mode.servo_pwm) { 131 | pin.port = &pwm_channels[aux_out_analog[pin.id].pwm_idx]; 132 | pin.config = init_pwm; 133 | pin.get_value = pwm_get_value; 134 | } 135 | info = &pin; 136 | } 137 | break; 138 | 139 | default: break; 140 | } 141 | 142 | return info; 143 | } 144 | 145 | static void set_pin_description (io_port_direction_t dir, uint8_t port, const char *description) 146 | { 147 | if(dir == Port_Input && port < analog.in.n_ports) 148 | aux_in_analog[port].description = description; 149 | else if(port < analog.out.n_ports) 150 | aux_out_analog[port].description = description; 151 | } 152 | 153 | FLASHMEM void ioports_init_analog (pin_group_pins_t *aux_inputs, pin_group_pins_t *aux_outputs) 154 | { 155 | io_analog_t ports = { 156 | .ports = &analog, 157 | .analog_out = analog_out, 158 | .get_pin_info = get_pin_info, 159 | .wait_on_input = wait_on_input, 160 | .set_pin_description = set_pin_description 161 | }; 162 | 163 | aux_in_analog = aux_inputs->pins.inputs; 164 | aux_out_analog = aux_outputs->pins.outputs; 165 | 166 | analog.in.n_ports = aux_inputs->n_pins; 167 | analog.out.n_ports = aux_outputs->n_pins; 168 | 169 | if(ioports_add_analog(&ports)) { 170 | 171 | if(analog.out.n_ports) { 172 | 173 | pwm_config_t config = { 174 | .freq_hz = 5000.0f, 175 | .min = 0.0f, 176 | .max = 100.0f, 177 | .off_value = 0.0f, 178 | .min_value = 0.0f, 179 | .max_value = 100.0f, 180 | .invert = Off 181 | }; 182 | 183 | uint_fast8_t i, n_pwm = 0; 184 | const pwm_signal_t *pwm; 185 | 186 | for(i = 0; i < analog.out.n_ports; i++) { 187 | if(aux_out_analog[i].mode.pwm) 188 | n_pwm++; 189 | } 190 | 191 | pwm_channels = calloc(n_pwm, sizeof(pwm_ch_t)); 192 | 193 | n_pwm = 0; 194 | for(i = 0; i < analog.out.n_ports; i++) { 195 | if(aux_out_analog[i].mode.pwm && !!pwm_channels && (pwm = pwm_claim(NULL, aux_out_analog[i].pin))) { 196 | pwm_channels[n_pwm].pwm = pwm; 197 | aux_out_analog[i].pwm_idx = n_pwm++; 198 | init_pwm(get_pin_info(Port_Output, i), &config, false); 199 | } 200 | analog_out(i, 0.0f); 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/littlefs/lfs_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * lfs utility functions 3 | * 4 | * Copyright (c) 2022, The littlefs authors. 5 | * Copyright (c) 2017, Arm Limited. All rights reserved. 6 | * SPDX-License-Identifier: BSD-3-Clause 7 | */ 8 | #ifndef LFS_UTIL_H 9 | #define LFS_UTIL_H 10 | 11 | // turned off for iMXRT1062 grblHAL here since the Arduino IDE is useless... 12 | #define LFS_NO_WARN 13 | #define LFS_NO_ERROR 14 | #define LFS_NO_ASSERT 15 | 16 | // Users can override lfs_util.h with their own configuration by defining 17 | // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). 18 | // 19 | // If LFS_CONFIG is used, none of the default utils will be emitted and must be 20 | // provided by the config file. To start, I would suggest copying lfs_util.h 21 | // and modifying as needed. 22 | #ifdef LFS_CONFIG 23 | #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) 24 | #define LFS_STRINGIZE2(x) #x 25 | #include LFS_STRINGIZE(LFS_CONFIG) 26 | #else 27 | 28 | // System includes 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #ifndef LFS_NO_MALLOC 35 | #include 36 | #endif 37 | #ifndef LFS_NO_ASSERT 38 | #include 39 | #endif 40 | #if !defined(LFS_NO_DEBUG) || \ 41 | !defined(LFS_NO_WARN) || \ 42 | !defined(LFS_NO_ERROR) || \ 43 | defined(LFS_YES_TRACE) 44 | #include 45 | #endif 46 | 47 | #ifdef __cplusplus 48 | extern "C" 49 | { 50 | #endif 51 | 52 | 53 | // Macros, may be replaced by system specific wrappers. Arguments to these 54 | // macros must not have side-effects as the macros can be removed for a smaller 55 | // code footprint 56 | 57 | // Logging functions 58 | #ifndef LFS_TRACE 59 | #ifdef LFS_YES_TRACE 60 | #define LFS_TRACE_(fmt, ...) \ 61 | printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 62 | #define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "") 63 | #else 64 | #define LFS_TRACE(...) 65 | #endif 66 | #endif 67 | 68 | #ifndef LFS_DEBUG 69 | #ifndef LFS_NO_DEBUG 70 | #define LFS_DEBUG_(fmt, ...) \ 71 | printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 72 | #define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "") 73 | #else 74 | #define LFS_DEBUG(...) 75 | #endif 76 | #endif 77 | 78 | #ifndef LFS_WARN 79 | #ifndef LFS_NO_WARN 80 | #define LFS_WARN_(fmt, ...) \ 81 | printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 82 | #define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "") 83 | #else 84 | #define LFS_WARN(...) 85 | #endif 86 | #endif 87 | 88 | #ifndef LFS_ERROR 89 | #ifndef LFS_NO_ERROR 90 | #define LFS_ERROR_(fmt, ...) \ 91 | printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__) 92 | #define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "") 93 | #else 94 | #define LFS_ERROR(...) 95 | #endif 96 | #endif 97 | 98 | // Runtime assertions 99 | #ifndef LFS_ASSERT 100 | #ifndef LFS_NO_ASSERT 101 | #define LFS_ASSERT(test) assert(test) 102 | #else 103 | #define LFS_ASSERT(test) 104 | #endif 105 | #endif 106 | 107 | 108 | // Builtin functions, these may be replaced by more efficient 109 | // toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more 110 | // expensive basic C implementation for debugging purposes 111 | 112 | // Min/max functions for unsigned 32-bit numbers 113 | static inline uint32_t lfs_max(uint32_t a, uint32_t b) { 114 | return (a > b) ? a : b; 115 | } 116 | 117 | static inline uint32_t lfs_min(uint32_t a, uint32_t b) { 118 | return (a < b) ? a : b; 119 | } 120 | 121 | // Align to nearest multiple of a size 122 | static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { 123 | return a - (a % alignment); 124 | } 125 | 126 | static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { 127 | return lfs_aligndown(a + alignment-1, alignment); 128 | } 129 | 130 | // Find the smallest power of 2 greater than or equal to a 131 | static inline uint32_t lfs_npw2(uint32_t a) { 132 | #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) 133 | return 32 - __builtin_clz(a-1); 134 | #else 135 | uint32_t r = 0; 136 | uint32_t s; 137 | a -= 1; 138 | s = (a > 0xffff) << 4; a >>= s; r |= s; 139 | s = (a > 0xff ) << 3; a >>= s; r |= s; 140 | s = (a > 0xf ) << 2; a >>= s; r |= s; 141 | s = (a > 0x3 ) << 1; a >>= s; r |= s; 142 | return (r | (a >> 1)) + 1; 143 | #endif 144 | } 145 | 146 | // Count the number of trailing binary zeros in a 147 | // lfs_ctz(0) may be undefined 148 | static inline uint32_t lfs_ctz(uint32_t a) { 149 | #if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__) 150 | return __builtin_ctz(a); 151 | #else 152 | return lfs_npw2((a & -a) + 1) - 1; 153 | #endif 154 | } 155 | 156 | // Count the number of binary ones in a 157 | static inline uint32_t lfs_popc(uint32_t a) { 158 | #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) 159 | return __builtin_popcount(a); 160 | #else 161 | a = a - ((a >> 1) & 0x55555555); 162 | a = (a & 0x33333333) + ((a >> 2) & 0x33333333); 163 | return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24; 164 | #endif 165 | } 166 | 167 | // Find the sequence comparison of a and b, this is the distance 168 | // between a and b ignoring overflow 169 | static inline int lfs_scmp(uint32_t a, uint32_t b) { 170 | return (int)(unsigned)(a - b); 171 | } 172 | 173 | // Convert between 32-bit little-endian and native order 174 | static inline uint32_t lfs_fromle32(uint32_t a) { 175 | #if !defined(LFS_NO_INTRINSICS) && ( \ 176 | (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ 177 | (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ 178 | (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) 179 | return a; 180 | #elif !defined(LFS_NO_INTRINSICS) && ( \ 181 | (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ 182 | (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ 183 | (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) 184 | return __builtin_bswap32(a); 185 | #else 186 | return (((uint8_t*)&a)[0] << 0) | 187 | (((uint8_t*)&a)[1] << 8) | 188 | (((uint8_t*)&a)[2] << 16) | 189 | (((uint8_t*)&a)[3] << 24); 190 | #endif 191 | } 192 | 193 | static inline uint32_t lfs_tole32(uint32_t a) { 194 | return lfs_fromle32(a); 195 | } 196 | 197 | // Convert between 32-bit big-endian and native order 198 | static inline uint32_t lfs_frombe32(uint32_t a) { 199 | #if !defined(LFS_NO_INTRINSICS) && ( \ 200 | (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \ 201 | (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \ 202 | (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) 203 | return __builtin_bswap32(a); 204 | #elif !defined(LFS_NO_INTRINSICS) && ( \ 205 | (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \ 206 | (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \ 207 | (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) 208 | return a; 209 | #else 210 | return (((uint8_t*)&a)[0] << 24) | 211 | (((uint8_t*)&a)[1] << 16) | 212 | (((uint8_t*)&a)[2] << 8) | 213 | (((uint8_t*)&a)[3] << 0); 214 | #endif 215 | } 216 | 217 | static inline uint32_t lfs_tobe32(uint32_t a) { 218 | return lfs_frombe32(a); 219 | } 220 | 221 | // Calculate CRC-32 with polynomial = 0x04c11db7 222 | uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size); 223 | 224 | // Allocate memory, only used if buffers are not provided to littlefs 225 | // Note, memory must be 64-bit aligned 226 | static inline void *lfs_malloc(size_t size) { 227 | #ifndef LFS_NO_MALLOC 228 | return malloc(size); 229 | #else 230 | (void)size; 231 | return NULL; 232 | #endif 233 | } 234 | 235 | // Deallocate memory, only used if buffers are not provided to littlefs 236 | static inline void lfs_free(void *p) { 237 | #ifndef LFS_NO_MALLOC 238 | free(p); 239 | #else 240 | (void)p; 241 | #endif 242 | } 243 | 244 | 245 | #ifdef __cplusplus 246 | } /* extern "C" */ 247 | #endif 248 | 249 | #endif 250 | #endif 251 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/ioports.c: -------------------------------------------------------------------------------- 1 | /* 2 | ioports.c - driver code for IMXRT1062 processor (on Teensy 4.1 board) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2020-2025 Terje Io 7 | 8 | grblHAL is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | grblHAL is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with grblHAL. If not, see . 20 | */ 21 | 22 | #include "driver.h" 23 | 24 | //#include "Arduino.h" 25 | #include 26 | #include 27 | #include 28 | 29 | #include "grbl/protocol.h" 30 | 31 | static io_ports_data_t digital; 32 | static input_signal_t *aux_in; 33 | static output_signal_t *aux_out; 34 | static volatile uint32_t event_bits; 35 | 36 | static bool digital_out_cfg (xbar_t *output, gpio_out_config_t *config, bool persistent) 37 | { 38 | if(output->id < digital.out.n_ports) { 39 | 40 | if(config->inverted != aux_out[output->id].mode.inverted) { 41 | aux_out[output->id].mode.inverted = config->inverted; 42 | // DIGITAL_OUT((*(aux_out[output->id].port)), !DIGITAL_IN((*(aux_out[output->id].port)))); 43 | } 44 | 45 | pinMode(output->pin, config->open_drain ? OUTPUT_OPENDRAIN : OUTPUT); 46 | 47 | if(persistent) 48 | ioport_save_output_settings(output, config); 49 | } 50 | 51 | return aux_out->id < digital.out.n_ports; 52 | } 53 | 54 | static void digital_out (uint8_t port, bool on) 55 | { 56 | if(port < digital.out.n_ports) 57 | DIGITAL_OUT((*(aux_out[port].port)), aux_out[port].mode.inverted ? !on : on); 58 | } 59 | 60 | static float digital_out_state (xbar_t *output) 61 | { 62 | float value = -1.0f; 63 | 64 | if(output->id < digital.out.n_ports) 65 | value = (float)(DIGITAL_IN((*(aux_out[output->id].port))) ^ aux_out[output->id].mode.inverted); 66 | 67 | return value; 68 | } 69 | 70 | static bool digital_in_cfg (xbar_t *input, gpio_in_config_t *config, bool persistent) 71 | { 72 | if(input->id < digital.in.n_ports && config->pull_mode != PullMode_UpDown) { 73 | 74 | aux_in[input->id].mode.inverted = config->inverted; 75 | aux_in[input->id].mode.pull_mode = config->pull_mode; 76 | aux_in[input->id].mode.debounce = config->debounce; 77 | 78 | pinMode(input->pin, config->pull_mode == PullMode_None ? INPUT : (config->pull_mode == PullMode_Up ? INPUT_PULLUP : INPUT_PULLDOWN)); 79 | 80 | if(persistent) 81 | ioport_save_input_settings(input, config); 82 | } 83 | 84 | return input->id < digital.in.n_ports; 85 | } 86 | 87 | static float digital_in_state (xbar_t *input) 88 | { 89 | float value = -1.0f; 90 | 91 | if(input->id < digital.in.n_ports) 92 | value = (float)(DIGITAL_IN(aux_in[input->id].gpio) ^ aux_in[input->id].mode.inverted); 93 | 94 | return value; 95 | } 96 | 97 | inline static __attribute__((always_inline)) int32_t get_input (const input_signal_t *input, wait_mode_t wait_mode, float timeout) 98 | { 99 | if(wait_mode == WaitMode_Immediate) 100 | return DIGITAL_IN(input->gpio) ^ input->mode.inverted; 101 | 102 | int32_t value = -1; 103 | uint_fast16_t delay = (uint_fast16_t)ceilf((1000.0f / 50.0f) * timeout) + 1; 104 | 105 | if(wait_mode == WaitMode_Rise || wait_mode == WaitMode_Fall) { 106 | 107 | pin_irq_mode_t irq_mode = wait_mode == WaitMode_Rise ? IRQ_Mode_Rising : IRQ_Mode_Falling; 108 | 109 | if(input->cap.irq_mode & irq_mode) { 110 | 111 | event_bits &= ~input->gpio.bit; 112 | pinEnableIRQ(input, irq_mode); 113 | 114 | do { 115 | if(event_bits & input->gpio.bit) { 116 | value = DIGITAL_IN(input->gpio) ^ input->mode.inverted; 117 | break; 118 | } 119 | if(delay) { 120 | protocol_execute_realtime(); 121 | hal.delay_ms(50, NULL); 122 | } else 123 | break; 124 | } while(--delay && !sys.abort); 125 | 126 | pinEnableIRQ(input, IRQ_Mode_None); // Restore pin interrupt status 127 | } 128 | 129 | } else { 130 | 131 | bool wait_for = wait_mode != WaitMode_Low; 132 | 133 | do { 134 | if((DIGITAL_IN(input->gpio) ^ input->mode.inverted) == wait_for) { 135 | value = DIGITAL_IN(input->gpio) ^ input->mode.inverted; 136 | break; 137 | } 138 | if(delay) { 139 | protocol_execute_realtime(); 140 | hal.delay_ms(50, NULL); 141 | } else 142 | break; 143 | } while(--delay && !sys.abort); 144 | } 145 | 146 | return value; 147 | } 148 | 149 | void ioports_event (input_signal_t *input) 150 | { 151 | event_bits |= input->gpio.bit; 152 | 153 | if(input->interrupt_callback) 154 | input->interrupt_callback(input->user_port, !!(input->port->reg->DR & input->port->bit)); 155 | } 156 | 157 | static int32_t wait_on_input (uint8_t port, wait_mode_t wait_mode, float timeout) 158 | { 159 | int32_t value = -1; 160 | 161 | if(port < digital.in.n_ports) 162 | value = get_input(&aux_in[port], wait_mode, timeout); 163 | 164 | return value; 165 | } 166 | 167 | static bool register_interrupt_handler (uint8_t port, uint8_t user_port, pin_irq_mode_t irq_mode, ioport_interrupt_callback_ptr interrupt_callback) 168 | { 169 | bool ok; 170 | 171 | if((ok = port < digital.in.n_ports && aux_in[port].cap.irq_mode != IRQ_Mode_None)) { 172 | 173 | input_signal_t *input = &aux_in[port]; 174 | 175 | if((ok = (irq_mode & aux_in[port].cap.irq_mode) == irq_mode && interrupt_callback != NULL)) { 176 | input->user_port = user_port; 177 | input->mode.irq_mode = irq_mode; 178 | input->interrupt_callback = interrupt_callback; 179 | pinEnableIRQ(input, irq_mode); 180 | } 181 | 182 | if(irq_mode == IRQ_Mode_None || !ok) { 183 | hal.irq_disable(); 184 | pinEnableIRQ(input, IRQ_Mode_None); 185 | input->mode.irq_mode = IRQ_Mode_None; 186 | input->interrupt_callback = NULL; 187 | hal.irq_enable(); 188 | } 189 | } 190 | 191 | return ok; 192 | } 193 | 194 | static bool set_function (xbar_t *port, pin_function_t function) 195 | { 196 | if(port->mode.input) 197 | aux_in[port->id].id = function; 198 | else { 199 | aux_out[port->id].id = function; 200 | if(function == Output_SpindlePWM || function == Output_Spindle1PWM) 201 | aux_out[port->id].mode.pwm = On; 202 | } 203 | 204 | return true; 205 | } 206 | 207 | static xbar_t *get_pin_info (io_port_direction_t dir, uint8_t port) 208 | { 209 | static xbar_t pin; 210 | 211 | xbar_t *info = NULL; 212 | 213 | pin.set_function = set_function; 214 | 215 | if(dir == Port_Input && port < digital.in.n_ports) { 216 | XBAR_SET_DIN_INFO(pin, port, aux_in[port], digital_in_cfg, digital_in_state); 217 | info = &pin; 218 | } 219 | 220 | if(dir == Port_Output && port < digital.out.n_ports) { 221 | XBAR_SET_DOUT_INFO(pin, port, aux_out[port], digital_out_cfg, digital_out_state); 222 | info = &pin; 223 | } 224 | 225 | return info; 226 | } 227 | 228 | static void set_pin_description (io_port_direction_t dir, uint8_t port, const char *s) 229 | { 230 | if(dir == Port_Input && port < digital.in.n_ports) 231 | aux_in[port].description = s; 232 | 233 | if(dir == Port_Output && port < digital.out.n_ports) 234 | aux_out[port].description = s; 235 | } 236 | 237 | FLASHMEM void ioports_init (pin_group_pins_t *aux_inputs, pin_group_pins_t *aux_outputs) 238 | { 239 | aux_in = aux_inputs->pins.inputs; 240 | aux_out = aux_outputs->pins.outputs; 241 | 242 | digital.in.n_ports = aux_inputs->n_pins; 243 | digital.out.n_ports = aux_outputs->n_pins; 244 | 245 | io_digital_t ports = { 246 | .ports = &digital, 247 | .digital_out = digital_out, 248 | .get_pin_info = get_pin_info, 249 | .wait_on_input = wait_on_input, 250 | .set_pin_description = set_pin_description, 251 | .register_interrupt_handler = register_interrupt_handler 252 | }; 253 | 254 | ioports_add_digital(&ports); 255 | } 256 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/tmc_spi.c: -------------------------------------------------------------------------------- 1 | /* 2 | tmc_spi.c - driver code for iMXRT1062 ARM processors 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2023-2025 Terje Io 7 | 8 | grblHAL is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | grblHAL is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with grblHAL. If not, see . 20 | */ 21 | 22 | #include "driver.h" 23 | 24 | #if TRINAMIC_SPI_ENABLE 25 | 26 | #include "t4_spi.h" 27 | #include "trinamic/common.h" 28 | 29 | #define TMC_SPI_FREQ 8000000 30 | 31 | #if TRINAMIC_SPI_ENABLE & TRINAMIC_SPI_CS_SINGLE 32 | 33 | #if TRINAMIC_SPI_ENABLE & TRINAMIC_SPI_20BIT 34 | #error "20 bit Trinamic SPI datagrams not yet supported!" 35 | #endif 36 | 37 | static struct { 38 | gpio_t port; 39 | } cs; 40 | 41 | static uint_fast8_t n_motors; 42 | static TMC_spi_datagram_t datagram[TMC_N_MOTORS_MAX]; 43 | 44 | TMC_spi_status_t tmc_spi_read (trinamic_motor_t driver, TMC_spi_datagram_t *reg) 45 | { 46 | static TMC_spi_status_t status = 0; 47 | 48 | uint8_t res; 49 | uint_fast8_t idx = n_motors; 50 | #ifndef TRINAMIC_SPI_PORT 51 | uint32_t f_spi = spi_set_speed(TMC_SPI_FREQ); 52 | #endif 53 | 54 | datagram[driver.seq].addr.value = reg->addr.value; 55 | datagram[driver.seq].addr.write = 0; 56 | 57 | DIGITAL_OUT(cs.port, 0); 58 | 59 | do { 60 | spi_put_byte(datagram[--idx].addr.value); 61 | spi_put_byte(0); 62 | spi_put_byte(0); 63 | spi_put_byte(0); 64 | spi_put_byte(0); 65 | } while(idx); 66 | 67 | delayMicroseconds(1); 68 | DIGITAL_OUT(cs.port, 1); 69 | delayMicroseconds(1); 70 | DIGITAL_OUT(cs.port, 0); 71 | 72 | idx = n_motors; 73 | do { 74 | res = spi_put_byte(datagram[--idx].addr.value); 75 | 76 | if(idx == driver.seq) { 77 | status = res; 78 | reg->payload.data[3] = spi_get_byte(); 79 | reg->payload.data[2] = spi_get_byte(); 80 | reg->payload.data[1] = spi_get_byte(); 81 | reg->payload.data[0] = spi_get_byte(); 82 | } else { 83 | spi_get_byte(); 84 | spi_get_byte(); 85 | spi_get_byte(); 86 | spi_get_byte(); 87 | } 88 | } while(idx); 89 | 90 | delayMicroseconds(1); 91 | DIGITAL_OUT(cs.port, 1); 92 | delayMicroseconds(1); 93 | 94 | #ifndef TRINAMIC_SPI_PORT 95 | spi_set_speed(f_spi); 96 | #endif 97 | 98 | return status; 99 | } 100 | 101 | TMC_spi_status_t tmc_spi_write (trinamic_motor_t driver, TMC_spi_datagram_t *reg) 102 | { 103 | TMC_spi_status_t status = 0; 104 | 105 | uint8_t res; 106 | uint_fast8_t idx = n_motors; 107 | #ifndef TRINAMIC_SPI_PORT 108 | uint32_t f_spi = spi_set_speed(TMC_SPI_FREQ); 109 | #endif 110 | 111 | memcpy(&datagram[driver.seq], reg, sizeof(TMC_spi_datagram_t)); 112 | datagram[driver.seq].addr.write = 1; 113 | 114 | DIGITAL_OUT(cs.port, 0); 115 | 116 | do { 117 | res = spi_put_byte(datagram[--idx].addr.value); 118 | spi_put_byte(datagram[idx].payload.data[3]); 119 | spi_put_byte(datagram[idx].payload.data[2]); 120 | spi_put_byte(datagram[idx].payload.data[1]); 121 | spi_put_byte(datagram[idx].payload.data[0]); 122 | 123 | if(idx == driver.seq) { 124 | status = res; 125 | datagram[idx].addr.idx = 0; // TMC_SPI_STATUS_REG; 126 | datagram[idx].addr.write = 0; 127 | } 128 | } while(idx); 129 | 130 | delayMicroseconds(1); 131 | DIGITAL_OUT(cs.port, 1); 132 | delayMicroseconds(1); 133 | 134 | #ifndef TRINAMIC_SPI_PORT 135 | spi_set_speed(f_spi); 136 | #endif 137 | 138 | return status; 139 | } 140 | 141 | static void add_cs_pin (xbar_t *gpio, void *data) 142 | { 143 | if(gpio->function == Output_MotorChipSelect) { 144 | cs.port.reg = (gpio_reg_t *)digital_pin_to_info_PGM[gpio->pin].reg; 145 | cs.port.bit = digital_pin_to_info_PGM[gpio->pin].mask; 146 | } 147 | } 148 | 149 | static void if_init (uint8_t motors, axes_signals_t axisflags) 150 | { 151 | n_motors = motors; 152 | hal.enumerate_pins(true, add_cs_pin, NULL); 153 | } 154 | 155 | void tmc_spi_init (void) 156 | { 157 | trinamic_driver_if_t driver = { 158 | .on_drivers_init = if_init 159 | }; 160 | 161 | t4_spi_init(); 162 | 163 | uint_fast8_t idx = TMC_N_MOTORS_MAX; 164 | do { 165 | datagram[--idx].addr.idx = 0; //TMC_SPI_STATUS_REG; 166 | } while(idx); 167 | 168 | trinamic_if_init(&driver); 169 | } 170 | 171 | #else // separate CS pins 172 | 173 | static struct { 174 | gpio_t port; 175 | } cs[TMC_N_MOTORS_MAX]; 176 | 177 | TMC_spi_status_t tmc_spi_read (trinamic_motor_t driver, TMC_spi_datagram_t *datagram) 178 | { 179 | TMC_spi_status_t status; 180 | #ifndef TRINAMIC_SPI_PORT 181 | uint32_t f_spi = spi_set_speed(TMC_SPI_FREQ); 182 | #endif 183 | 184 | DIGITAL_OUT(cs[driver.id].port, 0); 185 | 186 | datagram->payload.value = 0; 187 | 188 | datagram->addr.write = 0; 189 | spi_put_byte(datagram->addr.value); 190 | spi_put_byte(0); 191 | spi_put_byte(0); 192 | spi_put_byte(0); 193 | spi_put_byte(0); 194 | 195 | DIGITAL_OUT(cs[driver.id].port, 1); 196 | delayMicroseconds(1); 197 | DIGITAL_OUT(cs[driver.id].port, 0); 198 | 199 | status = spi_put_byte(datagram->addr.value); 200 | datagram->payload.data[3] = spi_get_byte(); 201 | datagram->payload.data[2] = spi_get_byte(); 202 | datagram->payload.data[1] = spi_get_byte(); 203 | datagram->payload.data[0] = spi_get_byte(); 204 | 205 | DIGITAL_OUT(cs[driver.id].port, 1); 206 | 207 | #ifndef TRINAMIC_SPI_PORT 208 | spi_set_speed(f_spi); 209 | #endif 210 | 211 | return status; 212 | } 213 | 214 | TMC_spi_status_t tmc_spi_write (trinamic_motor_t driver, TMC_spi_datagram_t *datagram) 215 | { 216 | TMC_spi_status_t status; 217 | #ifndef TRINAMIC_SPI_PORT 218 | uint32_t f_spi = spi_set_speed(TMC_SPI_FREQ); 219 | #endif 220 | 221 | DIGITAL_OUT(cs[driver.id].port, 0); 222 | 223 | datagram->addr.write = 1; 224 | status = spi_put_byte(datagram->addr.value); 225 | spi_put_byte(datagram->payload.data[3]); 226 | spi_put_byte(datagram->payload.data[2]); 227 | spi_put_byte(datagram->payload.data[1]); 228 | spi_put_byte(datagram->payload.data[0]); 229 | 230 | DIGITAL_OUT(cs[driver.id].port, 1); 231 | 232 | #ifndef TRINAMIC_SPI_PORT 233 | spi_set_speed(f_spi); 234 | #endif 235 | 236 | return status; 237 | } 238 | 239 | TMC_spi20_datagram_t tmc_spi20_write (trinamic_motor_t driver, TMC_spi20_datagram_t *datagram) 240 | { 241 | TMC_spi20_datagram_t status = {0}; 242 | #ifndef TRINAMIC_SPI_PORT 243 | uint32_t f_spi = spi_set_speed(TMC_SPI_FREQ); 244 | #endif 245 | 246 | DIGITAL_OUT(cs[driver.id].port, 0); 247 | 248 | status.data[2] = spi_put_byte(datagram->data[2]); 249 | status.data[1] = spi_put_byte(datagram->data[1]); 250 | status.data[0] = spi_put_byte(datagram->data[0]); 251 | 252 | DIGITAL_OUT(cs[driver.id].port, 1); 253 | 254 | status.value >>= 4; 255 | 256 | #ifndef TRINAMIC_SPI_PORT 257 | spi_set_speed(f_spi); 258 | #endif 259 | 260 | return status; 261 | } 262 | 263 | static void add_cs_pin (xbar_t *gpio, void *data) 264 | { 265 | gpio_t *port = NULL; 266 | 267 | if(gpio->group == PinGroup_MotorChipSelect) 268 | switch (gpio->function) { 269 | 270 | case Output_MotorChipSelectX: 271 | port = &cs[X_AXIS].port; 272 | break; 273 | 274 | case Output_MotorChipSelectY: 275 | port = &cs[Y_AXIS].port; 276 | break; 277 | 278 | case Output_MotorChipSelectZ: 279 | port = &cs[Z_AXIS].port; 280 | break; 281 | 282 | case Output_MotorChipSelectM3: 283 | port = &cs[3].port; 284 | break; 285 | 286 | case Output_MotorChipSelectM4: 287 | port = &cs[4].port; 288 | break; 289 | 290 | case Output_MotorChipSelectM5: 291 | port = &cs[5].port; 292 | break; 293 | 294 | default: 295 | break; 296 | } 297 | 298 | if(port) 299 | memcpy(port, gpio->port, sizeof(gpio_t)); 300 | } 301 | 302 | static void if_init (uint8_t motors, axes_signals_t enabled) 303 | { 304 | UNUSED(motors); 305 | 306 | hal.enumerate_pins(true, add_cs_pin, NULL); 307 | } 308 | 309 | void tmc_spi_init (void) 310 | { 311 | static trinamic_driver_if_t driver_if = {.on_drivers_init = if_init}; 312 | 313 | t4_spi_init(); 314 | 315 | trinamic_if_init(&driver_if); 316 | } 317 | #endif 318 | #endif // TRINAMIC_SPI_ENABLE 319 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/usb_serial_ard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | usb_serial_ard.cpp - driver code for IMXRT1062 processor (on Teensy 4.0 board) : USB serial port wrapper 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2018-2025 Terje Io 8 | 9 | 10 | grblHAL is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | grblHAL is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with grblHAL. If not, see . 22 | 23 | */ 24 | 25 | #include 26 | 27 | #include "Arduino.h" 28 | 29 | #include "driver.h" 30 | 31 | #if USB_SERIAL_CDC == 1 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | #include "grbl/protocol.h" 38 | 39 | #define BLOCK_RX_BUFFER_SIZE 20 40 | 41 | DMAMEM static stream_block_tx_buffer_t txbuf; 42 | DMAMEM static stream_rx_buffer_t rxbuf; 43 | static on_execute_realtime_ptr on_execute_realtime; 44 | static enqueue_realtime_command_ptr enqueue_realtime_command = protocol_enqueue_realtime_command; 45 | 46 | static bool usb_isConnected (void) 47 | { 48 | return sys.cold_start || SerialUSB; 49 | } 50 | 51 | // 52 | // Returns number of characters in serial input buffer 53 | // 54 | static uint16_t usb_serialRxCount (void) 55 | { 56 | uint_fast16_t tail = rxbuf.tail, head = rxbuf.head; 57 | 58 | return (uint16_t)BUFCOUNT(head, tail, RX_BUFFER_SIZE); 59 | } 60 | 61 | // 62 | // Returns number of free characters in serial input buffer 63 | // 64 | static uint16_t usb_serialRxFree (void) 65 | { 66 | uint_fast16_t tail = rxbuf.tail, head = rxbuf.head; 67 | 68 | return (uint16_t)((RX_BUFFER_SIZE - 1) - BUFCOUNT(head, tail, RX_BUFFER_SIZE)); 69 | } 70 | 71 | // 72 | // Flushes the serial input buffer (including the USB buffer) 73 | // 74 | void usb_serialRxFlush (void) 75 | { 76 | SerialUSB.flush(); 77 | rxbuf.tail = rxbuf.head; 78 | } 79 | 80 | // 81 | // Flushes and adds a CAN character to the serial input buffer 82 | // 83 | static void usb_serialRxCancel (void) 84 | { 85 | rxbuf.data[rxbuf.head] = CMD_RESET; 86 | rxbuf.tail = rxbuf.head; 87 | rxbuf.head = BUFNEXT(rxbuf.head, rxbuf); 88 | } 89 | 90 | // 91 | // Writes current buffer to the USB output stream, swaps buffers 92 | // 93 | static inline bool _usb_write (void) 94 | { 95 | size_t length, txfree; 96 | 97 | txbuf.s = txbuf.data; 98 | 99 | while(txbuf.length) { 100 | 101 | if((txfree = SerialUSB.availableForWrite()) > 10) { 102 | 103 | length = txfree < txbuf.length ? txfree : txbuf.length; 104 | 105 | SerialUSB.write((uint8_t *)txbuf.s, length); // doc is wrong - does not return bytes sent! 106 | 107 | txbuf.length -= length; 108 | txbuf.s += length; 109 | } 110 | 111 | if(txbuf.length && !hal.stream_blocking_callback()) { 112 | txbuf.length = 0; 113 | txbuf.s = txbuf.data; 114 | return false; 115 | } 116 | } 117 | 118 | txbuf.s = txbuf.data; 119 | 120 | return true; 121 | } 122 | 123 | // 124 | // Writes a number of characters from string to the USB output stream, blocks if buffer full 125 | // 126 | static void usb_serialWrite (const uint8_t *s, uint16_t length) 127 | { 128 | if(length == 0) 129 | return; 130 | 131 | if(txbuf.length && (txbuf.length + length) > txbuf.max_length) { 132 | if(!_usb_write()) 133 | return; 134 | } 135 | 136 | while(length > txbuf.max_length) { 137 | txbuf.length = txbuf.max_length; 138 | memcpy(txbuf.s, s, txbuf.length); 139 | if(!_usb_write()) 140 | return; 141 | length -= txbuf.max_length; 142 | s += txbuf.max_length; 143 | } 144 | 145 | if(length) { 146 | memcpy(txbuf.s, s, length); 147 | txbuf.length += length; 148 | txbuf.s += length; 149 | _usb_write(); 150 | } 151 | } 152 | 153 | // 154 | // Writes a null terminated string to the USB output stream, blocks if buffer full. 155 | // Buffers locally up to 40 characters or until the string is terminated with a ASCII_LF character. 156 | // NOTE: grbl always sends ASCII_LF terminated strings! 157 | // 158 | static void usb_serialWriteS (const char *s) 159 | { 160 | if(*s == '\0') 161 | return; 162 | 163 | size_t length = strlen(s); 164 | 165 | if((length + txbuf.length) < BLOCK_TX_BUFFER_SIZE) { 166 | 167 | memcpy(txbuf.s, s, length); 168 | txbuf.length += length; 169 | txbuf.s += length; 170 | 171 | if(s[length - 1] == ASCII_LF || txbuf.length > txbuf.max_length) { 172 | if(!_usb_write()) 173 | return; 174 | } 175 | } else 176 | usb_serialWrite((uint8_t *)s, (uint16_t)length); 177 | } 178 | 179 | // 180 | // Writes a character to the serial output stream 181 | // 182 | static bool usb_serialPutC (const uint8_t c) 183 | { 184 | if(txbuf.length) { 185 | char s[2]; 186 | s[0] = c; 187 | s[1] = '\0'; 188 | usb_serialWriteS(s); 189 | } 190 | else 191 | SerialUSB.write(c); 192 | 193 | return true; 194 | } 195 | 196 | // 197 | // serialGetC - returns -1 if no data available 198 | // 199 | static int32_t usb_serialGetC (void) 200 | { 201 | if(rxbuf.tail == rxbuf.head) 202 | return -1; // no data available else EOF 203 | 204 | int32_t data = (int32_t)rxbuf.data[rxbuf.tail]; // Get next character, increment tmp pointer 205 | rxbuf.tail = BUFNEXT(rxbuf.tail, rxbuf); // and update pointer 206 | 207 | return data; 208 | } 209 | 210 | static bool usb_serialSuspendInput (bool suspend) 211 | { 212 | return stream_rx_suspend(&rxbuf, suspend); 213 | } 214 | 215 | static bool usb_serialEnqueueRtCommand (uint8_t c) 216 | { 217 | return enqueue_realtime_command(c); 218 | } 219 | 220 | static enqueue_realtime_command_ptr usb_serialSetRtHandler (enqueue_realtime_command_ptr handler) 221 | { 222 | enqueue_realtime_command_ptr prev = enqueue_realtime_command; 223 | 224 | if(handler) 225 | enqueue_realtime_command = handler; 226 | 227 | return prev; 228 | } 229 | 230 | // 231 | // This function get called from the foregorund process, 232 | // used here to get characters off the USB serial input stream and buffer 233 | // them for processing by the core. Real time command characters are stripped out 234 | // and submitted for realtime processing. 235 | // 236 | static void usb_execute_realtime (sys_state_t state) 237 | { 238 | static volatile bool lock = false; 239 | static char tmpbuf[BLOCK_RX_BUFFER_SIZE]; 240 | 241 | on_execute_realtime(state); 242 | 243 | if(lock) 244 | return; 245 | 246 | char c, *dp; 247 | int avail, free; 248 | 249 | lock = true; 250 | 251 | if((avail = SerialUSB.available())) { 252 | 253 | dp = tmpbuf; 254 | free = usb_serialRxFree(); 255 | free = free > BLOCK_RX_BUFFER_SIZE ? BLOCK_RX_BUFFER_SIZE : free; 256 | 257 | avail = SerialUSB.readBytes(tmpbuf, avail > free ? free : avail); 258 | 259 | while(avail--) { 260 | c = *dp++; 261 | if(!enqueue_realtime_command(c)) { 262 | uint_fast16_t next_head = BUFNEXT(rxbuf.head, rxbuf); // Get next head pointer 263 | if(next_head == rxbuf.tail) // If buffer full 264 | rxbuf.overflow = On; // flag overflow, 265 | else { 266 | rxbuf.data[rxbuf.head] = c; // else add character data to buffer 267 | rxbuf.head = next_head; // and update pointer 268 | } 269 | } 270 | } 271 | } 272 | 273 | lock = false; 274 | } 275 | 276 | FLASHMEM const io_stream_t *usb_serialInit (void) 277 | { 278 | PROGMEM static const io_stream_t stream = { 279 | .type = StreamType_Serial, 280 | .instance = 0, 281 | .state = { .is_usb = On }, 282 | .is_connected = usb_isConnected, 283 | .get_rx_buffer_free = usb_serialRxFree, 284 | .write = usb_serialWriteS, 285 | .write_all = NULL, 286 | .write_char = usb_serialPutC, 287 | .enqueue_rt_command = usb_serialEnqueueRtCommand, 288 | .read = usb_serialGetC, 289 | .reset_read_buffer = usb_serialRxFlush, 290 | .cancel_read_buffer = usb_serialRxCancel, 291 | .set_enqueue_rt_handler = usb_serialSetRtHandler, 292 | .suspend_read = usb_serialSuspendInput, 293 | .write_n = usb_serialWrite, 294 | .disable_rx = NULL, 295 | .get_rx_buffer_count = usb_serialRxCount 296 | }; 297 | 298 | 299 | memset(&rxbuf, 0, sizeof(stream_rx_buffer_t)); 300 | memset(&txbuf, 0, sizeof(stream_block_tx_buffer_t)); 301 | 302 | SerialUSB.begin(BAUD_RATE); 303 | 304 | #if USB_SERIAL_WAIT 305 | while(!SerialUSB); // Wait for connection 306 | 307 | hal.stream.connected = true; 308 | #endif 309 | 310 | txbuf.s = txbuf.data; 311 | txbuf.max_length = SerialUSB.availableForWrite(); // 6144 bytes 312 | txbuf.max_length = (txbuf.max_length > BLOCK_TX_BUFFER_SIZE ? BLOCK_TX_BUFFER_SIZE : txbuf.max_length) - 20; 313 | 314 | on_execute_realtime = grbl.on_execute_realtime; 315 | grbl.on_execute_realtime = usb_execute_realtime; 316 | 317 | return &stream; 318 | } 319 | 320 | int usb_serial_input (void) 321 | { 322 | return 1; 323 | } 324 | 325 | #ifdef __cplusplus 326 | } 327 | #endif 328 | 329 | #endif 330 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/usb_serial_pjrc.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | usb_serial_pjrc.c - driver code for IMXRT1062 processor (on Teensy 4.0 board) : USB serial port wrapper, PJRC version 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2018-2025 Terje Io 8 | 9 | 10 | grblHAL is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | 15 | grblHAL is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | 20 | You should have received a copy of the GNU General Public License 21 | along with grblHAL. If not, see . 22 | 23 | */ 24 | 25 | #include 26 | 27 | #include "usb_serial.h" 28 | 29 | #include "driver.h" 30 | #include "grbl/protocol.h" 31 | 32 | #if USB_SERIAL_CDC == 2 33 | 34 | #define BLOCK_RX_BUFFER_SIZE 20 35 | 36 | DMAMEM static stream_block_tx_buffer_t txbuf; 37 | DMAMEM static stream_rx_buffer_t rxbuf; 38 | static on_execute_realtime_ptr on_execute_realtime; 39 | static enqueue_realtime_command_ptr enqueue_realtime_command = protocol_enqueue_realtime_command; 40 | 41 | extern volatile uint32_t usb_cdc_line_rtsdtr_millis; 42 | extern volatile uint32_t systick_millis_count; 43 | extern volatile uint8_t usb_cdc_line_rtsdtr; 44 | extern volatile uint8_t usb_configuration; 45 | 46 | static bool usb_isConnected (void) 47 | { 48 | return sys.cold_start || 49 | (usb_configuration && (usb_cdc_line_rtsdtr & USB_SERIAL_DTR) && 50 | ((uint32_t)(systick_millis_count - usb_cdc_line_rtsdtr_millis) >= 15)); 51 | } 52 | 53 | // 54 | // Returns number of characters in serial input buffer 55 | // 56 | static uint16_t usb_serialRxCount (void) 57 | { 58 | uint_fast16_t tail = rxbuf.tail, head = rxbuf.head; 59 | return (uint16_t)BUFCOUNT(head, tail, RX_BUFFER_SIZE); 60 | } 61 | 62 | // 63 | // Returns number of free characters in serial input buffer 64 | // 65 | static uint16_t usb_serialRxFree (void) 66 | { 67 | uint_fast16_t tail = rxbuf.tail, head = rxbuf.head; 68 | 69 | return (uint16_t)((RX_BUFFER_SIZE - 1) - BUFCOUNT(head, tail, RX_BUFFER_SIZE)); 70 | } 71 | 72 | // 73 | // Flushes the serial input buffer (including the USB buffer) 74 | // 75 | static void usb_serialRxFlush (void) 76 | { 77 | usb_serial_flush_input(); 78 | rxbuf.tail = rxbuf.head; 79 | } 80 | 81 | // 82 | // Flushes and adds a CAN character to the serial input buffer 83 | // 84 | static void usb_serialRxCancel (void) 85 | { 86 | rxbuf.data[rxbuf.head] = CMD_RESET; 87 | rxbuf.tail = rxbuf.head; 88 | rxbuf.head = BUFNEXT(rxbuf.head, rxbuf); 89 | } 90 | 91 | // 92 | // Writes current buffer to the USB output stream, swaps buffers 93 | // 94 | static inline bool _usb_write (void) 95 | { 96 | size_t length, txfree; 97 | 98 | txbuf.s = txbuf.data; 99 | 100 | while(txbuf.length) { 101 | 102 | if((txfree = usb_serial_write_buffer_free()) > 10) { 103 | 104 | length = txfree < txbuf.length ? txfree : txbuf.length; 105 | 106 | usb_serial_write(txbuf.s, length); // 107 | 108 | txbuf.length -= length; 109 | txbuf.s += length; 110 | } 111 | 112 | if(txbuf.length && !hal.stream_blocking_callback()) { 113 | txbuf.length = 0; 114 | txbuf.s = txbuf.data; 115 | return false; 116 | } 117 | } 118 | 119 | txbuf.s = txbuf.data; 120 | 121 | return true; 122 | } 123 | 124 | // 125 | // Writes a number of characters from string to the USB output stream, blocks if buffer full 126 | // 127 | static void usb_serialWrite (const uint8_t *s, uint16_t length) 128 | { 129 | if(length == 0) 130 | return; 131 | 132 | if(txbuf.length && (txbuf.length + length) > txbuf.max_length) { 133 | if(!_usb_write()) 134 | return; 135 | } 136 | 137 | while(length > txbuf.max_length) { 138 | txbuf.length = txbuf.max_length; 139 | memcpy(txbuf.s, s, txbuf.length); 140 | if(!_usb_write()) 141 | return; 142 | length -= txbuf.max_length; 143 | s += txbuf.max_length; 144 | } 145 | 146 | if(length) { 147 | memcpy(txbuf.s, s, length); 148 | txbuf.length += length; 149 | txbuf.s += length; 150 | _usb_write(); 151 | } 152 | } 153 | 154 | // 155 | // Writes a null terminated string to the USB output stream, blocks if buffer full 156 | // Buffers string up to EOL (LF) before transmitting 157 | // 158 | static void usb_serialWriteS (const char *s) 159 | { 160 | if(*s == '\0') 161 | return; 162 | 163 | size_t length = strlen(s); 164 | 165 | if((length + txbuf.length) < BLOCK_TX_BUFFER_SIZE) { 166 | 167 | memcpy(txbuf.s, s, length); 168 | txbuf.length += length; 169 | txbuf.s += length; 170 | 171 | if(s[length - 1] == ASCII_LF || txbuf.length > txbuf.max_length) { 172 | if(!_usb_write()) 173 | return; 174 | } 175 | } else 176 | usb_serialWrite((uint8_t *)s, (uint16_t)length); 177 | } 178 | 179 | // 180 | // Writes a character to the serial output stream 181 | // 182 | static bool usb_serialPutC (const uint8_t c) 183 | { 184 | static char s[2] = ""; 185 | 186 | if(txbuf.length) { 187 | *s = c; 188 | usb_serialWriteS(s); 189 | } else 190 | usb_serial_putchar(c); 191 | 192 | return true; 193 | } 194 | 195 | // 196 | // serialGetC - returns -1 if no data available 197 | // 198 | static int32_t usb_serialGetC (void) 199 | { 200 | if(rxbuf.tail == rxbuf.head) 201 | return -1; // no data available 202 | 203 | int32_t data = (int32_t)rxbuf.data[rxbuf.tail]; // Get next character, increment tmp pointer 204 | rxbuf.tail = BUFNEXT(rxbuf.tail, rxbuf); // and update pointer 205 | 206 | return data; 207 | } 208 | 209 | static bool usb_serialSuspendInput (bool suspend) 210 | { 211 | return stream_rx_suspend(&rxbuf, suspend); 212 | } 213 | 214 | static bool usb_serialEnqueueRtCommand (uint8_t c) 215 | { 216 | return enqueue_realtime_command(c); 217 | } 218 | 219 | static enqueue_realtime_command_ptr usb_serialSetRtHandler (enqueue_realtime_command_ptr handler) 220 | { 221 | enqueue_realtime_command_ptr prev = enqueue_realtime_command; 222 | 223 | if(handler) 224 | enqueue_realtime_command = handler; 225 | 226 | return prev; 227 | } 228 | 229 | // 230 | // This function get called from the foregorund process, 231 | // used here to get characters off the USB serial input stream and buffer 232 | // them for processing by the core. Real time command characters are stripped out 233 | // and submitted for realtime processing. 234 | // 235 | void usb_execute_realtime (sys_state_t state) 236 | { 237 | static volatile bool lock = false; 238 | static volatile uint32_t last_micros = 0; 239 | static char tmpbuf[BLOCK_RX_BUFFER_SIZE]; 240 | 241 | //if(lock) 242 | // return; 243 | 244 | on_execute_realtime(state); 245 | 246 | uint32_t current_micros; 247 | if(lock || ((current_micros = micros()) - last_micros) < 50) 248 | return; 249 | 250 | char c, *dp; 251 | int avail, free; 252 | 253 | lock = true; 254 | last_micros = current_micros; 255 | 256 | if((avail = usb_serial_available())) { 257 | 258 | dp = tmpbuf; 259 | free = usb_serialRxFree(); 260 | free = free > BLOCK_RX_BUFFER_SIZE ? BLOCK_RX_BUFFER_SIZE : free; 261 | 262 | avail = usb_serial_read(tmpbuf, avail > free ? free : avail); 263 | 264 | while(avail--) { 265 | c = *dp++; 266 | if(!enqueue_realtime_command(c)) { 267 | uint_fast16_t next_head = BUFNEXT(rxbuf.head, rxbuf); // Get next head pointer 268 | if(next_head == rxbuf.tail) // If buffer full 269 | rxbuf.overflow = On; // flag overflow, 270 | else { 271 | rxbuf.data[rxbuf.head] = c; // else add character data to buffer 272 | rxbuf.head = next_head; // and update pointer 273 | } 274 | } 275 | } 276 | } 277 | 278 | lock = false; 279 | } 280 | 281 | FLASHMEM const io_stream_t *usb_serialInit (void) 282 | { 283 | PROGMEM static const io_stream_t stream = { 284 | .type = StreamType_Serial, 285 | .state = { .is_usb = On }, 286 | .is_connected = usb_isConnected, 287 | .read = usb_serialGetC, 288 | .write = usb_serialWriteS, 289 | .write_char = usb_serialPutC, 290 | .write_n = usb_serialWrite, 291 | .enqueue_rt_command = usb_serialEnqueueRtCommand, 292 | .get_rx_buffer_free = usb_serialRxFree, 293 | .get_rx_buffer_count = usb_serialRxCount, 294 | .reset_read_buffer = usb_serialRxFlush, 295 | .cancel_read_buffer = usb_serialRxCancel, 296 | .suspend_read = usb_serialSuspendInput, 297 | .set_enqueue_rt_handler = usb_serialSetRtHandler 298 | }; 299 | 300 | memset(&rxbuf, 0, sizeof(stream_rx_buffer_t)); 301 | memset(&txbuf, 0, sizeof(stream_block_tx_buffer_t)); 302 | 303 | // usb_serial_configure(); // Done somewhere already - do not call again 304 | txbuf.s = txbuf.data; 305 | txbuf.max_length = usb_serial_write_buffer_free(); // 6144 306 | txbuf.max_length = (txbuf.max_length > BLOCK_TX_BUFFER_SIZE ? BLOCK_TX_BUFFER_SIZE : txbuf.max_length) - 20; 307 | 308 | on_execute_realtime = grbl.on_execute_realtime; 309 | grbl.on_execute_realtime = usb_execute_realtime; 310 | 311 | return &stream; 312 | } 313 | 314 | #endif // USB_SERIAL_CDC == 2 315 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | make 107 | 108 | iMXRT1062 109 | true 110 | true 111 | true 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/neopixel_uart.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | neopixel_uart.cpp - UART support for Neopixels 3 | 4 | Part of grblHAL driver for iMXRT1062 5 | 6 | Some parts Copyright (c) 2024-2025 Terje Io 7 | Some parts parts derived from WS2812Serial - Non-blocking WS2812 LED Display Library: 8 | https://github.com/PaulStoffregen/WS2812Serial 9 | Copyright (c) 2017 Paul Stoffregen, PJRC.COM, LLC 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in 19 | all copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 27 | THE SOFTWARE. 28 | */ 29 | 30 | #include "driver.h" 31 | 32 | #ifdef NEOPIXEL_UART_PIN 33 | 34 | #include "Arduino.h" 35 | #include "DMAChannel.h" 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | #ifndef NEOPIXELS_NUM 42 | #define NEOPIXELS_NUM 1 43 | #endif 44 | 45 | static DMAChannel *dma = NULL; 46 | static uint32_t prior_micros = 0; 47 | static IMXRT_LPUART_t *uart = NULL; 48 | static uint8_t *frameBuffer = NULL; 49 | static neopixel_cfg_t neopixel = { 50 | .num_leds = 0, 51 | .num_bytes = 0, 52 | .leds = NULL, 53 | .intensity = 255 54 | }; 55 | static settings_changed_ptr settings_changed; 56 | 57 | void onSettingsChanged (settings_t *settings, settings_changed_flags_t changed) 58 | { 59 | if(neopixel.leds == NULL || hal.rgb0.num_devices != settings->rgb_strip.length0) { 60 | 61 | if(settings->rgb_strip.length0 == 0) 62 | settings->rgb_strip.length0 = hal.rgb0.num_devices; 63 | else 64 | hal.rgb0.num_devices = settings->rgb_strip.length0; 65 | 66 | if(neopixel.leds) { 67 | free(neopixel.leds); 68 | neopixel.leds = NULL; 69 | } 70 | 71 | if(hal.rgb0.num_devices) { 72 | neopixel.num_bytes = hal.rgb0.num_devices * 3; 73 | if((neopixel.leds = (uint8_t *)calloc(neopixel.num_bytes, sizeof(uint8_t)))) { 74 | if(!(frameBuffer = (uint8_t *)malloc(hal.rgb0.num_devices * 12))) { 75 | hal.rgb0.num_devices = 0; 76 | free(neopixel.leds); 77 | neopixel.leds = NULL; 78 | } 79 | } 80 | } 81 | 82 | neopixel.num_leds = hal.rgb0.num_devices; 83 | } 84 | 85 | if(settings_changed) 86 | settings_changed(settings, changed); 87 | } 88 | 89 | static void _write (void) 90 | { 91 | while((DMA_ERQ & (1 << dma->channel))); 92 | 93 | rgb_color_t color; 94 | uint32_t microseconds_per_led = 30, bytes_per_led = 12; 95 | 96 | const uint8_t *p = neopixel.leds; 97 | const uint8_t *end = p + neopixel.num_leds * 3; 98 | uint8_t *fb = frameBuffer; 99 | 100 | while (p < end) { 101 | 102 | color.G = *p++; 103 | color.R = *p++; 104 | color.B = *p++; 105 | color = rgb_set_intensity(color, neopixel.intensity); 106 | 107 | uint32_t n = (color.G << 16) | (color.R << 8) | color.B; 108 | 109 | const uint8_t *stop = fb + 12; 110 | do { 111 | uint8_t x = 0x08; 112 | if (!(n & 0x00800000)) x |= 0x07; 113 | if (!(n & 0x00400000)) x |= 0xE0; 114 | n <<= 2; 115 | *fb++ = x; 116 | } while (fb < stop); 117 | } 118 | microseconds_per_led = 30; 119 | bytes_per_led = 12; 120 | 121 | // wait 300us WS2812 reset time 122 | uint32_t m, min_elapsed = (neopixel.num_leds * microseconds_per_led) + 300; 123 | 124 | while(true) { 125 | if(((m = micros()) - prior_micros) > min_elapsed) 126 | break; 127 | } 128 | prior_micros = m; 129 | 130 | // start DMA transfer to update LEDs 131 | 132 | // See if we need to muck with DMA cache... 133 | if((uint32_t)frameBuffer >= 0x20200000u) 134 | arm_dcache_flush(frameBuffer, neopixel.num_leds * bytes_per_led); 135 | 136 | dma->sourceBuffer(frameBuffer, neopixel.num_leds * bytes_per_led); 137 | dma->transferCount(neopixel.num_leds * bytes_per_led); 138 | dma->disableOnCompletion(); 139 | 140 | uart->STAT = 0; // try clearing out the status 141 | dma->enable(); 142 | } 143 | 144 | void neopixels_write (void) 145 | { 146 | if(neopixel.num_leds > 1) 147 | _write(); 148 | } 149 | 150 | static void neopixel_out_masked (uint16_t device, rgb_color_t color, rgb_color_mask_t mask) 151 | { 152 | if(neopixel.num_leds && device < neopixel.num_leds) { 153 | 154 | rgb_1bpp_assign(&neopixel.leds[device * 3], color, mask); 155 | 156 | if(neopixel.num_leds == 1) 157 | _write(); 158 | } 159 | } 160 | 161 | static void neopixel_out (uint16_t device, rgb_color_t color) 162 | { 163 | static const rgb_color_mask_t mask = { .mask = 0xFF }; 164 | 165 | neopixel_out_masked(device, color, mask); 166 | } 167 | 168 | static uint8_t neopixels_set_intensity (uint8_t intensity) 169 | { 170 | uint8_t prev = neopixel.intensity; 171 | 172 | if(neopixel.intensity != intensity) { 173 | 174 | neopixel.intensity = intensity; 175 | 176 | if(neopixel.num_leds) 177 | _write(); 178 | } 179 | 180 | return prev; 181 | } 182 | 183 | FLASHMEM void neopixel_init (void) 184 | { 185 | static bool init = false; 186 | 187 | if(!init) { 188 | 189 | uint32_t hwtrigger; 190 | 191 | switch (NEOPIXEL_UART_PIN) { 192 | 193 | case 1: // Serial1 194 | #if defined(ARDUINO_TEENSY41) 195 | case 53: 196 | #endif 197 | uart = &IMXRT_LPUART6; 198 | CCM_CCGR3 |= CCM_CCGR3_LPUART6(CCM_CCGR_ON); 199 | hwtrigger = DMAMUX_SOURCE_LPUART6_TX; 200 | break; 201 | case 8: // Serial2 202 | uart = &IMXRT_LPUART4; 203 | CCM_CCGR1 |= CCM_CCGR1_LPUART4(CCM_CCGR_ON); 204 | hwtrigger = DMAMUX_SOURCE_LPUART4_TX; 205 | break; 206 | case 14: // Serial3 207 | uart = &IMXRT_LPUART2; 208 | CCM_CCGR0 |= CCM_CCGR0_LPUART2(CCM_CCGR_ON); 209 | hwtrigger = DMAMUX_SOURCE_LPUART2_TX; 210 | break; 211 | case 17: // Serial4 212 | uart = &IMXRT_LPUART3; 213 | CCM_CCGR0 |= CCM_CCGR0_LPUART3(CCM_CCGR_ON); 214 | hwtrigger = DMAMUX_SOURCE_LPUART3_TX; 215 | break; 216 | case 20: // Serial5 217 | #if defined(ARDUINO_TEENSY40) 218 | case 39: // Serial5 alt 219 | #elif defined(ARDUINO_TEENSY41) 220 | case 47: 221 | #endif 222 | uart = &IMXRT_LPUART8; 223 | CCM_CCGR6 |= CCM_CCGR6_LPUART8(CCM_CCGR_ON); 224 | hwtrigger = DMAMUX_SOURCE_LPUART8_TX; 225 | break; 226 | case 24: // Serial6 227 | uart = &IMXRT_LPUART1; 228 | CCM_CCGR5 |= CCM_CCGR5_LPUART1(CCM_CCGR_ON); 229 | hwtrigger = DMAMUX_SOURCE_LPUART1_TX; 230 | break; 231 | case 29: // Serial7 232 | uart = &IMXRT_LPUART7; 233 | CCM_CCGR5 |= CCM_CCGR5_LPUART7(CCM_CCGR_ON); 234 | hwtrigger = DMAMUX_SOURCE_LPUART7_TX; 235 | break; 236 | #if defined(ARDUINO_TEENSY41) 237 | case 35: 238 | uart = &IMXRT_LPUART5; 239 | CCM_CCGR3 |= CCM_CCGR3_LPUART5(CCM_CCGR_ON); 240 | hwtrigger = DMAMUX_SOURCE_LPUART5_TX; 241 | break; 242 | #endif 243 | default: 244 | return; // pin not supported 245 | } 246 | 247 | if(!(dma = new DMAChannel)) 248 | return; // unable to allocate DMA channel 249 | 250 | // Convert Baud, computed values for 4mhz 251 | uart->CTRL = 0; 252 | uart->BAUD = LPUART_BAUD_OSR(5) | LPUART_BAUD_SBR(1) | LPUART_BAUD_TDMAE; // set baud configure for transfer DMA 253 | uart->PINCFG = 0; 254 | uint16_t tx_fifo_size = (((uart->FIFO >> 4) & 0x7) << 2); 255 | uint8_t tx_water = (tx_fifo_size < 16) ? tx_fifo_size >> 1 : 7; 256 | uart->WATER = LPUART_WATER_TXWATER(tx_water); 257 | uart->FIFO |= LPUART_FIFO_TXFE; 258 | uart->CTRL = (LPUART_CTRL_TE | LPUART_CTRL_TXINV); // enable transmitter and invert 259 | 260 | *(portControlRegister(NEOPIXEL_UART_PIN)) = IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(3) | IOMUXC_PAD_SPEED(3); 261 | #if NEOPIXEL_UART_PIN == 35 262 | *(portConfigRegister(NEOPIXEL_UART_PIN)) = 1; 263 | #else 264 | *(portConfigRegister(NEOPIXEL_UART_PIN)) = 2; 265 | #endif 266 | 267 | dma->destination((volatile uint8_t &)uart->DATA); 268 | dma->triggerAtHardwareEvent(hwtrigger); 269 | 270 | PROGMEM static const periph_pin_t neopix = { 271 | .function = Output_LED_Adressable, 272 | .group = PinGroup_UART, 273 | .port = NULL, 274 | .pin = NEOPIXEL_UART_PIN, 275 | .mode = { .mask = PINMODE_OUTPUT }, 276 | .description = "Neopixels" 277 | }; 278 | 279 | hal.periph_port.register_pin(&neopix); 280 | 281 | hal.rgb0.out = neopixel_out; 282 | hal.rgb0.out_masked = neopixel_out_masked; 283 | hal.rgb0.set_intensity = neopixels_set_intensity; 284 | hal.rgb0.write = neopixels_write; 285 | hal.rgb0.num_devices = NEOPIXELS_NUM; 286 | hal.rgb1.flags = (rgb_properties_t){ .is_strip = On }; 287 | hal.rgb0.cap.R = hal.rgb0.cap.G = hal.rgb0.cap.B = 255; 288 | 289 | settings_changed = hal.settings_changed; 290 | hal.settings_changed = onSettingsChanged; 291 | 292 | init = true; 293 | } 294 | } 295 | 296 | #ifdef __cplusplus 297 | } 298 | #endif 299 | 300 | #endif // NEOPIXEL_UART_PIN 301 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## iMXRT1062 Driver 2 | 3 | A grblHAL driver for the NXP iMXRT1062 processor on a [Teensy 4.x board](https://www.pjrc.com/store/teensy40.html). 4 | 5 | Available driver options can be found [here](https://github.com/grblHAL/iMXRT1062/blob/master/grblHAL_Teensy4/src/my_machine.h). 6 | 7 | This driver can be built with the [Web Builder](http://svn.io-engineering.com:8080/?driver=iMXRT1062), see [Compiling](#Compiling) for more information on building. 8 | 9 | --- 10 | 11 | __Important!__ There is a "bug" in Teensyduino prior to v1.54 that may cause [periodic stalls](https://github.com/grblHAL/iMXRT1062/issues/6) in processing. 12 | It is possible that this is only happening when networking is enabled and then not always so. 13 | Regardless of whether networking is enabled or not it is recommended that [Teensyduino v1.54](https://www.pjrc.com/teensy/td_download.html) is used to build this driver. 14 | 15 | --- 16 | 17 | #### Networking plugin 18 | 19 | The networking plugin is for Teensy 4.1 and needs the [teensy41_ethernet lwIP library](https://github.com/grblHAL/teensy41_ethernet), updated to lwIP 2.1.3 and configured for grblHAL. 20 | 21 | #### SD card plugin 22 | 23 | The SD card plugin needs the [uSDFS library](https://github.com/grblHAL/uSDFS), patched for bugs and configured for grblHAL. 24 | 25 | --- 26 | 27 | Download the libraries above as zip files and add to your Arduino installation with _Sketch > Include Library > Add .ZIP Library..._ 28 | 29 | --- 30 | #### Board maps: 31 | 32 | | |N_AXIS|Ganged axes1|Ethernet|EEPROM |SD card|I2C Keypad|Encoders|Digital I/O|Analog I/O| 33 | |-------------------------------------------------------------------------------------------------|------|----------------------------|--------|---------------|------------|----------|--------|-----------|----------| 34 | |Generic | 3 |no |no |yes2|yes |yes | - | - | - | 35 | |[BOARD_T40X101](https://github.com/phil-barrett/grbl-teensy-4) for Teensy 4.0 |max 4 |max 1 |no |yes2|no |yes | max 1 | - | - | 36 | |[BOARD_T41U5XBB](https://github.com/phil-barrett/grbl-teensy-4) for Teensy 4.1 |max 5 |max 2 |yes |yes2|yes |yes | max 1 |4/3 or 1/33|-| 37 | |[BOARD_T41BB5X_PRO](https://github.com/phil-barrett/grbl-teensy-4) for Teensy 4.1 |max 5 |max 2 |yes |yes \(FRAM\) |yes |yes | max 1 |4/3 or 1/33|-| 38 | |[BOARD_GRBLHAL2000](https://github.com/Expatria-Technologies/grblhal_2000_PrintNC) for Teensy 4.1|max 5 |max 2? |yes | |yes |yes | |4/? | | 39 | 40 | 1 Each enabled reduces N_AXIS with one. Currently the board map file must be edited to enable ganged/auto squared axes. 41 | 2 I2C EEPROM \(or FRAM\) is [optional](https://github.com/grblHAL/Plugin_EEPROM/blob/master/README.md) and must be added to the board. FRAM is recommended when the [Odometer plugin](https://github.com/grblHAL/Plugin_odometer/blob/master/README.md) is added to the build. 42 | 3 Number of digital input pins available is reduced when the [Encoder plugin](https://github.com/grblHAL/Plugin_encoder/blob/master/README.md) is added to the build. 43 | 44 | ### Compiling 45 | 46 | grblHAL can be built using the Arduino IDE or through the use of PlatformIO. 47 | Detailed directions may be found in the [grblHAL 48 | wiki](https://github.com/grblHAL/core/wiki/Compiling-GrblHAL). 49 | 50 | 51 | #### Arduino IDE 52 | 53 | This driver compiles and uploads from the Arduino IDE and is partially dependent on the Arduino framework. [Teensyduino](https://www.pjrc.com/teensy/td_download.html) is required and must be added to the Arduino IDE. 54 | 55 | See the Wiki-page for [compiling grblHAL](https://github.com/grblHAL/core/wiki/Compiling-GrblHAL) for instructions for how to import the project, configure the driver and compile. 56 | 57 | 58 | #### PlatformIO 59 | 60 | ##### About 61 | [PlatformIO][PlatformIO] is a cross platform build system for embedded systems. 62 | It provides both a GUI (delivered as an extension for VSCode) as well as a 63 | command line interface, both of which wrap the underlying toolsi (`scons`, 64 | `gdb`, etc). It features library management, a robust interface for dynamic 65 | builds and scripting, and a set of Python APIs for customization. Users 66 | interested in exploring complex project configurations utilzing many vendor 67 | provided hardware abstraction layers, processor specific customizations, etc may 68 | consult the configurations used within the Marlin project (configurations may be 69 | found in `platformio.ini` and `ini/*`). 70 | 71 | ##### Quick Start 72 | 73 | Compiling grblHAL with PlatformIO is quite trivial. PlatformIO will handle 74 | setting up any processor/architecture specific tooling needed to compile and 75 | flash grblHAL. To begin, decide whether you are choosing to use the GUI via 76 | VSCode or the command line tooling. Consult the [documentation][pio-docs] 77 | for directions on installing in the desired manner. 78 | 79 | Next we will clone this repository, ensuring that all submodules have been 80 | retrieved: 81 | 82 | ```bash 83 | git clone --recurse-submodules https://github.com/grblHAL/iMXRT1062.git 84 | ``` 85 | 86 | Next, change into the `grblHAL_Teensy4` sub-directory located within your checkout 87 | of the project (by default this would be `iMXRT1062/grblHAL_Teensy4`). 88 | 89 | This directory contains the `platformio.ini` configuration file. Within the 90 | configuration file we have some basic boilerplate information specifying how to 91 | build the project. These settings describe: 92 | 93 | - The `board` we desire to compile for (the Teensy 4.0 or 4.1) Note: Both 94 | boards are defined in `platformio.ini`. The primary distinction between the 95 | boards is the onboard flash size (1.94MB in the Teensy 4.0 and 7.75MB in the 96 | Teensy 4.1). While either environment will generally work, using the wrong 97 | environment may raise errors in the future if the build sizes become too 98 | large. 99 | - The `platform` to be used (Within PlatformIO a development platform is 100 | described as "a particular microcontroller or processor architecture that 101 | PlatformIO projects can be compiled to run on. (A few platforms, for example 102 | Teensy, use different target architectures for different boards.)" 103 | - The `framework` we will use for development (For the Teensy we use 104 | `arduino`. Examples of other frameworks inclue `CMSIS`, `FreeRTOS`, 105 | `STM32Cube`, etc). 106 | - A working `environment` which scopes specific configurations for the tools 107 | `pio run`, `pio test`, `pio check`, `pio debug`, and any custom targets 108 | which may be defined. Our environment re-uses the board name, `teensy41` 109 | and sets this value as the default environment. 110 | - Any 3rd-party libraries we may need (e.g. uSDFS, Ethernet, etc) 111 | - How assets should be flashed to the device (The `teensy-cli` application) 112 | 113 | The configuration file also provides a number of configuration abstractions 114 | where common configurations can be applied project wide or by build environment. 115 | For more information on customizing your configuration or build environment, 116 | consult the [PlatformIO documentation][pio-docs]. 117 | 118 | Next, make any desired edits to the file `src/my_machine.h` 119 | 120 | Begin compilation by running the command: 121 | 122 | ```bash 123 | pio run 124 | ``` 125 | 126 | This will begin the compilation, using the default environment. Alternate 127 | environments may be specified using the flag `-e`/`--environment`. Additional 128 | targets may be viewed by running `pio run --list-targets`. Changing the target 129 | from the default (compilation) can be done using the flag `-t`/`--target` 130 | (e.g. `pio run -t clean`). 131 | 132 | As the compilation begins all of the needed tooling and libraries will be 133 | retrieved. Tooling will be installed to the user's "global" PlatformIO 134 | installation. Project specific libraries will be stored in the subdirectory 135 | `.pio`. The `.pio` directory is solely used for temporary build artifacts and 136 | caching libraries. It is safe to completely remove and will be re-created on 137 | the next execution of `pio run`. 138 | 139 | At the end of compilation, two assets will be generated: 140 | - `.pio/build/teensy41/firmware.elf` 141 | - `.pio/build/teensy41/firmware.hex` 142 | 143 | Our ELF ([Executable and Linkable Format][elf]) binary contains the full set of 144 | headers desribing our program and section headers. Our HEX file is the binary 145 | rendering of solely the data section of the ELF file. The HEX file is the one 146 | used by the default Teensy tooling. The ELF file is useful when performing 147 | debugging (i.e. through the use of `gdb` or `openocd`). 148 | 149 | We may use the target `upload` to flash our new firmware. The default 150 | project-specific configuration in `platformio.ini` utilizes the Teensy CLI 151 | application. A complete list of supported upload protocols for the Teensy 4.1 152 | (e.g. `teensy-gui`, `jlink`) can be referenced on the [Teensy 4.1][pio-teensy41] 153 | page in the PlatformIO documentation. 154 | 155 | To execute our upload, run the following command: 156 | 157 | ```bash 158 | pio run -t upload 159 | ``` 160 | 161 | Congratulations! You should now have a newly flashed Teensy running grblHAL! 162 | 163 | ##### Updating your check-out 164 | 165 | To update your checkout in the future, ensure that all git submodules are 166 | updates along with the primary repository: 167 | 168 | ```bash 169 | git pull --recurse-submodules 170 | ``` 171 | 172 | [elf]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format 173 | [Marlin]: https://github.com/MarlinFirmware/Marlin/ 174 | [PlatformIO]: https://www.platformio.org 175 | [pio-docs]: https://docs.platformio.org/en/latest/ 176 | [pio-teensy41]: https://docs.platformio.org/en/latest/boards/teensy/teensy41.html 177 | 178 | --- 179 | 2023-09-20 180 | 181 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/driver.h: -------------------------------------------------------------------------------- 1 | /* 2 | driver.h - driver code for IMXRT1062 processor (on Teensy 4.x board) 3 | 4 | Part of grblHAL 5 | 6 | Copyright (c) 2020-2025 Terje Io 7 | 8 | grblHAL is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | grblHAL is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with grblHAL. If not, see . 20 | */ 21 | 22 | // 23 | // NOTE: do NOT change configuration here - edit my_machine.h instead! 24 | // 25 | 26 | #ifndef __DRIVER_H__ 27 | #define __DRIVER_H__ 28 | 29 | #include "imxrt.h" 30 | #include "core_pins.h" 31 | #include "pins_arduino.h" 32 | 33 | #ifndef OVERRIDE_MY_MACHINE 34 | #include "my_machine.h" 35 | #endif 36 | 37 | #if MODBUS_ENABLE & 0b100 // Modbus TCP 38 | #undef ETHERNET_ENABLE 39 | #define ETHERNET_ENABLE 1 40 | #endif 41 | 42 | #if WEBUI_ENABLE 43 | #ifdef WEBUI_INFLASH 44 | #undef WEBUI_INFLASH 45 | #endif 46 | #if !defined(LITTLEFS_ENABLE) || LITTLEFS_ENABLE == 0 47 | #undef LITTLEFS_ENABLE 48 | #define LITTLEFS_ENABLE 1 49 | #endif 50 | #define WEBUI_INFLASH 1 51 | #endif 52 | 53 | #define SDCARD_SDIO 1 54 | 55 | #include "grbl/driver_opts.h" 56 | 57 | #define DIGITAL_IN(gpio) (!!(gpio.reg->DR & gpio.bit)) 58 | #define DIGITAL_OUT(gpio, on) { if(on) gpio.reg->DR_SET = gpio.bit; else gpio.reg->DR_CLEAR = gpio.bit; } 59 | 60 | #define timer(t) timerN(t) 61 | #define timerN(t) TMR ## t 62 | #define timerINT(t) timerint(t) 63 | #define timerint(t) IRQ_QTIMER ## t 64 | #define timerENABLE(t) timerena(t) 65 | #define timerena(t) TMR ## t ## _ENBL 66 | #define timerCTRL(t, n) timerctrl(t, n) 67 | #define timerctrl(t, n) TMR ## t ## _CTRL ## n 68 | #define timerCMPLD1(t, n) timercmpld1(t, n) 69 | #define timercmpld1(t, n) TMR ## t ## _CMPLD1 ## n 70 | #define timerCOMP1(t, n) timercomp1(t, n) 71 | #define timercomp1(t, n) TMR ## t ## _COMP1 ## n 72 | #define timerCOMP2(t, n) timercomp2(t, n) 73 | #define timercomp2(t, n) TMR ## t ## _COMP2 ## n 74 | #define timerSCTRL(t, n) timersctrl(t, n) 75 | #define timersctrl(t, n) (TMR ## t ## _SCTRL ## n) 76 | #define timerCSCTRL(t, n) timercsctrl(t, n) 77 | #define timercsctrl(t, n) (TMR ## t ## _CSCTRL ## n) 78 | #define timerLOAD(t, n) timerload(t, n) 79 | #define timerload(t, n) TMR ## t ## _LOAD ## n 80 | 81 | #define PULSE_TIMER_N 4 82 | #define PULSE_TIMER timer(PULSE_TIMER_N) 83 | #define PULSE_TIMER_ENABLE timerENABLE(PULSE_TIMER_N) 84 | #define PULSE_TIMER_CTRL timerCTRL(PULSE_TIMER_N, 0) 85 | #define PULSE_TIMER_CSCTRL timerCSCTRL(PULSE_TIMER_N, 0) 86 | #define PULSE_TIMER_COMP1 timerCOMP1(PULSE_TIMER_N, 0) 87 | #define PULSE_TIMER_LOAD timerLOAD(PULSE_TIMER_N, 0) 88 | #define PULSE_TIMER_IRQ timerINT(PULSE_TIMER_N) 89 | 90 | // Other timer assignments (for reference) 91 | 92 | //#define STEPPER_TIMER PIT0 (32 bit) 93 | 94 | // Timers used for spindle encoder if spindle sync is enabled: 95 | //#define RPM_TIMER GPT1 96 | //#define RPM_COUNTER GPT2 97 | 98 | #ifndef CONTROL_ENABLE 99 | #define CONTROL_ENABLE (CONTROL_HALT|CONTROL_FEED_HOLD|CONTROL_CYCLE_START) 100 | #endif 101 | 102 | #ifdef BOARD_CNC_BOOSTERPACK 103 | #include "boards/cnc_boosterpack_map.h" 104 | #elif defined(BOARD_T40X101) 105 | #include "boards/T40X101_map.h" 106 | #elif defined(BOARD_T41U5XBB) 107 | #include "boards/T41U5XBB_map.h" 108 | #elif defined(BOARD_T41U5XBB_SS) 109 | #include "boards/T41U5XBB_ss_map.h" 110 | #elif defined(BOARD_T41BB5X_PRO) 111 | #include "boards/T41BB5X_Pro_map.h" 112 | #elif defined(BOARD_GRBLHAL2000) 113 | #include "boards/GRBLHAL2000_map.h" 114 | #elif defined(BOARD_E5XMCS_T41) 115 | #include "boards/E5XMCS_T41_map.h" 116 | #elif defined(BOARD_MY_MACHINE) 117 | #include "boards/my_machine_map.h" 118 | #else // default board 119 | #include "boards/generic_map.h" 120 | #endif 121 | 122 | #if SPINDLE_PWM_PIN && !(SPINDLE_PWM_PIN == 12 || SPINDLE_PWM_PIN == 13) 123 | #error "SPINDLE_PWM_PIN can only be routed to pin 12 or 13!" 124 | #endif 125 | 126 | #if STEP_INJECT_ENABLE && PPI_ENABLE 127 | #error "Plasma and PPI mode cannot be enabled at the same time!" 128 | #endif 129 | 130 | #ifndef SERIAL_PORT 131 | #define SERIAL_PORT 6 132 | #endif 133 | 134 | #include "grbl/driver_opts2.h" 135 | 136 | #if STEP_INJECT_ENABLE 137 | 138 | #if SPINDLE_PWM_PIN == 12 139 | #define PULSE2_TIMER_N 2 140 | #else 141 | #define PULSE2_TIMER_N 1 142 | #endif 143 | #define PULSE2_TIMER timer(PULSE2_TIMER_N) 144 | #define PULSE2_TIMER_ENABLE timerENABLE(PULSE2_TIMER_N) 145 | #define PULSE2_TIMER_CTRL timerCTRL(PULSE2_TIMER_N, 0) 146 | #define PULSE2_TIMER_CSCTRL timerCSCTRL(PULSE2_TIMER_N, 0) 147 | #define PULSE2_TIMER_COMP1 timerCOMP1(PULSE2_TIMER_N, 0) 148 | #define PULSE2_TIMER_LOAD timerLOAD(PULSE2_TIMER_N, 0) 149 | #define PULSE2_TIMER_IRQ timerINT(PULSE2_TIMER_N) 150 | 151 | #endif 152 | 153 | #if PPI_ENABLE 154 | 155 | #if SPINDLE_PWM_PIN == 12 156 | #define PPI_TIMER_N 2 157 | #else 158 | #define PPI_TIMER_N 1 159 | #endif 160 | #define PPI_TIMER timer(PPI_TIMER_N) 161 | #define PPI_TIMER_ENABLE timerENABLE(PPI_TIMER_N) 162 | #define PPI_TIMER_CTRL timerCTRL(PPI_TIMER_N, 0) 163 | #define PPI_TIMER_CSCTRL timerCSCTRL(PPI_TIMER_N, 0) 164 | #define PPI_TIMER_COMP1 timerCOMP1(PPI_TIMER_N, 0) 165 | #define PPI_TIMER_LOAD timerLOAD(PPI_TIMER_N, 0) 166 | #define PPI_TIMER_IRQ timerINT(PPI_TIMER_N) 167 | 168 | #endif 169 | 170 | #if SPINDLE_PWM_PIN == 12 171 | #define SPINDLE_PWM_TIMER_N 1 172 | #define SPINDLE_PWM_TIMER_C 1 173 | #else 174 | #define SPINDLE_PWM_TIMER_N 2 175 | #define SPINDLE_PWM_TIMER_C 0 176 | #endif 177 | #define SPINDLE_PWM_TIMER timer(SPINDLE_PWM_TIMER_N) 178 | #define SPINDLE_PWM_TIMER_ENABLE timerENABLE(SPINDLE_PWM_TIMER_N) 179 | #define SPINDLE_PWM_TIMER_CTRL timerCTRL(SPINDLE_PWM_TIMER_N, SPINDLE_PWM_TIMER_C) 180 | #define SPINDLE_PWM_TIMER_SCTRL timerSCTRL(SPINDLE_PWM_TIMER_N, SPINDLE_PWM_TIMER_C) 181 | #define SPINDLE_PWM_TIMER_COMP1 timerCOMP1(SPINDLE_PWM_TIMER_N, SPINDLE_PWM_TIMER_C) 182 | #define SPINDLE_PWM_TIMER_COMP2 timerCOMP2(SPINDLE_PWM_TIMER_N, SPINDLE_PWM_TIMER_C) 183 | #define SPINDLE_PWM_TIMER_CMPLD1 timerCMPLD1(SPINDLE_PWM_TIMER_N, SPINDLE_PWM_TIMER_C) 184 | #define SPINDLE_PWM_TIMER_LOAD timerLOAD(SPINDLE_PWM_TIMER_N, SPINDLE_PWM_TIMER_C) 185 | 186 | // Adjust STEP_PULSE_LATENCY to get accurate step pulse length when required, e.g if using high step rates. 187 | // The default value is calibrated for 5 microseconds length. 188 | // NOTE: step output mode, number of axes and compiler optimization settings may all affect this value. 189 | 190 | // Minimum pulse off time. 191 | #ifndef STEP_PULSE_TOFF_MIN 192 | #define STEP_PULSE_TOFF_MIN 2.0f 193 | #endif 194 | // Time from step out to step reset. 195 | // Adjust for correct step pulse time. 196 | #ifndef STEP_PULSE_LATENCY 197 | #define STEP_PULSE_LATENCY 0.2f // microseconds 198 | #endif 199 | 200 | #ifndef IOPORTS_ENABLE 201 | #define IOPORTS_ENABLE 0 202 | #endif 203 | 204 | #if EEPROM_ENABLE && !defined(EEPROM_IS_FRAM) 205 | #define EEPROM_IS_FRAM 0 206 | #endif 207 | 208 | #if QEI_ENABLE 209 | #include "encoder/encoder.h" 210 | #endif 211 | 212 | #if USB_SERIAL_CDC 213 | #define SP0 1 214 | #else 215 | #define SP0 0 216 | #endif 217 | 218 | #ifndef I2C_PORT 219 | #if EEPROM_ENABLE 220 | #error "EEPROM_ENABLE requires I2C_PORT to be defined!" 221 | #endif 222 | #if I2C_STROBE_ENABLE 223 | #error "KEYPAD_ENABLE requires I2C_PORT to be defined!" 224 | #endif 225 | #endif 226 | 227 | #if QEI_ENABLE > 1 228 | #error "Max number of quadrature interfaces is 1!" 229 | #endif 230 | 231 | #if QEI_ENABLE > 0 && !(defined(QEI_A_PIN) && defined(QEI_B_PIN)) 232 | #error "QEI_ENABLE requires encoder input pins A and B to be defined!" 233 | #endif 234 | 235 | typedef struct { 236 | volatile uint32_t DR; 237 | volatile uint32_t GDIR; 238 | volatile uint32_t PSR; 239 | volatile uint32_t ICR1; 240 | volatile uint32_t ICR2; 241 | volatile uint32_t IMR; 242 | volatile uint32_t ISR; 243 | volatile uint32_t EDGE_SEL; 244 | uint32_t unused[25]; 245 | volatile uint32_t DR_SET; 246 | volatile uint32_t DR_CLEAR; 247 | volatile uint32_t DR_TOGGLE; 248 | } gpio_reg_t; 249 | 250 | typedef struct { 251 | gpio_reg_t *reg; 252 | uint32_t bit; 253 | } gpio_t; 254 | 255 | typedef struct { 256 | pin_function_t id; 257 | pin_cap_t cap; 258 | pin_mode_t mode; 259 | uint8_t pin; 260 | uint32_t bit; 261 | pin_group_t group; 262 | gpio_t *port; 263 | gpio_t gpio; // doubled up for now for speed... 264 | uint8_t offset; 265 | uint8_t user_port; 266 | volatile bool active; 267 | ioport_interrupt_callback_ptr interrupt_callback; 268 | const char *description; 269 | } input_signal_t; 270 | 271 | typedef struct { 272 | pin_function_t id; 273 | gpio_t *port; 274 | uint8_t pin; 275 | pin_group_t group; 276 | pin_mode_t mode; 277 | const char *description; 278 | uint8_t pwm_idx; 279 | } output_signal_t; 280 | 281 | typedef struct { 282 | uint8_t n_pins; 283 | union { 284 | input_signal_t *inputs; 285 | output_signal_t *outputs; 286 | } pins; 287 | } pin_group_pins_t; 288 | 289 | // The following struct is pulled from the Teensy Library core, Copyright (c) 2019 PJRC.COM, LLC. 290 | 291 | typedef struct { 292 | const uint8_t pin; // The pin number 293 | const uint32_t mux_val; // Value to set for mux; 294 | volatile uint32_t *select_reg; // Which register controls the selection 295 | const uint32_t select_val; // Value for that selection 296 | } pin_info_t; 297 | 298 | void pinModeOutput (gpio_t *gpio, uint8_t pin); 299 | void pinEnableIRQ (const input_signal_t *signal, pin_irq_mode_t irq_mode); 300 | uint32_t xTaskGetTickCount(); 301 | 302 | void ioports_init (pin_group_pins_t *aux_inputs, pin_group_pins_t *aux_outputs); 303 | void ioports_init_analog (pin_group_pins_t *aux_inputs, pin_group_pins_t *aux_outputs); 304 | void ioports_event (input_signal_t *input); 305 | 306 | #endif // __DRIVER_H__ 307 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/pwm.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | pwm.c - driver code for iMXRT1062 ARM processor 4 | 5 | Part of grblHAL 6 | 7 | Copyright (c) 2025 Terje Io 8 | 9 | grblHAL is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | grblHAL is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with grblHAL. If not, see . 21 | */ 22 | 23 | #include "pwm.h" 24 | #include "driver.h" 25 | 26 | typedef union { 27 | IMXRT_FLEXPWM_t *flexpwm; 28 | IMXRT_TMR_t *qtimer; 29 | } pwm_periph_t; 30 | 31 | // Code lifted from PJRC and modified, pwm.c 32 | 33 | struct pwm_pin_info_struct { 34 | uint8_t type; // 0=no pwm, 1=flexpwm, 2=quad 35 | uint8_t module; // 0-3, 0-3 36 | uint8_t channel; // 0=X, 1=B, 2=A 37 | uint8_t muxval; // 38 | pwm_periph_t p; 39 | }; 40 | 41 | #define M(a, b) ((((a) - 1) << 4) | (b)) 42 | 43 | PROGMEM const struct pwm_pin_info_struct pwm_pin_infos[] = { 44 | {1, M(1, 1), 0, 4, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_X 0 // AD_B0_03 45 | {1, M(1, 0), 0, 4, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_X 1 // AD_B0_02 46 | {1, M(4, 2), 2, 1, { .flexpwm = &IMXRT_FLEXPWM4 } }, // FlexPWM4_2_A 2 // EMC_04 47 | {1, M(4, 2), 1, 1, { .flexpwm = &IMXRT_FLEXPWM4 } }, // FlexPWM4_2_B 3 // EMC_05 48 | {1, M(2, 0), 2, 1, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_0_A 4 // EMC_06 49 | {1, M(2, 1), 2, 1, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_1_A 5 // EMC_08 50 | {1, M(2, 2), 2, 2, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_2_A 6 // B0_10 51 | {1, M(1, 3), 1, 6, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_3_B 7 // B1_01 52 | {1, M(1, 3), 2, 6, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_3_A 8 // B1_00 53 | {1, M(2, 2), 1, 2, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_2_B 9 // B0_11 54 | {2, M(1, 0), 0, 1, { .qtimer = &IMXRT_TMR1 } }, // QuadTimer1_0 10 // B0_00 55 | {2, M(1, 2), 0, 1, { .qtimer = &IMXRT_TMR1 } }, // QuadTimer1_2 11 // B0_02 56 | {2, M(1, 1), 0, 1, { .qtimer = &IMXRT_TMR1 } }, // QuadTimer1_1 12 // B0_01 57 | {2, M(2, 0), 0, 1, { .qtimer = &IMXRT_TMR2 } }, // QuadTimer2_0 13 // B0_03 58 | {2, M(3, 2), 0, 1, { .qtimer = &IMXRT_TMR3 } }, // QuadTimer3_2 14 // AD_B1_02 59 | {2, M(3, 3), 0, 1, { .qtimer = &IMXRT_TMR3 } }, // QuadTimer3_3 15 // AD_B1_03 60 | {0, M(1, 0), 0, 0}, 61 | {0, M(1, 0), 0, 0}, 62 | {2, M(3, 1), 0, 1, { .qtimer = &IMXRT_TMR3 } }, // QuadTimer3_1 18 // AD_B1_01 63 | {2, M(3, 0), 0, 1, { .qtimer = &IMXRT_TMR3 } }, // QuadTimer3_0 19 // AD_B1_00 64 | {0, M(1, 0), 0, 0}, 65 | {0, M(1, 0), 0, 0}, 66 | {1, M(4, 0), 2, 1, { .flexpwm = &IMXRT_FLEXPWM4 } }, // FlexPWM4_0_A 22 // AD_B1_08 67 | {1, M(4, 1), 2, 1, { .flexpwm = &IMXRT_FLEXPWM4 } }, // FlexPWM4_1_A 23 // AD_B1_09 68 | {1, M(1, 2), 0, 4, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_X 24 // AD_B0_12 69 | {1, M(1, 3), 0, 4, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_3_X 25 // AD_B0_13 70 | {0, M(1, 0), 0, 0}, 71 | {0, M(1, 0), 0, 0}, 72 | {1, M(3, 1), 1, 1, { .flexpwm = &IMXRT_FLEXPWM3 } }, // FlexPWM3_1_B 28 // EMC_32 73 | {1, M(3, 1), 2, 1, { .flexpwm = &IMXRT_FLEXPWM3 } }, // FlexPWM3_1_A 29 // EMC_31 74 | {0, M(1, 0), 0, 0}, 75 | {0, M(1, 0), 0, 0}, 76 | {0, M(1, 0), 0, 0}, 77 | {1, M(2, 0), 1, 1, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_0_B 33 // EMC_07 78 | #ifdef ARDUINO_TEENSY40 79 | {1, M(1, 1), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_B 34 // SD_B0_03 80 | {1, M(1, 1), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_A 35 // SD_B0_02 81 | {1, M(1, 0), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_B 36 // SD_B0_01 82 | {1, M(1, 0), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_A 37 // SD_B0_00 83 | {1, M(1, 2), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_B 38 // SD_B0_05 84 | {1, M(1, 2), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_A 39 // SD_B0_04 85 | #endif 86 | #ifdef ARDUINO_TEENSY41 87 | {0, M(1, 0), 0, 0}, 88 | {0, M(1, 0), 0, 0}, 89 | {1, M(2, 3), 2, 6, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_3_A 36 // B1_00 90 | {1, M(2, 3), 1, 6, { .flexpwm = &IMXRT_FLEXPWM2 } }, // FlexPWM2_3_B 37 // B1_01 91 | {0, M(1, 0), 0, 0}, 92 | {0, M(1, 0), 0, 0}, 93 | {0, M(1, 0), 0, 0}, 94 | {0, M(1, 0), 0, 0}, 95 | {1, M(1, 1), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_B 42 // SD_B0_03 96 | {1, M(1, 1), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_A 43 // SD_B0_02 97 | {1, M(1, 0), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_B 44 // SD_B0_01 98 | {1, M(1, 0), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_A 45 // SD_B0_00 99 | {1, M(1, 2), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_B 46 // SD_B0_05 100 | {1, M(1, 2), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_A 47 // SD_B0_04 101 | {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_0_B 102 | {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_2_A 103 | {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_2_B 104 | {1, M(3, 3), 1, 1, { .flexpwm = &IMXRT_FLEXPWM3 } }, // FlexPWM3_3_B 51 // EMC_22 105 | {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_1_B 106 | {0, M(1, 0), 0, 0}, // duplicate FlexPWM1_1_A 107 | {1, M(3, 0), 2, 1, { .flexpwm = &IMXRT_FLEXPWM3 } }, // FlexPWM3_0_A 54 // EMC_29 108 | #endif 109 | #ifdef ARDUINO_TEENSY_MICROMOD 110 | {1, M(1, 1), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_B 34 // SD_B0_03 111 | {1, M(1, 1), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_1_A 35 // SD_B0_02 112 | {1, M(1, 0), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_B 36 // SD_B0_01 113 | {1, M(1, 0), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_0_A 37 // SD_B0_00 114 | {1, M(1, 2), 2, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_A 38 // SD_B0_04 115 | {1, M(1, 2), 1, 1, { .flexpwm = &IMXRT_FLEXPWM1 } }, // FlexPWM1_2_B 39 // SD_B0_05 116 | {2, M(2, 1), 0, 1, { .qtimer = &IMXRT_TMR2 } }, // QuadTimer2_1 40 // B0_04 117 | {2, M(2, 2), 0, 1, { .qtimer = &IMXRT_TMR2 } }, // QuadTimer2_2 41 // B0_05 118 | {0, M(1, 0), 0, 0}, // duplicate QuadTimer3_0 119 | {0, M(1, 0), 0, 0}, // duplicate QuadTimer3_1 120 | {0, M(1, 0), 0, 0}, // duplicate QuadTimer3_2 121 | {2, M(4, 0), 0, 1, { .qtimer = &IMXRT_TMR4 } }, // QuadTimer4_0 45 // B0_09 122 | #endif 123 | }; 124 | 125 | typedef struct { 126 | const pwm_signal_t *pwm; 127 | } pwm_claimed_t; 128 | 129 | uint_fast8_t n_claimed = 0; 130 | pwm_claimed_t pwm_claimed[5] = {0}; 131 | 132 | FLASHMEM bool pwm_is_available (void *port, uint8_t pin) 133 | { 134 | const struct pwm_pin_info_struct *pwm = NULL; 135 | 136 | if(pin < sizeof(pwm_pin_infos) / sizeof(struct pwm_pin_info_struct) && pwm_pin_infos[pin].type > 0) { 137 | 138 | uint_fast8_t i; 139 | 140 | pwm = &pwm_pin_infos[pin]; 141 | 142 | if(pwm && (i = n_claimed)) do { 143 | i--; 144 | if(pwm == pwm_claimed[i].pwm) 145 | return false; 146 | } while(i); 147 | } 148 | 149 | return pwm != NULL; 150 | } 151 | 152 | FLASHMEM const pwm_signal_t *pwm_claim (void *port, uint8_t pin) 153 | { 154 | const struct pwm_pin_info_struct *pwm = NULL; 155 | 156 | if(pwm_is_available(port, pin)) 157 | pwm_claimed[n_claimed++].pwm = pwm = &pwm_pin_infos[pin]; 158 | 159 | return pwm; 160 | } 161 | 162 | bool pwm_enable (const pwm_signal_t *pwm) 163 | { 164 | return true; 165 | } 166 | 167 | FLASHMEM bool pwm_config (const pwm_signal_t *pwm, uint32_t prescaler, uint32_t period, bool inverted) 168 | { 169 | uint32_t submodule = pwm->module & 0b11, 170 | pin = sizeof(pwm_pin_infos) / sizeof(struct pwm_pin_info_struct); 171 | 172 | do { 173 | if(pwm == &pwm_pin_infos[--pin]) 174 | break; 175 | } while(pin); 176 | 177 | if(pwm->type == 1) { 178 | 179 | switch((uint32_t)pwm->p.flexpwm) { 180 | 181 | case (uint32_t)&IMXRT_FLEXPWM1: 182 | CCM_CCGR4 |= CCM_CCGR4_PWM1(CCM_CCGR_ON); 183 | break; 184 | 185 | case (uint32_t)&IMXRT_FLEXPWM2: 186 | CCM_CCGR4 |= CCM_CCGR4_PWM2(CCM_CCGR_ON); 187 | break; 188 | 189 | case (uint32_t)&IMXRT_FLEXPWM3: 190 | CCM_CCGR4 |= CCM_CCGR4_PWM3(CCM_CCGR_ON); 191 | break; 192 | 193 | case (uint32_t)&IMXRT_FLEXPWM4: 194 | CCM_CCGR4 |= CCM_CCGR4_PWM4(CCM_CCGR_ON); 195 | break; 196 | } 197 | 198 | pwm->p.flexpwm->FCTRL0 = FLEXPWM_FCTRL0_FLVL(15); // logic high = fault 199 | pwm->p.flexpwm->FSTS0 = 0x000F; // clear fault status 200 | pwm->p.flexpwm->FFILT0 = 0; 201 | pwm->p.flexpwm->MCTRL |= FLEXPWM_MCTRL_CLDOK(15); 202 | pwm->p.flexpwm->SM[submodule].CTRL2 = FLEXPWM_SMCTRL2_INDEP | FLEXPWM_SMCTRL2_WAITEN | FLEXPWM_SMCTRL2_DBGEN; 203 | pwm->p.flexpwm->SM[submodule].CTRL = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(prescaler); 204 | pwm->p.flexpwm->SM[submodule].OCTRL = inverted ? (FLEXPWM_SMOCTRL_POLX << pwm->channel) : 0; 205 | pwm->p.flexpwm->SM[submodule].DTCNT0 = 0; 206 | pwm->p.flexpwm->SM[submodule].INIT = 0; 207 | pwm->p.flexpwm->SM[submodule].VAL0 = 0; 208 | pwm->p.flexpwm->SM[submodule].VAL1 = period; 209 | pwm->p.flexpwm->SM[submodule].VAL2 = 0; 210 | pwm->p.flexpwm->SM[submodule].VAL3 = 0; 211 | pwm->p.flexpwm->SM[submodule].VAL4 = 0; 212 | pwm->p.flexpwm->SM[submodule].VAL5 = 0; 213 | pwm->p.flexpwm->MCTRL |= FLEXPWM_MCTRL_LDOK(1 << submodule); 214 | pwm->p.flexpwm->MCTRL |= FLEXPWM_MCTRL_RUN(15); 215 | 216 | *(portConfigRegister(pin)) = pwm->muxval; 217 | 218 | } else if(pwm->type == 2) { 219 | 220 | pwm->p.qtimer->CH[submodule].CTRL = 0; 221 | pwm->p.qtimer->CH[submodule].SCTRL = inverted ? (TMR_SCTRL_OEN|TMR_SCTRL_FORCE|TMR_SCTRL_VAL|TMR_SCTRL_OPS) : (TMR_SCTRL_OEN|TMR_SCTRL_FORCE|TMR_SCTRL_VAL); 222 | pwm->p.qtimer->CH[submodule].LOAD = 0; 223 | pwm->p.qtimer->CH[submodule].COMP1 = period; 224 | pwm->p.qtimer->CH[submodule].CMPLD1 = period; 225 | pwm->p.qtimer->CH[submodule].CTRL = TMR_CTRL_CM(0b001) | TMR_CTRL_PCS(prescaler) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(0b100); 226 | pwm->p.qtimer->ENBL |= 1 << submodule; 227 | 228 | *(portConfigRegister(pin)) = pwm->muxval; 229 | } 230 | 231 | return pwm->type != 0; 232 | } 233 | 234 | bool pwm_out (const pwm_signal_t *pwm, uint32_t pwm_value) 235 | { 236 | uint32_t submodule = pwm->module & 0b11; 237 | 238 | if(pwm->type == 1) { 239 | 240 | pwm->p.flexpwm->MCTRL |= FLEXPWM_MCTRL_CLDOK(1 << submodule); 241 | 242 | switch(pwm->channel) { 243 | 244 | case 0: // X 245 | pwm->p.flexpwm->SM[submodule].VAL0 = pwm->p.flexpwm->SM[submodule].VAL1 - pwm_value; 246 | pwm->p.flexpwm->OUTEN |= FLEXPWM_OUTEN_PWMX_EN(1 << submodule); 247 | break; 248 | 249 | case 1: // B 250 | pwm->p.flexpwm->SM[submodule].VAL5 = pwm_value; 251 | pwm->p.flexpwm->OUTEN |= FLEXPWM_OUTEN_PWMB_EN(1 << submodule); 252 | break; 253 | 254 | case 2: // A 255 | pwm->p.flexpwm->SM[submodule].VAL3 = pwm_value; 256 | pwm->p.flexpwm->OUTEN |= FLEXPWM_OUTEN_PWMA_EN(1 << submodule); 257 | break; 258 | } 259 | 260 | pwm->p.flexpwm->MCTRL |= FLEXPWM_MCTRL_LDOK(1 << submodule); 261 | 262 | } else if(pwm->type == 2) { 263 | 264 | pwm->p.qtimer->CH[submodule].COMP2 = pwm_value; 265 | pwm->p.qtimer->CH[submodule].CMPLD1 = pwm->p.qtimer->CH[submodule].COMP1 - pwm_value; 266 | pwm->p.qtimer->CH[submodule].CTRL |= TMR_CTRL_CM(0b001); 267 | } 268 | 269 | return pwm->type != 0; 270 | } 271 | 272 | uint32_t pwm_get_clock_hz (const pwm_signal_t *pwm) 273 | { 274 | return F_BUS_ACTUAL; 275 | } 276 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/.settings/org.eclipse.cdt.codan.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.cdt.codan.checkers.errnoreturn=Warning 3 | org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return\\")",implicit\=>false} 4 | org.eclipse.cdt.codan.checkers.errreturnvalue=Error 5 | org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused return value\\")"} 6 | org.eclipse.cdt.codan.checkers.nocommentinside=-Error 7 | org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Nesting comments\\")"} 8 | org.eclipse.cdt.codan.checkers.nolinecomment=-Error 9 | org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Line comments\\")"} 10 | org.eclipse.cdt.codan.checkers.noreturn=Error 11 | org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No return value\\")",implicit\=>false} 12 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error 13 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Abstract class cannot be instantiated\\")"} 14 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error 15 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Ambiguous problem\\")"} 16 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning 17 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment in condition\\")"} 18 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error 19 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Assignment to itself\\")"} 20 | org.eclipse.cdt.codan.internal.checkers.CStyleCastProblem=-Warning 21 | org.eclipse.cdt.codan.internal.checkers.CStyleCastProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"C-Style cast instead of C++ cast\\")"} 22 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning 23 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"No break at end of case\\")",no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false,enable_fallthrough_quickfix_param\=>false} 24 | org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning 25 | org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Catching by reference is recommended\\")",unknown\=>false,exceptions\=>()} 26 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error 27 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Circular inheritance\\")"} 28 | org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning 29 | org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class members should be properly initialized\\")",skip\=>true} 30 | org.eclipse.cdt.codan.internal.checkers.CopyrightProblem=-Warning 31 | org.eclipse.cdt.codan.internal.checkers.CopyrightProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Lack of copyright information\\")",regex\=>".*Copyright.*"} 32 | org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem=Error 33 | org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid 'decltype(auto)' specifier\\")"} 34 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error 35 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Field cannot be resolved\\")"} 36 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error 37 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Function cannot be resolved\\")"} 38 | org.eclipse.cdt.codan.internal.checkers.GotoStatementProblem=-Warning 39 | org.eclipse.cdt.codan.internal.checkers.GotoStatementProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Goto statement used\\")"} 40 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error 41 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid arguments\\")"} 42 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error 43 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid template argument\\")"} 44 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error 45 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Label statement not found\\")"} 46 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error 47 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Member declaration not found\\")"} 48 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error 49 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Method cannot be resolved\\")"} 50 | org.eclipse.cdt.codan.internal.checkers.MissCaseProblem=-Warning 51 | org.eclipse.cdt.codan.internal.checkers.MissCaseProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing cases in switch\\")"} 52 | org.eclipse.cdt.codan.internal.checkers.MissDefaultProblem=-Warning 53 | org.eclipse.cdt.codan.internal.checkers.MissDefaultProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing default in switch\\")",defaultWithAllEnums\=>false} 54 | org.eclipse.cdt.codan.internal.checkers.MissReferenceProblem=-Warning 55 | org.eclipse.cdt.codan.internal.checkers.MissReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing reference return value in assignment operator\\")"} 56 | org.eclipse.cdt.codan.internal.checkers.MissSelfCheckProblem=-Warning 57 | org.eclipse.cdt.codan.internal.checkers.MissSelfCheckProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Missing self check in assignment operator\\")"} 58 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info 59 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Name convention for function\\")",pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} 60 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning 61 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Class has a virtual method and non-virtual destructor\\")"} 62 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error 63 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid overload\\")"} 64 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error 65 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redeclaration\\")"} 66 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error 67 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Invalid redefinition\\")"} 68 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning 69 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Return with parenthesis\\")"} 70 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning 71 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Format String Vulnerability\\")"} 72 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning 73 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Statement has no effect\\")",macro\=>true,exceptions\=>()} 74 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning 75 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suggested parenthesis around expression\\")",paramNot\=>false} 76 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning 77 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Suspicious semicolon\\")",else\=>false,afterelse\=>false} 78 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error 79 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Type cannot be resolved\\")"} 80 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning 81 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused function declaration\\")",macro\=>true} 82 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning 83 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused static function\\")",macro\=>true} 84 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning 85 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Unused variable declaration in file scope\\")",macro\=>true,exceptions\=>("@(\#)","$Id")} 86 | org.eclipse.cdt.codan.internal.checkers.UsingInHeaderProblem=-Warning 87 | org.eclipse.cdt.codan.internal.checkers.UsingInHeaderProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Using directive in header\\")"} 88 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error 89 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Symbol is not resolved\\")"} 90 | org.eclipse.cdt.codan.internal.checkers.VirtualMethodCallProblem=-Error 91 | org.eclipse.cdt.codan.internal.checkers.VirtualMethodCallProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>"@suppress(\\"Virtual method call in constructor/destructor\\")"} 92 | org.eclipse.cdt.qt.core.qtproblem=Warning 93 | org.eclipse.cdt.qt.core.qtproblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_ON_FILE_OPEN\=>true,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},suppression_comment\=>null} 94 | -------------------------------------------------------------------------------- /grblHAL_Teensy4/src/i2c.c: -------------------------------------------------------------------------------- 1 | /* 2 | i2c.c - driver code for IMXRT1062 processor (on Teensy 4.0 board) 3 | 4 | Part of grblHAL 5 | 6 | Some parts of this code is Copyright (c) 2020-2025 Terje Io 7 | 8 | Some parts are derived/pulled from WireIMXRT.cpp in the Teensyduino Core Library (no copyright header) 9 | 10 | */ 11 | 12 | #include "driver.h" 13 | 14 | #ifdef I2C_PORT 15 | 16 | #include 17 | 18 | #include "i2c.h" 19 | 20 | #if EEPROM_ENABLE 21 | #include "eeprom/eeprom.h" 22 | #endif 23 | 24 | #define i2cIsBusy (!(i2c.state == I2CState_Idle || i2c.state == I2CState_Error) || (port->MSR & (LPI2C_MSR_BBF|LPI2C_MSR_MBF))) 25 | 26 | // Timeout if a device stretches SCL this long, in microseconds 27 | #define CLOCK_STRETCH_TIMEOUT 15000 28 | #define PINCONFIG (IOMUXC_PAD_ODE | IOMUXC_PAD_SRE | IOMUXC_PAD_DSE(4) | IOMUXC_PAD_SPEED(1) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3)) 29 | 30 | typedef struct { 31 | volatile uint32_t *clock_gate_register; 32 | uint32_t clock_gate_mask; 33 | pin_info_t sda_pin; 34 | pin_info_t scl_pin; 35 | IMXRT_LPI2C_t *port; 36 | enum IRQ_NUMBER_t irq; 37 | } i2c_hardware_t; 38 | 39 | #if I2C_PORT == 0 40 | 41 | #define SCL_PIN 19 42 | #define SDA_PIN 18 43 | 44 | PROGMEM static const i2c_hardware_t i2c1_hardware = { 45 | .clock_gate_register = &CCM_CCGR2, 46 | .clock_gate_mask = CCM_CCGR2_LPI2C1(CCM_CCGR_ON), 47 | .port = &IMXRT_LPI2C1, 48 | .irq = IRQ_LPI2C1, 49 | .sda_pin = { 50 | .pin = SDA_PIN, 51 | .mux_val = 3 | 0x10, 52 | .select_reg = &IOMUXC_LPI2C1_SDA_SELECT_INPUT, 53 | .select_val = 1 54 | }, 55 | .scl_pin = { 56 | .pin = SCL_PIN, 57 | .mux_val = 3 | 0x10, 58 | .select_reg = &IOMUXC_LPI2C1_SCL_SELECT_INPUT, 59 | .select_val = 1 60 | } 61 | }; 62 | 63 | #elif I2C_PORT == 3 64 | 65 | #define SCL_PIN 17 66 | #define SDA_PIN 16 67 | 68 | // NOTE: port 3 has alternative mapping to pin 36 and 37 69 | PROGMEM static const i2c_hardware_t i2c3_hardware = { 70 | .clock_gate_register = &CCM_CCGR2, 71 | .clock_gate_mask = CCM_CCGR2_LPI2C3(CCM_CCGR_ON), 72 | .port = &IMXRT_LPI2C3, 73 | .irq = IRQ_LPI2C3, 74 | .sda_pin = { 75 | .pin = SDA_PIN, 76 | .mux_val = 1 | 0x10, 77 | .select_reg = &IOMUXC_LPI2C3_SDA_SELECT_INPUT, 78 | .select_val = 1 79 | }, 80 | .scl_pin = { 81 | .pin = SCL_PIN, 82 | .mux_val = 1 | 0x10, 83 | .select_reg = &IOMUXC_LPI2C3_SCL_SELECT_INPUT, 84 | .select_val = 1 85 | } 86 | }; 87 | 88 | #elif I2C_PORT == 4 89 | 90 | #define SCL_PIN 24 91 | #define SDA_PIN 25 92 | 93 | PROGMEM static const i2c_hardware_t i2c4_hardware = { 94 | .clock_gate_register = &CCM_CCGR6, 95 | .clock_gate_mask = CCM_CCGR6_LPI2C4_SERIAL(CCM_CCGR_ON), 96 | .port = &IMXRT_LPI2C4, 97 | .irq = IRQ_LPI2C4, 98 | .sda_pin = { 99 | .pin = SDA_PIN, 100 | .mux_val = 0 | 0x10, 101 | .select_reg = &IOMUXC_LPI2C4_SDA_SELECT_INPUT, 102 | .select_val = 1 103 | }, 104 | .scl_pin = { 105 | .pin = SCL_PIN, 106 | .mux_val = 0 | 0x10, 107 | .select_reg = &IOMUXC_LPI2C4_SCL_SELECT_INPUT, 108 | .select_val = 1 109 | } 110 | }; 111 | 112 | #endif 113 | 114 | FLASHMEM static bool force_clock (const i2c_hardware_t *hardware) 115 | { 116 | bool ret = false; 117 | uint32_t sda_pin = hardware->sda_pin.pin; 118 | uint32_t scl_pin = hardware->scl_pin.pin; 119 | uint32_t sda_mask = digitalPinToBitMask(sda_pin); 120 | uint32_t scl_mask = digitalPinToBitMask(scl_pin); 121 | // take control of pins with GPIO 122 | *portConfigRegister(sda_pin) = 5 | 0x10; 123 | *portSetRegister(sda_pin) = sda_mask; 124 | *portModeRegister(sda_pin) |= sda_mask; 125 | *portConfigRegister(scl_pin) = 5 | 0x10; 126 | *portSetRegister(scl_pin) = scl_mask; 127 | *portModeRegister(scl_pin) |= scl_mask; 128 | delayMicroseconds(10); 129 | for (int i=0; i < 9; i++) { 130 | if ((*portInputRegister(sda_pin) & sda_mask) && (*portInputRegister(scl_pin) & scl_mask)) { 131 | // success, both pins are high 132 | ret = true; 133 | break; 134 | } 135 | *portClearRegister(scl_pin) = scl_mask; 136 | delayMicroseconds(5); 137 | *portSetRegister(scl_pin) = scl_mask; 138 | delayMicroseconds(5); 139 | } 140 | // return control of pins to I2C 141 | *(portConfigRegister(sda_pin)) = hardware->sda_pin.mux_val; 142 | *(portConfigRegister(scl_pin)) = hardware->scl_pin.mux_val; 143 | 144 | return ret; 145 | } 146 | 147 | FLASHMEM static void set_clock (IMXRT_LPI2C_t *port, uint32_t frequency) 148 | { 149 | port->MCR = 0; 150 | 151 | if (frequency < 400000) { 152 | // 100 kHz 153 | port->MCCR0 = LPI2C_MCCR0_CLKHI(55) | LPI2C_MCCR0_CLKLO(59) | LPI2C_MCCR0_DATAVD(25) | LPI2C_MCCR0_SETHOLD(40); 154 | port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(1); 155 | port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(5) | LPI2C_MCFGR2_FILTSCL(5) | LPI2C_MCFGR2_BUSIDLE(3000); // idle timeout 250 us 156 | port->MCFGR3 = LPI2C_MCFGR3_PINLOW(CLOCK_STRETCH_TIMEOUT * 12 / 256 + 1); 157 | } else if (frequency < 1000000) { 158 | // 400 kHz 159 | port->MCCR0 = LPI2C_MCCR0_CLKHI(26) | LPI2C_MCCR0_CLKLO(28) | LPI2C_MCCR0_DATAVD(12) | LPI2C_MCCR0_SETHOLD(18); 160 | port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(0); 161 | port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(2) | LPI2C_MCFGR2_FILTSCL(2) | LPI2C_MCFGR2_BUSIDLE(3600); // idle timeout 150 us 162 | port->MCFGR3 = LPI2C_MCFGR3_PINLOW(CLOCK_STRETCH_TIMEOUT * 24 / 256 + 1); 163 | } else { 164 | // 1 MHz 165 | port->MCCR0 = LPI2C_MCCR0_CLKHI(9) | LPI2C_MCCR0_CLKLO(10) | LPI2C_MCCR0_DATAVD(4) | LPI2C_MCCR0_SETHOLD(7); 166 | port->MCFGR1 = LPI2C_MCFGR1_PRESCALE(0); 167 | port->MCFGR2 = LPI2C_MCFGR2_FILTSDA(1) | LPI2C_MCFGR2_FILTSCL(1) | LPI2C_MCFGR2_BUSIDLE(2400); // idle timeout 100 us 168 | port->MCFGR3 = LPI2C_MCFGR3_PINLOW(CLOCK_STRETCH_TIMEOUT * 24 / 256 + 1); 169 | } 170 | port->MCCR1 = port->MCCR0; 171 | port->MCFGR0 = 0; 172 | port->MFCR = LPI2C_MFCR_RXWATER(0) | LPI2C_MFCR_TXWATER(1); 173 | port->MCR = LPI2C_MCR_MEN; 174 | } 175 | 176 | typedef enum { 177 | I2CState_Idle = 0, 178 | I2CState_Restart, 179 | I2CState_SendAddr, 180 | I2CState_SendNext, 181 | I2CState_SendLast, 182 | I2CState_AwaitCompletion, 183 | I2CState_ReceiveNext, 184 | I2CState_ReceiveNextToLast, 185 | I2CState_ReceiveLast, 186 | I2CState_Poll, 187 | I2CState_Error 188 | } i2c_state_t; 189 | 190 | typedef struct { 191 | volatile i2c_state_t state; 192 | uint8_t addr; 193 | volatile uint16_t count; 194 | volatile uint16_t rcount; 195 | volatile uint8_t acount; 196 | uint8_t *data; 197 | uint8_t regaddr[2]; 198 | keycode_callback_ptr keycode_callback; 199 | uint8_t buffer[8]; 200 | } i2c_trans_t; 201 | 202 | static i2c_trans_t i2c; 203 | static uint8_t tx_fifo_size; 204 | static const i2c_hardware_t *hardware; 205 | static IMXRT_LPI2C_t *port = NULL; 206 | 207 | static void I2C_interrupt_handler (void); 208 | 209 | FLASHMEM i2c_cap_t i2c_start (void) 210 | { 211 | static i2c_cap_t cap = {}; 212 | 213 | if(!cap.started) { 214 | 215 | #ifndef I2C_PORT 216 | #error "I2C port is undefined!" 217 | #endif 218 | 219 | #if I2C_PORT == 0 220 | hardware = &i2c1_hardware; 221 | #elif I2C_PORT == 3 222 | hardware = &i2c3_hardware; 223 | #elif I2C_PORT == 4 224 | hardware = &i2c4_hardware; 225 | #else 226 | #error "No such I2C port!" 227 | #endif 228 | 229 | port = hardware->port; 230 | tx_fifo_size = 1 << (port->PARAM & 0b1111); 231 | 232 | CCM_CSCDR2 = (CCM_CSCDR2 & ~CCM_CSCDR2_LPI2C_CLK_PODF(63)) | CCM_CSCDR2_LPI2C_CLK_SEL; 233 | *hardware->clock_gate_register |= hardware->clock_gate_mask; 234 | port->MCR = LPI2C_MCR_RST; 235 | 236 | set_clock(port, 100000); 237 | 238 | // Setup SDA register 239 | *(portControlRegister(hardware->sda_pin.pin)) = PINCONFIG; 240 | *(portConfigRegister(hardware->sda_pin.pin)) = hardware->sda_pin.mux_val; 241 | *(hardware->sda_pin.select_reg) = hardware->sda_pin.select_val; 242 | 243 | // setup SCL register 244 | *(portControlRegister(hardware->scl_pin.pin)) = PINCONFIG; 245 | *(portConfigRegister(hardware->scl_pin.pin)) = hardware->scl_pin.mux_val; 246 | *(hardware->scl_pin.select_reg) = hardware->scl_pin.select_val; 247 | 248 | attachInterruptVector(hardware->irq, I2C_interrupt_handler); 249 | 250 | NVIC_SET_PRIORITY(hardware->irq, 1); 251 | NVIC_ENABLE_IRQ(hardware->irq); 252 | 253 | static const periph_pin_t scl = { 254 | .function = Output_SCK, 255 | .group = PinGroup_I2C, 256 | .pin = SCL_PIN, 257 | .mode = { .mask = PINMODE_OD } 258 | }; 259 | 260 | static const periph_pin_t sda = { 261 | .function = Bidirectional_SDA, 262 | .group = PinGroup_I2C, 263 | .pin = SDA_PIN, 264 | .mode = { .mask = PINMODE_OD } 265 | }; 266 | 267 | hal.periph_port.register_pin(&scl); 268 | hal.periph_port.register_pin(&sda); 269 | 270 | cap.started = cap.tx_non_blocking = On; 271 | } 272 | 273 | return cap; 274 | } 275 | 276 | // wait until ready for transfer, try peripheral reset if bus hangs 277 | inline static bool wait_ready (void) 278 | { 279 | while(i2cIsBusy) { 280 | if(port->MSR & LPI2C_MSR_PLTF) { 281 | if(force_clock(hardware)) { 282 | port->MCR = LPI2C_MCR_RST; 283 | set_clock(port, 100000); 284 | } else 285 | return false; 286 | } 287 | } 288 | 289 | return true; 290 | } 291 | 292 | bool i2c_probe (i2c_address_t i2cAddr) 293 | { 294 | bool ok = false; 295 | uint32_t ms, retries = 3; 296 | 297 | do { 298 | 299 | if((ok = wait_ready())) { 300 | 301 | ms = hal.get_elapsed_ticks(); 302 | 303 | port->MSR = 0; 304 | port->MTDR = LPI2C_MTDR_CMD_START|LPI2C_MTDR_CMD_TRANSMIT | (i2cAddr << 1); 305 | 306 | while(hal.get_elapsed_ticks() - ms < 3 && (ok = (port->MSR & (LPI2C_MSR_ALF|LPI2C_MSR_NDF|LPI2C_MSR_PLTF)) == 0)); 307 | 308 | port->MTDR = LPI2C_MTDR_CMD_STOP; 309 | } 310 | 311 | } while(!ok && --retries); 312 | 313 | if(!ok) { 314 | if(force_clock(hardware)) { 315 | port->MCR = LPI2C_MCR_RST; 316 | set_clock(port, 100000); 317 | } 318 | } 319 | 320 | return ok; 321 | } 322 | 323 | // get bytes (max 8 if local buffer, else max 255), waits for result 324 | bool i2c_receive (i2c_address_t i2cAddr, uint8_t *buf, size_t bytes, bool block) 325 | { 326 | i2c.data = buf ? buf : i2c.buffer; 327 | i2c.count = bytes; 328 | i2c.rcount = 0; 329 | i2c.state = bytes == 1 ? I2CState_ReceiveLast : (bytes == 2 ? I2CState_ReceiveNextToLast : I2CState_ReceiveNext); 330 | 331 | port->MSR = 0; 332 | port->MTDR = LPI2C_MTDR_CMD_START | (i2cAddr << 1) | 1; 333 | port->MTDR = LPI2C_MTDR_CMD_RECEIVE | ((uint32_t)i2c.count - 1); 334 | port->MIER = LPI2C_MIER_NDIE|LPI2C_MIER_RDIE; 335 | 336 | if(block) 337 | while(i2cIsBusy); 338 | 339 | return true; 340 | } 341 | 342 | bool i2c_send (i2c_address_t i2cAddr, uint8_t *buf, size_t bytes, bool block) 343 | { 344 | i2c.count = bytes; 345 | i2c.data = buf ? buf : i2c.buffer; 346 | 347 | port->MSR = 0; 348 | port->MTDR = LPI2C_MTDR_CMD_START | (i2cAddr << 1); 349 | 350 | while(i2c.count && (port->MFSR & 0b111) < tx_fifo_size) { 351 | port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | (uint32_t)(*i2c.data++); 352 | i2c.count--; 353 | } 354 | 355 | port->MIER = LPI2C_MIER_NDIE|LPI2C_MIER_TDIE; 356 | 357 | i2c.state = i2c.count == 0 ? I2CState_AwaitCompletion : (i2c.count == 1 ? I2CState_SendLast : I2CState_SendNext); 358 | 359 | if(block) { 360 | while(i2cIsBusy) { 361 | if(bytes == 0) { 362 | hal.delay_ms(2, 0); 363 | if(port->MSR & LPI2C_MSR_PLTF) { 364 | wait_ready(); 365 | i2c.state = I2CState_Error; 366 | } 367 | } 368 | } 369 | } 370 | 371 | return !block || i2c.state != I2CState_Error; 372 | } 373 | 374 | static uint8_t *I2C_ReadRegister (i2c_address_t i2cAddr, uint8_t *buf, uint8_t abytes, uint16_t bytes, bool block) 375 | { 376 | while(i2cIsBusy); 377 | 378 | i2c.addr = i2cAddr; 379 | i2c.count = bytes; 380 | i2c.rcount = 0; 381 | i2c.acount = abytes; 382 | i2c.data = buf ? buf : i2c.buffer; 383 | i2c.state = I2CState_SendAddr; 384 | 385 | port->MSR = 0; 386 | port->MTDR = LPI2C_MTDR_CMD_START | (i2cAddr << 1); 387 | port->MIER = LPI2C_MIER_NDIE|LPI2C_MIER_TDIE; 388 | 389 | if(block) 390 | while(i2cIsBusy); 391 | 392 | return i2c.buffer; 393 | } 394 | 395 | bool i2c_transfer (i2c_transfer_t *transfer, bool read) 396 | { 397 | static uint8_t txbuf[NVS_SIZE + 2]; 398 | 399 | bool ok; 400 | 401 | while(i2cIsBusy); 402 | 403 | if((ok = read)) { 404 | if(transfer->word_addr_bytes == 1) 405 | i2c.regaddr[0] = transfer->word_addr; 406 | else { 407 | i2c.regaddr[0] = transfer->word_addr & 0xFF; 408 | i2c.regaddr[1] = transfer->word_addr >> 8; 409 | } 410 | I2C_ReadRegister(transfer->address, transfer->data, transfer->word_addr_bytes, transfer->count, true); 411 | } else if((ok = transfer->count <= NVS_SIZE)) { 412 | memcpy(&txbuf[transfer->word_addr_bytes], transfer->data, transfer->count); 413 | if(transfer->word_addr_bytes == 1) 414 | txbuf[0] = transfer->word_addr; 415 | else { 416 | txbuf[0] = transfer->word_addr >> 8; 417 | txbuf[1] = transfer->word_addr & 0xFF; 418 | } 419 | i2c_send(transfer->address, txbuf, transfer->count + transfer->word_addr_bytes, !transfer->no_block); 420 | } 421 | 422 | return ok; 423 | } 424 | 425 | bool i2c_get_keycode (i2c_address_t i2cAddr, keycode_callback_ptr callback) 426 | { 427 | bool ok; 428 | 429 | if((ok = wait_ready())) { 430 | i2c.keycode_callback = callback; 431 | i2c_receive(i2cAddr, NULL, 1, false); 432 | } 433 | 434 | return ok; 435 | } 436 | 437 | #if TRINAMIC_ENABLE && TRINAMIC_I2C 438 | 439 | static TMC2130_status_t I2C_TMC_ReadRegister (TMC2130_t *driver, TMC2130_datagram_t *reg) 440 | { 441 | uint8_t *res, i2creg; 442 | TMC2130_status_t status = {0}; 443 | 444 | if((i2creg = TMCI2C_GetMapAddress((uint8_t)(driver ? (uint32_t)driver->cs_pin : 0), reg->addr).value) == 0xFF) 445 | return status; // unsupported register 446 | 447 | while(i2cIsBusy); 448 | 449 | i2c.buffer[0] = i2creg; 450 | i2c.buffer[1] = 0; 451 | i2c.buffer[2] = 0; 452 | i2c.buffer[3] = 0; 453 | i2c.buffer[4] = 0; 454 | 455 | res = I2C_ReadRegister(I2C_ADR_I2CBRIDGE, NULL, 5, true); 456 | 457 | status.value = (uint8_t)*res++; 458 | reg->payload.value = ((uint8_t)*res++ << 24); 459 | reg->payload.value |= ((uint8_t)*res++ << 16); 460 | reg->payload.value |= ((uint8_t)*res++ << 8); 461 | reg->payload.value |= (uint8_t)*res++; 462 | 463 | return status; 464 | } 465 | 466 | static TMC2130_status_t I2C_TMC_WriteRegister (TMC2130_t *driver, TMC2130_datagram_t *reg) 467 | { 468 | TMC2130_status_t status = {0}; 469 | 470 | while(i2cIsBusy); 471 | 472 | reg->addr.write = 1; 473 | i2c.buffer[0] = TMCI2C_GetMapAddress((uint8_t)(driver ? (uint32_t)driver->cs_pin : 0), reg->addr).value; 474 | reg->addr.write = 0; 475 | 476 | if(i2c.buffer[0] == 0xFF) 477 | return status; // unsupported register 478 | 479 | i2c.buffer[1] = (reg->payload.value >> 24) & 0xFF; 480 | i2c.buffer[2] = (reg->payload.value >> 16) & 0xFF; 481 | i2c.buffer[3] = (reg->payload.value >> 8) & 0xFF; 482 | i2c.buffer[4] = reg->payload.value & 0xFF; 483 | 484 | i2c_send(I2C_ADR_I2CBRIDGE, NULL, 5, true); 485 | 486 | return status; 487 | } 488 | 489 | void I2C_DriverInit (TMC_io_driver_t *driver) 490 | { 491 | i2c_init(); 492 | driver->WriteRegister = I2C_TMC_WriteRegister; 493 | driver->ReadRegister = I2C_TMC_ReadRegister; 494 | } 495 | 496 | #endif 497 | 498 | static void I2C_interrupt_handler (void) 499 | { 500 | uint32_t ifg = port->MSR & 0xFFFF; 501 | 502 | port->MSR &= ~ifg; 503 | 504 | if((ifg & port->MIER) == 0) return; 505 | 506 | //if(port->MSR & LPI2C_MSR_MBF) return; 507 | /* 508 | hal.stream.write("I:"); 509 | hal.stream.write(uitoa(ifg)); 510 | hal.stream.write(" "); 511 | hal.stream.write(uitoa(i2c.state)); 512 | hal.stream.write(ASCII_EOL); 513 | */ 514 | if(ifg & LPI2C_MSR_ALF) { 515 | port->MTDR = LPI2C_MTDR_CMD_STOP; 516 | i2c.state = I2CState_Error; 517 | } 518 | 519 | if(ifg & LPI2C_MSR_NDF) 520 | i2c.state = I2CState_Error; 521 | 522 | switch(i2c.state) { 523 | 524 | case I2CState_Idle: 525 | case I2CState_Error: 526 | port->MIER = 0; 527 | port->MCR |= (LPI2C_MCR_RTF|LPI2C_MCR_RRF); 528 | break; 529 | 530 | case I2CState_SendNext: 531 | port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | (uint32_t)(*i2c.data++); 532 | if(--i2c.count == 1) 533 | i2c.state = I2CState_SendLast; 534 | break; 535 | 536 | case I2CState_SendLast: 537 | port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | (uint32_t)(*i2c.data++); 538 | i2c.state = I2CState_AwaitCompletion; 539 | break; 540 | 541 | case I2CState_AwaitCompletion: 542 | port->MIER &= ~LPI2C_MIER_TDIE; 543 | port->MTDR = LPI2C_MTDR_CMD_STOP; 544 | i2c.count = 0; 545 | i2c.state = I2CState_Idle; 546 | break; 547 | 548 | case I2CState_SendAddr: 549 | port->MTDR = LPI2C_MTDR_CMD_TRANSMIT | (uint32_t)(i2c.regaddr[--i2c.acount]); 550 | if(i2c.acount == 0) 551 | i2c.state = I2CState_Restart; 552 | break; 553 | 554 | case I2CState_Restart: 555 | if(port->MIER & LPI2C_MIER_TDIE) { 556 | port->MIER &= ~LPI2C_MIER_TDIE; 557 | port->MIER |= LPI2C_MIER_EPIE; 558 | port->MTDR = LPI2C_MTDR_CMD_START | (i2c.addr << 1) | 1; 559 | } else if(port->MIER & LPI2C_MIER_EPIE) { 560 | port->MIER &= ~LPI2C_MIER_EPIE; 561 | port->MIER |= LPI2C_MIER_RDIE; 562 | port->MTDR = LPI2C_MTDR_CMD_RECEIVE | ((uint32_t)i2c.count - 1); 563 | i2c.state = i2c.count == 1 ? I2CState_ReceiveLast : (i2c.count == 2 ? I2CState_ReceiveNextToLast : I2CState_ReceiveNext); 564 | } 565 | break; 566 | 567 | case I2CState_ReceiveNext: // superfluous, to be removed... 568 | *i2c.data++ = port->MRDR & 0xFF; 569 | if(--i2c.count == 1) { 570 | i2c.state = I2CState_ReceiveLast; 571 | } 572 | ++i2c.rcount; 573 | break; 574 | 575 | case I2CState_ReceiveNextToLast: 576 | *i2c.data++ = port->MRDR & 0xFF; 577 | // port->MTDR = LPI2C_MTDR_CMD_STOP; 578 | i2c.count--; 579 | i2c.state = I2CState_ReceiveLast; 580 | break; 581 | 582 | case I2CState_ReceiveLast: 583 | *i2c.data = port->MRDR & 0xFF; 584 | i2c.count = 0; 585 | i2c.state = I2CState_Idle; 586 | port->MTDR = LPI2C_MTDR_CMD_STOP; 587 | #if KEYPAD_ENABLE == 1 588 | if(i2c.keycode_callback) { 589 | i2c.keycode_callback(*i2c.data); 590 | i2c.keycode_callback = NULL; 591 | } 592 | #endif 593 | break; 594 | 595 | default: 596 | break; 597 | } 598 | } 599 | 600 | #endif 601 | --------------------------------------------------------------------------------