├── 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 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
41 |
44 |
50 |
51 |
52 |
53 |
59 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
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 |
--------------------------------------------------------------------------------